diff options
| author | Martin Owens <doctormo@gmail.com> | 2014-03-27 01:33:44 +0000 |
|---|---|---|
| committer | Martin Owens <doctormo@gmail.com> | 2014-03-27 01:33:44 +0000 |
| commit | 5a4fb2325f60d292b47330f540b26a3279341c90 (patch) | |
| tree | d2aa7967be25450b83e625025366c618101ae49f /src/widgets | |
| parent | The Polar Arrange Tab of the Arrange Dialog now hides the parametric (diff) | |
| parent | Remove Snap menu item and improve grid menu item text (diff) | |
| download | inkscape-5a4fb2325f60d292b47330f540b26a3279341c90.tar.gz inkscape-5a4fb2325f60d292b47330f540b26a3279341c90.zip | |
Commit a merge to trunk, with probabal errors
(bzr r11073.1.36)
Diffstat (limited to 'src/widgets')
100 files changed, 15614 insertions, 12120 deletions
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index 7b76ccc83..fe4433153 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -1,6 +1,25 @@ set(widgets_SRC button.cpp + arc-toolbar.cpp + box3d-toolbar.cpp + calligraphy-toolbar.cpp + connector-toolbar.cpp + dropper-toolbar.cpp + eraser-toolbar.cpp + lpe-toolbar.cpp + measure-toolbar.cpp + mesh-toolbar.cpp + node-toolbar.cpp + paintbucket-toolbar.cpp + pencil-toolbar.cpp + rect-toolbar.cpp + spiral-toolbar.cpp + spray-toolbar.cpp + star-toolbar.cpp + text-toolbar.cpp + tweak-toolbar.cpp + zoom-toolbar.cpp dash-selector.cpp desktop-widget.cpp eek-preview.cpp @@ -17,7 +36,6 @@ set(widgets_SRC select-toolbar.cpp shrink-wrap-button.cpp sp-attribute-widget.cpp - sp-color-gtkselector.cpp sp-color-icc-selector.cpp sp-color-notebook.cpp sp-color-scales.cpp @@ -39,6 +57,25 @@ set(widgets_SRC # ------- # Headers button.h + arc-toolbar.h + box3d-toolbar.h + calligraphy-toolbar.h + connector-toolbar.h + dropper-toolbar.h + eraser-toolbar.h + lpe-toolbar.h + measure-toolbar.h + mesh-toolbar.h + node-toolbar.h + paintbucket-toolbar.h + pencil-toolbar.h + rect-toolbar.h + spiral-toolbar.h + spray-toolbar.h + star-toolbar.h + text-toolbar.h + tweak-toolbar.h + zoom-toolbar.h dash-selector.h desktop-widget.h eek-preview.h @@ -56,7 +93,6 @@ set(widgets_SRC select-toolbar.h shrink-wrap-button.h sp-attribute-widget.h - sp-color-gtkselector.h sp-color-icc-selector.h sp-color-notebook.h sp-color-scales.h diff --git a/src/widgets/Makefile_insert b/src/widgets/Makefile_insert index 255767d43..97713cbee 100644 --- a/src/widgets/Makefile_insert +++ b/src/widgets/Makefile_insert @@ -1,16 +1,28 @@ ## Makefile.am fragment sourced by src/Makefile.am. ink_common_sources += \ + widgets/arc-toolbar.cpp \ + widgets/arc-toolbar.h \ + widgets/box3d-toolbar.cpp \ + widgets/box3d-toolbar.h \ widgets/button.cpp \ widgets/button.h \ + widgets/calligraphy-toolbar.cpp \ + widgets/calligraphy-toolbar.h \ + widgets/connector-toolbar.cpp \ + widgets/connector-toolbar.h \ widgets/dash-selector.cpp \ widgets/dash-selector.h \ widgets/desktop-widget.cpp \ widgets/desktop-widget.h \ + widgets/dropper-toolbar.cpp \ + widgets/dropper-toolbar.h \ widgets/eek-preview.cpp \ widgets/eek-preview.h \ widgets/ege-paint-def.cpp \ widgets/ege-paint-def.h \ + widgets/eraser-toolbar.cpp \ + widgets/eraser-toolbar.h \ widgets/fill-style.cpp \ widgets/fill-style.h \ widgets/fill-n-stroke-factory.h \ @@ -26,18 +38,34 @@ ink_common_sources += \ widgets/gradient-vector.h \ widgets/icon.cpp \ widgets/icon.h \ + widgets/lpe-toolbar.cpp \ + widgets/lpe-toolbar.h \ + widgets/measure-toolbar.cpp \ + widgets/measure-toolbar.h \ + widgets/mesh-toolbar.cpp \ + widgets/mesh-toolbar.h \ + widgets/node-toolbar.cpp \ + widgets/node-toolbar.h \ widgets/paint-selector.cpp \ widgets/paint-selector.h \ + widgets/paintbucket-toolbar.cpp \ + widgets/paintbucket-toolbar.h \ + widgets/pencil-toolbar.cpp \ + widgets/pencil-toolbar.h \ + widgets/rect-toolbar.cpp \ + widgets/rect-toolbar.h \ widgets/ruler.cpp \ widgets/ruler.h \ widgets/select-toolbar.cpp \ widgets/select-toolbar.h \ widgets/shrink-wrap-button.cpp \ widgets/shrink-wrap-button.h \ + widgets/spray-toolbar.cpp \ + widgets/spray-toolbar.h \ + widgets/spiral-toolbar.cpp \ + widgets/spiral-toolbar.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 \ widgets/sp-color-icc-selector.h \ widgets/sp-color-notebook.cpp \ @@ -62,14 +90,23 @@ ink_common_sources += \ widgets/sp-xmlview-content.h \ widgets/sp-xmlview-tree.cpp \ widgets/sp-xmlview-tree.h \ + widgets/star-toolbar.cpp \ + widgets/star-toolbar.h \ widgets/stroke-marker-selector.cpp \ widgets/stroke-marker-selector.h \ widgets/stroke-style.cpp \ widgets/stroke-style.h \ widgets/swatch-selector.cpp \ widgets/swatch-selector.h \ + widgets/text-toolbar.cpp \ + widgets/text-toolbar.h \ widgets/toolbox.cpp \ widgets/toolbox.h \ + widgets/tweak-toolbar.cpp \ + widgets/tweak-toolbar.h \ + widgets/widget-sizes.h \ + widgets/zoom-toolbar.cpp \ + widgets/zoom-toolbar.h \ widgets/widget-sizes.h widgets/button.$(OBJEXT): helper/sp-marshal.h diff --git a/src/widgets/arc-toolbar.cpp b/src/widgets/arc-toolbar.cpp new file mode 100644 index 000000000..ca6810c81 --- /dev/null +++ b/src/widgets/arc-toolbar.cpp @@ -0,0 +1,423 @@ +/** + * @file + * Arc aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glibmm/i18n.h> + +#include "arc-toolbar.h" +#include "desktop-handles.h" +#include "desktop.h" +#include "document-undo.h" +#include "ege-adjustment-action.h" +#include "ege-output-action.h" +#include "ege-select-one-action.h" +#include "ink-action.h" +#include "mod360.h" +#include "preferences.h" +#include "selection.h" +#include "sp-ellipse.h" +#include "toolbox.h" +#include "ui/icon-names.h" +#include "ui/uxmanager.h" +#include "verbs.h" +#include "widgets/spinbutton-events.h" +#include "xml/node-event-vector.h" +#include "xml/repr.h" + +using Inkscape::UI::UXManager; +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; + +//######################## +//## Circle / Arc ## +//######################## + +static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 ) +{ + GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) ); + GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) ); + + if (v1 == 0 && v2 == 0) { + if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now) + gtk_action_set_sensitive( ocb, FALSE ); + gtk_action_set_sensitive( make_whole, FALSE ); + } + } else { + gtk_action_set_sensitive( ocb, TRUE ); + gtk_action_set_sensitive( make_whole, TRUE ); + } +} + +static void +sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + + if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble(Glib::ustring("/tools/shapes/arc/") + value_name, gtk_adjustment_get_value(adj)); + } + + // quit if run by the attr_changed listener + if (g_object_get_data( tbl, "freeze" )) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL); + + bool modmade = false; + for (GSList const *items = sp_desktop_selection(desktop)->itemList(); + items != NULL; + items = items->next) + { + SPItem *item = SP_ITEM(items->data); + + if (SP_IS_GENERICELLIPSE(item)) { + + SPGenericEllipse *ge = SP_GENERICELLIPSE(item); + + if (!strcmp(value_name, "start")) { + ge->start = (gtk_adjustment_get_value(adj) * M_PI)/ 180; + } else { + ge->end = (gtk_adjustment_get_value(adj) * M_PI)/ 180; + } + + ge->normalize(); + (SP_OBJECT(ge))->updateRepr(); + (SP_OBJECT(ge))->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + + modmade = true; + } + } + + g_free(namespaced_name); + + GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) ); + + sp_arctb_sensitivize( tbl, gtk_adjustment_get_value(adj), gtk_adjustment_get_value(other) ); + + if (modmade) { + DocumentUndo::maybeDone(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC, + _("Arc: Change start/end")); + } + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + + +static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + sp_arctb_startend_value_changed(adj, tbl, "start", "end"); +} + +static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + sp_arctb_startend_value_changed(adj, tbl, "end", "start"); +} + + +static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl ) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/shapes/arc/open", ege_select_one_action_get_active(act) != 0); + } + + // quit if run by the attr_changed listener + if (g_object_get_data( tbl, "freeze" )) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + bool modmade = false; + + if ( ege_select_one_action_get_active(act) != 0 ) { + for (GSList const *items = sp_desktop_selection(desktop)->itemList(); + items != NULL; + items = items->next) + { + SPItem *item = reinterpret_cast<SPItem*>(items->data); + if (SP_IS_GENERICELLIPSE(item)) { + Inkscape::XML::Node *repr = item->getRepr(); + repr->setAttribute("sodipodi:open", "true"); + item->updateRepr(); + modmade = true; + } + } + } else { + for (GSList const *items = sp_desktop_selection(desktop)->itemList(); + items != NULL; + items = items->next) + { + SPItem *item = reinterpret_cast<SPItem *>(items->data); + if (SP_IS_GENERICELLIPSE(item)) { + Inkscape::XML::Node *repr = item->getRepr(); + repr->setAttribute("sodipodi:open", NULL); + item->updateRepr(); + modmade = true; + } + } + } + + if (modmade) { + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC, + _("Arc: Change open/closed")); + } + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_arctb_defaults(GtkWidget *, GObject *obj) +{ + GtkAdjustment *adj; + adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") ); + gtk_adjustment_set_value(adj, 0.0); + gtk_adjustment_value_changed(adj); + + adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") ); + gtk_adjustment_set_value(adj, 0.0); + gtk_adjustment_value_changed(adj); + + spinbutton_defocus(GTK_WIDGET(obj)); +} + +static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const * /*name*/, + gchar const * /*old_value*/, gchar const * /*new_value*/, + bool /*is_interactive*/, gpointer data) +{ + GObject *tbl = G_OBJECT(data); + + // quit if run by the _changed callbacks + if (g_object_get_data( tbl, "freeze" )) { + return; + } + + // in turn, prevent callbacks from responding + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + gdouble start = 0.; + gdouble end = 0.; + sp_repr_get_double(repr, "sodipodi:start", &start); + sp_repr_get_double(repr, "sodipodi:end", &end); + + GtkAdjustment *adj1,*adj2; + adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) ); + gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI)); + adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) ); + gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI)); + + sp_arctb_sensitivize( tbl, gtk_adjustment_get_value(adj1), gtk_adjustment_get_value(adj2) ); + + char const *openstr = NULL; + openstr = repr->attribute("sodipodi:open"); + EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) ); + + if (openstr) { + ege_select_one_action_set_active( ocb, 1 ); + } else { + ege_select_one_action_set_active( ocb, 0 ); + } + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static Inkscape::XML::NodeEventVector arc_tb_repr_events = { + NULL, /* child_added */ + NULL, /* child_removed */ + arc_tb_event_attr_changed, + NULL, /* content_changed */ + NULL /* order_changed */ +}; + + +static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) +{ + int n_selected = 0; + Inkscape::XML::Node *repr = NULL; + + purge_repr_listener( tbl, tbl ); + + for (GSList const *items = selection->itemList(); + items != NULL; + items = items->next) + { + SPItem *item = reinterpret_cast<SPItem *>(items->data); + if (SP_IS_GENERICELLIPSE(item)) { + n_selected++; + repr = item->getRepr(); + } + } + + EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) ); + + g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) ); + if (n_selected == 0) { + g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL ); + } else if (n_selected == 1) { + g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) ); + g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); + + if (repr) { + g_object_set_data( tbl, "repr", repr ); + Inkscape::GC::anchor(repr); + sp_repr_add_listener(repr, &arc_tb_repr_events, tbl); + sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl); + } + } else { + // FIXME: implement averaging of all parameters for multiple selected + //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>")); + g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); + sp_arctb_sensitivize( tbl, 1, 0 ); + } +} + + +void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + EgeAdjustmentAction* eact = 0; + Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); + + + { + EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 ); + ege_output_action_set_use_markup( act, TRUE ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_object_set_data( holder, "mode_action", act ); + } + + /* Start */ + { + eact = create_adjustment_action( "ArcStartAction", + _("Start"), _("Start:"), + _("The angle (in degrees) from the horizontal to the arc's start point"), + "/tools/shapes/arc/start", 0.0, + GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-arc", + -360.0, 360.0, 1.0, 10.0, + 0, 0, 0, + sp_arctb_start_value_changed); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + /* End */ + { + eact = create_adjustment_action( "ArcEndAction", + _("End"), _("End:"), + _("The angle (in degrees) from the horizontal to the arc's end point"), + "/tools/shapes/arc/end", 0.0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + -360.0, 360.0, 1.0, 10.0, + 0, 0, 0, + sp_arctb_end_value_changed); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + /* Segments / Pie checkbox */ + { + GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); + + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Closed arc"), + 1, _("Switch to segment (closed shape with two radii)"), + 2, INKSCAPE_ICON("draw-ellipse-segment"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Open Arc"), + 1, _("Switch to arc (unclosed shape)"), + 2, INKSCAPE_ICON("draw-ellipse-arc"), + -1 ); + + EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", (""), (""), NULL, GTK_TREE_MODEL(model) ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "open_action", act ); + + ege_select_one_action_set_appearance( act, "full" ); + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); + ege_select_one_action_set_icon_column( act, 2 ); + ege_select_one_action_set_icon_size( act, secondarySize ); + ege_select_one_action_set_tooltip_column( act, 1 ); + + bool isClosed = !prefs->getBool("/tools/shapes/arc/open", false); + ege_select_one_action_set_active( act, isClosed ? 0 : 1 ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder ); + } + + /* Make Whole */ + { + InkAction* inky = ink_action_new( "ArcResetAction", + _("Make whole"), + _("Make the shape a whole ellipse, not arc or segment"), + INKSCAPE_ICON("draw-ellipse-whole"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + gtk_action_set_sensitive( GTK_ACTION(inky), TRUE ); + g_object_set_data( holder, "make_whole", inky ); + } + + g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) ); + // sensitivize make whole and open checkbox + { + GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) ); + GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) ); + sp_arctb_sensitivize( holder, gtk_adjustment_get_value(adj1), gtk_adjustment_get_value(adj2) ); + } + + + sigc::connection *connection = new sigc::connection( + sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), G_OBJECT(holder))) + ); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection ); + g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/arc-toolbar.h b/src/widgets/arc-toolbar.h new file mode 100644 index 000000000..ca1319631 --- /dev/null +++ b/src/widgets/arc-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_ARC_TOOLBAR_H +#define SEEN_ARC_TOOLBAR_H + +/** + * @file + * 3d box aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_ARC_TOOLBAR_H */ diff --git a/src/widgets/box3d-toolbar.cpp b/src/widgets/box3d-toolbar.cpp new file mode 100644 index 000000000..6d6b86c4d --- /dev/null +++ b/src/widgets/box3d-toolbar.cpp @@ -0,0 +1,428 @@ +/** + * @file + * 3d box aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glibmm/i18n.h> + +#include "box3d-toolbar.h" +#include "box3d.h" +#include "desktop-handles.h" +#include "desktop.h" +#include "document-undo.h" +#include "document.h" +#include "ege-adjustment-action.h" +#include "ink-action.h" +#include "inkscape.h" +#include "persp3d.h" +#include "selection.h" +#include "toolbox.h" +#include "ui/icon-names.h" +#include "ui/uxmanager.h" +#include "verbs.h" +#include "xml/node-event-vector.h" + +using Inkscape::UI::UXManager; +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; + +//######################## +//## 3D Box ## +//######################## + +// normalize angle so that it lies in the interval [0,360] +static double box3d_normalize_angle (double a) { + double angle = a + ((int) (a/360.0))*360; + if (angle < 0) { + angle += 360.0; + } + return angle; +} + +static void box3d_set_button_and_adjustment(Persp3D *persp, + Proj::Axis axis, + GtkAdjustment *adj, + GtkAction *act, + GtkToggleAction *tact) +{ + // TODO: Take all selected perspectives into account but don't touch the state button if not all of them + // have the same state (otherwise a call to box3d_vp_z_state_changed() is triggered and the states + // are reset). + bool is_infinite = !persp3d_VP_is_finite(persp->perspective_impl, axis); + + if (is_infinite) { + gtk_toggle_action_set_active(tact, TRUE); + gtk_action_set_sensitive(act, TRUE); + + double angle = persp3d_get_infinite_angle(persp, axis); + if (angle != Geom::infinity()) { // FIXME: We should catch this error earlier (don't show the spinbutton at all) + gtk_adjustment_set_value(adj, box3d_normalize_angle(angle)); + } + } else { + gtk_toggle_action_set_active(tact, FALSE); + gtk_action_set_sensitive(act, FALSE); + } +} + +static void box3d_resync_toolbar(Inkscape::XML::Node *persp_repr, GObject *data) +{ + if (!persp_repr) { + g_print ("No perspective given to box3d_resync_toolbar().\n"); + return; + } + + GtkWidget *tbl = GTK_WIDGET(data); + GtkAdjustment *adj = 0; + GtkAction *act = 0; + GtkToggleAction *tact = 0; + Persp3D *persp = persp3d_get_from_repr(persp_repr); + if (!persp) { + // Hmm, is it an error if this happens? + return; + } + { + adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x")); + act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x_action")); + tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_x_state_action"))->action; + + box3d_set_button_and_adjustment(persp, Proj::X, adj, act, tact); + } + { + adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "box3d_angle_y")); + act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_y_action")); + tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_y_state_action"))->action; + + box3d_set_button_and_adjustment(persp, Proj::Y, adj, act, tact); + } + { + adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "box3d_angle_z")); + act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_z_action")); + tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_z_state_action"))->action; + + box3d_set_button_and_adjustment(persp, Proj::Z, adj, act, tact); + } +} + +static void box3d_persp_tb_event_attr_changed(Inkscape::XML::Node *repr, + gchar const * /*name*/, + gchar const * /*old_value*/, + gchar const * /*new_value*/, + bool /*is_interactive*/, + gpointer data) +{ + GtkWidget *tbl = GTK_WIDGET(data); + + // quit if run by the attr_changed or selection changed listener + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + + // set freeze so that it can be caught in box3d_angle_z_value_changed() (to avoid calling + // SPDocumentUndo::maybeDone() when the document is undo insensitive) + g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE)); + + // TODO: Only update the appropriate part of the toolbar +// if (!strcmp(name, "inkscape:vp_z")) { + box3d_resync_toolbar(repr, G_OBJECT(tbl)); +// } + + Persp3D *persp = persp3d_get_from_repr(repr); + persp3d_update_box_reprs(persp); + + g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE)); +} + +static Inkscape::XML::NodeEventVector box3d_persp_tb_repr_events = +{ + NULL, /* child_added */ + NULL, /* child_removed */ + box3d_persp_tb_event_attr_changed, + NULL, /* content_changed */ + NULL /* order_changed */ +}; + +/** + * \param selection Should not be NULL. + */ +// FIXME: This should rather be put into persp3d-reference.cpp or something similar so that it reacts upon each +// Change of the perspective, and not of the current selection (but how to refer to the toolbar then?) +static void box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) +{ + // Here the following should be done: If all selected boxes have finite VPs in a certain direction, + // disable the angle entry fields for this direction (otherwise entering a value in them should only + // update the perspectives with infinite VPs and leave the other ones untouched). + + Inkscape::XML::Node *persp_repr = NULL; + purge_repr_listener(tbl, tbl); + + SPItem *item = selection->singleItem(); + if (item && SP_IS_BOX3D(item)) { + // FIXME: Also deal with multiple selected boxes + SPBox3D *box = SP_BOX3D(item); + Persp3D *persp = box3d_get_perspective(box); + persp_repr = persp->getRepr(); + if (persp_repr) { + g_object_set_data(tbl, "repr", persp_repr); + Inkscape::GC::anchor(persp_repr); + sp_repr_add_listener(persp_repr, &box3d_persp_tb_repr_events, tbl); + sp_repr_synthesize_events(persp_repr, &box3d_persp_tb_repr_events, tbl); + } + + inkscape_active_document()->setCurrentPersp3D(persp3d_get_from_repr(persp_repr)); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString("/tools/shapes/3dbox/persp", persp_repr->attribute("id")); + + g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE)); + box3d_resync_toolbar(persp_repr, tbl); + g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE)); + } +} + +static void box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis axis) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( dataKludge, "desktop" )); + SPDocument *document = sp_desktop_document(desktop); + + // quit if run by the attr_changed or selection changed listener + if (g_object_get_data( dataKludge, "freeze" )) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data(dataKludge, "freeze", GINT_TO_POINTER(TRUE)); + + std::list<Persp3D *> sel_persps = sp_desktop_selection(desktop)->perspList(); + if (sel_persps.empty()) { + // this can happen when the document is created; we silently ignore it + return; + } + Persp3D *persp = sel_persps.front(); + + persp->perspective_impl->tmat.set_infinite_direction (axis, + gtk_adjustment_get_value(adj)); + persp->updateRepr(); + + // TODO: use the correct axis here, too + DocumentUndo::maybeDone(document, "perspangle", SP_VERB_CONTEXT_3DBOX, _("3D Box: Change perspective (angle of infinite axis)")); + + g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); +} + + +static void box3d_angle_x_value_changed(GtkAdjustment *adj, GObject *dataKludge) +{ + box3d_angle_value_changed(adj, dataKludge, Proj::X); +} + +static void box3d_angle_y_value_changed(GtkAdjustment *adj, GObject *dataKludge) +{ + box3d_angle_value_changed(adj, dataKludge, Proj::Y); +} + +static void box3d_angle_z_value_changed(GtkAdjustment *adj, GObject *dataKludge) +{ + box3d_angle_value_changed(adj, dataKludge, Proj::Z); +} + + +static void box3d_vp_state_changed( GtkToggleAction *act, GtkAction * /*box3d_angle*/, Proj::Axis axis ) +{ + // TODO: Take all selected perspectives into account + std::list<Persp3D *> sel_persps = sp_desktop_selection(inkscape_active_desktop())->perspList(); + if (sel_persps.empty()) { + // this can happen when the document is created; we silently ignore it + return; + } + Persp3D *persp = sel_persps.front(); + + bool set_infinite = gtk_toggle_action_get_active(act); + persp3d_set_VP_state (persp, axis, set_infinite ? Proj::VP_INFINITE : Proj::VP_FINITE); +} + +static void box3d_vp_x_state_changed( GtkToggleAction *act, GtkAction *box3d_angle ) +{ + box3d_vp_state_changed(act, box3d_angle, Proj::X); +} + +static void box3d_vp_y_state_changed( GtkToggleAction *act, GtkAction *box3d_angle ) +{ + box3d_vp_state_changed(act, box3d_angle, Proj::Y); +} + +static void box3d_vp_z_state_changed( GtkToggleAction *act, GtkAction *box3d_angle ) +{ + box3d_vp_state_changed(act, box3d_angle, Proj::Z); +} + +void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + EgeAdjustmentAction* eact = 0; + SPDocument *document = sp_desktop_document (desktop); + Persp3DImpl *persp_impl = document->getCurrentPersp3DImpl(); + + EgeAdjustmentAction* box3d_angle_x = 0; + EgeAdjustmentAction* box3d_angle_y = 0; + EgeAdjustmentAction* box3d_angle_z = 0; + + /* Angle X */ + { + gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 }; + gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; + eact = create_adjustment_action( "3DBoxAngleXAction", + _("Angle in X direction"), _("Angle X:"), + // Translators: PL is short for 'perspective line' + _("Angle of PLs in X direction"), + "/tools/shapes/3dbox/box3d_angle_x", 30, + GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-box3d", + -360.0, 360.0, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + box3d_angle_x_value_changed ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + g_object_set_data( holder, "box3d_angle_x_action", eact ); + box3d_angle_x = eact; + } + + if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::X)) { + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } else { + gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); + } + + + /* VP X state */ + { + InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXStateAction", + // Translators: VP is short for 'vanishing point' + _("State of VP in X direction"), + _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"), + INKSCAPE_ICON("perspective-parallel"), + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_object_set_data( holder, "box3d_vp_x_state_action", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_x_state_changed), box3d_angle_x ); + gtk_action_set_sensitive( GTK_ACTION(box3d_angle_x), !prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) ); + } + + /* Angle Y */ + { + gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 }; + gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; + eact = create_adjustment_action( "3DBoxAngleYAction", + _("Angle in Y direction"), _("Angle Y:"), + // Translators: PL is short for 'perspective line' + _("Angle of PLs in Y direction"), + "/tools/shapes/3dbox/box3d_angle_y", 30, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + -360.0, 360.0, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + box3d_angle_y_value_changed ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + g_object_set_data( holder, "box3d_angle_y_action", eact ); + box3d_angle_y = eact; + } + + if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::Y)) { + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } else { + gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); + } + + /* VP Y state */ + { + InkToggleAction* act = ink_toggle_action_new( "3DBoxVPYStateAction", + // Translators: VP is short for 'vanishing point' + _("State of VP in Y direction"), + _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"), + INKSCAPE_ICON("perspective-parallel"), + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_object_set_data( holder, "box3d_vp_y_state_action", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_y_state_changed), box3d_angle_y ); + gtk_action_set_sensitive( GTK_ACTION(box3d_angle_y), !prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) ); + } + + /* Angle Z */ + { + gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 }; + gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; + eact = create_adjustment_action( "3DBoxAngleZAction", + _("Angle in Z direction"), _("Angle Z:"), + // Translators: PL is short for 'perspective line' + _("Angle of PLs in Z direction"), + "/tools/shapes/3dbox/box3d_angle_z", 30, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + -360.0, 360.0, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + box3d_angle_z_value_changed ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + g_object_set_data( holder, "box3d_angle_z_action", eact ); + box3d_angle_z = eact; + } + + if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::Z)) { + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } else { + gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); + } + + /* VP Z state */ + { + InkToggleAction* act = ink_toggle_action_new( "3DBoxVPZStateAction", + // Translators: VP is short for 'vanishing point' + _("State of VP in Z direction"), + _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"), + INKSCAPE_ICON("perspective-parallel"), + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_object_set_data( holder, "box3d_vp_z_state_action", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_z_state_changed), box3d_angle_z ); + gtk_action_set_sensitive( GTK_ACTION(box3d_angle_z), !prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) ); + } + + sigc::connection *connection = new sigc::connection( + sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(box3d_toolbox_selection_changed), G_OBJECT(holder))) + ); + g_signal_connect(holder, "destroy", G_CALLBACK(delete_connection), connection); + g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder); +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/box3d-toolbar.h b/src/widgets/box3d-toolbar.h new file mode 100644 index 000000000..cba9ca2d8 --- /dev/null +++ b/src/widgets/box3d-toolbar.h @@ -0,0 +1,38 @@ +#ifndef SEEN_BOX3D_TOOLBAR_H +#define SEEN_BOX3D_TOOLBAR_H + +/** + * @file + * 3d box aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_BOX3D_TOOLBAR_H */ diff --git a/src/widgets/button.cpp b/src/widgets/button.cpp index 0071fc56e..a1bd9b792 100644 --- a/src/widgets/button.cpp +++ b/src/widgets/button.cpp @@ -20,16 +20,13 @@ #include "icon.h" #include "shortcuts.h" #include "interface.h" +#include "helper/action-context.h" #include <gdk/gdkkeysyms.h> #include "button.h" -static void sp_button_class_init (SPButtonClass *klass); -static void sp_button_init (SPButton *button); -static void sp_button_destroy (GtkObject *object); - -static void sp_button_size_request (GtkWidget *widget, GtkRequisition *requisition); +static void sp_button_dispose(GObject *object); #if GTK_CHECK_VERSION(3,0,0) static void sp_button_get_preferred_width(GtkWidget *widget, @@ -39,6 +36,8 @@ static void sp_button_get_preferred_width(GtkWidget *widget, static void sp_button_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height); +#else +static void sp_button_size_request (GtkWidget *widget, GtkRequisition *requisition); #endif static void sp_button_clicked (GtkButton *button); @@ -50,39 +49,16 @@ static void sp_button_set_doubleclick_action (SPButton *button, SPAction *action static void sp_button_action_set_active (SPButton *button, bool active); static void sp_button_set_composed_tooltip (GtkWidget *widget, SPAction *action); -static GtkToggleButtonClass *parent_class; - -GType sp_button_get_type(void) -{ - static GType type = 0; - if (!type) { - GTypeInfo info = { - sizeof(SPButtonClass), - 0, // base_init - 0, // base_finalize - (GClassInitFunc)sp_button_class_init, - 0, // class_finalize - 0, // class_data - sizeof(SPButton), - 0, // n_preallocs - (GInstanceInitFunc)sp_button_init, - 0 // value_table - }; - type = g_type_register_static(GTK_TYPE_TOGGLE_BUTTON, "SPButton", &info, static_cast<GTypeFlags>(0)); - } - return type; -} +G_DEFINE_TYPE(SPButton, sp_button, GTK_TYPE_TOGGLE_BUTTON); static void sp_button_class_init (SPButtonClass *klass) { - GtkObjectClass *object_class=(GtkObjectClass *)klass; - GtkWidgetClass *widget_class=(GtkWidgetClass *)klass; - GtkButtonClass *button_class=(GtkButtonClass *)klass; - - parent_class = (GtkToggleButtonClass *)g_type_class_peek_parent (klass); + GObjectClass *object_class=G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class=GTK_WIDGET_CLASS(klass); + GtkButtonClass *button_class=GTK_BUTTON_CLASS(klass); - object_class->destroy = sp_button_destroy; + object_class->dispose = sp_button_dispose; #if GTK_CHECK_VERSION(3,0,0) widget_class->get_preferred_width = sp_button_get_preferred_width; widget_class->get_preferred_height = sp_button_get_preferred_height; @@ -109,8 +85,7 @@ sp_button_init (SPButton *button) g_signal_connect_after (G_OBJECT (button), "event", G_CALLBACK (sp_button_process_event), NULL); } -static void -sp_button_destroy (GtkObject *object) +static void sp_button_dispose(GObject *object) { SPButton *button = SP_BUTTON (object); @@ -121,19 +96,53 @@ sp_button_destroy (GtkObject *object) sp_button_set_doubleclick_action (button, NULL); } - button->c_set_active.~connection(); - button->c_set_sensitive.~connection(); + button->c_set_active.~connection(); + button->c_set_sensitive.~connection(); - ((GtkObjectClass *) (parent_class))->destroy (object); + (G_OBJECT_CLASS(sp_button_parent_class))->dispose(object); } -static void -sp_button_size_request (GtkWidget *widget, GtkRequisition *requisition) + + +#if GTK_CHECK_VERSION(3,0,0) +static void sp_button_get_preferred_width(GtkWidget *widget, gint *minimal_width, gint *natural_width) { - GtkWidget *child; + GtkWidget *child = gtk_bin_get_child(GTK_BIN (widget)); + GtkStyle *style = gtk_widget_get_style(widget); + + if (child) { + gtk_widget_get_preferred_width(GTK_WIDGET(child), minimal_width, natural_width); + } else { + *minimal_width = 0; + *natural_width = 0; + } + + *minimal_width += 2 + 2 * MAX(2, style->xthickness); + *natural_width += 2 + 2 * MAX(2, style->xthickness); +} + +static void sp_button_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height) +{ + GtkWidget *child = gtk_bin_get_child(GTK_BIN (widget)); + GtkStyle *style = gtk_widget_get_style(widget); + + if (child) { + gtk_widget_get_preferred_height(GTK_WIDGET(child), minimal_height, natural_height); + } else { + *minimal_height = 0; + *natural_height = 0; + } + + *minimal_height += 2 + 2 * MAX(2, style->ythickness); + *natural_height += 2 + 2 * MAX(2, style->ythickness); + +} +#else +static void sp_button_size_request(GtkWidget *widget, GtkRequisition *requisition) +{ + GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget)); GtkStyle *style = gtk_widget_get_style (widget); - child = gtk_bin_get_child (GTK_BIN (widget)); if (child) { gtk_widget_size_request (GTK_WIDGET (child), requisition); } else { @@ -144,21 +153,6 @@ sp_button_size_request (GtkWidget *widget, GtkRequisition *requisition) requisition->width += 2 + 2 * MAX (2, style->xthickness); requisition->height += 2 + 2 * MAX (2, style->ythickness); } - -#if GTK_CHECK_VERSION(3,0,0) -static void sp_button_get_preferred_width(GtkWidget *widget, gint *minimal_width, gint *natural_width) -{ - GtkRequisition requisition; - sp_button_size_request(widget, &requisition); - *minimal_width = *natural_width = requisition.width; -} - -static void sp_button_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height) -{ - GtkRequisition requisition; - sp_button_size_request(widget, &requisition); - *minimal_height = *natural_height = requisition.height; -} #endif static void @@ -167,7 +161,7 @@ sp_button_clicked (GtkButton *button) SPButton *sp_button=SP_BUTTON (button); if (sp_button->type == SP_BUTTON_TYPE_TOGGLE) { - ((GtkButtonClass *) (parent_class))->clicked (button); + (GTK_BUTTON_CLASS(sp_button_parent_class))->clicked (button); } } @@ -200,9 +194,7 @@ sp_button_perform_action (SPButton *button, gpointer /*data*/) GtkWidget * sp_button_new( Inkscape::IconSize size, SPButtonType type, SPAction *action, SPAction *doubleclick_action ) { - SPButton *button; - - button = (SPButton *)g_object_new (SP_TYPE_BUTTON, NULL); + SPButton *button = SP_BUTTON(g_object_new(SP_TYPE_BUTTON, NULL)); button->type = type; button->lsize = CLAMP( size, Inkscape::ICON_SIZE_MENU, Inkscape::ICON_SIZE_DECORATION ); @@ -214,7 +206,7 @@ sp_button_new( Inkscape::IconSize size, SPButtonType type, SPAction *action, SPA // The Inkscape style is no-relief buttons gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); - return (GtkWidget *) button; + return GTK_WIDGET(button); } void @@ -271,7 +263,7 @@ sp_button_set_action (SPButton *button, SPAction *action) } } - sp_button_set_composed_tooltip ((GtkWidget *) button, action); + sp_button_set_composed_tooltip(GTK_WIDGET(button), action); } static void @@ -291,7 +283,7 @@ static void sp_button_set_composed_tooltip(GtkWidget *widget, SPAction *action) { if (action) { unsigned int shortcut = sp_shortcut_get_primary (action->verb); - if (shortcut != GDK_VoidSymbol) { + if (shortcut != GDK_KEY_VoidSymbol) { // there's both action and shortcut gchar *key = sp_shortcut_get_label(shortcut); @@ -318,9 +310,19 @@ sp_button_new_from_data( Inkscape::IconSize size, const gchar *tip ) { GtkWidget *button; - SPAction *action=sp_action_new(view, name, name, tip, name, 0); + SPAction *action=sp_action_new(Inkscape::ActionContext(view), name, name, tip, name, 0); button = sp_button_new (size, type, action, NULL); g_object_unref(action); return button; } +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/calligraphy-toolbar.cpp b/src/widgets/calligraphy-toolbar.cpp new file mode 100644 index 000000000..9c0393cd9 --- /dev/null +++ b/src/widgets/calligraphy-toolbar.cpp @@ -0,0 +1,643 @@ +/** + * @file + * Calligraphy aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ui/dialog/calligraphic-profile-rename.h" +#include <glibmm/i18n.h> +#include "calligraphy-toolbar.h" + +#include "desktop.h" +#include "document-undo.h" +#include "ege-adjustment-action.h" +#include "ege-select-one-action.h" +#include "ink-action.h" +#include "preferences.h" +#include "toolbox.h" +#include "ui/icon-names.h" +#include "ui/uxmanager.h" + +using Inkscape::UI::UXManager; +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; + + +//######################## +//## Calligraphy ## +//######################## + +std::vector<Glib::ustring> get_presets_list() { + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset"); + + return presets; +} + +void update_presets_list(GObject *tbl) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (g_object_get_data(tbl, "presets_blocked")) { + return; + } + + EgeSelectOneAction *sel = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector")); + if (!sel) { + // WTF!? This will cause a segfault if ever reached + //ege_select_one_action_set_active(sel, 0); + return; + } + + std::vector<Glib::ustring> presets = get_presets_list(); + + int ege_index = 1; + for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i, ++ege_index) { + bool match = true; + + std::vector<Inkscape::Preferences::Entry> preset = prefs->getAllEntries(*i); + for (std::vector<Inkscape::Preferences::Entry>::iterator j = preset.begin(); j != preset.end(); ++j) { + Glib::ustring entry_name = j->getEntryName(); + if (entry_name == "id" || entry_name == "name") { + continue; + } + + void *widget = g_object_get_data(tbl, entry_name.data()); + if (widget) { + if (GTK_IS_ADJUSTMENT(widget)) { + double v = j->getDouble(); + GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget); + //std::cout << "compared adj " << attr_name << gtk_adjustment_get_value(adj) << " to " << v << "\n"; + if (fabs(gtk_adjustment_get_value(adj) - v) > 1e-6) { + match = false; + break; + } + } else if (GTK_IS_TOGGLE_ACTION(widget)) { + bool v = j->getBool(); + GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget); + //std::cout << "compared toggle " << attr_name << gtk_toggle_action_get_active(toggle) << " to " << v << "\n"; + if ( static_cast<bool>(gtk_toggle_action_get_active(toggle)) != v ) { + match = false; + break; + } + } + } + } + + if (match) { + // newly added item is at the same index as the + // save command, so we need to change twice for it to take effect + ege_select_one_action_set_active(sel, 0); + ege_select_one_action_set_active(sel, ege_index); // one-based index + return; + } + } + + // no match found + ege_select_one_action_set_active(sel, 0); +} + +static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* tbl ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/calligraphic/mass", gtk_adjustment_get_value(adj) ); + update_presets_list(tbl); +} + +static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* tbl ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/calligraphic/wiggle", gtk_adjustment_get_value(adj) ); + update_presets_list(tbl); +} + +static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* tbl ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/calligraphic/angle", gtk_adjustment_get_value(adj) ); + update_presets_list(tbl); +} + +static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject *tbl ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/calligraphic/width", gtk_adjustment_get_value(adj) ); + update_presets_list(tbl); +} + +static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/tools/calligraphic/thinning", gtk_adjustment_get_value(adj) ); + update_presets_list(tbl); +} + +static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* tbl ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/calligraphic/flatness", gtk_adjustment_get_value(adj) ); + update_presets_list(tbl); +} + +static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/calligraphic/tremor", gtk_adjustment_get_value(adj) ); + update_presets_list(tbl); +} + +static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* tbl ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/calligraphic/cap_rounding", gtk_adjustment_get_value(adj) ); + update_presets_list(tbl); +} + +static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GObject* tbl ) +{ + // TODO merge into PrefPusher + GtkAction * calligraphy_angle = static_cast<GtkAction *> (g_object_get_data(tbl,"angle_action")); + if (calligraphy_angle ) { + gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) ); + } +} + + +static gchar const *const widget_names[] = { + "width", + "mass", + "wiggle", + "angle", + "thinning", + "tremor", + "flatness", + "cap_rounding", + "usepressure", + "tracebackground", + "usetilt" +}; + + +static void sp_dcc_build_presets_list(GObject *tbl) +{ + g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE)); + + EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector")); + GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector)); + gtk_list_store_clear (model); + + { + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, 0, _("No preset"), 1, 0, -1 ); + } + + // iterate over all presets to populate the list + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + std::vector<Glib::ustring> presets = get_presets_list(); + int ii=1; + + for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i) { + GtkTreeIter iter; + Glib::ustring preset_name = prefs->getString(*i + "/name"); + if (!preset_name.empty()) { + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, 0, _(preset_name.data()), 1, ii++, -1 ); + } + } + +/* { + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, 0, _("Save..."), 1, ii, -1 ); + g_object_set_data(tbl, "save_presets_index", GINT_TO_POINTER(ii)); + }*/ + + g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE)); + + update_presets_list (tbl); +} + +static void sp_dcc_save_profile(GtkWidget * /*widget*/, GObject *tbl) +{ + using Inkscape::UI::Dialog::CalligraphicProfileRename; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(tbl, "desktop" )); + if (! desktop) { + return; + } + + if (g_object_get_data(tbl, "presets_blocked")) { + return; + } + + EgeSelectOneAction *sel = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector")); + //gint preset_index = ege_select_one_action_get_active( sel ); + Glib::ustring current_profile_name = _("No preset"); + if (ege_select_one_action_get_active_text( sel )) { + current_profile_name = ege_select_one_action_get_active_text( sel ); + } + + if (current_profile_name == _("No preset")) { + current_profile_name = ""; + } + CalligraphicProfileRename::show(desktop, current_profile_name); + if ( !CalligraphicProfileRename::applied()) { + // dialog cancelled + update_presets_list (tbl); + return; + } + Glib::ustring new_profile_name = CalligraphicProfileRename::getProfileName(); + + if (new_profile_name.empty()) { + // empty name entered + update_presets_list (tbl); + return; + } + + g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE)); + + // If there's a preset with the given name, find it and set save_path appropriately + std::vector<Glib::ustring> presets = get_presets_list(); + int total_presets = presets.size(); + int new_index = -1; + Glib::ustring save_path; // profile pref path without a trailing slash + + int temp_index = 0; + for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i, ++temp_index) { + Glib::ustring name = prefs->getString(*i + "/name"); + if (!name.empty() && (new_profile_name == name || current_profile_name == name)) { + new_index = temp_index; + save_path = *i; + break; + } + } + + + if ( CalligraphicProfileRename::deleted() && new_index != -1) { + prefs->remove(save_path); + g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE)); + sp_dcc_build_presets_list (tbl); + return; + } + + if (new_index == -1) { + // no preset with this name, create + new_index = total_presets + 1; + gchar *profile_id = g_strdup_printf("/dcc%d", new_index); + save_path = Glib::ustring("/tools/calligraphic/preset") + profile_id; + g_free(profile_id); + } + + for (unsigned i = 0; i < G_N_ELEMENTS(widget_names); ++i) { + gchar const *const widget_name = widget_names[i]; + void *widget = g_object_get_data(tbl, widget_name); + if (widget) { + if (GTK_IS_ADJUSTMENT(widget)) { + GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget); + prefs->setDouble(save_path + "/" + widget_name, gtk_adjustment_get_value(adj)); + //std::cout << "wrote adj " << widget_name << ": " << v << "\n"; + } else if (GTK_IS_TOGGLE_ACTION(widget)) { + GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget); + prefs->setBool(save_path + "/" + widget_name, gtk_toggle_action_get_active(toggle)); + //std::cout << "wrote tog " << widget_name << ": " << v << "\n"; + } else { + g_warning("Unknown widget type for preset: %s\n", widget_name); + } + } else { + g_warning("Bad key when writing preset: %s\n", widget_name); + } + } + prefs->setString(save_path + "/name", new_profile_name); + + g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE)); + sp_dcc_build_presets_list (tbl); +} + + +static void sp_ddc_change_profile(EgeSelectOneAction* act, GObject* tbl) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + guint preset_index = ege_select_one_action_get_active( act ); + // This is necessary because EgeSelectOneAction spams us with GObject "changed" signal calls + // even when the preset is not changed. It would be good to replace it with something more + // modern. Index 0 means "No preset", so we don't do anything. + if (preset_index == 0) { + return; + } + +/* + gint save_presets_index = GPOINTER_TO_INT(g_object_get_data(tbl, "save_presets_index")); + + if (preset_index == save_presets_index) { + // this is the Save command + sp_dcc_save_profile(NULL, tbl); + return; + } +*/ + + if (g_object_get_data(tbl, "presets_blocked")) { + return; + } + + // preset_index is one-based so we subtract 1 + std::vector<Glib::ustring> presets = get_presets_list(); + + Glib::ustring preset_path = ""; + if (preset_index - 1 < presets.size()) { + preset_path = presets.at(preset_index - 1); + } + + if (!preset_path.empty()) { + g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE)); //temporarily block the selector so no one will updadte it while we're reading it + + std::vector<Inkscape::Preferences::Entry> preset = prefs->getAllEntries(preset_path); + + // Shouldn't this be std::map? + for (std::vector<Inkscape::Preferences::Entry>::iterator i = preset.begin(); i != preset.end(); ++i) { + Glib::ustring entry_name = i->getEntryName(); + if (entry_name == "id" || entry_name == "name") { + continue; + } + void *widget = g_object_get_data(tbl, entry_name.data()); + if (widget) { + if (GTK_IS_ADJUSTMENT(widget)) { + GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget); + gtk_adjustment_set_value(adj, i->getDouble()); + //std::cout << "set adj " << attr_name << " to " << v << "\n"; + } else if (GTK_IS_TOGGLE_ACTION(widget)) { + GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget); + gtk_toggle_action_set_active(toggle, i->getBool()); + //std::cout << "set toggle " << attr_name << " to " << v << "\n"; + } else { + g_warning("Unknown widget type for preset: %s\n", entry_name.data()); + } + } else { + g_warning("Bad key found in a preset record: %s\n", entry_name.data()); + } + } + g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE)); + } else { + ege_select_one_action_set_active(act, 0); + } +} + +static void sp_ddc_edit_profile(GtkAction * /*act*/, GObject* tbl) +{ + sp_dcc_save_profile(NULL, tbl); +} + +void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + { + g_object_set_data(holder, "presets_blocked", GINT_TO_POINTER(TRUE)); + + EgeAdjustmentAction* calligraphy_angle = 0; + + { + /* Width */ + gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")}; + gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction", + _("Pen Width"), _("Width:"), + _("The width of the calligraphic pen (relative to the visible canvas area)"), + "/tools/calligraphic/width", 15, + GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-calligraphy", + 1, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_ddc_width_value_changed, NULL /*unit tracker*/, 1, 0 ); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + { + /* Thinning */ + gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")}; + gdouble values[] = {-100, -40, -20, -10, 0, 10, 20, 40, 100}; + EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction", + _("Stroke Thinning"), _("Thinning:"), + _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"), + "/tools/calligraphic/thinning", 10, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + -100, 100, 1, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_ddc_velthin_value_changed, NULL /*unit tracker*/, 1, 0); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + { + /* Angle */ + gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")}; + gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; + EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction", + _("Pen Angle"), _("Angle:"), + _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"), + "/tools/calligraphic/angle", 30, + GTK_WIDGET(desktop->canvas), holder, TRUE, "calligraphy-angle", + -90.0, 90.0, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_ddc_angle_value_changed, NULL /*unit tracker*/, 1, 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + g_object_set_data( holder, "angle_action", eact ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + calligraphy_angle = eact; + } + + { + /* Fixation */ + gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")}; + gdouble values[] = {0, 20, 40, 60, 90, 100}; + EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction", + _("Fixation"), _("Fixation:"), + _("Angle behavior (0 = nib always perpendicular to stroke direction, 100 = fixed angle)"), + "/tools/calligraphic/flatness", 90, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0.0, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_ddc_flatness_value_changed, NULL /*unit tracker*/, 1, 0); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + { + /* Cap Rounding */ + gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")}; + gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0}; + // TRANSLATORS: "cap" means "end" (both start and finish) here + EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction", + _("Cap rounding"), _("Caps:"), + _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"), + "/tools/calligraphic/cap_rounding", 0.0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0.0, 5.0, 0.01, 0.1, + labels, values, G_N_ELEMENTS(labels), + sp_ddc_cap_rounding_value_changed, NULL /*unit tracker*/, 0.01, 2 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + { + /* Tremor */ + gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")}; + gdouble values[] = {0, 10, 20, 40, 60, 100}; + EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction", + _("Stroke Tremor"), _("Tremor:"), + _("Increase to make strokes rugged and trembling"), + "/tools/calligraphic/tremor", 0.0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0.0, 100, 1, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_ddc_tremor_value_changed, NULL /*unit tracker*/, 1, 0); + + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + { + /* Wiggle */ + gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")}; + gdouble values[] = {0, 20, 40, 60, 100}; + EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction", + _("Pen Wiggle"), _("Wiggle:"), + _("Increase to make the pen waver and wiggle"), + "/tools/calligraphic/wiggle", 0.0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0.0, 100, 1, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_ddc_wiggle_value_changed, NULL /*unit tracker*/, 1, 0); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + { + /* Mass */ + gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")}; + gdouble values[] = {0.0, 2, 10, 20, 50, 100}; + EgeAdjustmentAction* eact = create_adjustment_action( "MassAction", + _("Pen Mass"), _("Mass:"), + _("Increase to make the pen drag behind, as if slowed by inertia"), + "/tools/calligraphic/mass", 2.0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0.0, 100, 1, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_ddc_mass_value_changed, NULL /*unit tracker*/, 1, 0); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + + /* Trace Background button */ + { + InkToggleAction* act = ink_toggle_action_new( "TraceAction", + _("Trace Background"), + _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"), + INKSCAPE_ICON("draw-trace-background"), + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/calligraphic/tracebackground", update_presets_list, holder); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + g_object_set_data( holder, "tracebackground", act ); + } + + /* Use Pressure button */ + { + InkToggleAction* act = ink_toggle_action_new( "PressureAction", + _("Pressure"), + _("Use the pressure of the input device to alter the width of the pen"), + INKSCAPE_ICON("draw-use-pressure"), + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/calligraphic/usepressure", update_presets_list, holder); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + g_object_set_data( holder, "usepressure", act ); + } + + /* Use Tilt button */ + { + InkToggleAction* act = ink_toggle_action_new( "TiltAction", + _("Tilt"), + _("Use the tilt of the input device to alter the angle of the pen's nib"), + INKSCAPE_ICON("draw-use-tilt"), + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/calligraphic/usetilt", update_presets_list, holder); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), holder ); + gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs->getBool("/tools/calligraphic/usetilt", true) ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/calligraphic/usetilt", true) ); + g_object_set_data( holder, "usetilt", act ); + } + + /*calligraphic profile */ + { + GtkListStore* model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT); + EgeSelectOneAction* act1 = ege_select_one_action_new ("SetProfileAction", "" , (_("Choose a preset")), NULL, GTK_TREE_MODEL(model)); + ege_select_one_action_set_appearance (act1, "compact"); + g_object_set_data (holder, "profile_selector", act1 ); + + g_object_set_data(holder, "presets_blocked", GINT_TO_POINTER(FALSE)); + + sp_dcc_build_presets_list (holder); + + g_signal_connect(G_OBJECT(act1), "changed", G_CALLBACK(sp_ddc_change_profile), holder); + gtk_action_group_add_action(mainActions, GTK_ACTION(act1)); + } + + /*calligraphic profile editor */ + { + InkAction* inky = ink_action_new( "ProfileEditAction", + _("Add/Edit Profile"), + _("Add or edit calligraphic profile"), + INKSCAPE_ICON("document-properties"), + Inkscape::ICON_SIZE_DECORATION ); + g_object_set( inky, "short_label", _("Edit"), NULL ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_ddc_edit_profile), (GObject*)holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + } +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/calligraphy-toolbar.h b/src/widgets/calligraphy-toolbar.h new file mode 100644 index 000000000..e3caa19ee --- /dev/null +++ b/src/widgets/calligraphy-toolbar.h @@ -0,0 +1,38 @@ +#ifndef SEEN_CALLIGRAPHY_TOOLBAR_H +#define SEEN_CALLIGRAPHY_TOOLBAR_H + +/** + * @file + * Calligraphy aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); +void update_presets_list(GObject *tbl); + +#endif /* !SEEN_CALLIGRAPHY_TOOLBAR_H */ diff --git a/src/widgets/connector-toolbar.cpp b/src/widgets/connector-toolbar.cpp new file mode 100644 index 000000000..a0965721f --- /dev/null +++ b/src/widgets/connector-toolbar.cpp @@ -0,0 +1,446 @@ +/** + * @file + * Connector aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "connector-toolbar.h" +#include "conn-avoid-ref.h" +#include "desktop-handles.h" +#include "desktop.h" +#include "document-undo.h" +#include "ege-adjustment-action.h" +#include "graphlayout.h" +#include "ink-action.h" +#include "inkscape.h" +#include "preferences.h" +#include "selection.h" +#include "sp-namedview.h" +#include "sp-path.h" +#include "toolbox.h" +#include "ui/icon-names.h" +#include "ui/tools/connector-tool.h" +#include "ui/uxmanager.h" +#include "verbs.h" +#include "widgets/spinbutton-events.h" +#include "xml/node-event-vector.h" +#include "xml/repr.h" + +using Inkscape::UI::UXManager; +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; + +//######################### +//## Connector ## +//######################### + +static void sp_connector_path_set_avoid(void) +{ + Inkscape::UI::Tools::cc_selection_set_avoid(true); +} + + +static void sp_connector_path_set_ignore(void) +{ + Inkscape::UI::Tools::cc_selection_set_avoid(false); +} + +static void sp_connector_orthogonal_toggled( GtkToggleAction* act, GObject *tbl ) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + Inkscape::Selection * selection = sp_desktop_selection(desktop); + SPDocument *doc = sp_desktop_document(desktop); + + if (!DocumentUndo::getUndoSensitive(doc)) { + return; + } + + + // quit if run by the _changed callbacks + if (g_object_get_data( tbl, "freeze" )) { + return; + } + + // in turn, prevent callbacks from responding + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + bool is_orthog = gtk_toggle_action_get_active( act ); + gchar orthog_str[] = "orthogonal"; + gchar polyline_str[] = "polyline"; + gchar *value = is_orthog ? orthog_str : polyline_str ; + + bool modmade = false; + GSList *l = (GSList *) selection->itemList(); + while (l) { + SPItem *item = SP_ITEM(l->data); + + if (Inkscape::UI::Tools::cc_item_is_connector(item)) { + item->setAttribute( "inkscape:connector-type", + value, NULL); + item->avoidRef->handleSettingChange(); + modmade = true; + } + l = l->next; + } + + if (!modmade) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/connector/orthogonal", is_orthog); + } else { + + DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, + is_orthog ? _("Set connector type: orthogonal"): _("Set connector type: polyline")); + } + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void connector_curvature_changed(GtkAdjustment *adj, GObject* tbl) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + Inkscape::Selection * selection = sp_desktop_selection(desktop); + SPDocument *doc = sp_desktop_document(desktop); + + if (!DocumentUndo::getUndoSensitive(doc)) { + return; + } + + + // quit if run by the _changed callbacks + if (g_object_get_data( tbl, "freeze" )) { + return; + } + + // in turn, prevent callbacks from responding + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + gdouble newValue = gtk_adjustment_get_value(adj); + gchar value[G_ASCII_DTOSTR_BUF_SIZE]; + g_ascii_dtostr(value, G_ASCII_DTOSTR_BUF_SIZE, newValue); + + bool modmade = false; + GSList *l = (GSList *) selection->itemList(); + while (l) { + SPItem *item = SP_ITEM(l->data); + + if (Inkscape::UI::Tools::cc_item_is_connector(item)) { + item->setAttribute( "inkscape:connector-curvature", + value, NULL); + item->avoidRef->handleSettingChange(); + modmade = true; + } + l = l->next; + } + + if (!modmade) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble(Glib::ustring("/tools/connector/curvature"), newValue); + } + else { + DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, + _("Change connector curvature")); + } + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + + +static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + SPDocument *doc = sp_desktop_document(desktop); + + if (!DocumentUndo::getUndoSensitive(doc)) { + return; + } + + Inkscape::XML::Node *repr = desktop->namedview->getRepr(); + + if ( !repr->attribute("inkscape:connector-spacing") && + ( gtk_adjustment_get_value(adj) == defaultConnSpacing )) { + // Don't need to update the repr if the attribute doesn't + // exist and it is being set to the default value -- as will + // happen at startup. + return; + } + + // quit if run by the attr_changed listener + if (g_object_get_data( tbl, "freeze" )) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE)); + + sp_repr_set_css_double(repr, "inkscape:connector-spacing", gtk_adjustment_get_value(adj)); + desktop->namedview->updateRepr(); + bool modmade = false; + + GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop); + for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) { + SPItem *item = reinterpret_cast<SPItem *>(iter->data); + Geom::Affine m = Geom::identity(); + avoid_item_move(&m, item); + modmade = true; + } + + if (items) { + g_slist_free(items); + } + if(modmade) { + DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, + _("Change connector spacing")); + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_connector_graph_layout(void) +{ + if (!SP_ACTIVE_DESKTOP) { + return; + } + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + // hack for clones, see comment in align-and-distribute.cpp + int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); + prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); + + graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList()); + + prefs->setInt("/options/clonecompensation/value", saved_compensation); + + DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network")); +} + +static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/connector/directedlayout", + gtk_toggle_action_get_active( act )); +} + +static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/connector/avoidoverlaplayout", + gtk_toggle_action_get_active( act )); +} + + +static void connector_length_changed(GtkAdjustment *adj, GObject* /*tbl*/) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/tools/connector/length", gtk_adjustment_get_value(adj)); +} + +static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr, + gchar const *name, gchar const * /*old_value*/, gchar const * /*new_value*/, + bool /*is_interactive*/, gpointer data) +{ + GtkWidget *tbl = GTK_WIDGET(data); + + if ( !g_object_get_data(G_OBJECT(tbl), "freeze") + && (strcmp(name, "inkscape:connector-spacing") == 0) ) { + GtkAdjustment *adj = static_cast<GtkAdjustment*>(g_object_get_data(G_OBJECT(tbl), "spacing")); + gdouble spacing = defaultConnSpacing; + sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing); + + gtk_adjustment_set_value(adj, spacing); + gtk_adjustment_value_changed(adj); + + spinbutton_defocus(tbl); + } +} + +static Inkscape::XML::NodeEventVector connector_tb_repr_events = { + NULL, /* child_added */ + NULL, /* child_removed */ + connector_tb_event_attr_changed, + NULL, /* content_changed */ + NULL /* order_changed */ +}; + +static void sp_connector_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) +{ + GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "curvature" ) ); + GtkToggleAction *act = GTK_TOGGLE_ACTION( g_object_get_data( tbl, "orthogonal" ) ); + SPItem *item = selection->singleItem(); + if (SP_IS_PATH(item)) + { + gdouble curvature = SP_PATH(item)->connEndPair.getCurvature(); + bool is_orthog = SP_PATH(item)->connEndPair.isOrthogonal(); + gtk_toggle_action_set_active(act, is_orthog); + gtk_adjustment_set_value(adj, curvature); + } + +} + +void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); + + { + InkAction* inky = ink_action_new( "ConnectorAvoidAction", + _("Avoid"), + _("Make connectors avoid selected objects"), + INKSCAPE_ICON("connector-avoid"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + { + InkAction* inky = ink_action_new( "ConnectorIgnoreAction", + _("Ignore"), + _("Make connectors ignore selected objects"), + INKSCAPE_ICON("connector-ignore"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + // Orthogonal connectors toggle button + { + InkToggleAction* act = ink_toggle_action_new( "ConnectorOrthogonalAction", + _("Orthogonal"), + _("Make connector orthogonal or polyline"), + INKSCAPE_ICON("connector-orthogonal"), + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + + bool tbuttonstate = prefs->getBool("/tools/connector/orthogonal"); + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), ( tbuttonstate ? TRUE : FALSE )); + g_object_set_data( holder, "orthogonal", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_connector_orthogonal_toggled), holder ); + } + + EgeAdjustmentAction* eact = 0; + // Curvature spinbox + eact = create_adjustment_action( "ConnectorCurvatureAction", + _("Connector Curvature"), _("Curvature:"), + _("The amount of connectors curvature"), + "/tools/connector/curvature", defaultConnCurvature, + GTK_WIDGET(desktop->canvas), holder, TRUE, "inkscape:connector-curvature", + 0, 100, 1.0, 10.0, + 0, 0, 0, + connector_curvature_changed, NULL /*unit tracker*/, 1, 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + + // Spacing spinbox + eact = create_adjustment_action( "ConnectorSpacingAction", + _("Connector Spacing"), _("Spacing:"), + _("The amount of space left around objects by auto-routing connectors"), + "/tools/connector/spacing", defaultConnSpacing, + GTK_WIDGET(desktop->canvas), holder, TRUE, "inkscape:connector-spacing", + 0, 100, 1.0, 10.0, + 0, 0, 0, + connector_spacing_changed, NULL /*unit tracker*/, 1, 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + + // Graph (connector network) layout + { + InkAction* inky = ink_action_new( "ConnectorGraphAction", + _("Graph"), + _("Nicely arrange selected connector network"), + INKSCAPE_ICON("distribute-graph"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + // Default connector length spinbox + eact = create_adjustment_action( "ConnectorLengthAction", + _("Connector Length"), _("Length:"), + _("Ideal length for connectors when layout is applied"), + "/tools/connector/length", 100, + GTK_WIDGET(desktop->canvas), holder, TRUE, "inkscape:connector-length", + 10, 1000, 10.0, 100.0, + 0, 0, 0, + connector_length_changed, NULL /*unit tracker*/, 1, 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + + + // Directed edges toggle button + { + InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction", + _("Downwards"), + _("Make connectors with end-markers (arrows) point downwards"), + INKSCAPE_ICON("distribute-graph-directed"), + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + + bool tbuttonstate = prefs->getBool("/tools/connector/directedlayout"); + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), ( tbuttonstate ? TRUE : FALSE )); + + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder ); + sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_connector_toolbox_selection_changed), holder)); + } + + // Avoid overlaps toggle button + { + InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction", + _("Remove overlaps"), + _("Do not allow overlapping shapes"), + INKSCAPE_ICON("distribute-remove-overlaps"), + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + + bool tbuttonstate = prefs->getBool("/tools/connector/avoidoverlaplayout"); + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), (tbuttonstate ? TRUE : FALSE )); + + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder ); + } + + + // Code to watch for changes to the connector-spacing attribute in + // the XML. + Inkscape::XML::Node *repr = desktop->namedview->getRepr(); + g_assert(repr != NULL); + + purge_repr_listener( holder, holder ); + + if (repr) { + g_object_set_data( holder, "repr", repr ); + Inkscape::GC::anchor(repr); + sp_repr_add_listener( repr, &connector_tb_repr_events, holder ); + sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder ); + } +} // end of sp_connector_toolbox_prep() + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/connector-toolbar.h b/src/widgets/connector-toolbar.h new file mode 100644 index 000000000..180c11e0f --- /dev/null +++ b/src/widgets/connector-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_CONNECTOR_TOOLBAR_H +#define SEEN_CONNECTOR_TOOLBAR_H + +/** + * @file + * Connector aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_CONNECTOR_TOOLBAR_H */ diff --git a/src/widgets/dash-selector.cpp b/src/widgets/dash-selector.cpp index 901d3b68c..fce7a9d9f 100644 --- a/src/widgets/dash-selector.cpp +++ b/src/widgets/dash-selector.cpp @@ -39,6 +39,7 @@ static double dash_4_1[] = {4.0, 1.0, -1.0}; static double dash_1_2[] = {1.0, 2.0, -1.0}; static double dash_1_4[] = {1.0, 4.0, -1.0}; +static size_t BD_LEN = 7; // must correspond to the number of entries in the next line static double *builtin_dashes[] = {dash_0, dash_1_1, dash_2_1, dash_4_1, dash_1_2, dash_1_4, NULL}; static double **dashes = NULL; @@ -79,12 +80,18 @@ SPDashSelector::SPDashSelector() this->pack_start(*sb, false, false, 0); - for (int i = 0; dashes[i]; i++) { + int np=0; + while (dashes[np]){ np++;} + for (int i = 0; i<np-1; i++) { // all but the custom one go this way // Add the dashes to the combobox Gtk::TreeModel::Row row = *(dash_store->append()); row[dash_columns.dash] = dashes[i]; row[dash_columns.pixbuf] = Glib::wrap(sp_dash_to_pixbuf(dashes[i])); } + // add the custom one + Gtk::TreeModel::Row row = *(dash_store->append()); + row[dash_columns.dash] = dashes[np-1]; + row[dash_columns.pixbuf] = Glib::wrap(sp_text_to_pixbuf((char *)"Custom")); this->set_data("pattern", dashes[0]); } @@ -109,20 +116,20 @@ void SPDashSelector::init_dashes() { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); std::vector<Glib::ustring> dash_prefs = prefs->getAllDirs(_prefs_path); + int pos = 0; if (!dash_prefs.empty()) { - int pos = 0; SPStyle *style = sp_style_new (NULL); - dashes = g_new (double *, dash_prefs.size() + 1); + dashes = g_new (double *, dash_prefs.size() + 2); // +1 for custom slot, +1 for terminator slot for (std::vector<Glib::ustring>::iterator i = dash_prefs.begin(); i != dash_prefs.end(); ++i) { sp_style_read_from_prefs(style, *i); - if (style->stroke_dash.n_dash > 0) { - dashes[pos] = g_new (double, style->stroke_dash.n_dash + 1); + if (!style->stroke_dasharray.values.empty()) { + dashes[pos] = g_new (double, style->stroke_dasharray.values.size() + 1); double *d = dashes[pos]; - int i = 0; - for (; i < style->stroke_dash.n_dash; i++) { - d[i] = style->stroke_dash.dash[i]; + unsigned i = 0; + for (; i < style->stroke_dasharray.values.size(); i++) { + d[i] = style->stroke_dasharray.values[i]; } d[i] = -1; } else { @@ -130,23 +137,36 @@ void SPDashSelector::init_dashes() { } pos += 1; } - dashes[pos] = NULL; - } else { - dashes = builtin_dashes; + } else { // This code may never execute - a new preferences.xml is created for a new user. Maybe if the user deletes dashes from preferences.xml? + dashes = g_new (double *, BD_LEN + 2); // +1 for custom slot, +1 for terminator slot + unsigned i; + for(i=0;i<BD_LEN;i++) { + dashes[i] = builtin_dashes[i]; + } + pos = BD_LEN; } + // make a place to hold the custom dashes, up to 15 positions long (+ terminator) + dashes[pos] = g_new (double, 16); + double *d = dashes[pos]; + int i=0; + for(i=0;i<15;i++){ d[i]=i; } // have to put something in there, this is a pattern hopefully nobody would choose + d[15]=-1.0; + // final terminator + dashes[++pos] = NULL; } } void SPDashSelector::set_dash (int ndash, double *dash, double o) { - int pos = 0; + int pos = -1; // Allows custom patterns to remain unscathed by this. + int count = 0; // will hold the NULL terminator at the end of the dashes list if (ndash > 0) { double delta = 0.0; for (int i = 0; i < ndash; i++) delta += dash[i]; delta /= 1000.0; - for (int i = 0; dashes[i]; i++) { + for (int i = 0; dashes[i]; i++,count++) { double *pattern = dashes[i]; int np = 0; while (pattern[np] >= 0.0) @@ -154,6 +174,7 @@ void SPDashSelector::set_dash (int ndash, double *dash, double o) if (np == ndash) { int j; for (j = 0; j < ndash; j++) { + if (!Geom::are_near(dash[j], pattern[j], delta)) break; } @@ -164,10 +185,27 @@ void SPDashSelector::set_dash (int ndash, double *dash, double o) } } } + else if(ndash==0) { + pos = 0; + } - this->set_data("pattern", dashes[pos]); - this->dash_combo.set_active(pos); - this->offset->set_value(o); + if(pos>=0){ + this->set_data("pattern", dashes[pos]); + this->dash_combo.set_active(pos); + this->offset->set_value(o); + } + else { // Hit a custom pattern in the SVG, write it into the combobox. + count--; // the one slot for custom patterns + double *d = dashes[count]; + int i=0; + for(i=0;i< (ndash > 15 ? 15 : ndash) ;i++) { + d[i]=dash[i]; + } // store the custom pattern + d[ndash]=-1.0; //terminate it + this->set_data("pattern", dashes[count]); + this->dash_combo.set_active(count); + this->offset->set_value(o); // what does this do???? + } } void SPDashSelector::get_dash(int *ndash, double **dash, double *off) @@ -200,33 +238,51 @@ void SPDashSelector::get_dash(int *ndash, double **dash, double *off) /** * Fill a pixbuf with the dash pattern using standard cairo drawing */ -GdkPixbuf* SPDashSelector::sp_dash_to_pixbuf(double *pattern) { - - int n_dashes; - for (n_dashes = 0; pattern[n_dashes] >= 0.0; n_dashes ++) ; - - cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, preview_width, preview_height); - cairo_t *ct = cairo_create(s); - - cairo_set_line_width (ct, preview_lineheight); - cairo_scale (ct, preview_lineheight, 1); - //cairo_set_source_rgb (ct, 0, 0, 0); - cairo_move_to (ct, 0, preview_height/2); - cairo_line_to (ct, preview_width, preview_height/2); - cairo_set_dash(ct, pattern, n_dashes, 0); - cairo_stroke (ct); - - cairo_destroy(ct); - cairo_surface_flush(s); - - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), - GDK_COLORSPACE_RGB, TRUE, 8, - preview_width, preview_height, cairo_image_surface_get_stride(s), - ink_cairo_pixbuf_cleanup, s); - convert_pixbuf_argb32_to_normal(pixbuf); - return pixbuf; +GdkPixbuf* SPDashSelector::sp_dash_to_pixbuf(double *pattern) +{ + int n_dashes; + for (n_dashes = 0; pattern[n_dashes] >= 0.0; n_dashes ++) ; + + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, preview_width, preview_height); + cairo_t *ct = cairo_create(s); + + cairo_set_line_width (ct, preview_lineheight); + cairo_scale (ct, preview_lineheight, 1); + //cairo_set_source_rgb (ct, 0, 0, 0); + cairo_move_to (ct, 0, preview_height/2); + cairo_line_to (ct, preview_width, preview_height/2); + cairo_set_dash(ct, pattern, n_dashes, 0); + cairo_stroke (ct); + + cairo_destroy(ct); + cairo_surface_flush(s); + + GdkPixbuf* pixbuf = ink_pixbuf_create_from_cairo_surface(s); + return pixbuf; } +/** + * Fill a pixbuf with a text label using standard cairo drawing + */ +GdkPixbuf* SPDashSelector::sp_text_to_pixbuf(char *text) +{ + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, preview_width, preview_height); + cairo_t *ct = cairo_create(s); + + cairo_select_font_face (ct, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (ct, 12.0); + cairo_set_source_rgb (ct, 0.0, 0.0, 0.0); + cairo_move_to (ct, 16.0, 13.0); + cairo_show_text (ct, text); + + cairo_stroke (ct); + + cairo_destroy(ct); + cairo_surface_flush(s); + + GdkPixbuf* pixbuf = ink_pixbuf_create_from_cairo_surface(s); + return pixbuf; +} void SPDashSelector::on_selection () { diff --git a/src/widgets/dash-selector.h b/src/widgets/dash-selector.h index 0a572f4de..5b9ebfa2b 100644 --- a/src/widgets/dash-selector.h +++ b/src/widgets/dash-selector.h @@ -10,6 +10,14 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + #include <gtkmm/box.h> #include <gtkmm/combobox.h> #include <gtkmm/liststore.h> @@ -46,6 +54,11 @@ private: GdkPixbuf* sp_dash_to_pixbuf(double *pattern); /** + * Fill a pixbuf with text standard cairo drawing + */ + GdkPixbuf* sp_text_to_pixbuf(char *text); + + /** * Callback for combobox image renderer */ void prepareImageRenderer( Gtk::TreeModel::const_iterator const &row ); diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index 6aecc4ada..583dbec85 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -27,7 +27,7 @@ #include <2geom/rect.h> #include "ui/dialog/dialog-manager.h" -#include "box3d-context.h" +#include "ui/tools/box3d-tool.h" #include "cms-system.h" #include "conn-avoid-ref.h" #include "desktop.h" @@ -41,8 +41,10 @@ #include "ege-select-one-action.h" #include <extension/db.h> #include "file.h" -#include "helper/units.h" -#include "helper/unit-tracker.h" +#include "helper/action.h" +#include "helper/action-context.h" +#include "util/units.h" +#include "ui/widget/unit-tracker.h" #include "inkscape-private.h" #include "interface.h" #include "macros.h" @@ -69,6 +71,7 @@ #include "verbs.h" #include <gtkmm/paned.h> +#include <gtkmm/messagedialog.h> #include <gtk/gtk.h> @@ -77,15 +80,11 @@ using Inkscape::round; #endif -using Inkscape::UnitTracker; +using Inkscape::UI::Widget::UnitTracker; using Inkscape::UI::UXManager; using Inkscape::UI::ToolboxFactory; using ege::AppearTimeTracker; - -#ifdef WITH_INKBOARD -#endif - - +using Inkscape::Util::unit_table; enum { ACTIVATE, @@ -100,7 +99,7 @@ enum { /* SPDesktopWidget */ static void sp_desktop_widget_class_init (SPDesktopWidgetClass *klass); -static void sp_desktop_widget_destroy (GtkObject *object); +static void sp_desktop_widget_dispose(GObject *object); static void sp_desktop_widget_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static void sp_desktop_widget_realize (GtkWidget *widget); @@ -257,10 +256,13 @@ SPDesktopWidget::window_get_pointer() #if GTK_CHECK_VERSION(3,0,0) GdkDisplay *display = gdk_window_get_display(window); - gdk_window_get_device_position(window, display->core_pointer, &x, &y, NULL); + GdkDeviceManager *dm = gdk_display_get_device_manager(display); + GdkDevice *device = gdk_device_manager_get_client_pointer(dm); + gdk_window_get_device_position(window, device, &x, &y, NULL); #else gdk_window_get_pointer(window, &x, &y, NULL); #endif + return Geom::Point(x,y); } @@ -298,35 +300,41 @@ GType SPDesktopWidget::getType(void) static void sp_desktop_widget_class_init (SPDesktopWidgetClass *klass) { - dtw_parent_class = (SPViewWidgetClass*)g_type_class_peek_parent (klass); + dtw_parent_class = SP_VIEW_WIDGET_CLASS(g_type_class_peek_parent(klass)); - GtkObjectClass *object_class = (GtkObjectClass *) klass; - GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + GObjectClass *object_class = G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); - object_class->destroy = sp_desktop_widget_destroy; + object_class->dispose = sp_desktop_widget_dispose; widget_class->size_allocate = sp_desktop_widget_size_allocate; widget_class->realize = sp_desktop_widget_realize; } /** + * Callback for changes in size of the canvas table (i.e. the container for + * the canvas, the rulers etc). + * + * This adjusts the range of the rulers when the dock container is adjusted + * (fixes lp:950552) + */ +static void canvas_tbl_size_allocate(GtkWidget * /*widget*/, + GdkRectangle * /*allocation*/, + gpointer data) +{ + SPDesktopWidget *dtw = SP_DESKTOP_WIDGET(data); + sp_desktop_widget_update_rulers(dtw); +} + +/** * Callback for SPDesktopWidget object initialization. */ void SPDesktopWidget::init( SPDesktopWidget *dtw ) { - GtkWidget *widget; - GtkWidget *tbl; - GtkWidget *canvas_tbl; - - GtkWidget *eventbox; - GtkStyle *style; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); new (&dtw->modified_connection) sigc::connection(); - widget = GTK_WIDGET (dtw); - dtw->window = 0; dtw->desktop = NULL; dtw->_interaction_disabled_counter = 0; @@ -334,7 +342,6 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) /* Main table */ #if GTK_CHECK_VERSION(3,0,0) dtw->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_box_set_homogeneous(GTK_BOX(dtw->vbox), FALSE); #else dtw->vbox = gtk_vbox_new (FALSE, 0); #endif @@ -342,7 +349,6 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) #if GTK_CHECK_VERSION(3,0,0) dtw->statusbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_set_homogeneous(GTK_BOX(dtw->statusbar), FALSE); #else dtw->statusbar = gtk_hbox_new (FALSE, 0); #endif @@ -354,15 +360,20 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) dtw->panels = new SwatchesPanel("/embedded/swatches"); dtw->panels->setOrientation(SP_ANCHOR_SOUTH); + +#if GTK_CHECK_VERSION(3,0,0) + dtw->panels->set_vexpand(false); +#endif + gtk_box_pack_end( GTK_BOX( dtw->vbox ), GTK_WIDGET(dtw->panels->gobj()), FALSE, TRUE, 0 ); } #if GTK_CHECK_VERSION(3,0,0) dtw->hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_set_homogeneous(GTK_BOX(dtw->hbox), FALSE); #else dtw->hbox = gtk_hbox_new(FALSE, 0); #endif + gtk_box_pack_end( GTK_BOX (dtw->vbox), dtw->hbox, TRUE, TRUE, 0 ); gtk_widget_show(dtw->hbox); @@ -380,53 +391,74 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) ToolboxFactory::setOrientation( dtw->tool_toolbox, GTK_ORIENTATION_VERTICAL ); gtk_box_pack_start( GTK_BOX(dtw->hbox), dtw->tool_toolbox, FALSE, TRUE, 0 ); - tbl = gtk_table_new (2, 3, FALSE); - gtk_box_pack_start( GTK_BOX(dtw->hbox), tbl, TRUE, TRUE, 1 ); - - canvas_tbl = gtk_table_new (3, 3, FALSE); - /* Horizontal ruler */ - eventbox = gtk_event_box_new (); - dtw->hruler = sp_hruler_new (); + GtkWidget *eventbox = gtk_event_box_new (); + dtw->hruler = sp_ruler_new(GTK_ORIENTATION_HORIZONTAL); dtw->hruler_box = eventbox; - sp_ruler_set_metric (GTK_DEPRECATED_RULER (dtw->hruler), SP_PT); - gtk_widget_set_tooltip_text (dtw->hruler_box, gettext(sp_unit_get_plural (&sp_unit_get_by_id(SP_UNIT_PT)))); + Inkscape::Util::Unit const *pt = unit_table.getUnit("pt"); + sp_ruler_set_unit(SP_RULER(dtw->hruler), pt); + gtk_widget_set_tooltip_text (dtw->hruler_box, gettext(pt->name_plural.c_str())); gtk_container_add (GTK_CONTAINER (eventbox), dtw->hruler); - gtk_table_attach (GTK_TABLE (canvas_tbl), eventbox, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(GTK_FILL), - gtk_widget_get_style(widget)->xthickness, 0); g_signal_connect (G_OBJECT (eventbox), "button_press_event", G_CALLBACK (sp_dt_hruler_event), dtw); g_signal_connect (G_OBJECT (eventbox), "button_release_event", G_CALLBACK (sp_dt_hruler_event), dtw); g_signal_connect (G_OBJECT (eventbox), "motion_notify_event", G_CALLBACK (sp_dt_hruler_event), dtw); +#if GTK_CHECK_VERSION(3,0,0) + GtkWidget *tbl = gtk_grid_new(); + dtw->canvas_tbl = gtk_grid_new(); + + gtk_grid_attach(GTK_GRID(dtw->canvas_tbl), eventbox, 1, 0, 1, 1); +#else + GtkWidget *tbl = gtk_table_new(2, 3, FALSE); + dtw->canvas_tbl = gtk_table_new(3, 3, FALSE); + + gtk_table_attach(GTK_TABLE(dtw->canvas_tbl), + eventbox, + 1, 2, 0, 1, + GTK_FILL, GTK_FILL, + 0, 0); +#endif + + gtk_box_pack_start( GTK_BOX(dtw->hbox), tbl, TRUE, TRUE, 1 ); + /* Vertical ruler */ eventbox = gtk_event_box_new (); - dtw->vruler = sp_vruler_new (); + dtw->vruler = sp_ruler_new(GTK_ORIENTATION_VERTICAL); dtw->vruler_box = eventbox; - sp_ruler_set_metric (GTK_DEPRECATED_RULER (dtw->vruler), SP_PT); - gtk_widget_set_tooltip_text (dtw->vruler_box, gettext(sp_unit_get_plural (&sp_unit_get_by_id(SP_UNIT_PT)))); + sp_ruler_set_unit (SP_RULER (dtw->vruler), pt); + gtk_widget_set_tooltip_text (dtw->vruler_box, gettext(pt->name_plural.c_str())); gtk_container_add (GTK_CONTAINER (eventbox), GTK_WIDGET (dtw->vruler)); - gtk_table_attach (GTK_TABLE (canvas_tbl), eventbox, 0, 1, 1, 2, (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(GTK_FILL), 0, - gtk_widget_get_style(widget)->ythickness); - g_signal_connect (G_OBJECT (eventbox), "button_press_event", G_CALLBACK (sp_dt_vruler_event), dtw); - g_signal_connect (G_OBJECT (eventbox), "button_release_event", G_CALLBACK (sp_dt_vruler_event), dtw); - g_signal_connect (G_OBJECT (eventbox), "motion_notify_event", G_CALLBACK (sp_dt_vruler_event), dtw); - /* Horizontal scrollbar */ - dtw->hadj = (GtkAdjustment *) gtk_adjustment_new (0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0); #if GTK_CHECK_VERSION(3,0,0) - dtw->hscrollbar = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (dtw->hadj)); + gtk_grid_attach(GTK_GRID(dtw->canvas_tbl), eventbox, 0, 1, 1, 1); #else - dtw->hscrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (dtw->hadj)); + gtk_table_attach(GTK_TABLE (dtw->canvas_tbl), + eventbox, + 0, 1, 1, 2, + GTK_FILL, GTK_FILL, + 0, 0); #endif - gtk_table_attach (GTK_TABLE (canvas_tbl), dtw->hscrollbar, 1, 2, 2, 3, (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(GTK_SHRINK), 0, 0); - /* Vertical scrollbar and the sticky zoom button */ + g_signal_connect (G_OBJECT (eventbox), "button_press_event", G_CALLBACK (sp_dt_vruler_event), dtw); + g_signal_connect (G_OBJECT (eventbox), "button_release_event", G_CALLBACK (sp_dt_vruler_event), dtw); + g_signal_connect (G_OBJECT (eventbox), "motion_notify_event", G_CALLBACK (sp_dt_vruler_event), dtw); + + // Horizontal scrollbar + dtw->hadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0)); + #if GTK_CHECK_VERSION(3,0,0) + dtw->hscrollbar = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (dtw->hadj)); + gtk_grid_attach(GTK_GRID(dtw->canvas_tbl), dtw->hscrollbar, 1, 2, 1, 1); dtw->vscrollbar_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_box_set_homogeneous(GTK_BOX(dtw->vscrollbar_box), FALSE); #else + dtw->hscrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (dtw->hadj)); + gtk_table_attach(GTK_TABLE (dtw->canvas_tbl), dtw->hscrollbar, 1, 2, 2, 3, + GTK_FILL, GTK_SHRINK, + 0, 0); dtw->vscrollbar_box = gtk_vbox_new (FALSE, 0); #endif + + // Sticky zoom button dtw->sticky_zoom = sp_button_new_from_data ( Inkscape::ICON_SIZE_DECORATION, SP_BUTTON_TYPE_TOGGLE, NULL, @@ -435,20 +467,30 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dtw->sticky_zoom), prefs->getBool("/options/stickyzoom/value")); gtk_box_pack_start (GTK_BOX (dtw->vscrollbar_box), dtw->sticky_zoom, FALSE, FALSE, 0); g_signal_connect (G_OBJECT (dtw->sticky_zoom), "toggled", G_CALLBACK (sp_dtw_sticky_zoom_toggled), dtw); - dtw->vadj = (GtkAdjustment *) gtk_adjustment_new (0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0); + + // Vertical scrollbar + dtw->vadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0)); + #if GTK_CHECK_VERSION(3,0,0) dtw->vscrollbar = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT(dtw->vadj)); #else dtw->vscrollbar = gtk_vscrollbar_new (GTK_ADJUSTMENT (dtw->vadj)); #endif + gtk_box_pack_start (GTK_BOX (dtw->vscrollbar_box), dtw->vscrollbar, TRUE, TRUE, 0); - gtk_table_attach (GTK_TABLE (canvas_tbl), dtw->vscrollbar_box, 2, 3, 0, 2, (GtkAttachOptions)(GTK_SHRINK), (GtkAttachOptions)(GTK_FILL), 0, 0); +#if GTK_CHECK_VERSION(3,0,0) + gtk_grid_attach(GTK_GRID(dtw->canvas_tbl), dtw->vscrollbar_box, 2, 0, 1, 2); +#else + gtk_table_attach(GTK_TABLE(dtw->canvas_tbl), dtw->vscrollbar_box, 2, 3, 0, 2, + GTK_SHRINK, GTK_FILL, + 0, 0); +#endif gchar const* tip = ""; Inkscape::Verb* verb = Inkscape::Verb::get( SP_VERB_VIEW_CMS_TOGGLE ); if ( verb ) { - SPAction *act = verb->get_action( dtw->viewwidget.view ); + SPAction *act = verb->get_action( Inkscape::ActionContext( dtw->viewwidget.view ) ); if ( act && act->tip ) { tip = act->tip; } @@ -474,7 +516,16 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) #else cms_adjust_set_sensitive(dtw, FALSE); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - gtk_table_attach( GTK_TABLE(canvas_tbl), dtw->cms_adjust, 2, 3, 2, 3, (GtkAttachOptions)(GTK_SHRINK), (GtkAttachOptions)(GTK_SHRINK), 0, 0); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_grid_attach( GTK_GRID(dtw->canvas_tbl), dtw->cms_adjust, 2, 2, 1, 1); +#else + gtk_table_attach( GTK_TABLE(dtw->canvas_tbl), dtw->cms_adjust, 2, 3, 2, 3, + (GtkAttachOptions)(GTK_SHRINK), + (GtkAttachOptions)(GTK_SHRINK), + 0, 0); +#endif + { if (!watcher) { watcher = new CMSPrefWatcher(); @@ -488,13 +539,30 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) dtw->canvas->enable_cms_display_adj = prefs->getBool("/options/displayprofile/enable"); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) gtk_widget_set_can_focus (GTK_WIDGET (dtw->canvas), TRUE); - style = gtk_style_copy(gtk_widget_get_style(GTK_WIDGET(dtw->canvas))); + + sp_ruler_add_track_widget (SP_RULER(dtw->hruler), GTK_WIDGET(dtw->canvas)); + sp_ruler_add_track_widget (SP_RULER(dtw->vruler), GTK_WIDGET(dtw->canvas)); + +#if GTK_CHECK_VERSION(3,0,0) + GdkRGBA white = {1,1,1,1}; + gtk_widget_override_background_color(GTK_WIDGET(dtw->canvas), + GTK_STATE_FLAG_NORMAL, + &white); +#else + GtkStyle *style = gtk_style_copy(gtk_widget_get_style(GTK_WIDGET(dtw->canvas))); style->bg[GTK_STATE_NORMAL] = style->white; gtk_widget_set_style (GTK_WIDGET (dtw->canvas), style); - if ( prefs->getBool("/options/useextinput/value", true) ) - gtk_widget_set_extension_events(GTK_WIDGET (dtw->canvas) , GDK_EXTENSION_EVENTS_ALL); //set extension events for tablets, unless disabled in preferences +#endif + g_signal_connect (G_OBJECT (dtw->canvas), "event", G_CALLBACK (sp_desktop_widget_event), dtw); - gtk_table_attach (GTK_TABLE (canvas_tbl), GTK_WIDGET(dtw->canvas), 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), 0, 0); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_hexpand(GTK_WIDGET(dtw->canvas), TRUE); + gtk_widget_set_vexpand(GTK_WIDGET(dtw->canvas), TRUE); + gtk_grid_attach(GTK_GRID(dtw->canvas_tbl), GTK_WIDGET(dtw->canvas), 1, 1, 1, 1); +#else + gtk_table_attach (GTK_TABLE (dtw->canvas_tbl), GTK_WIDGET(dtw->canvas), 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), 0, 0); +#endif /* Dock */ bool create_dock = @@ -504,8 +572,13 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) if (create_dock) { dtw->dock = new Inkscape::UI::Widget::Dock(); +#if WITH_GTKMM_3_0 + Gtk::Paned *paned = new Gtk::Paned(); +#else Gtk::HPaned *paned = new Gtk::HPaned(); - paned->pack1(*Glib::wrap(canvas_tbl)); +#endif + + paned->pack1(*Glib::wrap(dtw->canvas_tbl)); paned->pack2(dtw->dock->getWidget(), Gtk::FILL); /* Prevent the paned from catching F6 and F8 by unsetting the default callbacks */ @@ -514,12 +587,24 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) paned_class->cycle_handle_focus = NULL; } +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_hexpand(GTK_WIDGET(paned->gobj()), TRUE); + gtk_widget_set_vexpand(GTK_WIDGET(paned->gobj()), TRUE); + gtk_grid_attach(GTK_GRID(tbl), GTK_WIDGET (paned->gobj()), 1, 1, 1, 1); +#else gtk_table_attach (GTK_TABLE (tbl), GTK_WIDGET (paned->gobj()), 1, 2, 1, 2, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0); +#endif } else { - gtk_table_attach (GTK_TABLE (tbl), GTK_WIDGET (canvas_tbl), 1, 2, 1, 2, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_hexpand(GTK_WIDGET(dtw->canvas_tbl), TRUE); + gtk_widget_set_vexpand(GTK_WIDGET(dtw->canvas_tbl), TRUE); + gtk_grid_attach(GTK_GRID(tbl), GTK_WIDGET (dtw->canvas_tbl), 1, 1, 1, 1); +#else + gtk_table_attach (GTK_TABLE (tbl), GTK_WIDGET (dtw->canvas_tbl), 1, 2, 1, 2, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0); +#endif } dtw->selected_style = new Inkscape::UI::Widget::SelectedStyle(true); @@ -539,7 +624,6 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) g_signal_connect (G_OBJECT (dtw->vadj), "value-changed", G_CALLBACK (sp_desktop_widget_adjustment_value_changed), dtw); GtkWidget *statusbar_tail=gtk_statusbar_new(); - gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusbar_tail), TRUE); gtk_box_pack_end (GTK_BOX (dtw->statusbar), statusbar_tail, FALSE, FALSE, 0); // zoom status spinbutton @@ -558,35 +642,66 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) dtw->zoom_update = g_signal_connect (G_OBJECT (dtw->zoom_status), "populate_popup", G_CALLBACK (sp_dtw_zoom_populate_popup), dtw); // cursor coordinates - dtw->coord_status = gtk_table_new (5, 2, FALSE); +#if GTK_CHECK_VERSION(3,0,0) + dtw->coord_status = gtk_grid_new(); + gtk_grid_set_row_spacing(GTK_GRID(dtw->coord_status), 0); + gtk_grid_set_column_spacing(GTK_GRID(dtw->coord_status), 2); + GtkWidget* sep = gtk_separator_new(GTK_ORIENTATION_VERTICAL); + gtk_grid_attach(GTK_GRID(dtw->coord_status), + GTK_WIDGET(sep), + 0, 0, 1, 2); +#else + dtw->coord_status = gtk_table_new(5, 2, FALSE); gtk_table_set_row_spacings(GTK_TABLE(dtw->coord_status), 0); gtk_table_set_col_spacings(GTK_TABLE(dtw->coord_status), 2); gtk_table_attach(GTK_TABLE(dtw->coord_status), -#if GTK_CHECK_VERSION(3,0,0) - gtk_separator_new(GTK_ORIENTATION_VERTICAL), -#else gtk_vseparator_new(), + 0, 1, 0, 2, + GTK_FILL, GTK_FILL, 0, 0); #endif - 0,1, 0,2, GTK_FILL, GTK_FILL, 0, 0); + eventbox = gtk_event_box_new (); gtk_container_add (GTK_CONTAINER (eventbox), dtw->coord_status); gtk_widget_set_tooltip_text (eventbox, _("Cursor coordinates")); GtkWidget *label_x = gtk_label_new(_("X:")); gtk_misc_set_alignment (GTK_MISC(label_x), 0.0, 0.5); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_grid_attach(GTK_GRID(dtw->coord_status), + label_x, 1, 0, 1, 1); +#else gtk_table_attach(GTK_TABLE(dtw->coord_status), label_x, 1,2, 0,1, GTK_FILL, GTK_FILL, 0, 0); +#endif + GtkWidget *label_y = gtk_label_new(_("Y:")); gtk_misc_set_alignment (GTK_MISC(label_y), 0.0, 0.5); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_grid_attach(GTK_GRID(dtw->coord_status), label_y, 1, 1, 1, 1); +#else gtk_table_attach(GTK_TABLE(dtw->coord_status), label_y, 1,2, 1,2, GTK_FILL, GTK_FILL, 0, 0); +#endif + dtw->coord_status_x = gtk_label_new(NULL); gtk_label_set_markup( GTK_LABEL(dtw->coord_status_x), "<tt> 0.00 </tt>" ); gtk_misc_set_alignment (GTK_MISC(dtw->coord_status_x), 1.0, 0.5); dtw->coord_status_y = gtk_label_new(NULL); gtk_label_set_markup( GTK_LABEL(dtw->coord_status_y), "<tt> 0.00 </tt>" ); gtk_misc_set_alignment (GTK_MISC(dtw->coord_status_y), 1.0, 0.5); + GtkWidget* label_z = gtk_label_new(_("Z:")); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->coord_status_x, 2, 0, 1, 1); + gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->coord_status_y, 2, 1, 1, 1); + gtk_grid_attach(GTK_GRID(dtw->coord_status), label_z, 3, 0, 1, 2); + gtk_grid_attach(GTK_GRID(dtw->coord_status), dtw->zoom_status, 4, 0, 1, 2); +#else gtk_table_attach(GTK_TABLE(dtw->coord_status), dtw->coord_status_x, 2,3, 0,1, GTK_FILL, GTK_FILL, 0, 0); gtk_table_attach(GTK_TABLE(dtw->coord_status), dtw->coord_status_y, 2,3, 1,2, GTK_FILL, GTK_FILL, 0, 0); - gtk_table_attach(GTK_TABLE(dtw->coord_status), gtk_label_new(_("Z:")), 3,4, 0,2, GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(dtw->coord_status), label_z, 3,4, 0,2, GTK_FILL, GTK_FILL, 0, 0); gtk_table_attach(GTK_TABLE(dtw->coord_status), dtw->zoom_status, 4,5, 0,2, GTK_FILL, GTK_FILL, 0, 0); +#endif + sp_set_font_size_smaller (dtw->coord_status); gtk_box_pack_end (GTK_BOX (statusbar_tail), eventbox, FALSE, FALSE, 1); @@ -612,9 +727,7 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) dtw->select_status_eventbox = gtk_event_box_new (); dtw->select_status = gtk_label_new (NULL); -#if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 6 gtk_label_set_ellipsize (GTK_LABEL(dtw->select_status), PANGO_ELLIPSIZE_END); -#endif gtk_misc_set_alignment (GTK_MISC (dtw->select_status), 0.0, 0.5); gtk_widget_set_size_request (dtw->select_status, 1, -1); // display the initial welcome message in the statusbar @@ -645,16 +758,26 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) } overallTimer = 0; } + + // Ensure that ruler ranges are updated correctly whenever the canvas table + // is resized + g_signal_connect (G_OBJECT (dtw->canvas_tbl), + "size-allocate", + G_CALLBACK (canvas_tbl_size_allocate), + dtw); } /** * Called before SPDesktopWidget destruction. */ -static void -sp_desktop_widget_destroy (GtkObject *object) +static void sp_desktop_widget_dispose(GObject *object) { SPDesktopWidget *dtw = SP_DESKTOP_WIDGET (object); + if (dtw == NULL) { + return; + } + UXManager::getInstance()->delTrack(dtw); if (dtw->desktop) { @@ -667,7 +790,10 @@ sp_desktop_widget_destroy (GtkObject *object) g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->zoom_status), (gpointer) G_CALLBACK (sp_dtw_zoom_value_changed), dtw); g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->zoom_status), (gpointer) G_CALLBACK (sp_dtw_zoom_populate_popup), dtw); g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->canvas), (gpointer) G_CALLBACK (sp_desktop_widget_event), dtw); + g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->canvas_tbl), (gpointer) G_CALLBACK (canvas_tbl_size_allocate), dtw); + + dtw->layer_selector->setDesktop(NULL); dtw->layer_selector->unreference(); inkscape_remove_desktop (dtw->desktop); // clears selection too dtw->modified_connection.disconnect(); @@ -678,8 +804,8 @@ sp_desktop_widget_destroy (GtkObject *object) dtw->modified_connection.~connection(); - if (GTK_OBJECT_CLASS (dtw_parent_class)->destroy) { - (* GTK_OBJECT_CLASS (dtw_parent_class)->destroy) (object); + if (G_OBJECT_CLASS (dtw_parent_class)->dispose) { + (* G_OBJECT_CLASS (dtw_parent_class)->dispose) (object); } } @@ -693,18 +819,21 @@ sp_desktop_widget_destroy (GtkObject *object) void SPDesktopWidget::updateTitle(gchar const* uri) { - Gtk::Window *window = (Gtk::Window*)g_object_get_data(G_OBJECT(this), "window"); + Gtk::Window *window = static_cast<Gtk::Window*>(g_object_get_data(G_OBJECT(this), "window")); if (window) { gchar const *fname = uri; GString *name = g_string_new (""); - gchar const *grayscalename = "(grayscale) "; - gchar const *grayscalenamecomma = ", grayscale"; - gchar const *printcolorsname = "(print colors preview) "; - gchar const *printcolorsnamecomma = ", print colors preview"; - gchar const *colormodename = ""; - gchar const *colormodenamecomma = ""; + gchar const *grayscalename = N_("grayscale"); + gchar const *grayscalenamecomma = N_(", grayscale"); + gchar const *printcolorsname = N_("print colors preview"); + gchar const *printcolorsnamecomma = N_(", print colors preview"); + gchar const *outlinename = N_("outline"); + gchar const *nofiltersname = N_("no filters"); + gchar const *colormodename = NULL; + gchar const *colormodenamecomma = NULL; + gchar const *rendermodename = NULL; gchar const *modifiedname = ""; SPDocument *doc = this->desktop->doc(); if (doc->isModifiedSinceSave()) { @@ -718,22 +847,40 @@ SPDesktopWidget::updateTitle(gchar const* uri) colormodename = printcolorsname; colormodenamecomma = printcolorsnamecomma; } + if (this->desktop->getMode() == Inkscape::RENDERMODE_OUTLINE) { + rendermodename = outlinename; + } else if (this->desktop->getMode() == Inkscape::RENDERMODE_NO_FILTERS) { + rendermodename = nofiltersname; + } + if (this->desktop->number > 1) { - if (this->desktop->getMode() == Inkscape::RENDERMODE_OUTLINE) { - g_string_printf (name, _("%s%s: %d (outline%s) - Inkscape"), modifiedname, fname, this->desktop->number, colormodenamecomma); - } else if (this->desktop->getMode() == Inkscape::RENDERMODE_NO_FILTERS) { - g_string_printf (name, _("%s%s: %d (no filters%s) - Inkscape"), modifiedname, fname, this->desktop->number, colormodenamecomma); + if (rendermodename) { + if (colormodenamecomma) { + g_string_printf (name, _("%s%s: %d (%s%s) - Inkscape"), modifiedname, fname, this->desktop->number, _(rendermodename), _(colormodenamecomma)); + } else { + g_string_printf (name, _("%s%s: %d (%s) - Inkscape"), modifiedname, fname, this->desktop->number, _(rendermodename)); + } } else { - g_string_printf (name, _("%s%s: %d %s- Inkscape"), modifiedname, fname, this->desktop->number, colormodename); + if (colormodename) { + g_string_printf (name, _("%s%s: %d (%s) - Inkscape"), modifiedname, fname, this->desktop->number, _(colormodename)); + } else { + g_string_printf (name, _("%s%s: %d - Inkscape"), modifiedname, fname, this->desktop->number); + } } } else { - if (this->desktop->getMode() == Inkscape::RENDERMODE_OUTLINE) { - g_string_printf (name, _("%s%s (outline%s) - Inkscape"), modifiedname, fname, colormodenamecomma); - } else if (this->desktop->getMode() == Inkscape::RENDERMODE_NO_FILTERS) { - g_string_printf (name, _("%s%s (no filters%s) - Inkscape"), modifiedname, fname, colormodenamecomma); + if (rendermodename) { + if (colormodenamecomma) { + g_string_printf (name, _("%s%s (%s%s) - Inkscape"), modifiedname, fname, _(rendermodename), _(colormodenamecomma)); + } else { + g_string_printf (name, _("%s%s (%s) - Inkscape"), modifiedname, fname, _(rendermodename)); + } } else { - g_string_printf (name, _("%s%s %s- Inkscape"), modifiedname, fname, colormodename); + if (colormodename) { + g_string_printf (name, _("%s%s (%s) - Inkscape"), modifiedname, fname, _(colormodename)); + } else { + g_string_printf (name, _("%s%s - Inkscape"), modifiedname, fname); + } } } window->set_title (name->str); @@ -854,12 +1001,13 @@ sp_desktop_widget_event (GtkWidget *widget, GdkEvent *event, SPDesktopWidget *dt if (GTK_WIDGET_CLASS (dtw_parent_class)->event) { return (* GTK_WIDGET_CLASS (dtw_parent_class)->event) (widget, event); } else { - // The keypress events need to be passed to desktop handler explicitly, - // because otherwise the event contexts only receive keypresses when the mouse cursor - // is over the canvas. This redirection is only done for keypresses and only if there's no + // The key press/release events need to be passed to desktop handler explicitly, + // because otherwise the event contexts only receive key events when the mouse cursor + // is over the canvas. This redirection is only done for key events and only if there's no // current item on the canvas, because item events and all mouse events are caught // and passed on by the canvas acetate (I think). --bb - if (event->type == GDK_KEY_PRESS && !dtw->canvas->current_item) { + if ((event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE) + && !dtw->canvas->current_item) { return sp_desktop_root_handler (NULL, event, dtw->desktop); } } @@ -912,7 +1060,7 @@ void cms_adjust_set_sensitive( SPDesktopWidget *dtw, bool enabled ) { Inkscape::Verb* verb = Inkscape::Verb::get( SP_VERB_VIEW_CMS_TOGGLE ); if ( verb ) { - SPAction *act = verb->get_action( dtw->viewwidget.view ); + SPAction *act = verb->get_action( Inkscape::ActionContext( dtw->viewwidget.view ) ); if ( act ) { sp_action_set_sensitive( act, enabled ); } @@ -961,15 +1109,18 @@ SPDesktopWidget::shutdown() "If you close without saving, your changes will be discarded."), doc->getName()); // fix for bug lp:168809 - gtk_widget_set_can_focus(GTK_WIDGET(GTK_MESSAGE_DIALOG(dialog)->label), FALSE); + GtkWidget *ma = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog)); + GList *ma_labels = gtk_container_get_children(GTK_CONTAINER(ma)); + GtkWidget *label = GTK_WIDGET(g_list_first(ma_labels)->data); + gtk_widget_set_can_focus(label, FALSE); GtkWidget *close_button; close_button = gtk_button_new_with_mnemonic(_("Close _without saving")); gtk_widget_show(close_button); gtk_dialog_add_action_widget(GTK_DIALOG(dialog), close_button, GTK_RESPONSE_NO); - gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); - gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_SAVE, GTK_RESPONSE_YES); + gtk_dialog_add_button(GTK_DIALOG(dialog), _("_Cancel"), GTK_RESPONSE_CANCEL); + gtk_dialog_add_button(GTK_DIALOG(dialog), _("_Save"), GTK_RESPONSE_YES); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES); gint response; @@ -979,7 +1130,7 @@ SPDesktopWidget::shutdown() switch (response) { case GTK_RESPONSE_YES: { - Gtk::Window *window = (Gtk::Window*)g_object_get_data(G_OBJECT(this), "window"); + Gtk::Window *window = static_cast<Gtk::Window*>(g_object_get_data(G_OBJECT(this), "window")); doc->doRef(); sp_namedview_document_from_window(desktop); @@ -1017,17 +1168,20 @@ SPDesktopWidget::shutdown() "Do you want to save this file as Inkscape SVG?"), doc->getName() ? doc->getName() : "Unnamed"); // fix for bug lp:168809 - gtk_widget_set_can_focus(GTK_WIDGET(GTK_MESSAGE_DIALOG(dialog)->label), FALSE); + GtkWidget *ma = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog)); + GList *ma_labels = gtk_container_get_children(GTK_CONTAINER(ma)); + GtkWidget *label = GTK_WIDGET(g_list_first(ma_labels)->data); + gtk_widget_set_can_focus(label, FALSE); GtkWidget *close_button; close_button = gtk_button_new_with_mnemonic(_("Close _without saving")); gtk_widget_show(close_button); - GtkWidget *save_button; - save_button = gtk_button_new_with_mnemonic(_("_Save as Inkscape SVG")); + GtkWidget *save_button = gtk_button_new_with_mnemonic(_("_Save as Inkscape SVG")); + gtk_widget_set_can_default(save_button, TRUE); gtk_widget_show(save_button); gtk_dialog_add_action_widget(GTK_DIALOG(dialog), close_button, GTK_RESPONSE_NO); - gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + gtk_dialog_add_button(GTK_DIALOG(dialog), _("_Cancel"), GTK_RESPONSE_CANCEL); gtk_dialog_add_action_widget(GTK_DIALOG(dialog), save_button, GTK_RESPONSE_YES); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES); @@ -1040,7 +1194,7 @@ SPDesktopWidget::shutdown() { doc->doRef(); - Gtk::Window *window = (Gtk::Window*)g_object_get_data(G_OBJECT(this), "window"); + Gtk::Window *window = static_cast<Gtk::Window*>(g_object_get_data(G_OBJECT(this), "window")); if (sp_file_save_dialog(*window, doc, Inkscape::Extension::FILE_SAVE_METHOD_INKSCAPE_SVG)) { doc->doUnref(); @@ -1152,7 +1306,7 @@ SPDesktopWidget::getWindowGeometry (gint &x, gint &y, gint &w, gint &h) gboolean vis = gtk_widget_get_visible (GTK_WIDGET(this)); (void)vis; // TODO figure out why it is here but not used. - Gtk::Window *window = (Gtk::Window*)g_object_get_data(G_OBJECT(this), "window"); + Gtk::Window *window = static_cast<Gtk::Window*>(g_object_get_data(G_OBJECT(this), "window")); if (window) { @@ -1164,7 +1318,7 @@ SPDesktopWidget::getWindowGeometry (gint &x, gint &y, gint &w, gint &h) void SPDesktopWidget::setWindowPosition (Geom::Point p) { - Gtk::Window *window = (Gtk::Window*)g_object_get_data(G_OBJECT(this), "window"); + Gtk::Window *window = static_cast<Gtk::Window*>(g_object_get_data(G_OBJECT(this), "window")); if (window) { @@ -1175,7 +1329,7 @@ SPDesktopWidget::setWindowPosition (Geom::Point p) void SPDesktopWidget::setWindowSize (gint w, gint h) { - Gtk::Window *window = (Gtk::Window*)g_object_get_data(G_OBJECT(this), "window"); + Gtk::Window *window = static_cast<Gtk::Window*>(g_object_get_data(G_OBJECT(this), "window")); if (window) { @@ -1193,10 +1347,10 @@ SPDesktopWidget::setWindowSize (gint w, gint h) void SPDesktopWidget::setWindowTransient (void *p, int transient_policy) { - Gtk::Window *window = (Gtk::Window*)g_object_get_data(G_OBJECT(this), "window"); + Gtk::Window *window = static_cast<Gtk::Window*>(g_object_get_data(G_OBJECT(this), "window")); if (window) { - GtkWindow *w = (GtkWindow *) window->gobj(); + GtkWindow *w = GTK_WINDOW(window->gobj()); gtk_window_set_transient_for (GTK_WINDOW(p), w); /* @@ -1239,24 +1393,14 @@ bool SPDesktopWidget::showInfoDialog( Glib::ustring const &message ) return result; } -bool -SPDesktopWidget::warnDialog (gchar* text) +bool SPDesktopWidget::warnDialog (Glib::ustring const &text) { - GtkWindow *w =GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(this))); - if (w) - { - GtkWidget *dialog = gtk_message_dialog_new( - w, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_YES_NO, - "%s", text); - gint response = gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - if (response == GTK_RESPONSE_YES) - return true; - } - return false; + Gtk::MessageDialog dialog (*window, text, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK_CANCEL); + gint response = dialog.run(); + if (response == Gtk::RESPONSE_OK) + return true; + else + return false; } void @@ -1441,7 +1585,7 @@ SPDesktopWidget::setToolboxSelectOneValue (gchar const *id, int value) { gpointer hb = sp_search_by_data_recursive(aux_toolbox, (gpointer) id); if (hb) { - ege_select_one_action_set_active((EgeSelectOneAction*) hb, value); + ege_select_one_action_set_active(EGE_SELECT_ONE_ACTION(hb), value); } } @@ -1518,7 +1662,7 @@ SPDesktopWidget* SPDesktopWidget::createInstance(SPNamedView *namedview) { SPDesktopWidget *dtw = static_cast<SPDesktopWidget*>(g_object_new(SP_TYPE_DESKTOP_WIDGET, NULL)); - dtw->dt2r = 1.0 / namedview->doc_units->unittobase; + dtw->dt2r = 1. / namedview->doc_units->factor; dtw->ruler_origin = Geom::Point(0,0); //namedview->gridorigin; Why was the grid origin used here? @@ -1563,59 +1707,25 @@ SPDesktopWidget* SPDesktopWidget::createInstance(SPNamedView *namedview) return dtw; } -void -SPDesktopWidget::viewSetPosition (Geom::Point p) -{ - Geom::Point const origin = ( p - ruler_origin ); - gdouble hlower, hupper, hmax_range; - gdouble vlower, vupper, vmax_range; - gtk_deprecated_ruler_get_range(GTK_DEPRECATED_RULER(hruler), &hlower, &hupper, NULL, &hmax_range); - gtk_deprecated_ruler_set_range(GTK_DEPRECATED_RULER(hruler), hlower, hupper, origin[Geom::X], hmax_range); - gtk_deprecated_ruler_get_range(GTK_DEPRECATED_RULER(vruler), &vlower, &vupper, NULL, &vmax_range); - gtk_deprecated_ruler_set_range(GTK_DEPRECATED_RULER(vruler), vlower, vupper, origin[Geom::Y], vmax_range); -} void sp_desktop_widget_update_rulers (SPDesktopWidget *dtw) { - sp_desktop_widget_update_hruler(dtw); - sp_desktop_widget_update_vruler(dtw); -} + Geom::Rect viewbox = dtw->desktop->get_display_area(); -void -sp_desktop_widget_update_hruler (SPDesktopWidget *dtw) -{ - /* The viewbox (in integers) must exactly match the size of SPCanvasbuf's pixel buffer. - * This is important because the former is being used for drawing the ruler, whereas - * the latter is used for drawing e.g. the grids and guides. Only when the viewbox - * coincides with the pixel buffer, everything will line up nicely. - */ - Geom::IntRect viewbox = dtw->canvas->getViewboxIntegers(); - gdouble position; + double lower_x = dtw->dt2r * (viewbox.left() - dtw->ruler_origin[Geom::X]); + double upper_x = dtw->dt2r * (viewbox.right() - dtw->ruler_origin[Geom::X]); + sp_ruler_set_range(SP_RULER(dtw->hruler), + lower_x, + upper_x, + (upper_x - lower_x)); - double const scale = dtw->desktop->current_zoom(); - double s = viewbox.min()[Geom::X] / scale - dtw->ruler_origin[Geom::X]; - double e = viewbox.max()[Geom::X] / scale - dtw->ruler_origin[Geom::X]; - gtk_deprecated_ruler_get_range(GTK_DEPRECATED_RULER(dtw->hruler), NULL, NULL, &position, NULL); - gtk_deprecated_ruler_set_range(GTK_DEPRECATED_RULER(dtw->hruler), s, e, position, (e - s)); -} - -void -sp_desktop_widget_update_vruler (SPDesktopWidget *dtw) -{ - /* The viewbox (in integers) must exactly match the size of SPCanvasbuf's pixel buffer. - * This is important because the former is being used for drawing the ruler, whereas - * the latter is used for drawing e.g. the grids and guides. Only when the viewbox - * coincides with the pixel buffer, everything will line up nicely. - */ - Geom::IntRect viewbox = dtw->canvas->getViewboxIntegers(); - gdouble position; - - double const scale = dtw->desktop->current_zoom(); - double s = viewbox.min()[Geom::Y] / -scale - dtw->ruler_origin[Geom::Y]; - double e = viewbox.max()[Geom::Y] / -scale - dtw->ruler_origin[Geom::Y]; - gtk_deprecated_ruler_get_range(GTK_DEPRECATED_RULER(dtw->vruler), NULL, NULL, &position, NULL); - gtk_deprecated_ruler_set_range(GTK_DEPRECATED_RULER(dtw->vruler), s, e, position, (e - s)); + double lower_y = dtw->dt2r * (viewbox.bottom() - dtw->ruler_origin[Geom::Y]); + double upper_y = dtw->dt2r * (viewbox.top() - dtw->ruler_origin[Geom::Y]); + sp_ruler_set_range(SP_RULER(dtw->vruler), + lower_y, + upper_y, + (upper_y - lower_y)); } @@ -1624,11 +1734,11 @@ void SPDesktopWidget::namedviewModified(SPObject *obj, guint flags) SPNamedView *nv=SP_NAMEDVIEW(obj); if (flags & SP_OBJECT_MODIFIED_FLAG) { - this->dt2r = 1.0 / nv->doc_units->unittobase; + this->dt2r = 1. / nv->doc_units->factor; this->ruler_origin = Geom::Point(0,0); //nv->gridorigin; Why was the grid origin used here? - sp_ruler_set_metric(GTK_DEPRECATED_RULER (this->vruler), nv->getDefaultMetric()); - sp_ruler_set_metric(GTK_DEPRECATED_RULER (this->hruler), nv->getDefaultMetric()); + sp_ruler_set_unit(SP_RULER (this->vruler), nv->getDefaultUnit()); + sp_ruler_set_unit(SP_RULER (this->hruler), nv->getDefaultUnit()); /* This loops through all the grandchildren of aux toolbox, * and for each that it finds, it performs an sp_search_by_data_recursive(), @@ -1664,8 +1774,8 @@ void SPDesktopWidget::namedviewModified(SPObject *obj, guint flags) } // children } // if aux_toolbox is a container - gtk_widget_set_tooltip_text(this->hruler_box, gettext(sp_unit_get_plural (nv->doc_units))); - gtk_widget_set_tooltip_text(this->vruler_box, gettext(sp_unit_get_plural (nv->doc_units))); + gtk_widget_set_tooltip_text(this->hruler_box, gettext(nv->doc_units->name_plural.c_str())); + gtk_widget_set_tooltip_text(this->vruler_box, gettext(nv->doc_units->name_plural.c_str())); sp_desktop_widget_update_rulers(this); ToolboxFactory::updateSnapToolbox(this->desktop, 0, this->snap_toolbox); @@ -1685,7 +1795,10 @@ sp_desktop_widget_adjustment_value_changed (GtkAdjustment */*adj*/, SPDesktopWid sp_desktop_widget_update_rulers (dtw); /* update perspective lines if we are in the 3D box tool (so that infinite ones are shown correctly) */ - sp_box3d_context_update_lines(dtw->desktop->event_context); + //sp_box3d_context_update_lines(dtw->desktop->event_context); + if (SP_IS_BOX3D_CONTEXT(dtw->desktop->event_context)) { + SP_BOX3D_CONTEXT(dtw->desktop->event_context)->_vpdrag->updateLines(); + } dtw->update = 0; } @@ -1765,6 +1878,67 @@ sp_dtw_zoom_value_changed (GtkSpinButton *spin, gpointer data) spinbutton_defocus (GTK_WIDGET(spin)); } + +static void +sp_dtw_zoom_10 (GtkMenuItem */*item*/, gpointer data) +{ + sp_dtw_zoom_menu_handler (static_cast<SPDesktop*>(data), 0.1); +} + +static void +sp_dtw_zoom_25 (GtkMenuItem */*item*/, gpointer data) +{ + sp_dtw_zoom_menu_handler (static_cast<SPDesktop*>(data), 0.25); +} + +static void +sp_dtw_zoom_50 (GtkMenuItem */*item*/, gpointer data) +{ + sp_dtw_zoom_menu_handler (static_cast<SPDesktop*>(data), 0.5); +} + +static void +sp_dtw_zoom_100 (GtkMenuItem */*item*/, gpointer data) +{ + sp_dtw_zoom_menu_handler (static_cast<SPDesktop*>(data), 1.0); +} + +static void +sp_dtw_zoom_200 (GtkMenuItem */*item*/, gpointer data) +{ + sp_dtw_zoom_menu_handler (static_cast<SPDesktop*>(data), 2.0); +} + +static void +sp_dtw_zoom_500 (GtkMenuItem */*item*/, gpointer data) +{ + sp_dtw_zoom_menu_handler (static_cast<SPDesktop*>(data), 5.0); +} + +static void +sp_dtw_zoom_1000 (GtkMenuItem */*item*/, gpointer data) +{ + sp_dtw_zoom_menu_handler (static_cast<SPDesktop*>(data), 10.0); +} + +static void +sp_dtw_zoom_page (GtkMenuItem */*item*/, gpointer data) +{ + static_cast<SPDesktop*>(data)->zoom_page(); +} + +static void +sp_dtw_zoom_drawing (GtkMenuItem */*item*/, gpointer data) +{ + static_cast<SPDesktop*>(data)->zoom_drawing(); +} + +static void +sp_dtw_zoom_selection (GtkMenuItem */*item*/, gpointer data) +{ + static_cast<SPDesktop*>(data)->zoom_selection(); +} + static void sp_dtw_zoom_populate_popup (GtkEntry */*entry*/, GtkMenu *menu, gpointer data) { @@ -1778,6 +1952,14 @@ sp_dtw_zoom_populate_popup (GtkEntry */*entry*/, GtkMenu *menu, gpointer data) } g_list_free (children); + item = gtk_menu_item_new_with_label ("1000%"); + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_1000), dt); + gtk_widget_show (item); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + item = gtk_menu_item_new_with_label ("500%"); + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_500), dt); + gtk_widget_show (item); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); item = gtk_menu_item_new_with_label ("200%"); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_200), dt); gtk_widget_show (item); @@ -1790,6 +1972,15 @@ sp_dtw_zoom_populate_popup (GtkEntry */*entry*/, GtkMenu *menu, gpointer data) g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_50), dt); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + item = gtk_menu_item_new_with_label ("25%"); + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_25), dt); + gtk_widget_show (item); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + item = gtk_menu_item_new_with_label ("10%"); + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_10), dt); + gtk_widget_show (item); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); item = gtk_separator_menu_item_new (); gtk_widget_show (item); @@ -1816,41 +2007,6 @@ sp_dtw_zoom_menu_handler (SPDesktop *dt, gdouble factor) dt->zoom_absolute(d.midpoint()[Geom::X], d.midpoint()[Geom::Y], factor); } -static void -sp_dtw_zoom_50 (GtkMenuItem */*item*/, gpointer data) -{ - sp_dtw_zoom_menu_handler (static_cast<SPDesktop*>(data), 0.5); -} - -static void -sp_dtw_zoom_100 (GtkMenuItem */*item*/, gpointer data) -{ - sp_dtw_zoom_menu_handler (static_cast<SPDesktop*>(data), 1.0); -} - -static void -sp_dtw_zoom_200 (GtkMenuItem */*item*/, gpointer data) -{ - sp_dtw_zoom_menu_handler (static_cast<SPDesktop*>(data), 2.0); -} - -static void -sp_dtw_zoom_page (GtkMenuItem */*item*/, gpointer data) -{ - static_cast<SPDesktop*>(data)->zoom_page(); -} - -static void -sp_dtw_zoom_drawing (GtkMenuItem */*item*/, gpointer data) -{ - static_cast<SPDesktop*>(data)->zoom_drawing(); -} - -static void -sp_dtw_zoom_selection (GtkMenuItem */*item*/, gpointer data) -{ - static_cast<SPDesktop*>(data)->zoom_selection(); -} static void sp_dtw_sticky_zoom_toggled (GtkMenuItem *, gpointer data) @@ -1906,6 +2062,12 @@ sp_desktop_widget_toggle_scrollbars (SPDesktopWidget *dtw) } } +bool sp_desktop_widget_color_prof_adj_enabled( SPDesktopWidget *dtw ) +{ + return gtk_widget_get_sensitive( dtw->cms_adjust ) && + SP_BUTTON_IS_DOWN(dtw->cms_adjust) ; +} + void sp_desktop_widget_toggle_color_prof_adj( SPDesktopWidget *dtw ) { @@ -1959,8 +2121,8 @@ sp_desktop_widget_update_scrollbars (SPDesktopWidget *dtw, double scale) /* The desktop region we always show unconditionally */ SPDocument *doc = dtw->desktop->doc(); - Geom::Rect darea ( Geom::Point(-doc->getWidth(), -doc->getHeight()), - Geom::Point(2 * doc->getWidth(), 2 * doc->getHeight()) ); + Geom::Rect darea ( Geom::Point(-doc->getWidth().value("px"), -doc->getHeight().value("px")), + Geom::Point(2 * doc->getWidth().value("px"), 2 * doc->getHeight().value("px")) ); Geom::OptRect deskarea; if (Inkscape::Preferences::get()->getInt("/tools/bounding_box") == 0) { diff --git a/src/widgets/desktop-widget.h b/src/widgets/desktop-widget.h index 798b65abd..a77d56fc3 100644 --- a/src/widgets/desktop-widget.h +++ b/src/widgets/desktop-widget.h @@ -12,6 +12,14 @@ * ? -2004 */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + #include <gtkmm/window.h> #include "message.h" #include "ui/view/view-widget.h" @@ -25,7 +33,7 @@ typedef struct _EgeColorProfTracker EgeColorProfTracker; struct SPCanvas; class SPDesktop; -class SPDesktopWidget; +struct SPDesktopWidget; class SPObject; @@ -35,8 +43,6 @@ class SPObject; #define SP_IS_DESKTOP_WIDGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_DESKTOP_WIDGET)) #define SP_IS_DESKTOP_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_DESKTOP_WIDGET)) -void sp_desktop_widget_destroy (SPDesktopWidget* dtw); - void sp_desktop_widget_show_decorations(SPDesktopWidget *dtw, gboolean show); void sp_desktop_widget_iconify(SPDesktopWidget *dtw); void sp_desktop_widget_maximize(SPDesktopWidget *dtw); @@ -51,6 +57,7 @@ void sp_desktop_widget_toggle_rulers (SPDesktopWidget *dtw); void sp_desktop_widget_toggle_scrollbars (SPDesktopWidget *dtw); void sp_desktop_widget_update_scrollbars (SPDesktopWidget *dtw, double scale); void sp_desktop_widget_toggle_color_prof_adj( SPDesktopWidget *dtw ); +bool sp_desktop_widget_color_prof_adj_enabled( SPDesktopWidget *dtw ); void sp_dtw_desktop_activate (SPDesktopWidget *dtw); void sp_dtw_desktop_deactivate (SPDesktopWidget *dtw); @@ -106,7 +113,11 @@ struct SPDesktopWidget { unsigned int _interaction_disabled_counter; - SPCanvas *canvas; + SPCanvas *canvas; + + /** A table for displaying the canvas, rulers etc */ + GtkWidget *canvas_tbl; + Geom::Point ruler_origin; double dt2r; @@ -118,7 +129,6 @@ struct SPDesktopWidget { struct WidgetStub : public Inkscape::UI::View::EditWidgetInterface { SPDesktopWidget *_dtw; - SPDesktop *_dt; WidgetStub (SPDesktopWidget* dtw) : _dtw(dtw) {} virtual void setTitle (gchar const *uri) @@ -169,8 +179,6 @@ struct SPDesktopWidget { { sp_dtw_desktop_activate (_dtw); } virtual void deactivateDesktop() { sp_dtw_desktop_deactivate (_dtw); } - virtual void viewSetPosition (Geom::Point p) - { _dtw->viewSetPosition (p); } virtual void updateRulers() { sp_desktop_widget_update_rulers (_dtw); } virtual void updateScrollbars (double scale) @@ -181,6 +189,8 @@ struct SPDesktopWidget { { sp_desktop_widget_toggle_scrollbars (_dtw); } virtual void toggleColorProfAdjust() { sp_desktop_widget_toggle_color_prof_adj(_dtw); } + virtual bool colorProfAdjustEnabled() + { return sp_desktop_widget_color_prof_adj_enabled(_dtw); } virtual void updateZoom() { sp_desktop_widget_update_zoom (_dtw); } virtual void letZoomGrabFocus() @@ -202,7 +212,7 @@ struct SPDesktopWidget { return _dtw->showInfoDialog( message ); } - virtual bool warnDialog (gchar* text) + virtual bool warnDialog (Glib::ustring const &text) { return _dtw->warnDialog (text); } virtual Inkscape::UI::Widget::Dock* getDock () @@ -222,7 +232,7 @@ struct SPDesktopWidget { void setWindowTransient (void *p, int transient_policy); void presentWindow(); bool showInfoDialog( Glib::ustring const &message ); - bool warnDialog (gchar *text); + bool warnDialog (Glib::ustring const &text); void setToolboxFocusTo (gchar const *); void setToolboxAdjustmentValue (gchar const * id, double value); void setToolboxSelectOneValue (gchar const * id, gint value); diff --git a/src/widgets/dropper-toolbar.cpp b/src/widgets/dropper-toolbar.cpp new file mode 100644 index 000000000..478d0c1a4 --- /dev/null +++ b/src/widgets/dropper-toolbar.cpp @@ -0,0 +1,127 @@ +/** + * @file + * Dropper aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glibmm/i18n.h> + +#include "dropper-toolbar.h" +#include "document-undo.h" +#include "ege-output-action.h" +#include "ink-action.h" +#include "preferences.h" +#include "widgets/spinbutton-events.h" + +using Inkscape::DocumentUndo; + +//######################## +//## Dropper ## +//######################## + +static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt( "/tools/dropper/pick", gtk_toggle_action_get_active( act ) ); + GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") ); + if ( set_action ) { + if ( gtk_toggle_action_get_active( act ) ) { + gtk_action_set_sensitive( set_action, TRUE ); + } else { + gtk_action_set_sensitive( set_action, FALSE ); + } + } + + spinbutton_defocus(GTK_WIDGET(tbl)); +} + +static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool( "/tools/dropper/setalpha", gtk_toggle_action_get_active( act ) ); + spinbutton_defocus(GTK_WIDGET(tbl)); +} + + +/** + * Dropper auxiliary toolbar construction and setup. + * + * TODO: Would like to add swatch of current color. + * TODO: Add queue of last 5 or so colors selected with new swatches so that + * can drag and drop places. Will provide a nice mixing palette. + */ +void sp_dropper_toolbox_prep(SPDesktop * /*desktop*/, GtkActionGroup* mainActions, GObject* holder) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gint pickAlpha = prefs->getInt( "/tools/dropper/pick", 1 ); + + { + EgeOutputAction* act = ege_output_action_new( "DropperOpacityAction", _("Opacity:"), "", 0 ); + ege_output_action_set_use_markup( act, TRUE ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + } + + { + InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction", + _("Pick opacity"), + _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"), + NULL, + Inkscape::ICON_SIZE_DECORATION ); + g_object_set( act, "short_label", _("Pick"), NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_object_set_data( holder, "pick_action", act ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder ); + } + + { + InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction", + _("Assign opacity"), + _("If alpha was picked, assign it to selection as fill or stroke transparency"), + NULL, + Inkscape::ICON_SIZE_DECORATION ); + g_object_set( act, "short_label", _("Assign"), NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_object_set_data( holder, "set_action", act ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/dropper/setalpha", true) ); + // make sure it's disabled if we're not picking alpha + gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder ); + } +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/dropper-toolbar.h b/src/widgets/dropper-toolbar.h new file mode 100644 index 000000000..8d5ea2d0a --- /dev/null +++ b/src/widgets/dropper-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_DROPPER_TOOLBAR_H +#define SEEN_DROPPER_TOOLBAR_H + +/** + * @file + * Dropper aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_DROPPER_TOOLBAR_H */ diff --git a/src/widgets/eek-preview.cpp b/src/widgets/eek-preview.cpp index db9cb96bd..19dbb04ab 100644 --- a/src/widgets/eek-preview.cpp +++ b/src/widgets/eek-preview.cpp @@ -37,72 +37,88 @@ # include "config.h" #endif +#include <algorithm> +using std::min; + #include <gtk/gtk.h> #include "eek-preview.h" +#include "preferences.h" #define PRIME_BUTTON_MAGIC_NUMBER 1 -#define FOCUS_PROP_ID 1 - -/* Keep in sycn with last value in eek-preview.h */ +/* Keep in sync 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 ); +enum { + PROP_0, + PROP_FOCUS +}; + +typedef struct +{ + int scaledW; + int scaledH; + + int r; + int g; + int b; + + gboolean hot; + gboolean within; + gboolean takesFocus; + ViewType view; + PreviewSize size; + guint ratio; + guint linked; + guint border; + GdkPixbuf *previewPixbuf; + GdkPixbuf *scaled; +} EekPreviewPrivate; + +#define EEK_PREVIEW_GET_PRIVATE(preview) \ + G_TYPE_INSTANCE_GET_PRIVATE(preview, EEK_PREVIEW_TYPE, EekPreviewPrivate) + +static void eek_preview_class_init( EekPreviewClass *klass ); +static void eek_preview_init( EekPreview *preview ); +static gboolean eek_preview_draw(GtkWidget* widget, cairo_t* cr); + +G_DEFINE_TYPE(EekPreview, eek_preview, GTK_TYPE_DRAWING_AREA); 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; + EekPreviewPrivate *priv = EEK_PREVIEW_GET_PRIVATE(preview); + + priv->r = r; + priv->g = g; + priv->b = b; gtk_widget_queue_draw(GTK_WIDGET(preview)); } -void eek_preview_set_pixbuf( EekPreview* preview, GdkPixbuf* pixbuf ) +void +eek_preview_set_pixbuf(EekPreview *preview, + GdkPixbuf *pixbuf) { - preview->_previewPixbuf = pixbuf; + EekPreviewPrivate *priv = EEK_PREVIEW_GET_PRIVATE(preview); - 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); -} + priv->previewPixbuf = pixbuf; + gtk_widget_queue_draw(GTK_WIDGET(preview)); -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 ); + if (priv->scaled) + { + g_object_unref(priv->scaled); + priv->scaled = NULL; } - return preview_type; + priv->scaledW = gdk_pixbuf_get_width(priv->previewPixbuf); + priv->scaledH = gdk_pixbuf_get_height(priv->previewPixbuf); } static gboolean setupDone = FALSE; @@ -144,9 +160,10 @@ void eek_preview_set_size_mappings( guint count, GtkIconSize const* sizes ) static void eek_preview_size_request( GtkWidget* widget, GtkRequisition* req ) { - gint width = 0; - gint height = 0; - EekPreview* preview = EEK_PREVIEW(widget); + gint width = 0; + gint height = 0; + EekPreview *preview = EEK_PREVIEW(widget); + EekPreviewPrivate *priv = EEK_PREVIEW_GET_PRIVATE(preview); if ( !setupDone ) { GtkIconSize sizes[] = { @@ -159,15 +176,15 @@ static void eek_preview_size_request( GtkWidget* widget, GtkRequisition* req ) eek_preview_set_size_mappings( G_N_ELEMENTS(sizes), sizes ); } - width = sizeThings[preview->_size].width; - height = sizeThings[preview->_size].height; + width = sizeThings[priv->size].width; + height = sizeThings[priv->size].height; - if ( preview->_view == VIEW_TYPE_LIST ) { + if ( priv->view == VIEW_TYPE_LIST ) { width *= 3; } - if ( preview->_ratio != 100 ) { - width = (width * preview->_ratio) / 100; + if ( priv->ratio != 100 ) { + width = (width * priv->ratio) / 100; if ( width < 0 ) { width = 1; } @@ -202,230 +219,325 @@ enum { static guint eek_preview_signals[LAST_SIGNAL] = { 0 }; - -gboolean eek_preview_expose_event( GtkWidget* widget, GdkEventExpose* event ) +#if !GTK_CHECK_VERSION(3,0,0) +static 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; + gboolean result = FALSE; - (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_is_drawable(widget)) { + GdkWindow* window = gtk_widget_get_window(widget); + cairo_t* cr = gdk_cairo_create(window); + result = eek_preview_draw(widget, cr); + cairo_destroy(cr); } -*/ - if ( gtk_widget_is_drawable( widget ) ) { - GtkStyle* style = gtk_widget_get_style( widget ); - GtkAllocation allocation; - - if ( insetX > 0 || insetY > 0 ) { - gtk_widget_get_allocation (widget, &allocation); - - gtk_paint_flat_box( style, - gtk_widget_get_window (widget), - (GtkStateType)gtk_widget_get_state(widget), - GTK_SHADOW_NONE, - NULL, - widget, - NULL, - 0, 0, - allocation.width, allocation.height); - } + return result; +} +#endif - EekPreview* preview = EEK_PREVIEW(widget); - GdkColor fg = {0, preview->_r, preview->_g, preview->_b}; +static +gboolean eek_preview_draw(GtkWidget *widget, + cairo_t *cr) +{ + GtkStyle *style = gtk_widget_get_style(widget); + EekPreview *preview = EEK_PREVIEW(widget); + EekPreviewPrivate *priv = EEK_PREVIEW_GET_PRIVATE(preview); + + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + +#if !GTK_CHECK_VERSION(3,0,0) + GdkColor fg = { 0, + static_cast<guint16>(priv->r), + static_cast<guint16>(priv->g), + static_cast<guint16>(priv->b) + }; +#endif - gdk_colormap_alloc_color( gdk_colormap_get_system(), &fg, FALSE, TRUE ); + gint insetTop = 0, insetBottom = 0; + gint insetLeft = 0, insetRight = 0; - gtk_widget_get_allocation (widget, &allocation); - cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(widget)); + if (priv->border == BORDER_SOLID) { + insetTop = 1; + insetLeft = 1; + } + if (priv->border == BORDER_SOLID_LAST_ROW) { + insetTop = insetBottom = 1; + insetLeft = 1; + } + if (priv->border == BORDER_WIDE) { + insetTop = insetBottom = 1; + insetLeft = insetRight = 1; + } - GdkRectangle rect = {insetX, - insetY, - allocation.width - (insetX * 2), - allocation.height - (insetY * 2)}; - gdk_cairo_set_source_color(cr, &fg); - gdk_cairo_rectangle(cr, &rect); - cairo_paint(cr); - cairo_destroy(cr); - - if ( preview->_previewPixbuf ) { - GtkDrawingArea* da = &(preview->drawing); - GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(da)); - GdkDrawable* drawable = (GdkDrawable*) window; - gint w = 0; - gint h = 0; -#if GTK_CHECK_VERSION(2,24,0) - w = gdk_window_get_width(window); - h = gdk_window_get_height(window); +#if GTK_CHECK_VERSION(3,0,0) + GtkStyleContext *context = gtk_widget_get_style_context(widget); + + gtk_render_frame(context, + cr, + 0, 0, + allocation.width, allocation.height); + + gtk_render_background(context, + cr, + 0, 0, + allocation.width, allocation.height); #else - gdk_drawable_get_size(drawable, &w, &h); + GdkWindow* window = gtk_widget_get_window(widget); + + gtk_paint_flat_box( style, + window, + (GtkStateType)gtk_widget_get_state(widget), + GTK_SHADOW_NONE, + NULL, + widget, + NULL, + 0, 0, + allocation.width, allocation.height); + + gdk_colormap_alloc_color( gdk_colormap_get_system(), &fg, FALSE, TRUE ); #endif - - 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; - cairo_t* cr2 = gdk_cairo_create(drawable); - gdk_cairo_set_source_pixbuf(cr2, pix, 0, 0); - cairo_paint(cr2); - cairo_destroy(cr); - } + // Border + if (priv->border != BORDER_NONE) { + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + cairo_rectangle(cr, 0, 0, allocation.width, allocation.height); + cairo_fill(cr); + } - if ( preview->_linked ) { - gtk_widget_get_allocation (widget, &allocation); + cairo_set_source_rgb(cr, priv->r/65535.0, priv->g/65535.0, priv->b/65535.0 ); + cairo_rectangle(cr, insetLeft, insetTop, allocation.width - (insetLeft + insetRight), allocation.height - (insetTop + insetBottom)); + cairo_fill(cr); - /* Draw arrow */ - GdkRectangle possible = {insetX, insetY, (allocation.width - (insetX * 2)), (allocation.height - (insetY * 2)) }; - GdkRectangle area = {possible.x, possible.y, possible.width / 2, possible.height / 2 }; + if (priv->previewPixbuf ) + { + GtkDrawingArea *da = &(preview->drawing); + GdkWindow *da_window = gtk_widget_get_window(GTK_WIDGET(da)); + cairo_t *cr = gdk_cairo_create(da_window); - /* Make it square */ - if ( area.width > area.height ) - area.width = area.height; - if ( area.height > area.width ) - area.height = area.width; + gint w = gdk_window_get_width(da_window); + gint h = gdk_window_get_height(da_window); - /* Center it horizontally */ - if ( area.width < possible.width ) { - int diff = (possible.width - area.width) / 2; - area.x += diff; + if ((w != priv->scaledW) || (h != priv->scaledH)) { + if (priv->scaled) + { + g_object_unref(priv->scaled); } + priv->scaled = gdk_pixbuf_scale_simple(priv->previewPixbuf, + w - (insetLeft + insetRight), + h - (insetTop + insetBottom), + GDK_INTERP_BILINEAR); - if ( preview->_linked & PREVIEW_LINK_IN ) { - gtk_paint_arrow( style, - gtk_widget_get_window (widget), - gtk_widget_get_state (widget), - 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 - ); - } + priv->scaledW = w - (insetLeft + insetRight); + priv->scaledH = h - (insetTop + insetBottom); + } - 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, - gtk_widget_get_window (widget), - gtk_widget_get_state (widget), - GTK_SHADOW_ETCHED_OUT, - NULL, /* clip area. &area, */ - widget, /* may be NULL */ - NULL, /* detail */ - GTK_ARROW_DOWN, - FALSE, - otherArea.x, otherArea.y, - otherArea.width, otherArea.height - ); - } + GdkPixbuf *pix = (priv->scaled) ? priv->scaled : priv->previewPixbuf; - 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, - gtk_widget_get_window (widget), - gtk_widget_get_state (widget), - 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 - ); - } + // Border + if (priv->border != BORDER_NONE) { + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + cairo_rectangle(cr, 0, 0, allocation.width, allocation.height); + cairo_fill(cr); + } + gdk_cairo_set_source_pixbuf(cr, pix, insetLeft, insetTop); + cairo_paint(cr); + cairo_destroy(cr); + } - if ( preview->_linked & PREVIEW_FILL ) { - GdkRectangle otherArea = {possible.x + ((possible.width / 4) - (area.width / 2)), - area.y, - area.width, area.height}; - if ( otherArea.height < possible.height ) { - otherArea.y = possible.y + (possible.height - otherArea.height) / 2; - } - gtk_paint_check( style, - gtk_widget_get_window (widget), - gtk_widget_get_state (widget), - GTK_SHADOW_ETCHED_OUT, - NULL, - widget, - NULL, - otherArea.x, otherArea.y, - otherArea.width, otherArea.height ); - } + if (priv->linked) + { + /* Draw arrow */ + GdkRectangle possible = {insetLeft, + insetTop, + (allocation.width - (insetLeft + insetRight)), + (allocation.height - (insetTop + insetBottom)) + }; + + 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 (priv->linked & PREVIEW_LINK_IN) + { +#if GTK_CHECK_VERSION(3,0,0) + gtk_render_arrow(context, + cr, + G_PI, // Down-pointing arrow + area.x, area.y, + min(area.width, area.height) + ); +#else + gtk_paint_arrow( style, + window, + gtk_widget_get_state (widget), + 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 + ); +#endif + } - if ( preview->_linked & PREVIEW_STROKE ) { - GdkRectangle otherArea = {possible.x + (((possible.width * 3) / 4) - (area.width / 2)), - area.y, - area.width, area.height}; - if ( otherArea.height < possible.height ) { - otherArea.y = possible.y + (possible.height - otherArea.height) / 2; - } - gtk_paint_diamond( style, - gtk_widget_get_window (widget), - gtk_widget_get_state (widget), - GTK_SHADOW_ETCHED_OUT, - NULL, - widget, - NULL, - otherArea.x, otherArea.y, - otherArea.width, otherArea.height ); + if (priv->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); } + +#if GTK_CHECK_VERSION(3,0,0) + gtk_render_arrow(context, + cr, + G_PI, // Down-pointing arrow + otherArea.x, otherArea.y, + min(otherArea.width, otherArea.height) + ); +#else + gtk_paint_arrow( style, + window, + gtk_widget_get_state (widget), + GTK_SHADOW_ETCHED_OUT, + NULL, /* clip area. &area, */ + widget, /* may be NULL */ + NULL, /* detail */ + GTK_ARROW_DOWN, + FALSE, + otherArea.x, otherArea.y, + otherArea.width, otherArea.height + ); +#endif } + if (priv->linked & PREVIEW_LINK_OTHER) + { + GdkRectangle otherArea = {insetLeft, area.y, area.width, area.height}; + if ( otherArea.height < possible.height ) { + otherArea.y = possible.y + (possible.height - otherArea.height) / 2; + } + +#if GTK_CHECK_VERSION(3,0,0) + gtk_render_arrow(context, + cr, + 1.5*G_PI, // Left-pointing arrow + otherArea.x, otherArea.y, + min(otherArea.width, otherArea.height) + ); +#else + gtk_paint_arrow( style, + window, + gtk_widget_get_state (widget), + 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 + ); +#endif + } - if ( gtk_widget_has_focus(widget) ) { - gtk_widget_get_allocation (widget, &allocation); - gtk_paint_focus( style, - gtk_widget_get_window (widget), - GTK_STATE_NORMAL, - NULL, /* GdkRectangle *area, */ + if (priv->linked & PREVIEW_FILL) + { + GdkRectangle otherArea = {possible.x + ((possible.width / 4) - (area.width / 2)), + area.y, + area.width, area.height}; + if ( otherArea.height < possible.height ) { + otherArea.y = possible.y + (possible.height - otherArea.height) / 2; + } +#if GTK_CHECK_VERSION(3,0,0) + gtk_render_check(context, + cr, + otherArea.x, otherArea.y, + otherArea.width, otherArea.height ); +#else + gtk_paint_check( style, + window, + gtk_widget_get_state (widget), + GTK_SHADOW_ETCHED_OUT, + NULL, widget, NULL, - 0 + 1, 0 + 1, - allocation.width - 2, allocation.height - 2 ); + otherArea.x, otherArea.y, + otherArea.width, otherArea.height ); +#endif + } + + if (priv->linked & PREVIEW_STROKE) + { + GdkRectangle otherArea = {possible.x + (((possible.width * 3) / 4) - (area.width / 2)), + area.y, + area.width, area.height}; + if ( otherArea.height < possible.height ) { + otherArea.y = possible.y + (possible.height - otherArea.height) / 2; + } +#if GTK_CHECK_VERSION(3,0,0) + gtk_paint_diamond( style, + cr, + gtk_widget_get_state (widget), + GTK_SHADOW_ETCHED_OUT, + widget, + NULL, + otherArea.x, otherArea.y, + otherArea.width, otherArea.height ); +#else + gtk_paint_diamond( style, + window, + gtk_widget_get_state (widget), + GTK_SHADOW_ETCHED_OUT, + NULL, + widget, + NULL, + otherArea.x, otherArea.y, + otherArea.width, otherArea.height ); +#endif } } + if ( gtk_widget_has_focus(widget) ) { + gtk_widget_get_allocation (widget, &allocation); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_render_focus(context, + cr, + 0 + 1, 0 + 1, + allocation.width - 2, allocation.height - 2 ); +#else + gtk_paint_focus( style, + window, + GTK_STATE_NORMAL, + NULL, /* GdkRectangle *area, */ + widget, + NULL, + 0 + 1, 0 + 1, + allocation.width - 2, allocation.height - 2 ); +#endif + } + return FALSE; } @@ -433,51 +545,48 @@ gboolean eek_preview_expose_event( GtkWidget* widget, GdkEventExpose* event ) 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 ); + EekPreview *preview = EEK_PREVIEW(widget); + EekPreviewPrivate *priv = EEK_PREVIEW_GET_PRIVATE(preview); + + priv->within = TRUE; + gtk_widget_set_state( widget, priv->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; + EekPreview *preview = EEK_PREVIEW(widget); + EekPreviewPrivate *priv = EEK_PREVIEW_GET_PRIVATE(preview); + + priv->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; + return FALSE; } -*/ 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 ( gtk_get_event_widget( (GdkEvent*)event ) == widget ) + { + EekPreview *preview = EEK_PREVIEW(widget); + EekPreviewPrivate *priv = EEK_PREVIEW_GET_PRIVATE(preview); - if ( preview->_takesFocus && !gtk_widget_has_focus(widget) ) { + if ( priv->takesFocus && !gtk_widget_has_focus(widget) ) + { gtk_widget_grab_focus(widget); } - if ( event->button == PRIME_BUTTON_MAGIC_NUMBER ) { - preview->_hot = TRUE; - if ( preview->_within ) { + if ( event->button == PRIME_BUTTON_MAGIC_NUMBER || + event->button == 2 ) + { + priv->hot = TRUE; + + if ( priv->within ) + { gtk_widget_set_state( widget, GTK_STATE_ACTIVE ); } } @@ -489,89 +598,76 @@ static gboolean eek_preview_button_press_cb( GtkWidget* widget, GdkEventButton* 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; + EekPreview *preview = EEK_PREVIEW(widget); + EekPreviewPrivate *priv = EEK_PREVIEW_GET_PRIVATE(preview); + + priv->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 ) { + if ( priv->within && + (event->button == PRIME_BUTTON_MAGIC_NUMBER || + event->button == 2)) + { + gboolean isAlt = ( ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) || + (event->button == 2)); + + if ( isAlt ) + { g_signal_emit( widget, eek_preview_signals[ALTCLICKED_SIGNAL], 0, 2 ); - } else { + } + 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, +static void eek_preview_get_property( GObject *object, + guint prop_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; + EekPreview *preview = EEK_PREVIEW( object ); + EekPreviewPrivate *priv = EEK_PREVIEW_GET_PRIVATE(preview); + + switch (prop_id) + { + case PROP_FOCUS: + g_value_set_boolean( value, priv->takesFocus ); + break; + default: - { - if ( gobjClass->get_property ) { - gobjClass->get_property( object, property_id, value, pspec ); - } - } + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; } } -static void eek_preview_set_property( GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) +static void +eek_preview_set_property(GObject *object, + guint prop_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; + EekPreview *preview = EEK_PREVIEW( object ); + + switch (prop_id) + { + case PROP_FOCUS: + eek_preview_set_focus_on_click(preview, g_value_get_boolean(value)); + break; + default: - { - if ( gobjClass->set_property ) { - gobjClass->set_property( object, property_id, value, pspec ); - } - } + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; } } 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; } @@ -579,71 +675,32 @@ static gboolean eek_preview_popup_menu( GtkWidget* widget ) static void eek_preview_class_init( EekPreviewClass *klass ) { - GObjectClass* gobjClass = G_OBJECT_CLASS(klass); - /*GtkObjectClass* objectClass = (GtkObjectClass*)klass;*/ + GObjectClass* gobjClass = G_OBJECT_CLASS(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 = ;*/ #if GTK_CHECK_VERSION(3,0,0) widgetClass->get_preferred_width = eek_preview_get_preferred_width; widgetClass->get_preferred_height = eek_preview_get_preferred_height; + widgetClass->draw = eek_preview_draw; #else widgetClass->size_request = eek_preview_size_request; + widgetClass->expose_event = eek_preview_expose_event; #endif - /*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 = ;*/ + g_type_class_add_private(gobjClass, sizeof(EekPreviewPrivate)); eek_preview_signals[CLICKED_SIGNAL] = g_signal_new( "clicked", @@ -664,7 +721,7 @@ static void eek_preview_class_init( EekPreviewClass *klass ) g_object_class_install_property( gobjClass, - FOCUS_PROP_ID, + PROP_FOCUS, g_param_spec_boolean( "focus-on-click", NULL, @@ -672,57 +729,94 @@ static void eek_preview_class_init( EekPreviewClass *klass ) TRUE, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_CONSTRUCT) ) - ); + ); } -void eek_preview_set_linked( EekPreview* splat, LinkType link ) +void +eek_preview_set_linked(EekPreview *preview, + LinkType link) { + EekPreviewPrivate *priv = EEK_PREVIEW_GET_PRIVATE(preview); + + g_return_if_fail(IS_EEK_PREVIEW(preview)); + link = (LinkType)(link & PREVIEW_LINK_ALL); - if ( link != (LinkType)splat->_linked ) { - splat->_linked = link; - gtk_widget_queue_draw( GTK_WIDGET(splat) ); + if (link != (LinkType)priv->linked) + { + priv->linked = link; + + gtk_widget_queue_draw(GTK_WIDGET(preview)); } } -LinkType eek_preview_get_linked( EekPreview* splat ) +LinkType +eek_preview_get_linked(EekPreview *preview) { - return (LinkType)splat->_linked; + g_return_val_if_fail(IS_EEK_PREVIEW(preview), PREVIEW_LINK_NONE); + + return (LinkType)EEK_PREVIEW_GET_PRIVATE(preview)->linked; } -gboolean eek_preview_get_focus_on_click( EekPreview* preview ) +gboolean +eek_preview_get_focus_on_click(EekPreview* preview) { - return preview->_takesFocus; + g_return_val_if_fail(IS_EEK_PREVIEW(preview), FALSE); + + return EEK_PREVIEW_GET_PRIVATE(preview)->takesFocus; } -void eek_preview_set_focus_on_click( EekPreview* preview, gboolean focus_on_click ) +void +eek_preview_set_focus_on_click(EekPreview *preview, + gboolean focus_on_click) { - if ( focus_on_click != preview->_takesFocus ) { - preview->_takesFocus = focus_on_click; + EekPreviewPrivate *priv = EEK_PREVIEW_GET_PRIVATE(preview); + + g_return_if_fail(IS_EEK_PREVIEW(preview)); + + if (focus_on_click != priv->takesFocus) + { + priv->takesFocus = focus_on_click; } } -void eek_preview_set_details( EekPreview* preview, PreviewStyle prevstyle, ViewType view, PreviewSize size, guint ratio ) +void +eek_preview_set_details(EekPreview *preview, + ViewType view, + PreviewSize size, + guint ratio, + guint border) { - preview->_prevstyle = prevstyle; - preview->_view = view; + EekPreviewPrivate *priv = EEK_PREVIEW_GET_PRIVATE(preview); + + g_return_if_fail(IS_EEK_PREVIEW(preview)); + + priv->view = view; - if ( size > PREVIEW_SIZE_LAST ) { + if ( size > PREVIEW_SIZE_LAST ) + { size = PREVIEW_SIZE_LAST; } - preview->_size = size; - if ( ratio > PREVIEW_MAX_RATIO ) { + priv->size = size; + + if ( ratio > PREVIEW_MAX_RATIO ) + { ratio = PREVIEW_MAX_RATIO; } - preview->_ratio = ratio; + + priv->ratio = ratio; + priv->border = border; gtk_widget_queue_draw(GTK_WIDGET(preview)); } -static void eek_preview_init( EekPreview *preview ) +static void +eek_preview_init(EekPreview *preview) { - GtkWidget* widg = GTK_WIDGET(preview); + GtkWidget *widg = GTK_WIDGET(preview); + EekPreviewPrivate *priv = EEK_PREVIEW_GET_PRIVATE(preview); + gtk_widget_set_can_focus( widg, TRUE ); gtk_widget_set_receives_default( widg, TRUE ); @@ -736,63 +830,22 @@ static void eek_preview_init( EekPreview *preview ) | 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 ); - } + priv->r = 0x80; + priv->g = 0x80; + priv->b = 0xcc; + priv->scaledW = 0; + priv->scaledH = 0; + + priv->hot = FALSE; + priv->within = FALSE; + priv->takesFocus = FALSE; + + priv->view = VIEW_TYPE_LIST; + priv->size = PREVIEW_SIZE_SMALL; + priv->ratio = 100; + priv->border = BORDER_NONE; + priv->previewPixbuf = 0; + priv->scaled = 0; } diff --git a/src/widgets/eek-preview.h b/src/widgets/eek-preview.h index 7275ab9b4..e4c724cc5 100644 --- a/src/widgets/eek-preview.h +++ b/src/widgets/eek-preview.h @@ -42,12 +42,11 @@ /** * @file - * Generic implementation of a object that can be shown by a preview. + * Generic implementation of an object that can be shown by a preview. */ 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)) @@ -90,31 +89,19 @@ typedef enum { PREVIEW_LINK_ALL = 31 } LinkType; +typedef enum { + BORDER_NONE = 0, + BORDER_SOLID, + BORDER_WIDE, + BORDER_SOLID_LAST_ROW, +} BorderStyle; + 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 @@ -124,11 +111,14 @@ struct _EekPreviewClass 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_details(EekPreview *preview, + ViewType view, + PreviewSize size, + guint ratio, + guint border); void eek_preview_set_color( EekPreview* splat, int r, int g, int b ); void eek_preview_set_pixbuf( EekPreview* splat, GdkPixbuf* pixbuf ); diff --git a/src/widgets/eraser-toolbar.cpp b/src/widgets/eraser-toolbar.cpp new file mode 100644 index 000000000..14e7cbf4e --- /dev/null +++ b/src/widgets/eraser-toolbar.cpp @@ -0,0 +1,151 @@ +/** + * @file + * Erasor aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glibmm/i18n.h> + +#include "eraser-toolbar.h" +#include "calligraphy-toolbar.h" // TODO: needed for update_presets_list +#include "desktop-handles.h" +#include "desktop.h" +#include "document-undo.h" +#include "ege-adjustment-action.h" +#include "ege-select-one-action.h" +#include "ink-action.h" +#include "preferences.h" +#include "toolbox.h" +#include "ui/icon-names.h" + +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; + +//######################## +//## Eraser ## +//######################## + +static void sp_erc_width_value_changed( GtkAdjustment *adj, GObject *tbl ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/eraser/width", gtk_adjustment_get_value(adj) ); + update_presets_list(tbl); +} + +static void sp_erasertb_mode_changed( EgeSelectOneAction *act, GObject *tbl ) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + bool eraserMode = ege_select_one_action_get_active( act ) != 0; + if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool( "/tools/eraser/mode", eraserMode ); + } + + // only take action if run by the attr_changed listener + if (!g_object_get_data( tbl, "freeze" )) { + // in turn, prevent listener from responding + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + /* + if ( eraserMode != 0 ) { + } else { + } + */ + // TODO finish implementation + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); + } +} + +void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + { + GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); + + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Delete"), + 1, _("Delete objects touched by the eraser"), + 2, INKSCAPE_ICON("draw-eraser-delete-objects"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Cut"), + 1, _("Cut out from objects"), + 2, INKSCAPE_ICON("path-difference"), + -1 ); + + EgeSelectOneAction* act = ege_select_one_action_new( "EraserModeAction", (""), (""), NULL, GTK_TREE_MODEL(model) ); + g_object_set( act, "short_label", _("Mode:"), NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "eraser_mode_action", act ); + + ege_select_one_action_set_appearance( act, "full" ); + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); + ege_select_one_action_set_icon_column( act, 2 ); + ege_select_one_action_set_tooltip_column( act, 1 ); + + /// @todo Convert to boolean? + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0; + ege_select_one_action_set_active( act, eraserMode ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_erasertb_mode_changed), holder ); + } + + { + /* Width */ + gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")}; + gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "EraserWidthAction", + _("Pen Width"), _("Width:"), + _("The width of the eraser pen (relative to the visible canvas area)"), + "/tools/eraser/width", 15, + GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-eraser", + 1, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_erc_width_value_changed, NULL /*unit tracker*/, 1, 0); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/eraser-toolbar.h b/src/widgets/eraser-toolbar.h new file mode 100644 index 000000000..3c88d344e --- /dev/null +++ b/src/widgets/eraser-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_ERASOR_TOOLBAR_H +#define SEEN_ERASOR_TOOLBAR_H + +/** + * @file + * Erasor aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_ERASOR_TOOLBAR_H */ diff --git a/src/widgets/fill-n-stroke-factory.h b/src/widgets/fill-n-stroke-factory.h index c671842fc..89726dc0d 100644 --- a/src/widgets/fill-n-stroke-factory.h +++ b/src/widgets/fill-n-stroke-factory.h @@ -18,6 +18,7 @@ namespace Inkscape { namespace Widgets { Gtk::Widget *createStyleWidget( FillOrStroke kind ); +Gtk::Widget *createStrokeStyleWidget( ); } // namespace Widgets } // namespace Inkscape diff --git a/src/widgets/fill-style.cpp b/src/widgets/fill-style.cpp index d9d818643..d1d318abe 100644 --- a/src/widgets/fill-style.cpp +++ b/src/widgets/fill-style.cpp @@ -22,8 +22,12 @@ # include "config.h" #endif -#include <glibmm/i18n.h> +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + #include <gtkmm/box.h> +#include <glibmm/i18n.h> #include "verbs.h" @@ -84,6 +88,7 @@ private: static void fillruleChangedCB( SPPaintSelector *psel, SPPaintSelector::FillRule mode, FillNStroke *self ); void selectionModifiedCB(guint flags); + void eventContextCB(SPDesktop *desktop, Inkscape::UI::Tools::ToolBase *eventcontext); void dragFromPaint(); void updateFromPaint(); @@ -99,6 +104,7 @@ private: sigc::connection selectChangedConn; sigc::connection subselChangedConn; sigc::connection selectModifiedConn; + sigc::connection eventContextConn; }; } // namespace Inkscape @@ -133,7 +139,8 @@ FillNStroke::FillNStroke( FillOrStroke kind ) : update(false), selectChangedConn(), subselChangedConn(), - selectModifiedConn() + selectModifiedConn(), + eventContextConn() { // Add and connect up the paint selector widget: psel = sp_paint_selector_new(kind); @@ -169,6 +176,7 @@ FillNStroke::~FillNStroke() selectModifiedConn.disconnect(); subselChangedConn.disconnect(); selectChangedConn.disconnect(); + eventContextConn.disconnect(); } /** @@ -197,11 +205,13 @@ void FillNStroke::setDesktop(SPDesktop *desktop) selectModifiedConn.disconnect(); subselChangedConn.disconnect(); selectChangedConn.disconnect(); + eventContextConn.disconnect(); } this->desktop = desktop; if (desktop && desktop->selection) { selectChangedConn = desktop->selection->connectChanged(sigc::hide(sigc::mem_fun(*this, &FillNStroke::performUpdate))); subselChangedConn = desktop->connectToolSubselectionChanged(sigc::hide(sigc::mem_fun(*this, &FillNStroke::performUpdate))); + eventContextConn = desktop->connectEventContextChanged(sigc::hide(sigc::bind(sigc::mem_fun(*this, &FillNStroke::eventContextCB), (Inkscape::UI::Tools::ToolBase *)NULL))); // Must check flags, so can't call performUpdate() directly. selectModifiedConn = desktop->selection->connectModified(sigc::hide<0>(sigc::mem_fun(*this, &FillNStroke::selectionModifiedCB))); @@ -211,6 +221,16 @@ void FillNStroke::setDesktop(SPDesktop *desktop) } /** + * Listen to this "change in tool" event, in case a subselection tool (such as Gradient or Node) selection + * is changed back to a selection tool - especially needed for selected gradient stops. + */ +void FillNStroke::eventContextCB(SPDesktop * /*desktop*/, Inkscape::UI::Tools::ToolBase * /*eventcontext*/) +{ + performUpdate(); +} + + +/** * Gets the active fill or stroke style property, then sets the appropriate * color, alpha, gradient, pattern, etc. for the paint-selector. * @@ -566,15 +586,19 @@ void FillNStroke::updateFromPaint() } if (!vector) { - SPGradient *gr = sp_gradient_vector_for_object( document, desktop, reinterpret_cast<SPObject*>(i->data), kind == FILL, createSwatch ); + SPGradient *gr = sp_gradient_vector_for_object( document, + desktop, + reinterpret_cast<SPObject*>(i->data), + (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE, + createSwatch ); if ( gr && createSwatch ) { gr->setSwatch(); } sp_item_set_gradient(SP_ITEM(i->data), gr, - gradient_type, kind == FILL); + gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); } else { - sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, kind == FILL); + sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); } } } else { @@ -587,7 +611,7 @@ void FillNStroke::updateFromPaint() sp_repr_css_change_recursive(reinterpret_cast<SPObject*>(i->data)->getRepr(), css, "style"); } - SPGradient *gr = sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, kind == FILL); + SPGradient *gr = sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); psel->pushAttrsToGradient( gr ); } } diff --git a/src/widgets/font-selector.cpp b/src/widgets/font-selector.cpp index affc6bed9..0e862638c 100644 --- a/src/widgets/font-selector.cpp +++ b/src/widgets/font-selector.cpp @@ -8,10 +8,11 @@ * Lauris Kaplinski <lauris@kaplinski.com> * bulia byak <buliabyak@users.sf.net> * Johan Engelen <j.b.c.engelen@ewi.utwente.nl> + * Tavmjong Bah <tavmjong@free.fr> * * Copyright (C) 1999-2001 Ximian, Inc. * Copyright (C) 2002 Lauris Kaplinski - * Copyright (C) -2007 Authors + * Copyright (C) -2013 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -31,6 +32,7 @@ #include "desktop.h" #include "widgets/font-selector.h" +#include "preferences.h" /* SPFontSelector */ @@ -49,11 +51,9 @@ struct SPFontSelector NRNameList families; NRStyleList styles; - int familyidx; - int styleidx; gfloat fontsize; bool fontsize_dirty; - font_instance *font; + Glib::ustring *fontspec; }; @@ -61,7 +61,7 @@ struct SPFontSelectorClass { GtkHBoxClass parent_class; - void (* font_set) (SPFontSelector *fsel, font_instance *font); + void (* font_set) (SPFontSelector *fsel, gchar *fontspec); }; enum { @@ -71,7 +71,7 @@ enum { static void sp_font_selector_class_init (SPFontSelectorClass *c); static void sp_font_selector_init (SPFontSelector *fsel); -static void sp_font_selector_destroy (GtkObject *object); +static void sp_font_selector_dispose (GObject *object); static void sp_font_selector_family_select_row (GtkTreeSelection *selection, SPFontSelector *fsel); @@ -83,15 +83,7 @@ static void sp_font_selector_size_changed (GtkComboBox *combobo SPFontSelector *fsel); static void sp_font_selector_emit_set (SPFontSelector *fsel); - -namespace { - const char *sizes[] = { - "4", "6", "8", "9", "10", "11", "12", "13", "14", - "16", "18", "20", "22", "24", "28", - "32", "36", "40", "48", "56", "64", "72", "144", - NULL - }; -} +static void sp_font_selector_set_sizes( SPFontSelector *fsel ); static GtkHBoxClass *fs_parent_class = NULL; static guint fs_signals[LAST_SIGNAL] = { 0 }; @@ -119,7 +111,7 @@ GType sp_font_selector_get_type() static void sp_font_selector_class_init(SPFontSelectorClass *c) { - GtkObjectClass *object_class = (GtkObjectClass *) c; + GObjectClass *object_class = G_OBJECT_CLASS(c); fs_parent_class = (GtkHBoxClass* )g_type_class_peek_parent (c); @@ -132,9 +124,21 @@ static void sp_font_selector_class_init(SPFontSelectorClass *c) G_TYPE_NONE, 1, G_TYPE_POINTER); - object_class->destroy = sp_font_selector_destroy; + object_class->dispose = sp_font_selector_dispose; +} + +static void sp_font_selector_set_size_tooltip(SPFontSelector *fsel) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT); + Glib::ustring tooltip = Glib::ustring::format(_("Font size"), " (", sp_style_get_css_unit_string(unit), ")"); + gtk_widget_set_tooltip_text (fsel->size, _(tooltip.c_str())); } + +/* + * Create a widget with children for selecting font-family, font-style, and font-size. + */ static void sp_font_selector_init(SPFontSelector *fsel) { gtk_box_set_homogeneous(GTK_BOX(fsel), TRUE); @@ -152,15 +156,27 @@ static void sp_font_selector_init(SPFontSelector *fsel) gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN); gtk_container_add(GTK_CONTAINER(f), sw); - Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); - fsel->family_treeview = gtk_tree_view_new (); GtkTreeViewColumn *column = gtk_tree_view_column_new (); GtkCellRenderer *cell = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (column, cell, FALSE); gtk_tree_view_column_set_attributes (column, cell, "text", 0, NULL); + gtk_tree_view_column_set_cell_data_func (column, cell, + GtkTreeCellDataFunc (font_lister_cell_data_func), + NULL, NULL ); gtk_tree_view_append_column (GTK_TREE_VIEW(fsel->family_treeview), column); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(fsel->family_treeview), FALSE); + gtk_tree_view_set_row_separator_func( GTK_TREE_VIEW(fsel->family_treeview), + GtkTreeViewRowSeparatorFunc ((gpointer)font_lister_separator_func), + NULL, NULL ); + + /* Muck with style, see text-toolbar.cpp */ + gtk_widget_set_name( GTK_WIDGET(fsel->family_treeview), "font_selector_family" ); + gtk_rc_parse_string ( + "widget \"*font_selector_family\" style \"fontfamily-separator-style\""); + + + Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); Glib::RefPtr<Gtk::ListStore> store = fontlister->get_font_list(); gtk_tree_view_set_model (GTK_TREE_VIEW(fsel->family_treeview), GTK_TREE_MODEL (Glib::unwrap (store))); gtk_container_add(GTK_CONTAINER(sw), fsel->family_treeview); @@ -215,51 +231,36 @@ static void sp_font_selector_init(SPFontSelector *fsel) gtk_widget_show(hb); gtk_box_pack_start(GTK_BOX(vb), hb, FALSE, FALSE, 0); -/* -This would introduce dependency on gtk version 2.24 which is currently not available in -Trisquel GNU/Linux 4.5.1 (released on May 25th, 2011) -This conditional and its #else block can be deleted in the future. -*/ -#if GTK_CHECK_VERSION(2, 24,0) + // Font-size fsel->size = gtk_combo_box_text_new_with_entry (); -#else - fsel->size = gtk_combo_box_entry_new_text (); -#endif - gtk_widget_set_tooltip_text (fsel->size, _("Font size (px)")); + sp_font_selector_set_size_tooltip(fsel); gtk_widget_set_size_request(fsel->size, 90, -1); g_signal_connect (G_OBJECT(fsel->size), "changed", G_CALLBACK (sp_font_selector_size_changed), fsel); gtk_box_pack_end (GTK_BOX(hb), fsel->size, FALSE, FALSE, 0); GtkWidget *l = gtk_label_new(_("Font size:")); gtk_widget_show_all (l); - gtk_box_pack_end(GTK_BOX (hb), l, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX (hb), l, TRUE, TRUE, 0); - for (unsigned int n = 0; sizes[n]; ++n) - { -#if GTK_CHECK_VERSION(2, 24,0) - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(fsel->size), sizes[n]); -#else - gtk_combo_box_append_text (GTK_COMBO_BOX(fsel->size), sizes[n]); -#endif - } + sp_font_selector_set_sizes(fsel); gtk_widget_show_all (fsel->size); - fsel->familyidx = 0; - fsel->styleidx = 0; - fsel->fontsize = 10.0; + // Set default size... next two lines must match + gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(fsel->size))), "18.0"); + fsel->fontsize = 18.0; fsel->fontsize_dirty = false; - fsel->font = NULL; + + fsel->fontspec = new Glib::ustring; } -static void sp_font_selector_destroy(GtkObject *object) +static void sp_font_selector_dispose(GObject *object) { SPFontSelector *fsel = SP_FONT_SELECTOR (object); - if (fsel->font) { - fsel->font->Unref(); - fsel->font = NULL; + if (fsel->fontspec) { + delete fsel->fontspec; } if (fsel->families.length > 0) { @@ -272,68 +273,108 @@ static void sp_font_selector_destroy(GtkObject *object) fsel->styles.length = 0; } - if (GTK_OBJECT_CLASS(fs_parent_class)->destroy) { - GTK_OBJECT_CLASS(fs_parent_class)->destroy(object); + if (G_OBJECT_CLASS(fs_parent_class)->dispose) { + G_OBJECT_CLASS(fs_parent_class)->dispose(object); } } +// Callback when family changed, updates style list for new family. static void sp_font_selector_family_select_row(GtkTreeSelection *selection, SPFontSelector *fsel) { - GtkTreeIter iter; - GtkTreeModel *model; - GtkListStore *store; - GtkTreePath *path; - GList *list=0; + // We need our own copy of the style list store since the font-family + // may not be the same in the font-selector as stored in the font-lister + // TODO: use font-lister class for this by modifying new_font_family to accept an optional style list + // TODO: add store to SPFontSelector struct and reuse. + + // Start by getting iterator to selected font + GtkTreeModel *model; + GtkTreeIter iter; if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; - path = gtk_tree_model_get_path (model, &iter); - gtk_tree_model_get (model, &iter, 1, &list, -1); - fsel->familyidx = gtk_tree_path_get_indices (path)[0]; - fsel->styleidx = 0; + // Next get family name with its style list + gchar *family; + GList *list=NULL; + gtk_tree_model_get (model, &iter, 0, &family, 1, &list, -1); - store = gtk_list_store_new (1, G_TYPE_STRING); + // Find best style match for selected family with current style (e.g. of selected text). + Inkscape::FontLister *fontlister = Inkscape::FontLister::get_instance(); + Glib::ustring style = fontlister->get_font_style(); + Glib::ustring best = fontlister->get_best_style_match (family, style); + // Create our own store of styles for selected font-family and find index of best style match + int path_index = 0; + int index = 0; + GtkListStore *store = gtk_list_store_new (1, G_TYPE_STRING); // Where is this deleted? for ( ; list ; list = list->next ) { gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, (char*)list->data, -1); + + if( best.compare( (char*)list->data ) == 0 ) { + path_index = index; + } + ++index; } + // Attach store to tree view. Can trigger style changed signal (but not FONT_SET): gtk_tree_view_set_model (GTK_TREE_VIEW (fsel->style_treeview), GTK_TREE_MODEL (store)); - path = gtk_tree_path_new (); - gtk_tree_path_append_index (path, 0); + + // Get path to best style + GtkTreePath *path = gtk_tree_path_new (); + gtk_tree_path_append_index (path, path_index); + + // Highlight best style. Triggers style changed signal: gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->style_treeview)), path); gtk_tree_path_free (path); } -static void sp_font_selector_style_select_row (GtkTreeSelection *selection, +// Callback when row changed +static void sp_font_selector_style_select_row (GtkTreeSelection * /*selection*/, SPFontSelector *fsel) { - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; + if (!fsel->block_emit) + { + sp_font_selector_emit_set (fsel); + } +} - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; - path = gtk_tree_model_get_path (model, &iter); - fsel->styleidx = gtk_tree_path_get_indices (path)[0]; +/* + * Set the default list of font sizes, scaled to the users preferred unit + * TODO: This routine occurs both here and in text-toolbar. Move to font-lister? + */ +static void sp_font_selector_set_sizes( SPFontSelector *fsel ) +{ + GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model (GTK_COMBO_BOX(fsel->size))); + gtk_list_store_clear(store); - if (!fsel->block_emit) + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT); + + int sizes[] = { + 4, 6, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 28, + 32, 36, 40, 48, 56, 64, 72, 144 + }; + + // Array must be same length as SPCSSUnit in style.h + float ratios[] = {1, 1, 1, 10, 4, 40, 100, 16, 8, 0.16}; + + for (unsigned int n = 0; n < G_N_ELEMENTS(sizes); ++n) { - sp_font_selector_emit_set (fsel); + double size = sizes[n] / ratios[unit]; + + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(fsel->size), Glib::ustring::format(size).c_str()); } + } +// Callback when size changed static void sp_font_selector_size_changed( GtkComboBox */*cbox*/, SPFontSelector *fsel ) { char *text = NULL; -#if GTK_CHECK_VERSION(2, 24,0) text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (fsel->size)); -#else - text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (fsel->size)); -#endif gfloat old_size = fsel->fontsize; gchar *endptr; @@ -344,11 +385,15 @@ static void sp_font_selector_size_changed( GtkComboBox */*cbox*/, SPFontSelector value = -1; free (text); } + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int max_size = prefs->getInt("/dialogs/textandfont/maxFontSize", 10000); // somewhat arbitrary, but text&font preview freezes with too huge fontsizes + if (value <= 0) { return; // could not parse value } - if (value > 10000) - value = 10000; // somewhat arbitrary, but text&font preview freezes with too huge fontsizes + if (value > max_size) + value = max_size; fsel->fontsize = value; if ( fabs(fsel->fontsize-old_size) > 0.001) @@ -359,9 +404,13 @@ static void sp_font_selector_size_changed( GtkComboBox */*cbox*/, SPFontSelector sp_font_selector_emit_set (fsel); } + +// Called from sp_font_selector_style_select_row +// Called from sp_font_selector_size_changed +// Called indirectly for sp_font_selector_family_select_row (since style changes). +// Emits FONT_SET signal (handled by TextEdit::onFontChange, GlyphsPanel::fontChangeCB). static void sp_font_selector_emit_set (SPFontSelector *fsel) { - font_instance *font; GtkTreeSelection *selection_family; GtkTreeSelection *selection_style; @@ -369,168 +418,111 @@ static void sp_font_selector_emit_set (SPFontSelector *fsel) GtkTreeModel *model_style; GtkTreeIter iter_family; GtkTreeIter iter_style; - char *family=0, *style=0; + char *family=NULL, *style=NULL; //We need to check this here since most GtkTreeModel operations are not atomic //See GtkListStore documenation, Chapter "Atomic Operations" --mderezynski model_family = gtk_tree_view_get_model (GTK_TREE_VIEW (fsel->family_treeview)); if (!model_family) return; - model_style = gtk_tree_view_get_model (GTK_TREE_VIEW (fsel->style_treeview)); - if (!model_style) return; + model_style = gtk_tree_view_get_model (GTK_TREE_VIEW (fsel->style_treeview)); + if (!model_style ) return; selection_family = gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->family_treeview)); - selection_style = gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->style_treeview)); + selection_style = gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->style_treeview )); if (!gtk_tree_selection_get_selected (selection_family, NULL, &iter_family)) return; - if (!gtk_tree_selection_get_selected (selection_style, NULL, &iter_style)) return; + if (!gtk_tree_selection_get_selected (selection_style, NULL, &iter_style )) return; gtk_tree_model_get (model_family, &iter_family, 0, &family, -1); - gtk_tree_model_get (model_style, &iter_style, 0, &style, -1); + gtk_tree_model_get (model_style, &iter_style, 0, &style, -1); if ((!family) || (!style)) return; - font = (font_factory::Default())->FaceFromUIStrings (family, style); + Glib::ustring fontspec = family; + fontspec += ", "; + fontspec += style; - // FIXME: when a text object uses non-available font, font==NULL and we can't set size - // (and the size shown in the widget is invalid). To fix, here we must always get some - // default font, exactly the same as sptext uses for on-canvas display, so that - // font!=NULL ever. - if (font != fsel->font || ( font && fsel->fontsize_dirty ) ) { - if ( font ) { - font->Ref(); - } - if ( fsel->font ) { - fsel->font->Unref(); - } - fsel->font = font; - g_signal_emit(GTK_OBJECT(fsel), fs_signals[FONT_SET], 0, fsel->font); - } - fsel->fontsize_dirty = false; - if (font) { - font->Unref(); - } - font = NULL; + *(fsel->fontspec) = fontspec; + + g_signal_emit(fsel, fs_signals[FONT_SET], 0, fontspec.c_str()); } GtkWidget *sp_font_selector_new() { - SPFontSelector *fsel = (SPFontSelector*) g_object_new(SP_TYPE_FONT_SELECTOR, NULL); + SPFontSelector *fsel = SP_FONT_SELECTOR(g_object_new(SP_TYPE_FONT_SELECTOR, NULL)); - return (GtkWidget *) fsel; + return GTK_WIDGET(fsel); } -void sp_font_selector_set_font (SPFontSelector *fsel, font_instance *font, double size) + +/* + * Sets the values displayed in the font-selector from a fontspec. + * It is only called from TextEdit with a new selection and from GlyphsPanel + */ +void sp_font_selector_set_fontspec (SPFontSelector *fsel, Glib::ustring fontspec, double size) { - if (font) - { - Gtk::TreePath path; - font_instance *tempFont = NULL; - - Glib::ustring family = font_factory::Default()->GetUIFamilyString(font->descr); + if (!fontspec.empty()) + { + Inkscape::FontLister *font_lister = Inkscape::FontLister::get_instance(); + std::pair<Glib::ustring, Glib::ustring> ui = font_lister->ui_from_fontspec( fontspec ); + Glib::ustring family = ui.first; + Glib::ustring style = ui.second; + + Gtk::TreePath path; try { - path = Inkscape::FontLister::get_instance()->get_row_for_font (family); + path = font_lister->get_row_for_font (family); } catch (...) { + g_warning( "Couldn't find row for font-family: %s", family.c_str() ); return; } + // High light selected family and scroll so it is in view. fsel->block_emit = TRUE; gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->family_treeview)), path.gobj()); gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fsel->family_treeview), path.gobj(), NULL, TRUE, 0.5, 0.5); - fsel->block_emit = FALSE; + fsel->block_emit = FALSE; // TODO: Should this be moved to the end? - GList *list = 0; - GtkTreeIter iter; - GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW(fsel->family_treeview)); - gtk_tree_model_get_iter (model, &iter, path.gobj()); - gtk_tree_model_get (model, &iter, 1, &list, -1); - unsigned int currentStyleNumber = 0; - unsigned int bestStyleNumber = 0; - - PangoFontDescription *incomingFont = pango_font_description_copy(font->descr); - pango_font_description_unset_fields(incomingFont, PANGO_FONT_MASK_SIZE); - - char *incomingFontString = pango_font_description_to_string(incomingFont); - - tempFont = (font_factory::Default())->FaceFromUIStrings(family.c_str(), (char*)list->data); - - PangoFontDescription *bestMatchForFont = NULL; - if (tempFont) { - bestMatchForFont = pango_font_description_copy(tempFont->descr); - tempFont->Unref(); - tempFont = NULL; - } - - pango_font_description_unset_fields(bestMatchForFont, PANGO_FONT_MASK_SIZE); - - list = list->next; - - while (list) { - currentStyleNumber++; - - tempFont = font_factory::Default()->FaceFromUIStrings(family.c_str(), (char*)list->data); - - PangoFontDescription *currentMatchForFont = NULL; - if (tempFont) { - currentMatchForFont = pango_font_description_copy(tempFont->descr); - tempFont->Unref(); - tempFont = NULL; - } - - if (currentMatchForFont) { - pango_font_description_unset_fields(currentMatchForFont, PANGO_FONT_MASK_SIZE); - - char *currentMatchString = pango_font_description_to_string(currentMatchForFont); - - if (!strcmp(incomingFontString, currentMatchString) - || pango_font_description_better_match(incomingFont, bestMatchForFont, currentMatchForFont)) { - // Found a better match for the font we are looking for - pango_font_description_free(bestMatchForFont); - bestMatchForFont = pango_font_description_copy(currentMatchForFont); - bestStyleNumber = currentStyleNumber; - } - - g_free(currentMatchString); - - pango_font_description_free(currentMatchForFont); - } - - list = list->next; + // We don't need to get best style since this is only called on a new + // selection where we already know the "best" style. + // Glib::ustring bestStyle = font_lister->get_best_style_match (family, style); + // std::cout << "Best: " << bestStyle << std::endl; + + // The "trial" style list and the regular list are the same in this case. + Gtk::TreePath path_c; + try { + path_c = font_lister->get_row_for_style( style ); + } catch (...) { + g_warning( "Couldn't find row for style: %s (%s)", style.c_str(), family.c_str() ); + return; } - - if (bestMatchForFont) - pango_font_description_free(bestMatchForFont); - if (incomingFont) - pango_font_description_free(incomingFont); - g_free(incomingFontString); - - GtkTreePath *path_c = gtk_tree_path_new (); - gtk_tree_path_append_index (path_c, bestStyleNumber); - gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->style_treeview)), path_c); - gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fsel->style_treeview), path_c, NULL, TRUE, 0.5, 0.5); - + + gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (fsel->style_treeview)), path_c.gobj()); + gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fsel->style_treeview), path_c.gobj(), NULL, TRUE, 0.5, 0.5); + if (size != fsel->fontsize) { gchar s[8]; g_snprintf (s, 8, "%.5g", size); // UI, so printf is ok gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(fsel->size))), s); fsel->fontsize = size; + sp_font_selector_set_size_tooltip(fsel); + sp_font_selector_set_sizes(fsel); } } } -font_instance* sp_font_selector_get_font(SPFontSelector *fsel) +Glib::ustring sp_font_selector_get_fontspec(SPFontSelector *fsel) { - if (fsel->font) { - fsel->font->Ref(); - } - - return fsel->font; + return *(fsel->fontspec); } +/* + * Return the font size in pixels + */ double sp_font_selector_get_size(SPFontSelector *fsel) { return fsel->fontsize; diff --git a/src/widgets/font-selector.h b/src/widgets/font-selector.h index da32b3640..66715f048 100644 --- a/src/widgets/font-selector.h +++ b/src/widgets/font-selector.h @@ -7,9 +7,11 @@ * Authors: * Chris Lahey <clahey@ximian.com> * Lauris Kaplinski <lauris@kaplinski.com> + * Tavmjong Bah <tavmjong@free.fr> * * Copyright (C) 1999-2001 Ximian, Inc. * Copyright (C) 2002 Lauris Kaplinski + * Copyright (C) 1999-2013 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -22,7 +24,24 @@ struct SPFontSelector; #define SP_FONT_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_FONT_SELECTOR, SPFontSelector)) #define SP_IS_FONT_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_FONT_SELECTOR)) -class font_instance; +/* + * The routines here create and manage a font selector widget with three parts, + * one each for font-family, font-style, and font-size. + * + * It is used by the TextEdit and Glyphs panel dialogs. The FontLister class is used + * to access the list of font-families and their associated styles for fonts either + * on the system or in the document. The FontLister class is also used by the Text + * toolbar. Fonts are kept track of by their "fontspecs" which are the same as the + * strings that Pango generates. + * + * The main functions are: + * Create the font-seletor widget. + * Update the lists when a new text selection is made. + * Update the Style list when a new font-family is selected, highlighting the + * best match to the original font style (as not all fonts have the same style options). + * Emit a signal when any change is made so that the Text Preview can be updated. + * Provide the currently selected values. + */ /* SPFontSelector */ @@ -30,13 +49,11 @@ GType sp_font_selector_get_type (void); GtkWidget *sp_font_selector_new (void); -void sp_font_selector_set_font (SPFontSelector *fsel, font_instance *font, double size); +void sp_font_selector_set_fontspec (SPFontSelector *fsel, Glib::ustring fontspec, double size); +Glib::ustring sp_font_selector_get_fontspec (SPFontSelector *fsel); -font_instance *sp_font_selector_get_font (SPFontSelector *fsel); double sp_font_selector_get_size (SPFontSelector *fsel); - - #endif // SP_FONT_SELECTOR_H /* diff --git a/src/widgets/gradient-image.cpp b/src/widgets/gradient-image.cpp index 114d76293..64b058f62 100644 --- a/src/widgets/gradient-image.cpp +++ b/src/widgets/gradient-image.cpp @@ -16,7 +16,6 @@ #include "display/cairo-utils.h" #include "gradient-image.h" #include "sp-gradient.h" -#include "sp-gradient-fns.h" #include <sigc++/functors/ptr_fun.h> #include <sigc++/adaptors/bind.h> @@ -25,150 +24,166 @@ static void sp_gradient_image_class_init (SPGradientImageClass *klass); static void sp_gradient_image_init (SPGradientImage *image); -static void sp_gradient_image_destroy (GtkObject *object); - static void sp_gradient_image_size_request (GtkWidget *widget, GtkRequisition *requisition); #if GTK_CHECK_VERSION(3,0,0) +static void sp_gradient_image_destroy(GtkWidget *object); static void sp_gradient_image_get_preferred_width(GtkWidget *widget, gint *minimal_width, - gint *natural_width); + gint *natural_width); static void sp_gradient_image_get_preferred_height(GtkWidget *widget, gint *minimal_height, - gint *natural_height); + gint *natural_height); +#else +static void sp_gradient_image_destroy(GtkObject *object); +static gboolean sp_gradient_image_expose(GtkWidget *widget, GdkEventExpose *event); #endif -static gint sp_gradient_image_expose (GtkWidget *widget, GdkEventExpose *event); - +static gboolean sp_gradient_image_draw(GtkWidget *widget, cairo_t *cr); static void sp_gradient_image_gradient_release (SPObject *, SPGradientImage *im); static void sp_gradient_image_gradient_modified (SPObject *, guint flags, SPGradientImage *im); static void sp_gradient_image_update (SPGradientImage *img); static GtkWidgetClass *parent_class; -GType -sp_gradient_image_get_type (void) +GType sp_gradient_image_get_type(void) { - static GType type = 0; - if (!type) { - GTypeInfo info = { - sizeof (SPGradientImageClass), - NULL, NULL, - (GClassInitFunc) sp_gradient_image_class_init, - NULL, NULL, - sizeof (SPGradientImage), - 0, - (GInstanceInitFunc) sp_gradient_image_init, - NULL - }; - type = g_type_register_static (GTK_TYPE_WIDGET, "SPGradientImage", &info, (GTypeFlags)0); - } - return type; + static GType type = 0; + if (!type) { + GTypeInfo info = { + sizeof (SPGradientImageClass), + NULL, NULL, + (GClassInitFunc) sp_gradient_image_class_init, + NULL, NULL, + sizeof (SPGradientImage), + 0, + (GInstanceInitFunc) sp_gradient_image_init, + NULL + }; + type = g_type_register_static (GTK_TYPE_WIDGET, "SPGradientImage", &info, (GTypeFlags)0); + } + return type; } -static void -sp_gradient_image_class_init (SPGradientImageClass *klass) +static void sp_gradient_image_class_init(SPGradientImageClass *klass) { - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - object_class = (GtkObjectClass *) klass; - widget_class = (GtkWidgetClass *) klass; - - parent_class = (GtkWidgetClass*)g_type_class_peek_parent (klass); - - object_class->destroy = sp_gradient_image_destroy; + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + parent_class = GTK_WIDGET_CLASS(g_type_class_peek_parent (klass)); #if GTK_CHECK_VERSION(3,0,0) - widget_class->get_preferred_width = sp_gradient_image_get_preferred_width; - widget_class->get_preferred_height = sp_gradient_image_get_preferred_height; +// GObjectClass *object_class = G_OBJECT_CLASS(klass); + + widget_class->get_preferred_width = sp_gradient_image_get_preferred_width; + widget_class->get_preferred_height = sp_gradient_image_get_preferred_height; + widget_class->draw = sp_gradient_image_draw; + widget_class->destroy = sp_gradient_image_destroy; #else - widget_class->size_request = sp_gradient_image_size_request; + GtkObjectClass *object_class = GTK_OBJECT_CLASS(klass); + + object_class->destroy = sp_gradient_image_destroy; + widget_class->size_request = sp_gradient_image_size_request; + widget_class->expose_event = sp_gradient_image_expose; #endif - widget_class->expose_event = sp_gradient_image_expose; } static void sp_gradient_image_init (SPGradientImage *image) { - gtk_widget_set_has_window (GTK_WIDGET(image), FALSE); + gtk_widget_set_has_window (GTK_WIDGET(image), FALSE); - image->gradient = NULL; + image->gradient = NULL; - new (&image->release_connection) sigc::connection(); - new (&image->modified_connection) sigc::connection(); + new (&image->release_connection) sigc::connection(); + new (&image->modified_connection) sigc::connection(); } -static void -sp_gradient_image_destroy (GtkObject *object) +#if GTK_CHECK_VERSION(3,0,0) +static void sp_gradient_image_destroy(GtkWidget *object) +#else +static void sp_gradient_image_destroy(GtkObject *object) +#endif { - SPGradientImage *image; - - image = SP_GRADIENT_IMAGE (object); + SPGradientImage *image = SP_GRADIENT_IMAGE (object); - if (image->gradient) { - image->release_connection.disconnect(); - image->modified_connection.disconnect(); - image->gradient = NULL; - } + if (image->gradient) { + image->release_connection.disconnect(); + image->modified_connection.disconnect(); + image->gradient = NULL; + } - image->release_connection.~connection(); - image->modified_connection.~connection(); + image->release_connection.~connection(); + image->modified_connection.~connection(); - if (((GtkObjectClass *) (parent_class))->destroy) - (* ((GtkObjectClass *) (parent_class))->destroy) (object); +#if GTK_CHECK_VERSION(3,0,0) + if (parent_class->destroy) + (* (parent_class)->destroy) (object); +#else + if ((GTK_OBJECT_CLASS(parent_class))->destroy) + (* (GTK_OBJECT_CLASS(parent_class))->destroy) (object); +#endif } static void sp_gradient_image_size_request(GtkWidget * /*widget*/, GtkRequisition *requisition) { - requisition->width = 64; + requisition->width = 54; requisition->height = 12; } #if GTK_CHECK_VERSION(3,0,0) static void sp_gradient_image_get_preferred_width(GtkWidget *widget, gint *minimal_width, gint *natural_width) { - GtkRequisition requisition; - sp_gradient_image_size_request(widget, &requisition); - *minimal_width = *natural_width = requisition.width; + GtkRequisition requisition; + sp_gradient_image_size_request(widget, &requisition); + *minimal_width = *natural_width = requisition.width; } static void sp_gradient_image_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height) { - GtkRequisition requisition; - sp_gradient_image_size_request(widget, &requisition); - *minimal_height = *natural_height = requisition.height; + GtkRequisition requisition; + sp_gradient_image_size_request(widget, &requisition); + *minimal_height = *natural_height = requisition.height; } #endif -static gint -sp_gradient_image_expose (GtkWidget *widget, GdkEventExpose *event) +#if !GTK_CHECK_VERSION(3,0,0) +static gboolean sp_gradient_image_expose(GtkWidget *widget, GdkEventExpose *event) { - GtkAllocation allocation; - SPGradientImage *image = SP_GRADIENT_IMAGE (widget); - SPGradient *gr = image->gradient; + gboolean result = TRUE; + if(gtk_widget_is_drawable(widget)) { + cairo_t *ct = gdk_cairo_create(gtk_widget_get_window (widget)); + cairo_rectangle(ct, event->area.x, event->area.y, + event->area.width, event->area.height); + cairo_clip(ct); + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + cairo_translate(ct, allocation.x, allocation.y); + result = sp_gradient_image_draw(widget, ct); + cairo_destroy(ct); + } + + return result; +} +#endif - cairo_t *ct = gdk_cairo_create(gtk_widget_get_window (widget)); - - cairo_rectangle(ct, event->area.x, event->area.y, - event->area.width, event->area.height); - cairo_clip(ct); - gtk_widget_get_allocation (widget, &allocation); - cairo_translate(ct, allocation.x, allocation.y); +static gboolean sp_gradient_image_draw(GtkWidget *widget, cairo_t *ct) +{ + SPGradientImage *image = SP_GRADIENT_IMAGE(widget); + SPGradient *gr = image->gradient; + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard(); cairo_set_source(ct, check); cairo_paint(ct); cairo_pattern_destroy(check); - if (gr) { + if (gr) { cairo_pattern_t *p = sp_gradient_create_preview_pattern(gr, allocation.width); cairo_set_source(ct, p); cairo_paint(ct); cairo_pattern_destroy(p); } - cairo_destroy(ct); return TRUE; } @@ -176,13 +191,11 @@ sp_gradient_image_expose (GtkWidget *widget, GdkEventExpose *event) GtkWidget * sp_gradient_image_new (SPGradient *gradient) { - SPGradientImage *image; - - image = (SPGradientImage*)g_object_new (SP_TYPE_GRADIENT_IMAGE, NULL); + SPGradientImage *image = SP_GRADIENT_IMAGE(g_object_new(SP_TYPE_GRADIENT_IMAGE, NULL)); - sp_gradient_image_set_gradient (image, gradient); + sp_gradient_image_set_gradient (image, gradient); - return (GtkWidget *) image; + return GTK_WIDGET(image); } GdkPixbuf* @@ -206,12 +219,8 @@ sp_gradient_to_pixbuf (SPGradient *gr, int width, int height) cairo_destroy(ct); cairo_surface_flush(s); - GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( cairo_image_surface_get_data(s), - GDK_COLORSPACE_RGB, TRUE, 8, - width, height, cairo_image_surface_get_stride(s), - ink_cairo_pixbuf_cleanup, s); - convert_pixbuf_argb32_to_normal(pixbuf); - + // no need to free s - the call below takes ownership + GdkPixbuf *pixbuf = ink_pixbuf_create_from_cairo_surface(s); return pixbuf; } @@ -219,44 +228,44 @@ sp_gradient_to_pixbuf (SPGradient *gr, int width, int height) void sp_gradient_image_set_gradient (SPGradientImage *image, SPGradient *gradient) { - if (image->gradient) { - image->release_connection.disconnect(); - image->modified_connection.disconnect(); - } + if (image->gradient) { + image->release_connection.disconnect(); + image->modified_connection.disconnect(); + } - image->gradient = gradient; + image->gradient = gradient; - if (gradient) { - image->release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_image_gradient_release), image)); - image->modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_image_gradient_modified), image)); - } + if (gradient) { + image->release_connection = gradient->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gradient_image_gradient_release), image)); + image->modified_connection = gradient->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_gradient_image_gradient_modified), image)); + } - sp_gradient_image_update (image); + sp_gradient_image_update (image); } static void sp_gradient_image_gradient_release (SPObject *, SPGradientImage *image) { - if (image->gradient) { - image->release_connection.disconnect(); - image->modified_connection.disconnect(); - } + if (image->gradient) { + image->release_connection.disconnect(); + image->modified_connection.disconnect(); + } - image->gradient = NULL; + image->gradient = NULL; - sp_gradient_image_update (image); + sp_gradient_image_update (image); } static void sp_gradient_image_gradient_modified (SPObject *, guint /*flags*/, SPGradientImage *image) { - sp_gradient_image_update (image); + sp_gradient_image_update (image); } static void sp_gradient_image_update (SPGradientImage *image) { - if (gtk_widget_is_drawable (GTK_WIDGET(image))) { - gtk_widget_queue_draw (GTK_WIDGET (image)); - } + if (gtk_widget_is_drawable (GTK_WIDGET(image))) { + gtk_widget_queue_draw (GTK_WIDGET (image)); + } } diff --git a/src/widgets/gradient-selector.cpp b/src/widgets/gradient-selector.cpp index e820beac6..871d1ee4c 100644 --- a/src/widgets/gradient-selector.cpp +++ b/src/widgets/gradient-selector.cpp @@ -16,18 +16,27 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif +#include "gradient-vector.h" #include <gtk/gtk.h> #include "document.h" +#include "../document-undo.h" #include "../document-private.h" #include "../gradient-chemistry.h" +#include "inkscape.h" +#include "verbs.h" +#include "helper/action.h" +#include "helper/action-context.h" +#include "preferences.h" #include <glibmm/i18n.h> #include <xml/repr.h> -#include "gradient-vector.h" - #include "gradient-selector.h" +#include "paint-selector.h" +#include "style.h" +#include "id-clash.h" +#include "ui/icon-names.h" enum { GRABBED, @@ -37,15 +46,17 @@ enum { LAST_SIGNAL }; + static void sp_gradient_selector_class_init (SPGradientSelectorClass *klass); static void sp_gradient_selector_init (SPGradientSelector *selector); -static void sp_gradient_selector_destroy (GtkObject *object); +static void sp_gradient_selector_dispose(GObject *object); /* Signal handlers */ static void sp_gradient_selector_vector_set (SPGradientVectorSelector *gvs, SPGradient *gr, SPGradientSelector *sel); static void sp_gradient_selector_edit_vector_clicked (GtkWidget *w, SPGradientSelector *sel); static void sp_gradient_selector_add_vector_clicked (GtkWidget *w, SPGradientSelector *sel); -static void sp_gradient_selector_spread_changed (GtkComboBox *widget, SPGradientSelector *sel); +static void sp_gradient_selector_delete_vector_clicked (GtkWidget *w, SPGradientSelector *sel); + static GtkVBoxClass *parent_class; static guint signals[LAST_SIGNAL] = {0}; @@ -75,14 +86,11 @@ GType sp_gradient_selector_get_type(void) return type; } -static void -sp_gradient_selector_class_init (SPGradientSelectorClass *klass) +static void sp_gradient_selector_class_init(SPGradientSelectorClass *klass) { - GtkObjectClass *object_class; + GObjectClass *object_class = G_OBJECT_CLASS(klass); - object_class = (GtkObjectClass *) klass; - - parent_class = (GtkVBoxClass*)g_type_class_peek_parent (klass); + parent_class = GTK_VBOX_CLASS(g_type_class_peek_parent (klass)); signals[GRABBED] = g_signal_new ("grabbed", G_TYPE_FROM_CLASS(object_class), @@ -113,13 +121,15 @@ sp_gradient_selector_class_init (SPGradientSelectorClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - object_class->destroy = sp_gradient_selector_destroy; + object_class->dispose = sp_gradient_selector_dispose; } static void sp_gradient_selector_init(SPGradientSelector *sel) { sel->safelyInit = true; + sel->blocked = false; new (&sel->nonsolid) std::vector<GtkWidget*>(); + new (&sel->swatch_widgets) std::vector<GtkWidget*>(); sel->mode = SPGradientSelector::MODE_LINEAR; @@ -128,81 +138,118 @@ static void sp_gradient_selector_init(SPGradientSelector *sel) /* Vectors */ sel->vectors = sp_gradient_vector_selector_new (NULL, NULL); - gtk_widget_show (sel->vectors); - gtk_box_pack_start (GTK_BOX (sel), sel->vectors, FALSE, FALSE, 0); - g_signal_connect (G_OBJECT (sel->vectors), "vector_set", G_CALLBACK (sp_gradient_selector_vector_set), sel); + SPGradientVectorSelector *gvs = SP_GRADIENT_VECTOR_SELECTOR(sel->vectors); + sel->store = gvs->store; + sel->columns = gvs->columns; + + sel->treeview = Gtk::manage(new Gtk::TreeView()); + sel->treeview->set_model(gvs->store); + sel->treeview->set_headers_clickable (true); + sel->treeview->set_search_column(1); + sel->icon_renderer = Gtk::manage(new Gtk::CellRendererPixbuf()); + sel->text_renderer = Gtk::manage(new Gtk::CellRendererText()); + + sel->treeview->append_column(_("Gradient"), *sel->icon_renderer); + Gtk::TreeView::Column* icon_column = sel->treeview->get_column(0); + icon_column->add_attribute(sel->icon_renderer->property_pixbuf(), sel->columns->pixbuf); + icon_column->set_sort_column(sel->columns->color); + icon_column->set_clickable(true); + + sel->treeview->append_column(_("Name"), *sel->text_renderer); + Gtk::TreeView::Column* name_column = sel->treeview->get_column(1); + sel->text_renderer->property_editable() = true; + name_column->add_attribute(sel->text_renderer->property_text(), sel->columns->name); + name_column->set_min_width(180); + name_column->set_clickable(true); + name_column->set_resizable(true); + + sel->treeview->append_column("#", sel->columns->refcount); + Gtk::TreeView::Column* count_column = sel->treeview->get_column(2); + count_column->set_clickable(true); + count_column->set_resizable(true); + + sel->treeview->show(); + + icon_column->signal_clicked().connect( sigc::mem_fun(*sel, &SPGradientSelector::onTreeColorColClick) ); + name_column->signal_clicked().connect( sigc::mem_fun(*sel, &SPGradientSelector::onTreeNameColClick) ); + count_column->signal_clicked().connect( sigc::mem_fun(*sel, &SPGradientSelector::onTreeCountColClick) ); + + gvs->tree_select_connection = sel->treeview->get_selection()->signal_changed().connect( sigc::mem_fun(*sel, &SPGradientSelector::onTreeSelection) ); + sel->text_renderer->signal_edited().connect( sigc::mem_fun(*sel, &SPGradientSelector::onGradientRename) ); + + sel->scrolled_window = Gtk::manage(new Gtk::ScrolledWindow()); + sel->scrolled_window->add(*sel->treeview); + sel->scrolled_window->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + sel->scrolled_window->set_shadow_type(Gtk::SHADOW_IN); + sel->scrolled_window->set_size_request(0, 150); + sel->scrolled_window->show(); + + gtk_box_pack_start (GTK_BOX (sel), GTK_WIDGET(sel->scrolled_window->gobj()), TRUE, TRUE, 4); + /* Create box for buttons */ #if GTK_CHECK_VERSION(3,0,0) GtkWidget *hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_set_homogeneous(GTK_BOX(hb), FALSE); #else - GtkWidget *hb = gtk_hbox_new( FALSE, 0 ); + GtkWidget *hb = gtk_hbox_new( FALSE, 2 ); #endif - sel->nonsolid.push_back(hb); + //sel->nonsolid.push_back(hb); gtk_box_pack_start( GTK_BOX(sel), hb, FALSE, FALSE, 0 ); - sel->add = gtk_button_new_with_label (_("Duplicate")); +#if GTK_CHECK_VERSION(3,10,0) + sel->add = gtk_button_new_from_icon_name(INKSCAPE_ICON("list-add"), GTK_ICON_SIZE_SMALL_TOOLBAR); +#else + sel->add = gtk_button_new (); + GtkWidget *img = gtk_image_new_from_icon_name(INKSCAPE_ICON("list-add"), GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_button_set_image(GTK_BUTTON(sel->add), img); +#endif + sel->nonsolid.push_back(sel->add); - gtk_box_pack_start (GTK_BOX (hb), sel->add, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hb), sel->add, FALSE, FALSE, 0); + g_signal_connect (G_OBJECT (sel->add), "clicked", G_CALLBACK (sp_gradient_selector_add_vector_clicked), sel); gtk_widget_set_sensitive (sel->add, FALSE); + gtk_button_set_relief(GTK_BUTTON(sel->add), GTK_RELIEF_NONE); + gtk_widget_set_tooltip_text( sel->add, _("Create a duplicate gradient")); + + // FIXME: Probably better to either use something from the icon naming spec or ship our own "edit-gradient" icon +#if GTK_CHECK_VERSION(3,10,0) + sel->edit = gtk_button_new_from_icon_name(INKSCAPE_ICON("gtk-edit"), GTK_ICON_SIZE_SMALL_TOOLBAR); +#else + sel->edit = gtk_button_new (); + img = gtk_image_new_from_icon_name(INKSCAPE_ICON("gtk-edit"), GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_button_set_image(GTK_BUTTON(sel->edit), img); +#endif - sel->edit = gtk_button_new_with_label (_("Edit...")); sel->nonsolid.push_back(sel->edit); - gtk_box_pack_start (GTK_BOX (hb), sel->edit, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hb), sel->edit, FALSE, FALSE, 0); g_signal_connect (G_OBJECT (sel->edit), "clicked", G_CALLBACK (sp_gradient_selector_edit_vector_clicked), sel); gtk_widget_set_sensitive (sel->edit, FALSE); + gtk_button_set_relief(GTK_BUTTON(sel->edit), GTK_RELIEF_NONE); + gtk_widget_set_tooltip_text( sel->edit, _("Edit gradient")); - gtk_widget_show_all(hb); - - /* Spread selector */ -#if GTK_CHECK_VERSION(3,0,0) - hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_set_homogeneous(GTK_BOX(hb), FALSE); +#if GTK_CHECK_VERSION(3,10,0) + sel->del = gtk_button_new_from_icon_name(INKSCAPE_ICON("list-remove"), GTK_ICON_SIZE_SMALL_TOOLBAR); #else - hb = gtk_hbox_new( FALSE, 0 ); + sel->del = gtk_button_new (); + img = gtk_image_new_from_icon_name(INKSCAPE_ICON("list-remove"), GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_button_set_image(GTK_BUTTON(sel->del), img); #endif - sel->nonsolid.push_back(hb); - gtk_widget_show(hb); - gtk_box_pack_start( GTK_BOX(sel), hb, FALSE, FALSE, 0 ); -// The GtkComboBoxText API only appeared in Gtk 2.24 but Inkscape supports -// builds for Gtk >= 2.20. -// Older versions need to use now-deprecated parts of -// the GtkComboBox API instead. -#if GTK_CHECK_VERSION(2,24,0) - sel->spread = gtk_combo_box_text_new (); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (sel->spread), _("none")); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (sel->spread), _("reflected")); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (sel->spread), _("direct")); -#else - sel->spread = gtk_combo_box_new_text (); - gtk_combo_box_append_text (GTK_COMBO_BOX (sel->spread), _("none")); - gtk_combo_box_append_text (GTK_COMBO_BOX (sel->spread), _("reflected")); - gtk_combo_box_append_text (GTK_COMBO_BOX (sel->spread), _("direct")); -#endif + sel->swatch_widgets.push_back(sel->del); + gtk_box_pack_start (GTK_BOX (hb), sel->del, FALSE, FALSE, 0); + g_signal_connect (G_OBJECT (sel->del), "clicked", G_CALLBACK (sp_gradient_selector_delete_vector_clicked), sel); + gtk_widget_set_sensitive (sel->del, FALSE); + gtk_button_set_relief(GTK_BUTTON(sel->del), GTK_RELIEF_NONE); + gtk_widget_set_tooltip_text( sel->del, _("Delete swatch")); + + gtk_widget_show_all(hb); + - sel->nonsolid.push_back(sel->spread); - gtk_widget_show(sel->spread); - gtk_box_pack_end( GTK_BOX(hb), sel->spread, FALSE, FALSE, 0 ); - gtk_widget_set_tooltip_text( sel->spread, - // TRANSLATORS: for info, see http://www.w3.org/TR/2000/CR-SVG-20000802/pservers.html#LinearGradientSpreadMethodAttribute - _("Whether to fill with flat color beyond the ends of the gradient vector " - "(spreadMethod=\"pad\"), or repeat the gradient in the same direction " - "(spreadMethod=\"repeat\"), or repeat the gradient in alternating opposite " - "directions (spreadMethod=\"reflect\")")); - - g_signal_connect (G_OBJECT (sel->spread), "changed", - G_CALLBACK (sp_gradient_selector_spread_changed), sel); - - sel->spreadLbl = gtk_label_new( _("Repeat:") ); - sel->nonsolid.push_back(sel->spreadLbl); - gtk_widget_show( sel->spreadLbl ); - gtk_box_pack_end( GTK_BOX(hb), sel->spreadLbl, FALSE, FALSE, 4 ); } -static void sp_gradient_selector_destroy(GtkObject *object) +static void sp_gradient_selector_dispose(GObject *object) { SPGradientSelector *sel = SP_GRADIENT_SELECTOR( object ); @@ -210,21 +257,35 @@ static void sp_gradient_selector_destroy(GtkObject *object) sel->safelyInit = false; using std::vector; sel->nonsolid.~vector<GtkWidget*>(); + sel->swatch_widgets.~vector<GtkWidget*>(); + } + + if (sel->icon_renderer) { + delete sel->icon_renderer; + sel->icon_renderer = NULL; + } + if (sel->text_renderer) { + delete sel->text_renderer; + sel->text_renderer = NULL; } - if (((GtkObjectClass *) (parent_class))->destroy) { - (* ((GtkObjectClass *) (parent_class))->destroy) (object); + if ((G_OBJECT_CLASS(parent_class))->dispose) { + (* (G_OBJECT_CLASS(parent_class))->dispose) (object); } } -GtkWidget * -sp_gradient_selector_new (void) +void SPGradientSelector::setSpread(SPGradientSpread spread) { - SPGradientSelector *sel; + gradientSpread = spread; + //gtk_combo_box_set_active (GTK_COMBO_BOX(this->spread), gradientSpread); +} - sel = (SPGradientSelector*)g_object_new (SP_TYPE_GRADIENT_SELECTOR, NULL); - return (GtkWidget *) sel; +GtkWidget *sp_gradient_selector_new() +{ + SPGradientSelector *sel = SP_GRADIENT_SELECTOR(g_object_new (SP_TYPE_GRADIENT_SELECTOR, NULL)); + + return GTK_WIDGET(sel); } void SPGradientSelector::setMode(SelectorMode mode) @@ -236,9 +297,28 @@ void SPGradientSelector::setMode(SelectorMode mode) { gtk_widget_hide(*it); } + for (std::vector<GtkWidget*>::iterator it = swatch_widgets.begin(); it != swatch_widgets.end(); ++it) + { + gtk_widget_show_all(*it); + } + + Gtk::TreeView::Column* icon_column = treeview->get_column(0); + icon_column->set_title(_("Swatch")); SPGradientVectorSelector* vs = SP_GRADIENT_VECTOR_SELECTOR(vectors); vs->setSwatched(); + } else { + for (std::vector<GtkWidget*>::iterator it = nonsolid.begin(); it != nonsolid.end(); ++it) + { + gtk_widget_show_all(*it); + } + for (std::vector<GtkWidget*>::iterator it = swatch_widgets.begin(); it != swatch_widgets.end(); ++it) + { + gtk_widget_hide(*it); + } + Gtk::TreeView::Column* icon_column = treeview->get_column(0); + icon_column->set_title(_("Gradient")); + } } } @@ -248,12 +328,6 @@ void SPGradientSelector::setUnits(SPGradientUnits units) gradientUnits = units; } -void SPGradientSelector::setSpread(SPGradientSpread spread) -{ - gradientSpread = spread; - gtk_combo_box_set_active (GTK_COMBO_BOX(this->spread), gradientSpread); -} - SPGradientUnits SPGradientSelector::getUnits() { return gradientUnits; @@ -264,6 +338,105 @@ SPGradientSpread SPGradientSelector::getSpread() return gradientSpread; } +void SPGradientSelector::onGradientRename( const Glib::ustring& path_string, const Glib::ustring& new_text) +{ + Gtk::TreePath path(path_string); + Gtk::TreeModel::iterator iter = store->get_iter(path); + + if( iter ) + { + Gtk::TreeModel::Row row = *iter; + if ( row ) { + SPObject* obj = row[columns->data]; + if ( obj ) { + row[columns->name] = gr_prepare_label(obj); + if (!new_text.empty() && new_text != row[columns->name]) { + rename_id(obj, new_text ); + Inkscape::DocumentUndo::done(obj->document, SP_VERB_CONTEXT_GRADIENT, + _("Rename gradient")); + } + } + } + } +} + +void SPGradientSelector::onTreeColorColClick() { + Gtk::TreeView::Column* column = treeview->get_column(0); + column->set_sort_column(columns->color); +} + +void SPGradientSelector::onTreeNameColClick() { + Gtk::TreeView::Column* column = treeview->get_column(1); + column->set_sort_column(columns->name); +} + + +void SPGradientSelector::onTreeCountColClick() { + Gtk::TreeView::Column* column = treeview->get_column(2); + column->set_sort_column(columns->refcount); +} + + +void SPGradientSelector::onTreeSelection() +{ + if (!treeview) { + return; + } + + if (blocked) { + return; + } + + if (!treeview->has_focus()) { + /* Workaround for GTK bug on Windows/OS X + * When the treeview initially doesn't have focus and is clicked + * sometimes get_selection()->signal_changed() has the wrong selection + */ + treeview->grab_focus(); + } + + const Glib::RefPtr<Gtk::TreeSelection> sel = treeview->get_selection(); + if (!sel) { + return; + } + + SPGradient *obj = NULL; + /* Single selection */ + Gtk::TreeModel::iterator iter = sel->get_selected(); + if ( iter ) { + Gtk::TreeModel::Row row = *iter; + obj = row[columns->data]; + } + + if (obj) { + sp_gradient_selector_vector_set (NULL, SP_GRADIENT(obj), this); + } +} + +bool SPGradientSelector::_checkForSelected(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPGradient *vector) +{ + bool found = false; + + Gtk::TreeModel::Row row = *iter; + if ( vector == row[columns->data] ) + { + treeview->scroll_to_row(path, 0.5); + Glib::RefPtr<Gtk::TreeSelection> select = treeview->get_selection(); + bool wasBlocked = blocked; + blocked = true; + select->select(iter); + blocked = wasBlocked; + found = true; + } + + return found; +} + +void SPGradientSelector::selectGradientInTree(SPGradient *vector) +{ + store->foreach( sigc::bind<SPGradient*>(sigc::mem_fun(*this, &SPGradientSelector::_checkForSelected), vector) ); +} + void SPGradientSelector::setVector(SPDocument *doc, SPGradient *vector) { g_return_if_fail(!vector || SP_IS_GRADIENT(vector)); @@ -275,6 +448,8 @@ void SPGradientSelector::setVector(SPDocument *doc, SPGradient *vector) sp_gradient_vector_selector_set_gradient(SP_GRADIENT_VECTOR_SELECTOR(vectors), doc, vector); + selectGradientInTree(vector); + if (vector) { if ( (mode == MODE_SWATCH) && vector->isSwatch() ) { if ( vector->isSolid() ) { @@ -288,6 +463,17 @@ void SPGradientSelector::setVector(SPDocument *doc, SPGradient *vector) gtk_widget_show_all(*it); } } + } else if (mode != MODE_SWATCH) { + + for (std::vector<GtkWidget*>::iterator it = swatch_widgets.begin(); it != swatch_widgets.end(); ++it) + { + gtk_widget_hide(*it); + } + for (std::vector<GtkWidget*>::iterator it = nonsolid.begin(); it != nonsolid.end(); ++it) + { + gtk_widget_show_all(*it); + } + } if (edit) { @@ -296,6 +482,9 @@ void SPGradientSelector::setVector(SPDocument *doc, SPGradient *vector) if (add) { gtk_widget_set_sensitive(add, TRUE); } + if (del) { + gtk_widget_set_sensitive(del, TRUE); + } } else { if (edit) { gtk_widget_set_sensitive(edit, FALSE); @@ -303,6 +492,9 @@ void SPGradientSelector::setVector(SPDocument *doc, SPGradient *vector) if (add) { gtk_widget_set_sensitive(add, (doc != NULL)); } + if (del) { + gtk_widget_set_sensitive(del, FALSE); + } } } @@ -312,42 +504,72 @@ SPGradient *SPGradientSelector::getVector() return SP_GRADIENT_VECTOR_SELECTOR(vectors)->gr; } -static void -sp_gradient_selector_vector_set (SPGradientVectorSelector */*gvs*/, SPGradient *gr, SPGradientSelector *sel) + +static void sp_gradient_selector_vector_set(SPGradientVectorSelector * /*gvs*/, SPGradient *gr, SPGradientSelector *sel) { - static gboolean blocked = FALSE; - if (!blocked) { - blocked = TRUE; + if (!sel->blocked) { + sel->blocked = TRUE; gr = sp_gradient_ensure_vector_normalized (gr); sel->setVector((gr) ? gr->document : 0, gr); g_signal_emit (G_OBJECT (sel), signals[CHANGED], 0, gr); - blocked = FALSE; + sel->blocked = FALSE; } } + static void -sp_gradient_selector_edit_vector_clicked (GtkWidget */*w*/, SPGradientSelector *sel) +sp_gradient_selector_delete_vector_clicked (GtkWidget */*w*/, SPGradientSelector *sel) { - GtkWidget *dialog; + const Glib::RefPtr<Gtk::TreeSelection> selection = sel->treeview->get_selection(); + if (!selection) { + return; + } - /* fixme: */ - dialog = sp_gradient_vector_editor_new (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)->gr); + SPGradient *obj = NULL; + /* Single selection */ + Gtk::TreeModel::iterator iter = selection->get_selected(); + if ( iter ) { + Gtk::TreeModel::Row row = *iter; + obj = row[sel->columns->data]; + } + + if (obj) { + sp_gradient_unset_swatch(SP_ACTIVE_DESKTOP, obj->getId()); + } - gtk_widget_show (dialog); +} + +static void +sp_gradient_selector_edit_vector_clicked (GtkWidget */*w*/, SPGradientSelector *sel) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/dialogs/gradienteditor/showlegacy", false)) { + // Legacy gradient dialog + GtkWidget *dialog; + dialog = sp_gradient_vector_editor_new (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)->gr); + gtk_widget_show (dialog); + } else { + // Invoke the gradient tool + Inkscape::Verb *verb = Inkscape::Verb::get( SP_VERB_CONTEXT_GRADIENT ); + if ( verb ) { + SPAction *action = verb->get_action( Inkscape::ActionContext( ( Inkscape::UI::View::View * ) SP_ACTIVE_DESKTOP ) ); + if ( action ) { + sp_action_perform( action, NULL ); + } + } + } } static void sp_gradient_selector_add_vector_clicked (GtkWidget */*w*/, SPGradientSelector *sel) { - SPDocument *doc = sp_gradient_vector_selector_get_document ( - SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)); + SPDocument *doc = sp_gradient_vector_selector_get_document (SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)); if (!doc) return; - SPGradient *gr = sp_gradient_vector_selector_get_gradient( - SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)); + SPGradient *gr = sp_gradient_vector_selector_get_gradient( SP_GRADIENT_VECTOR_SELECTOR (sel->vectors)); Inkscape::XML::Document *xml_doc = doc->getReprDoc(); Inkscape::XML::Node *repr = NULL; @@ -370,18 +592,18 @@ sp_gradient_selector_add_vector_clicked (GtkWidget */*w*/, SPGradientSelector *s doc->getDefs()->getRepr()->addChild(repr, NULL); - gr = static_cast<SPGradient *>(doc->getObjectByRepr(repr)); - sp_gradient_vector_selector_set_gradient( - SP_GRADIENT_VECTOR_SELECTOR (sel->vectors), doc, gr); + Glib::ustring old_id = gr->getId(); - Inkscape::GC::release(repr); -} + gr = SP_GRADIENT(doc->getObjectByRepr(repr)); -static void -sp_gradient_selector_spread_changed (GtkComboBox *widget, SPGradientSelector *sel) -{ - sel->gradientSpread = (SPGradientSpread) gtk_combo_box_get_active (GTK_COMBO_BOX(widget)); - g_signal_emit (G_OBJECT (sel), signals[CHANGED], 0); + // Rename the new gradients id to be similar to the cloned gradients + rename_id(gr, old_id); + + sp_gradient_vector_selector_set_gradient( SP_GRADIENT_VECTOR_SELECTOR (sel->vectors), doc, gr); + + sel->selectGradientInTree(gr); + + Inkscape::GC::release(repr); } /* diff --git a/src/widgets/gradient-selector.h b/src/widgets/gradient-selector.h index d957f7baf..1f58de2e4 100644 --- a/src/widgets/gradient-selector.h +++ b/src/widgets/gradient-selector.h @@ -15,8 +15,24 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + #include <glib.h> #include <gtk/gtk.h> + +#include <gtkmm/entry.h> +#include <gtkmm/label.h> +#include <gtkmm/table.h> +#include <gtkmm/liststore.h> +#include <gtkmm/treeview.h> +#include <gtkmm/scrolledwindow.h> + #include <vector> #include "sp-gradient.h" #include "sp-gradient-spread.h" @@ -49,24 +65,63 @@ struct SPGradientSelector { /* Vector selector */ GtkWidget *vectors; + /* Tree */ + bool _checkForSelected(const Gtk::TreePath& path, const Gtk::TreeIter& iter, SPGradient *vector); + void onTreeSelection(); + void onGradientRename( const Glib::ustring& path_string, const Glib::ustring& new_text); + void onTreeNameColClick(); + void onTreeColorColClick(); + void onTreeCountColClick(); + + Gtk::TreeView *treeview; + Gtk::ScrolledWindow *scrolled_window; + class ModelColumns : public Gtk::TreeModel::ColumnRecord + { + public: + ModelColumns() + { + add(name); + add(refcount); + add(color); + add(data); + add(pixbuf); + } + virtual ~ModelColumns() {} + + Gtk::TreeModelColumn<Glib::ustring> name; + Gtk::TreeModelColumn<unsigned long> color; + Gtk::TreeModelColumn<gint> refcount; + Gtk::TreeModelColumn<SPGradient*> data; + Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > pixbuf; + + }; + + ModelColumns *columns; + Glib::RefPtr<Gtk::ListStore> store; + Gtk::CellRendererPixbuf* icon_renderer; + Gtk::CellRendererText* text_renderer; + /* Editing buttons */ GtkWidget *edit; GtkWidget *add; + GtkWidget *del; + GtkWidget *merge; /* Position widget */ GtkWidget *position; - /* Spread selector */ - GtkWidget *spread; - GtkWidget *spreadLbl; - bool safelyInit; + bool blocked; + std::vector<GtkWidget*> nonsolid; + std::vector<GtkWidget*> swatch_widgets; void setMode(SelectorMode mode); void setUnits(SPGradientUnits units); void setSpread(SPGradientSpread spread); void setVector(SPDocument *doc, SPGradient *vector); + void selectGradientInTree(SPGradient *vector); + SPGradientUnits getUnits(); SPGradientSpread getSpread(); SPGradient *getVector(); diff --git a/src/widgets/gradient-toolbar.cpp b/src/widgets/gradient-toolbar.cpp index 92ed82845..4fda44c8d 100644 --- a/src/widgets/gradient-toolbar.cpp +++ b/src/widgets/gradient-toolbar.cpp @@ -17,51 +17,37 @@ #endif #include "ui/widget/color-preview.h" -#include "verbs.h" - -#include "macros.h" -#include "widgets/button.h" -#include "widgets/widget-sizes.h" -#include "widgets/spw-utilities.h" -#include "widgets/spinbutton-events.h" -#include "widgets/gradient-vector.h" -#include "widgets/gradient-image.h" -#include "style.h" - -#include "preferences.h" -#include "document-private.h" -#include "document-undo.h" -#include "desktop.h" -#include "desktop-handles.h" #include <glibmm/i18n.h> - -#include "gradient-context.h" +#include "desktop-handles.h" +#include "desktop.h" +#include "document-undo.h" +#include "document.h" +#include "ege-adjustment-action.h" +#include "ege-select-one-action.h" +#include "gradient-chemistry.h" #include "gradient-drag.h" +#include "gradient-toolbar.h" +#include "ink-action.h" +#include "macros.h" +#include "preferences.h" +#include "selection.h" +#include "sp-defs.h" #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" -#include "gradient-chemistry.h" -#include "gradient-selector.h" -#include "selection.h" -#include "ui/icon-names.h" - -#include "../ege-adjustment-action.h" -#include "../ege-output-action.h" -#include "../ege-select-one-action.h" -#include "../ink-action.h" -#include "../ink-comboboxentry-action.h" - #include "sp-stop.h" -#include "svg/css-ostringstream.h" -#include "svg/svg-color.h" -#include "desktop-style.h" -#include "gradient-context.h" - +#include "style.h" #include "toolbox.h" +#include "ui/icon-names.h" +#include "ui/tools/gradient-tool.h" +#include "verbs.h" +#include "widgets/gradient-image.h" +#include "widgets/gradient-vector.h" using Inkscape::DocumentUndo; using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::Tools::ToolBase; -void gr_apply_gradient_to_item( SPItem *item, SPGradient *gr, SPGradientType new_type, guint new_fill, bool do_fill, bool do_stroke ); +void gr_apply_gradient_to_item( SPItem *item, SPGradient *gr, SPGradientType initialType, Inkscape::PaintTarget initialMode, Inkscape::PaintTarget mode ); void gr_apply_gradient(Inkscape::Selection *selection, GrDrag *drag, SPGradient *gr); gboolean gr_vector_list(GtkWidget *combo_box, SPDesktop *desktop, bool selection_empty, SPGradient *gr_selected, bool gr_multi); void gr_get_dt_selected_gradient(Inkscape::Selection *selection, SPGradient *&gr_selected); @@ -69,8 +55,8 @@ void gr_read_selection( Inkscape::Selection *selection, GrDrag *drag, SPGradient static gboolean update_stop_list( GtkWidget *stop_combo, SPGradient *gradient, SPStop *new_stop, GtkWidget *widget, bool gr_multi); static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradient *gradient); static void select_stop_in_list( GtkWidget *combo_box, SPGradient *gradient, SPStop *new_stop, GtkWidget *data, gboolean block); -static void select_stop_by_drag( GtkWidget *combo_box, SPGradient *gradient, SPEventContext *ev, GtkWidget *data); -static void select_drag_by_stop( GtkWidget *combo_box, SPGradient *gradient, SPEventContext *ev); +static void select_stop_by_drag( GtkWidget *combo_box, SPGradient *gradient, ToolBase *ev, GtkWidget *data); +static void select_drag_by_stop( GtkWidget *combo_box, SPGradient *gradient, ToolBase *ev); static SPGradient *gr_get_selected_gradient(GtkWidget *widget); static void gr_stop_set_offset(GtkComboBox *widget, GtkWidget *data); void add_toolbar_widget(GtkWidget *tbl, GtkWidget *widget); @@ -84,36 +70,24 @@ static gboolean blocked = FALSE; //## Gradient ## //######################## -void gr_apply_gradient_to_item( SPItem *item, SPGradient *gr, SPGradientType new_type, guint new_fill, bool do_fill, bool do_stroke ) +void gr_apply_gradient_to_item( SPItem *item, SPGradient *gr, SPGradientType initialType, Inkscape::PaintTarget initialMode, Inkscape::PaintTarget mode ) { SPStyle *style = item->style; - - if (do_fill) { - if (style && (style->fill.isPaintserver()) && - SP_IS_GRADIENT( item->style->getFillPaintServer() )) { - SPPaintServer *server = item->style->getFillPaintServer(); - if ( SP_IS_LINEARGRADIENT(server) ) { - sp_item_set_gradient(item, gr, SP_GRADIENT_TYPE_LINEAR, true); - } else if ( SP_IS_RADIALGRADIENT(server) ) { - sp_item_set_gradient(item, gr, SP_GRADIENT_TYPE_RADIAL, true); - } - } else if (new_fill) { - sp_item_set_gradient(item, gr, new_type, true); + bool isFill = (mode == Inkscape::FOR_FILL); + if (style + && (isFill ? style->fill.isPaintserver() : style->stroke.isPaintserver()) + //&& SP_IS_GRADIENT(isFill ? style->getFillPaintServer() : style->getStrokePaintServer()) ) { + && (isFill ? SP_IS_GRADIENT(style->getFillPaintServer()) : SP_IS_GRADIENT(style->getStrokePaintServer())) ) { + SPPaintServer *server = isFill ? style->getFillPaintServer() : style->getStrokePaintServer(); + if ( SP_IS_LINEARGRADIENT(server) ) { + sp_item_set_gradient(item, gr, SP_GRADIENT_TYPE_LINEAR, mode); + } else if ( SP_IS_RADIALGRADIENT(server) ) { + sp_item_set_gradient(item, gr, SP_GRADIENT_TYPE_RADIAL, mode); } } - - if (do_stroke) { - if (style && (style->stroke.isPaintserver()) && - SP_IS_GRADIENT( item->style->getStrokePaintServer() )) { - SPPaintServer *server = item->style->getStrokePaintServer(); - if ( SP_IS_LINEARGRADIENT(server) ) { - sp_item_set_gradient(item, gr, SP_GRADIENT_TYPE_LINEAR, false); - } else if ( SP_IS_RADIALGRADIENT(server) ) { - sp_item_set_gradient(item, gr, SP_GRADIENT_TYPE_RADIAL, false); - } - } else if (!new_fill) { - sp_item_set_gradient(item, gr, new_type, false); - } + else if (initialMode == mode) + { + sp_item_set_gradient(item, gr, initialType, mode); } } @@ -126,8 +100,8 @@ gradient. void gr_apply_gradient(Inkscape::Selection *selection, GrDrag *drag, SPGradient *gr) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - SPGradientType new_type = static_cast<SPGradientType>(prefs->getInt("/tools/gradient/newgradient", SP_GRADIENT_TYPE_LINEAR)); - guint new_fill = prefs->getBool("/tools/gradient/newfillorstroke", true); + SPGradientType initialType = static_cast<SPGradientType>(prefs->getInt("/tools/gradient/newgradient", SP_GRADIENT_TYPE_LINEAR)); + Inkscape::PaintTarget initialMode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; // GRADIENTFIXME: make this work for multiple selected draggers. @@ -135,15 +109,15 @@ void gr_apply_gradient(Inkscape::Selection *selection, GrDrag *drag, SPGradient if (drag && drag->selected) { GrDragger *dragger = static_cast<GrDragger*>(drag->selected->data); for (GSList const* i = dragger->draggables; i != NULL; i = i->next) { // for all draggables of dragger - GrDraggable *draggable = (GrDraggable *) i->data; - gr_apply_gradient_to_item(draggable->item, gr, new_type, new_fill, draggable->fill_or_stroke, !draggable->fill_or_stroke); + GrDraggable *draggable = static_cast<GrDraggable*>(i->data); + gr_apply_gradient_to_item(draggable->item, gr, initialType, initialMode, draggable->fill_or_stroke); } return; } // If no drag or no dragger selected, act on selection for (GSList const* i = selection->itemList(); i != NULL; i = i->next) { - gr_apply_gradient_to_item(SP_ITEM(i->data), gr, new_type, new_fill, new_fill, !new_fill); + gr_apply_gradient_to_item(SP_ITEM(i->data), gr, initialType, initialMode, initialMode); } } @@ -207,11 +181,10 @@ gboolean gr_vector_list(GtkWidget *combo_box, SPDesktop *desktop, bool selection SPGradient *gradient = SP_GRADIENT(gl->data); gl = g_slist_remove(gl, gradient); - gchar *label = gr_prepare_label(gradient); + Glib::ustring label = gr_prepare_label(gradient); GdkPixbuf *pixb = sp_gradient_to_pixbuf(gradient, 64, 16); gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, 0, label, 1, pixb, 2, gradient, -1); - g_free(label); + gtk_list_store_set(store, &iter, 0, label.c_str(), 1, pixb, 2, gradient, -1); if (gradient == gr_selected) { pos = idx; @@ -298,7 +271,7 @@ void gr_read_selection( Inkscape::Selection *selection, } } if (spread != spr_selected) { - if (spr_selected != INT_MAX) { + if (spr_selected != SP_GRADIENT_SPREAD_UNDEFINED) { spr_multi = true; } else { spr_selected = spread; @@ -331,7 +304,7 @@ void gr_read_selection( Inkscape::Selection *selection, } } if (spread != spr_selected) { - if (spr_selected != INT_MAX) { + if (spr_selected != SP_GRADIENT_SPREAD_UNDEFINED) { spr_multi = true; } else { spr_selected = spread; @@ -357,7 +330,7 @@ void gr_read_selection( Inkscape::Selection *selection, } } if (spread != spr_selected) { - if (spr_selected != INT_MAX) { + if (spr_selected != SP_GRADIENT_SPREAD_UNDEFINED) { spr_multi = true; } else { spr_selected = spread; @@ -385,14 +358,14 @@ static void gr_tb_selection_changed(Inkscape::Selection * /*selection*/, gpointe Inkscape::Selection *selection = sp_desktop_selection(desktop); // take from desktop, not from args if (selection) { - SPEventContext *ev = sp_desktop_event_context(desktop); + ToolBase *ev = desktop->getEventContext(); GrDrag *drag = NULL; if (ev) { drag = ev->get_drag(); } SPGradient *gr_selected = 0; - SPGradientSpread spr_selected = static_cast<SPGradientSpread>(INT_MAX); // meaning undefined + SPGradientSpread spr_selected = SP_GRADIENT_SPREAD_UNDEFINED; bool gr_multi = false; bool spr_multi = false; @@ -597,8 +570,8 @@ static void gr_add_stop(GtkWidget * /*button*/, GtkWidget *vb) return; } - SPEventContext *ev = sp_desktop_event_context(desktop); - SPGradientContext *rc = SP_GRADIENT_CONTEXT(ev); + ToolBase *ev = desktop->getEventContext(); + Inkscape::UI::Tools::GradientTool *rc = SP_GRADIENT_CONTEXT(ev); if (rc) { sp_gradient_context_add_stops_between_selected_stops(rc); @@ -619,7 +592,7 @@ static void gr_remove_stop(GtkWidget * /*button*/, GtkWidget *vb) return; } - SPEventContext *ev = sp_desktop_event_context(desktop); + ToolBase *ev = desktop->getEventContext(); GrDrag *drag = NULL; if (ev) { drag = ev->get_drag(); @@ -647,33 +620,13 @@ static void gr_linked_changed(GtkToggleAction *act, gpointer /*data*/) static void gr_reverse(GtkWidget * /*button*/, gpointer data) { SPDesktop *desktop = static_cast<SPDesktop *>(data); - Inkscape::Selection *selection = sp_desktop_selection(desktop); - SPEventContext *ev = sp_desktop_event_context(desktop); - - if (!ev) { - return; - } - - GrDrag *drag = ev->get_drag(); - - // First try selected dragger - if (drag && drag->selected) { - drag->selected_reverse_vector(); - } else { // If no drag or no dragger selected, act on selection (both fill and stroke gradients) - for (GSList const* i = selection->itemList(); i != NULL; i = i->next) { - sp_item_gradient_reverse_vector(SP_ITEM(i->data), true); - sp_item_gradient_reverse_vector(SP_ITEM(i->data), false); - } - } - // we did an undoable action - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_GRADIENT, - _("Invert gradient")); + sp_gradient_reverse_selected_gradients(desktop); } /* * Change desktop drag selection to this stop */ -static void select_drag_by_stop( GtkWidget *data, SPGradient *gradient, SPEventContext *ev) +static void select_drag_by_stop( GtkWidget *data, SPGradient *gradient, ToolBase *ev) { if (blocked || !ev || !gradient) return; @@ -685,25 +638,11 @@ static void select_drag_by_stop( GtkWidget *data, SPGradient *gradient, SPEventC SPStop *stop = get_selected_stop(data); - - SPStop *stop_iter; - GList *i; - - // Walk thru the draggers and the gradient stops at the same time - for (i = drag->draggers, stop_iter = gradient->getFirstStop(); - i != NULL && stop_iter && SP_IS_STOP(stop_iter); - i = i->next, stop_iter = SP_STOP(stop_iter->getNext())) { - - if (stop == stop_iter) { - GrDragger *d = (GrDragger *) i->data; - drag->setSelected(d, false, true); - blocked = FALSE; - return; - } - } + drag->selectByStop(stop, false, true); + blocked = FALSE; } -static void select_stop_by_drag(GtkWidget *combo_box, SPGradient *gradient, SPEventContext *ev, GtkWidget *data) +static void select_stop_by_drag(GtkWidget *combo_box, SPGradient *gradient, ToolBase *ev, GtkWidget *data) { if (blocked || !ev || !gradient) return; @@ -722,10 +661,10 @@ static void select_stop_by_drag(GtkWidget *combo_box, SPGradient *gradient, SPEv // for all selected draggers for (GList *i = drag->selected; i != NULL; i = i->next) { - GrDragger *dragger = (GrDragger *) i->data; + GrDragger *dragger = static_cast<GrDragger*>(i->data); // for all draggables of dragger for (GSList const* j = dragger->draggables; j != NULL; j = j->next) { - GrDraggable *draggable = (GrDraggable *) j->data; + GrDraggable *draggable = static_cast<GrDraggable*>(j->data); if (draggable->point_type != POINT_RG_FOCUS) { n++; @@ -846,11 +785,12 @@ static gboolean update_stop_list( GtkWidget *stop_combo, SPGradient *gradient, S if (SP_IS_STOP(sl->data)){ SPStop *stop = SP_STOP(sl->data); Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(sl->data)->getRepr(); - Inkscape::UI::Widget::ColorPreview *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(sp_stop_get_rgba32(stop))); + Inkscape::UI::Widget::ColorPreview *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(stop->get_rgba32())); GdkPixbuf *pb = cpv->toPixbuf(32, 16); + Glib::ustring label = gr_ellipsize_text(repr->attribute("id"), 25); gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, 0, repr->attribute("id"), 1, pb, 2, stop, -1); + gtk_list_store_set(store, &iter, 0, label.c_str(), 1, pb, 2, stop, -1); sensitive = FALSE; } } @@ -958,14 +898,14 @@ static void gr_new_type_changed( EgeSelectOneAction *act, GObject * /*tbl*/ ) static void gr_new_fillstroke_changed( EgeSelectOneAction *act, GObject * /*tbl*/ ) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool fillmode = ege_select_one_action_get_active( act ) == 0; - prefs->setBool("/tools/gradient/newfillorstroke", fillmode); + Inkscape::PaintTarget fsmode = (ege_select_one_action_get_active( act ) == 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; + prefs->setInt("/tools/gradient/newfillorstroke", (fsmode == Inkscape::FOR_FILL) ? 1 : 0); } /* * User selected a gradient from the combobox */ -void gr_gradient_combo_changed(EgeSelectOneAction *act, gpointer data) +static void gr_gradient_combo_changed(EgeSelectOneAction *act, gpointer data) { if (blocked) { return; @@ -984,7 +924,7 @@ void gr_gradient_combo_changed(EgeSelectOneAction *act, gpointer data) SPDesktop *desktop = static_cast<SPDesktop *>(data); Inkscape::Selection *selection = sp_desktop_selection(desktop); - SPEventContext *ev = sp_desktop_event_context(desktop); + ToolBase *ev = desktop->getEventContext(); gr_apply_gradient(selection, ev? ev->get_drag() : NULL, gr); @@ -994,7 +934,7 @@ void gr_gradient_combo_changed(EgeSelectOneAction *act, gpointer data) } -void gr_spread_change(EgeSelectOneAction *act, GtkWidget *widget) +static void gr_spread_change(EgeSelectOneAction *act, GtkWidget *widget) { if (blocked) { return; @@ -1026,7 +966,7 @@ static void gr_stop_combo_changed(GtkComboBox * /*widget*/, GtkWidget *data) } SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(G_OBJECT(data), "desktop")); - SPEventContext *ev = sp_desktop_event_context(desktop); + ToolBase *ev = desktop->getEventContext(); SPGradient *gr = gr_get_selected_gradient(data); select_drag_by_stop(data, gr, ev); @@ -1140,10 +1080,9 @@ void sp_gradient_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, ege_select_one_action_set_icon_column( act, 2 ); ege_select_one_action_set_tooltip_column( act, 1 ); - /// @todo Convert to boolean? Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool fillstrokemode = !prefs->getBool("/tools/gradient/newfillorstroke", true); - ege_select_one_action_set_active( act, fillstrokemode ); + Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; + ege_select_one_action_set_active( act, (fsmode == Inkscape::FOR_FILL) ? 0 : 1 ); g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(gr_new_fillstroke_changed), holder ); } @@ -1156,7 +1095,7 @@ void sp_gradient_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, _("No gradient"), 1, NULL, 2, NULL, -1); - EgeSelectOneAction* act1 = ege_select_one_action_new( "GradientSelectGradientAction", _("Select"), ("Choose a gradient"), NULL, GTK_TREE_MODEL(store) ); + EgeSelectOneAction* act1 = ege_select_one_action_new( "GradientSelectGradientAction", _("Select"), (_("Choose a gradient")), NULL, GTK_TREE_MODEL(store) ); g_object_set( act1, "short_label", _("Select:"), NULL ); ege_select_one_action_set_appearance( act1, "compact" ); gtk_action_set_sensitive( GTK_ACTION(act1), FALSE ); @@ -1172,13 +1111,13 @@ void sp_gradient_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GtkTreeIter iter; gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("none"), 1, SP_GRADIENT_SPREAD_PAD, -1 ); + gtk_list_store_set( model, &iter, 0, _("None"), 1, SP_GRADIENT_SPREAD_PAD, -1 ); gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("reflected"), 1, SP_GRADIENT_SPREAD_REFLECT, -1 ); + gtk_list_store_set( model, &iter, 0, _("Reflected"), 1, SP_GRADIENT_SPREAD_REFLECT, -1 ); gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("direct"), 1, SP_GRADIENT_SPREAD_REPEAT, -1 ); + gtk_list_store_set( model, &iter, 0, _("Direct"), 1, SP_GRADIENT_SPREAD_REPEAT, -1 ); EgeSelectOneAction* act1 = ege_select_one_action_new( "GradientSelectRepeatAction", _("Repeat"), (// TRANSLATORS: for info, see http://www.w3.org/TR/2000/CR-SVG-20000802/pservers.html#LinearGradientSpreadMethodAttribute @@ -1201,10 +1140,10 @@ void sp_gradient_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GtkTreeIter iter; gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, 0, _("No gradient"), 1, NULL, 2, NULL, -1); + gtk_list_store_set(store, &iter, 0, _("No stops"), 1, NULL, 2, NULL, -1); EgeSelectOneAction* act1 = ege_select_one_action_new( "GradientEditStopsAction", _("Stops"), _("Select a stop for the current gradient"), NULL, GTK_TREE_MODEL(store) ); - g_object_set( act1, "short_label", _("Edit:"), NULL ); + g_object_set( act1, "short_label", _("Stops:"), NULL ); ege_select_one_action_set_appearance( act1, "compact" ); gtk_action_set_sensitive( GTK_ACTION(act1), FALSE ); g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(gr_stop_combo_changed), holder ); @@ -1216,13 +1155,14 @@ void sp_gradient_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, { EgeAdjustmentAction* eact = 0; eact = create_adjustment_action( "GradientEditOffsetAction", - _("Offset"), _("Offset:"), _("Offset of selected stop"), + _("Offset"), C_("Gradient", "Offset:"), _("Offset of selected stop"), "/tools/gradient/stopoffset", 0, - GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, 0.0, 1.0, 0.01, 0.1, 0, 0, 0, - gr_stop_offset_adjustment_changed - , 0.01, 2, 1.0); + gr_stop_offset_adjustment_changed, + NULL /*unit tracker*/, + 0.01, 2, 1.0); gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); g_object_set_data( holder, "offset_action", eact ); @@ -1279,7 +1219,7 @@ void sp_gradient_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, _("Link gradients"), _("Link gradients to change all related gradients"), INKSCAPE_ICON("object-unlocked"), - secondarySize ); + Inkscape::ICON_SIZE_DECORATION ); g_object_set( itact, "short_label", "Lock", NULL ); g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(gr_linked_changed), desktop) ; gtk_action_group_add_action( mainActions, GTK_ACTION(itact) ); diff --git a/src/widgets/gradient-toolbar.h b/src/widgets/gradient-toolbar.h index 938f45dc6..38afb743b 100644 --- a/src/widgets/gradient-toolbar.h +++ b/src/widgets/gradient-toolbar.h @@ -12,9 +12,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <gtk/gtk.h> -struct SPDesktop; +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; void sp_gradient_toolbox_prep(SPDesktop * /*desktop*/, GtkActionGroup* mainActions, GObject* holder); -#endif /* !SEEN_SELECT_TOOLBAR_H */ +#endif /* !SEEN_GRADIENT_TOOLBAR_H */ diff --git a/src/widgets/gradient-vector.cpp b/src/widgets/gradient-vector.cpp index 8348f7045..17ac887c4 100644 --- a/src/widgets/gradient-vector.cpp +++ b/src/widgets/gradient-vector.cpp @@ -22,19 +22,20 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif -#ifdef HAVE_STRING_H -#endif -#include "ui/widget/color-preview.h" + #include "gradient-vector.h" +#include "ui/widget/color-preview.h" #include "verbs.h" #include <gtk/gtk.h> #include "macros.h" #include <glibmm/i18n.h> +#include <set> #include "../widgets/gradient-image.h" #include "../inkscape.h" #include "../document-private.h" #include "../gradient-chemistry.h" #include "../helper/window.h" +#include "io/resource.h" #include "xml/repr.h" @@ -42,6 +43,12 @@ #include "../preferences.h" #include "svg/css-ostringstream.h" #include "sp-stop.h" +#include "selection-chemistry.h" +#include "style.h" +#include "sp-linear-gradient.h" +#include "sp-radial-gradient.h" +#include "desktop.h" +#include "layer-manager.h" #include <sigc++/functors/ptr_fun.h> #include <sigc++/adaptors/bind.h> @@ -56,15 +63,21 @@ enum { static void sp_gradient_vector_selector_class_init(SPGradientVectorSelectorClass *klass); static void sp_gradient_vector_selector_init(SPGradientVectorSelector *gvs); + +#if GTK_CHECK_VERSION(3,0,0) +static void sp_gradient_vector_selector_destroy(GtkWidget *object); +#else static void sp_gradient_vector_selector_destroy(GtkObject *object); +#endif static void sp_gvs_gradient_release(SPObject *obj, SPGradientVectorSelector *gvs); static void sp_gvs_defs_release(SPObject *defs, SPGradientVectorSelector *gvs); static void sp_gvs_defs_modified(SPObject *defs, guint flags, SPGradientVectorSelector *gvs); static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs); -static void gr_combo_box_changed (GtkComboBox *widget, SPGradientVectorSelector *gvs); static SPStop *get_selected_stop( GtkWidget *vb); +void gr_get_usage_counts(SPDocument *doc, std::map<SPGradient *, gint> *mapUsageCount ); +unsigned long sp_gradient_to_hhssll(SPGradient *gr); static GtkVBoxClass *parent_class; static guint signals[LAST_SIGNAL] = {0}; @@ -102,22 +115,25 @@ GType sp_gradient_vector_selector_get_type(void) static void sp_gradient_vector_selector_class_init(SPGradientVectorSelectorClass *klass) { - GtkObjectClass *object_class; - - object_class = GTK_OBJECT_CLASS(klass); - + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); parent_class = static_cast<GtkVBoxClass*>(g_type_class_peek_parent(klass)); signals[VECTOR_SET] = g_signal_new( "vector_set", - G_TYPE_FROM_CLASS(object_class), - G_SIGNAL_RUN_LAST, + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(SPGradientVectorSelectorClass, vector_set), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); +#if GTK_CHECK_VERSION(3,0,0) + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + widget_class->destroy = sp_gradient_vector_selector_destroy; +#else + GtkObjectClass *object_class = GTK_OBJECT_CLASS(klass); object_class->destroy = sp_gradient_vector_selector_destroy; +#endif } static void sp_gradient_vector_selector_init(SPGradientVectorSelector *gvs) @@ -133,31 +149,23 @@ static void sp_gradient_vector_selector_init(SPGradientVectorSelector *gvs) new (&gvs->defs_release_connection) sigc::connection(); new (&gvs->defs_modified_connection) sigc::connection(); - gvs->store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER); - gvs->combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (gvs->store)); - gvs->combo_connection = g_signal_connect (G_OBJECT (gvs->combo_box), "changed", G_CALLBACK (gr_combo_box_changed), gvs); - - GtkCellRenderer *renderer = gtk_cell_renderer_pixbuf_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (gvs->combo_box), renderer, FALSE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (gvs->combo_box), renderer, "pixbuf", 0, NULL); - gtk_cell_renderer_set_padding(renderer, 5, 0); - - renderer = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (gvs->combo_box), renderer, TRUE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (gvs->combo_box), renderer, "text", 1, NULL); - gtk_cell_renderer_set_padding(renderer, 0, 0); - - gtk_widget_show(gvs->combo_box); - gtk_box_pack_start(GTK_BOX(gvs), gvs->combo_box, TRUE, TRUE, 0); + gvs->columns = new SPGradientSelector::ModelColumns(); + gvs->store = Gtk::ListStore::create(*gvs->columns); + new (&gvs->tree_select_connection) sigc::connection(); } +#if GTK_CHECK_VERSION(3,0,0) +static void sp_gradient_vector_selector_destroy(GtkWidget *object) +#else static void sp_gradient_vector_selector_destroy(GtkObject *object) +#endif { SPGradientVectorSelector *gvs = SP_GRADIENT_VECTOR_SELECTOR(object); if (gvs->gr) { gvs->gradient_release_connection.disconnect(); + gvs->tree_select_connection.disconnect(); gvs->gr = NULL; } @@ -170,10 +178,17 @@ static void sp_gradient_vector_selector_destroy(GtkObject *object) gvs->gradient_release_connection.~connection(); gvs->defs_release_connection.~connection(); gvs->defs_modified_connection.~connection(); + gvs->tree_select_connection.~connection(); +#if GTK_CHECK_VERSION(3,0,0) + if ((reinterpret_cast<GtkWidgetClass *>(parent_class))->destroy) { + (* (reinterpret_cast<GtkWidgetClass *>(parent_class))->destroy) (object); + } +#else if ((reinterpret_cast<GtkObjectClass *>(parent_class))->destroy) { (* (reinterpret_cast<GtkObjectClass *>(parent_class))->destroy) (object); } +#endif } GtkWidget *sp_gradient_vector_selector_new(SPDocument *doc, SPGradient *gr) @@ -261,19 +276,39 @@ SPGradient *sp_gradient_vector_selector_get_gradient(SPGradientVectorSelector *g return gvs->gr; } -gchar *gr_prepare_label (SPObject *obj) +Glib::ustring gr_prepare_label (SPObject *obj) { - const gchar *id = obj->defaultLabel(); - if (strlen(id) > 15 && (!strncmp (id, "#linearGradient", 15) || !strncmp (id, "#radialGradient", 15))) - return g_strdup_printf ("#%s", id+15); - return g_strdup_printf ("%s", id); + const gchar *id = obj->label() ? obj->label() : obj->getId(); + if (!id) { + id = obj->getRepr()->name(); + } + + if (strlen(id) > 14 && (!strncmp (id, "linearGradient", 14) || !strncmp (id, "radialGradient", 14))) + return gr_ellipsize_text (g_strdup_printf ("%s", id+14), 35); + return gr_ellipsize_text (id, 35); +} + +/* + * Ellipse text if longer than maxlen, "50% start text + ... + ~50% end text" + * Text should be > length 8 or just return the original text + */ +Glib::ustring gr_ellipsize_text(Glib::ustring const &src, size_t maxlen) +{ + if (src.length() > maxlen && maxlen > 8) { + size_t p1 = (size_t) maxlen / 2; + size_t p2 = (size_t) src.length() - (maxlen - p1 - 1); + return src.substr(0, p1) + "…" + src.substr(p2); + } + return src; } static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs) { + + gvs->tree_select_connection.block(); + /* Clear old list, if there is any */ - gtk_list_store_clear(gvs->store); - GtkTreeIter iter; + gvs->store->clear(); /* Pick up all gradients with vectors */ GSList *gl = NULL; @@ -288,103 +323,126 @@ static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs) } gl = g_slist_reverse(gl); - gint pos = 0; + /* Get usage count of all the gradients */ + std::map<SPGradient *, gint> usageCount; + gr_get_usage_counts(gvs->doc, &usageCount); if (!gvs->doc) { - gtk_list_store_append (gvs->store, &iter); - gtk_list_store_set (gvs->store, &iter, 0, NULL, 1, _("No document selected"), 2, NULL, -1); - gtk_widget_set_sensitive (gvs->combo_box, FALSE); + Gtk::TreeModel::Row row = *(gvs->store->append()); + row[gvs->columns->name] = _("No document selected"); } else if (!gl) { - gtk_list_store_append (gvs->store, &iter); - gtk_list_store_set (gvs->store, &iter, 0, NULL, 1, _("No gradients in document"), 2, NULL, -1); - gtk_widget_set_sensitive (gvs->combo_box, FALSE); + Gtk::TreeModel::Row row = *(gvs->store->append()); + row[gvs->columns->name] = _("No gradients in document"); } else if (!gvs->gr) { - gtk_list_store_append (gvs->store, &iter); - gtk_list_store_set (gvs->store, &iter, 0, NULL, 1, _("No gradient selected"), 2, NULL, -1); - gtk_widget_set_sensitive (gvs->combo_box, FALSE); + Gtk::TreeModel::Row row = *(gvs->store->append()); + row[gvs->columns->name] = _("No gradient selected"); } else { - gint idx = 0; while (gl) { SPGradient *gr; gr = SP_GRADIENT(gl->data); gl = g_slist_remove(gl, gr); - /* We have to know: */ - /* Gradient destroy */ - /* Gradient name change */ - - gchar *label = gr_prepare_label(gr); + unsigned long hhssll = sp_gradient_to_hhssll(gr); GdkPixbuf *pixb = sp_gradient_to_pixbuf (gr, 64, 18); - gtk_list_store_append (gvs->store, &iter); - gtk_list_store_set (gvs->store, &iter, 0, pixb, 1, label, 2, gr, -1); - g_free (label); + Glib::ustring label = gr_prepare_label(gr); + + Gtk::TreeModel::Row row = *(gvs->store->append()); + row[gvs->columns->name] = label.c_str(); + row[gvs->columns->color] = hhssll; + row[gvs->columns->refcount] = usageCount[gr]; + row[gvs->columns->data] = gr; + row[gvs->columns->pixbuf] = Glib::wrap(pixb); - if (gr == gvs->gr) { - pos = idx; - } - idx += 1; } - gtk_widget_set_sensitive (gvs->combo_box, TRUE); } - /* Block signal to prevent recursive loop */ - g_signal_handler_block(G_OBJECT (gvs->combo_box), gvs->combo_connection); + gvs->tree_select_connection.unblock(); - /* Set selected */ - gtk_combo_box_set_active (GTK_COMBO_BOX(gvs->combo_box) , pos); - - g_signal_handler_unblock(G_OBJECT (gvs->combo_box), gvs->combo_connection); } -static void gr_combo_box_changed (GtkComboBox *widget, SPGradientVectorSelector *gvs) +/* + * Return a "HHSSLL" version of the first stop color so we can sort by it + */ +unsigned long sp_gradient_to_hhssll(SPGradient *gr) { - GtkTreeIter iter; - if (!gtk_combo_box_get_active_iter (widget, &iter)) { - return; - } + SPStop *stop = gr->getFirstStop(); + unsigned long rgba = stop->get_rgba32(); + float hsl[3]; + sp_color_rgb_to_hsl_floatv (hsl, SP_RGBA32_R_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_B_F(rgba)); - SPGradient *gr = NULL; - gtk_tree_model_get (GTK_TREE_MODEL(gvs->store), &iter, 2, &gr, -1); - - if (gr) { + return ((int)(hsl[0]*100 * 10000)) + ((int)(hsl[1]*100 * 100)) + ((int)(hsl[2]*100 * 1)); +} - SPGradient *norm = sp_gradient_ensure_vector_normalized(gr); - if (norm != gr) { - //g_print("SPGradientVectorSelector: become %s after normalization\n", norm->getId()); - /* But be careful that we do not have gradient saved anywhere else */ - //g_object_set_data(G_OBJECT(mi), "gradient", norm); - gtk_list_store_set (gvs->store, &iter, 2, norm, -1); +static GSList *get_all_doc_items(GSList *list, SPObject *from, bool onlyvisible, bool onlysensitive, bool ingroups, GSList const *exclude) +{ + for ( SPObject *child = from->firstChild() ; child; child = child->getNext() ) { + if (SP_IS_ITEM(child)) { + list = g_slist_prepend(list, SP_ITEM(child)); } - /* fixme: Really we would want to use _set_vector */ - /* Detach old */ - if (gvs->gr) { - gvs->gradient_release_connection.disconnect(); - gvs->gr = NULL; - } - /* Attach new */ - if (norm) { - gvs->gradient_release_connection = norm->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_gvs_gradient_release), gvs)); - gvs->gr = norm; + if (ingroups || SP_IS_ITEM(child)) { + list = get_all_doc_items(list, child, onlyvisible, onlysensitive, ingroups, exclude); } + } + + return list; +} + +/* + * Return a SPItem's gradient + */ +static SPGradient * gr_item_get_gradient(SPItem *item, gboolean fillorstroke) +{ + SPIPaint *item_paint = (fillorstroke) ? &(item->style->fill) : &(item->style->stroke); + if (item_paint->isPaintserver()) { - g_signal_emit(G_OBJECT(gvs), signals[VECTOR_SET], 0, norm); + SPPaintServer *item_server = (fillorstroke) ? + item->style->getFillPaintServer() : item->style->getStrokePaintServer(); - if (norm != gr) { - /* We do extra undo push here */ - /* If handler has already done it, it is just NOP */ - // FIXME: looks like this is never a valid undo step, consider removing this - DocumentUndo::done(norm->document, SP_VERB_CONTEXT_GRADIENT, - /* TODO: annotate */ "gradient-vector.cpp:350"); + if (SP_IS_LINEARGRADIENT(item_server) || SP_IS_RADIALGRADIENT(item_server) || + (SP_IS_GRADIENT(item_server) && SP_GRADIENT(item_server)->getVector()->isSwatch())) { + + return SP_GRADIENT(item_server)->getVector(); } + } + return NULL; +} +/* + * Map each gradient to its usage count for both fill and stroke styles + */ +void gr_get_usage_counts(SPDocument *doc, std::map<SPGradient *, gint> *mapUsageCount ) +{ + if (!doc) + return; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); + bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true); + bool ingroups = TRUE; + + GSList *all_list = get_all_doc_items(NULL, doc->getRoot(), onlyvisible, onlysensitive, ingroups, NULL); + + for (GSList *i = all_list; i != NULL; i = i->next) { + SPItem *item = SP_ITEM(i->data); + if (!item->getId()) + continue; + SPGradient *gr = NULL; + gr = gr_item_get_gradient(item, true); // fill + if (gr) { + mapUsageCount->count(gr) > 0 ? (*mapUsageCount)[gr] += 1 : (*mapUsageCount)[gr] = 1; + } + gr = gr_item_get_gradient(item, false); // stroke + if (gr) { + mapUsageCount->count(gr) > 0 ? (*mapUsageCount)[gr] += 1 : (*mapUsageCount)[gr] = 1; + } } } + static void sp_gvs_gradient_release(SPObject */*obj*/, SPGradientVectorSelector *gvs) { /* Disconnect gradient */ @@ -417,7 +475,6 @@ static void sp_gvs_defs_release(SPObject */*defs*/, SPGradientVectorSelector *gv static void sp_gvs_defs_modified(SPObject */*defs*/, guint /*flags*/, SPGradientVectorSelector *gvs) { /* fixme: We probably have to check some flags here (Lauris) */ - sp_gvs_rebuild_gui_full(gvs); } @@ -443,13 +500,19 @@ static GtkWidget *sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *st static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradient *gradient); static gint sp_gradient_vector_dialog_delete(GtkWidget *widget, GdkEvent *event, GtkWidget *dialog); -static void sp_gradient_vector_dialog_destroy(GtkObject *object, gpointer data); +#if GTK_CHECK_VERSION(3,0,0) +static void sp_gradient_vector_dialog_destroy(GtkWidget *object, gpointer data); +static void sp_gradient_vector_widget_destroy(GtkWidget *object, gpointer data); +#else +static void sp_gradient_vector_dialog_destroy(GtkObject *object, gpointer data); static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer data); +#endif + static void sp_gradient_vector_gradient_release(SPObject *obj, GtkWidget *widget); static void sp_gradient_vector_gradient_modified(SPObject *obj, guint flags, GtkWidget *widget); -static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object); -static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *object); +static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GObject *object); +static void sp_gradient_vector_color_changed(SPColorSelector *csel, GObject *object); static void update_stop_list( GtkWidget *vb, SPGradient *gradient, SPStop *new_stop); static gboolean blocked = FALSE; @@ -545,7 +608,7 @@ static void update_stop_list( GtkWidget *vb, SPGradient *gradient, SPStop *new_s if (!combo_box) { return; } - GtkListStore *store = (GtkListStore *)gtk_combo_box_get_model (GTK_COMBO_BOX(combo_box)); + GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box))); if (!store) { return; } @@ -572,7 +635,7 @@ static void update_stop_list( GtkWidget *vb, SPGradient *gradient, SPStop *new_s if (SP_IS_STOP(sl->data)){ SPStop *stop = SP_STOP(sl->data); Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(sl->data)->getRepr(); - Inkscape::UI::Widget::ColorPreview *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(sp_stop_get_rgba32(stop))); + Inkscape::UI::Widget::ColorPreview *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(stop->get_rgba32())); GdkPixbuf *pb = cpv->toPixbuf(64, 16); gtk_list_store_append (store, &iter); @@ -605,7 +668,7 @@ static void sp_grad_edit_combo_box_changed (GtkComboBox * /*widget*/, GtkWidget blocked = TRUE; - SPColorSelector *csel = (SPColorSelector*)g_object_get_data(G_OBJECT(tbl), "cselector"); + SPColorSelector *csel = static_cast<SPColorSelector*>(g_object_get_data(G_OBJECT(tbl), "cselector")); // set its color, from the stored array csel->base->setColorAlpha( stop->getEffectiveColor(), stop->opacity ); GtkWidget *offspin = GTK_WIDGET(g_object_get_data(G_OBJECT(tbl), "offspn")); @@ -656,7 +719,7 @@ static SPStop *get_selected_stop( GtkWidget *vb) if (combo_box) { GtkTreeIter iter; if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX(combo_box), &iter)) { - GtkListStore *store = (GtkListStore *)gtk_combo_box_get_model (GTK_COMBO_BOX(combo_box)); + GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box))); gtk_tree_model_get (GTK_TREE_MODEL(store), &iter, 2, &stop, -1); } } @@ -728,8 +791,8 @@ static void sp_grd_ed_add_stop(GtkWidget */*widget*/, GtkWidget *vb) newstop->offset = (stop->offset + next->offset) * 0.5 ; - guint32 const c1 = sp_stop_get_rgba32(stop); - guint32 const c2 = sp_stop_get_rgba32(next); + guint32 const c1 = stop->get_rgba32(); + guint32 const c2 = next->get_rgba32(); guint32 cnew = sp_average_color(c1, c2); Inkscape::CSSOStringStream os; @@ -860,14 +923,14 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s #endif /* Label */ - GtkWidget *l = gtk_label_new(_("Offset:")); + GtkWidget *l = gtk_label_new(C_("Gradient","Offset:")); gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5); gtk_box_pack_start(GTK_BOX(hb),l, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS); gtk_widget_show(l); /* Adjustment */ GtkAdjustment *Offset_adj = NULL; - Offset_adj= (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.01, 0.0); + Offset_adj= GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.01, 0.0)); g_object_set_data(G_OBJECT(vb), "offset", Offset_adj); SPStop *stop = get_selected_stop(vb); @@ -938,8 +1001,6 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s GtkWidget * sp_gradient_vector_editor_new(SPGradient *gradient, SPStop *stop) { - GtkWidget *wid; - if (dlg == NULL) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -981,7 +1042,7 @@ GtkWidget * sp_gradient_vector_editor_new(SPGradient *gradient, SPStop *stop) gtk_container_set_border_width(GTK_CONTAINER(dlg), PAD); - wid = static_cast<GtkWidget*>(sp_gradient_vector_widget_new(gradient, stop)); + GtkWidget *wid = static_cast<GtkWidget*>(sp_gradient_vector_widget_new(gradient, stop)); g_object_set_data(G_OBJECT(dlg), "gradient-vector-widget", wid); /* Connect signals */ gtk_widget_show(wid); @@ -1094,7 +1155,11 @@ static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradien blocked = FALSE; } -static void sp_gradient_vector_dialog_destroy(GtkObject */*object*/, gpointer /*data*/) +#if GTK_CHECK_VERSION(3,0,0) +static void sp_gradient_vector_dialog_destroy(GtkWidget * /*object*/, gpointer /*data*/) +#else +static void sp_gradient_vector_dialog_destroy(GtkObject * /*object*/, gpointer /*data*/) +#endif { sp_signal_disconnect_by_data(INKSCAPE, dlg); wd.win = dlg = NULL; @@ -1123,13 +1188,16 @@ static gboolean sp_gradient_vector_dialog_delete(GtkWidget */*widget*/, GdkEvent } /* Widget destroy handler */ - +#if GTK_CHECK_VERSION(3,0,0) +static void sp_gradient_vector_widget_destroy(GtkWidget *object, gpointer /*data*/) +#else static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer /*data*/) +#endif { - SPObject *gradient = reinterpret_cast<SPObject*>(g_object_get_data(G_OBJECT(object), "gradient")); + SPObject *gradient = SP_OBJECT(g_object_get_data(G_OBJECT(object), "gradient")); - sigc::connection *release_connection = (sigc::connection *)g_object_get_data(G_OBJECT(object), "gradient_release_connection"); - sigc::connection *modified_connection = (sigc::connection *)g_object_get_data(G_OBJECT(object), "gradient_modified_connection"); + sigc::connection *release_connection = static_cast<sigc::connection *>(g_object_get_data(G_OBJECT(object), "gradient_release_connection")); + sigc::connection *modified_connection = static_cast<sigc::connection *>(g_object_get_data(G_OBJECT(object), "gradient_modified_connection")); if (gradient) { g_assert( release_connection != NULL ); @@ -1137,10 +1205,10 @@ static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer /*data release_connection->disconnect(); modified_connection->disconnect(); sp_signal_disconnect_by_data(gradient, object); - } - if (gradient && gradient->getRepr()) { - sp_repr_remove_listener_by_data(gradient->getRepr(), object); + if (gradient->getRepr()) { + sp_repr_remove_listener_by_data(gradient->getRepr(), object); + } } } @@ -1159,7 +1227,7 @@ static void sp_gradient_vector_gradient_modified(SPObject *object, guint /*flags } } -static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *object) +static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GObject *object) { SPGradient *gradient, *ngr; @@ -1193,7 +1261,7 @@ static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GtkObject *o blocked = FALSE; } -static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *object) +static void sp_gradient_vector_color_changed(SPColorSelector *csel, GObject *object) { if (blocked) { return; @@ -1245,9 +1313,9 @@ static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *o if (combo_box) { GtkTreeIter iter; if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX(combo_box), &iter)) { - GtkListStore *store = (GtkListStore *)gtk_combo_box_get_model (GTK_COMBO_BOX(combo_box)); + GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo_box))); - Inkscape::UI::Widget::ColorPreview *cp = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(sp_stop_get_rgba32(stop))); + Inkscape::UI::Widget::ColorPreview *cp = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(stop->get_rgba32())); GdkPixbuf *pb = cp->toPixbuf(64, 16); gtk_list_store_set (store, &iter, 0, pb, /*1, repr->attribute("id"),*/ 2, stop, -1); diff --git a/src/widgets/gradient-vector.h b/src/widgets/gradient-vector.h index 9858ce784..b63120a6e 100644 --- a/src/widgets/gradient-vector.h +++ b/src/widgets/gradient-vector.h @@ -15,12 +15,21 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <glib.h> +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + +#include <gtkmm/liststore.h> #include <stddef.h> #include <sigc++/connection.h> #include <gtk/gtk.h> +#include "gradient-selector.h" #define SP_TYPE_GRADIENT_VECTOR_SELECTOR (sp_gradient_vector_selector_get_type ()) #define SP_GRADIENT_VECTOR_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_GRADIENT_VECTOR_SELECTOR, SPGradientVectorSelector)) @@ -43,16 +52,14 @@ struct SPGradientVectorSelector { SPDocument *doc; SPGradient *gr; - /* ComboBox of gradient vectors */ - GtkWidget *combo_box; - GtkListStore *store; + /* Gradient vectors store */ + Glib::RefPtr<Gtk::ListStore> store; + SPGradientSelector::ModelColumns *columns; sigc::connection gradient_release_connection; sigc::connection defs_release_connection; sigc::connection defs_modified_connection; - - gulong combo_connection; - + sigc::connection tree_select_connection; void setSwatched(); }; @@ -77,8 +84,8 @@ GtkWidget *sp_gradient_vector_editor_new (SPGradient *gradient, SPStop *stop = N guint32 sp_average_color(guint32 c1, guint32 c2, gdouble p = 0.5); -gchar *gr_prepare_label (SPObject *obj); - +Glib::ustring gr_prepare_label (SPObject *obj); +Glib::ustring gr_ellipsize_text(Glib::ustring const &src, size_t maxlen); #endif // SEEN_GRADIENT_VECTOR_H diff --git a/src/widgets/icon.cpp b/src/widgets/icon.cpp index a58645015..eb16cfece 100644 --- a/src/widgets/icon.cpp +++ b/src/widgets/icon.cpp @@ -16,6 +16,10 @@ # include "config.h" #endif +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + #include <gtkmm/icontheme.h> #include <cstring> #include <glib.h> @@ -24,6 +28,7 @@ #include <gtkmm/image.h> #include <gdkmm/pixbuf.h> #include <glibmm/fileutils.h> +#include <glibmm/miscutils.h> #include <2geom/transforms.h> #include "path-prefix.h" @@ -37,22 +42,12 @@ #include "display/drawing.h" #include "io/sys.h" #include "sp-root.h" +#include "util/units.h" #include "icon.h" - -// Bring in work-around for Glib versions missing GStatBuf -#if !GLIB_CHECK_VERSION(2,25,0) -#if defined (_MSC_VER) && !defined(_WIN64) -typedef struct _stat32 GStatBuf; -#else //defined (_MSC_VER) && !defined(_WIN64) -typedef struct stat GStatBuf; -#endif //defined (_MSC_VER) && !defined(_WIN64) -#endif //!GLIB_CHECK_VERSION(2,25,0) +#include "ui/icon-names.h" struct IconImpl { - static void classInit(SPIconClass *klass); - static void init(SPIcon *icon); - static GtkWidget *newFull( Inkscape::IconSize lsize, gchar const *name ); static void dispose(GObject *object); @@ -71,9 +66,11 @@ struct IconImpl { gint *natural_height); static void sizeAllocate(GtkWidget *widget, GtkAllocation *allocation); - static int expose(GtkWidget *widget, GdkEventExpose *event); + static gboolean draw(GtkWidget *widget, cairo_t *cr); - static void paint(SPIcon *icon, GdkRectangle const *area); +#if !GTK_CHECK_VERSION(3,0,0) + static gboolean expose(GtkWidget *widget, GdkEventExpose *event); +#endif static void screenChanged( GtkWidget *widget, GdkScreen *previous_screen ); static void styleSet( GtkWidget *widget, GtkStyle *previous_style ); @@ -111,12 +108,10 @@ struct IconImpl { private: static const std::string magicNumber; - static GtkWidgetClass *parent_class; static std::map<Glib::ustring, Glib::ustring> legacyNames; }; const std::string IconImpl::magicNumber = "1.0"; -GtkWidgetClass *IconImpl::parent_class = 0; std::map<Glib::ustring, Glib::ustring> IconImpl::legacyNames; @@ -148,58 +143,37 @@ public: static std::map<Glib::ustring, std::vector<IconCacheItem> > iconSetCache; static std::set<Glib::ustring> internalNames; -GType SPIcon::getType() -{ - static GType type = 0; - if (!type) { - GTypeInfo info = { - sizeof(SPIconClass), - NULL, - NULL, - reinterpret_cast<GClassInitFunc>(IconImpl::classInit), - NULL, - NULL, - sizeof(SPIcon), - 0, - reinterpret_cast<GInstanceInitFunc>(IconImpl::init), - NULL - }; - type = g_type_register_static(GTK_TYPE_WIDGET, "SPIcon", &info, (GTypeFlags)0); - } - return type; -} +G_DEFINE_TYPE(SPIcon, sp_icon, GTK_TYPE_WIDGET); -void IconImpl::classInit(SPIconClass *klass) +static void +sp_icon_class_init(SPIconClass *klass) { - GObjectClass *object_class; - GtkWidgetClass *widget_class; - - object_class = (GObjectClass *) klass; - widget_class = (GtkWidgetClass *) klass; - - parent_class = (GtkWidgetClass*)g_type_class_peek_parent(klass); + GObjectClass *object_class = G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); object_class->dispose = IconImpl::dispose; #if GTK_CHECK_VERSION(3,0,0) widget_class->get_preferred_width = IconImpl::getPreferredWidth; widget_class->get_preferred_height = IconImpl::getPreferredHeight; + widget_class->draw = IconImpl::draw; #else widget_class->size_request = IconImpl::sizeRequest; + widget_class->expose_event = IconImpl::expose; #endif widget_class->size_allocate = IconImpl::sizeAllocate; - widget_class->expose_event = IconImpl::expose; widget_class->screen_changed = IconImpl::screenChanged; widget_class->style_set = IconImpl::styleSet; } -void IconImpl::init(SPIcon *icon) +static void +sp_icon_init(SPIcon *icon) { gtk_widget_set_has_window (GTK_WIDGET (icon), FALSE); icon->lsize = Inkscape::ICON_SIZE_BUTTON; icon->psize = 0; - icon->name = 0; - icon->pb = 0; + icon->name = NULL; + icon->pb = NULL; } void IconImpl::dispose(GObject *object) @@ -208,10 +182,10 @@ void IconImpl::dispose(GObject *object) clear(icon); if ( icon->name ) { g_free( icon->name ); - icon->name = 0; + icon->name = NULL; } - ((GObjectClass *) (parent_class))->dispose(object); + (G_OBJECT_CLASS(sp_icon_parent_class))->dispose(object); } void IconImpl::reset( SPIcon *icon ) @@ -262,20 +236,76 @@ void IconImpl::sizeAllocate(GtkWidget *widget, GtkAllocation *allocation) } } -int IconImpl::expose(GtkWidget *widget, GdkEventExpose *event) +gboolean IconImpl::draw(GtkWidget *widget, cairo_t* cr) { - if ( gtk_widget_is_drawable(widget) ) { - SPIcon *icon = SP_ICON(widget); - if ( !icon->pb ) { - fetchPixbuf( icon ); - } + SPIcon *icon = SP_ICON(widget); + if ( !icon->pb ) { + fetchPixbuf( icon ); + } + + GdkPixbuf *image = icon->pb; + bool unref_image = false; + + /* copied from the expose function of GtkImage */ + if (gtk_widget_get_state (GTK_WIDGET(icon)) != GTK_STATE_NORMAL && image) { + GtkIconSource *source = gtk_icon_source_new(); + gtk_icon_source_set_pixbuf(source, icon->pb); + gtk_icon_source_set_size(source, GTK_ICON_SIZE_SMALL_TOOLBAR); // note: this is boilerplate and not used + gtk_icon_source_set_size_wildcarded(source, FALSE); - paint(icon, &event->area); +#if GTK_CHECK_VERSION(3,0,0) + image = gtk_render_icon_pixbuf(gtk_widget_get_style_context(widget), + source, + (GtkIconSize)-1); +#else + image = gtk_style_render_icon(gtk_widget_get_style(widget), source, + gtk_widget_get_direction(widget), + (GtkStateType) gtk_widget_get_state(widget), + (GtkIconSize)-1, widget, "gtk-image"); +#endif + + gtk_icon_source_free(source); + unref_image = true; } + if (image) { + GtkAllocation allocation; + GtkRequisition requisition; + gtk_widget_get_allocation(widget, &allocation); + gtk_widget_get_requisition(widget, &requisition); + int x = floor(allocation.x + ((allocation.width - requisition.width) * 0.5)); + int y = floor(allocation.y + ((allocation.height - requisition.height) * 0.5)); + int width = gdk_pixbuf_get_width(image); + int height = gdk_pixbuf_get_height(image); + // Limit drawing to when we actually have something. Avoids some crashes. + if ( (width > 0) && (height > 0) ) { + gdk_cairo_set_source_pixbuf(cr, image, x, y); + cairo_paint(cr); + } + } + + if (unref_image) { + g_object_unref(G_OBJECT(image)); + } + return TRUE; } +#if !GTK_CHECK_VERSION(3,0,0) +gboolean IconImpl::expose(GtkWidget *widget, GdkEventExpose * /*event*/) +{ + gboolean result = TRUE; + + if (gtk_widget_is_drawable(widget)) { + cairo_t * cr = gdk_cairo_create(gtk_widget_get_window(widget)); + result = draw(widget, cr); + cairo_destroy(cr); + } + + return result; +} +#endif + // PUBLIC CALL: void sp_icon_fetch_pixbuf( SPIcon *icon ) { @@ -295,7 +325,7 @@ void IconImpl::fetchPixbuf( SPIcon *icon ) GdkPixbuf* IconImpl::renderup( gchar const* name, Inkscape::IconSize lsize, unsigned psize ) { GtkIconTheme *theme = gtk_icon_theme_get_default(); - GdkPixbuf *pb = 0; + GdkPixbuf *pb = NULL; if (gtk_icon_theme_has_icon(theme, name)) { pb = gtk_icon_theme_load_icon(theme, name, psize, (GtkIconLookupFlags) 0, NULL); } @@ -328,8 +358,8 @@ GdkPixbuf* IconImpl::renderup( gchar const* name, Inkscape::IconSize lsize, unsi void IconImpl::screenChanged( GtkWidget *widget, GdkScreen *previous_screen ) { - if ( GTK_WIDGET_CLASS( parent_class )->screen_changed ) { - GTK_WIDGET_CLASS( parent_class )->screen_changed( widget, previous_screen ); + if ( GTK_WIDGET_CLASS( sp_icon_parent_class )->screen_changed ) { + GTK_WIDGET_CLASS( sp_icon_parent_class )->screen_changed( widget, previous_screen ); } SPIcon *icon = SP_ICON(widget); themeChanged(icon); @@ -337,8 +367,8 @@ void IconImpl::screenChanged( GtkWidget *widget, GdkScreen *previous_screen ) void IconImpl::styleSet( GtkWidget *widget, GtkStyle *previous_style ) { - if ( GTK_WIDGET_CLASS( parent_class )->style_set ) { - GTK_WIDGET_CLASS( parent_class )->style_set( widget, previous_style ); + if ( GTK_WIDGET_CLASS( sp_icon_parent_class )->style_set ) { + GTK_WIDGET_CLASS( sp_icon_parent_class )->style_set( widget, previous_style ); } SPIcon *icon = SP_ICON(widget); themeChanged(icon); @@ -422,13 +452,13 @@ void IconImpl::validateCache() std::string present; { - gchar *contents = 0; + gchar *contents = NULL; if ( g_file_get_contents(iconCacheFile.c_str(), &contents, 0, 0) ) { if ( contents ) { present = contents; } g_free(contents); - contents = 0; + contents = NULL; } } bool cacheValid = (present == wanted); @@ -754,53 +784,29 @@ GtkWidget *IconImpl::newFull( Inkscape::IconSize lsize, gchar const *name ) { static bool dump = Inkscape::Preferences::get()->getBool("/debug/icons/dumpGtk"); - GtkWidget *widget = 0; + GtkWidget *widget = NULL; gint trySize = CLAMP( static_cast<gint>(lsize), 0, static_cast<gint>(G_N_ELEMENTS(iconSizeLookup) - 1) ); if ( !sizeMapDone ) { injectCustomSize(); } GtkIconSize mappedSize = iconSizeLookup[trySize]; - GtkStockItem stock; - gboolean stockFound = gtk_stock_lookup( name, &stock ); - - GtkWidget *img = 0; if ( legacyNames.empty() ) { setupLegacyNaming(); } - if ( stockFound ) { - img = gtk_image_new_from_stock( name, mappedSize ); - } else { - img = gtk_image_new_from_icon_name( name, mappedSize ); - if ( dump ) { - g_message("gtk_image_new_from_icon_name( '%s', %d ) = %p", name, mappedSize, img); - GtkImageType thing = gtk_image_get_storage_type(GTK_IMAGE(img)); - g_message(" Type is %d %s", (int)thing, (thing == GTK_IMAGE_EMPTY ? "Empty" : "ok")); - } + GtkWidget *img = gtk_image_new_from_icon_name( name, mappedSize ); + if ( dump ) { + g_message("gtk_image_new_from_icon_name( '%s', %d ) = %p", name, mappedSize, img); + GtkImageType thing = gtk_image_get_storage_type(GTK_IMAGE(img)); + g_message(" Type is %d %s", (int)thing, (thing == GTK_IMAGE_EMPTY ? "Empty" : "ok")); } if ( img ) { GtkImageType type = gtk_image_get_storage_type( GTK_IMAGE(img) ); - if ( type == GTK_IMAGE_STOCK ) { - if ( !stockFound ) { - // It's not showing as a stock ID, so assume it will be present internally - addPreRender( mappedSize, name ); - - // Add a hook to render if set visible before prerender is done. - g_signal_connect( G_OBJECT(img), "map", G_CALLBACK(imageMapCB), GINT_TO_POINTER(static_cast<int>(mappedSize)) ); - if ( dump ) { - g_message(" connecting %p for imageMapCB for [%s] %d", img, name, (int)mappedSize); - } - } - widget = GTK_WIDGET(img); - img = 0; - if ( dump ) { - g_message( "loaded gtk '%s' %d (GTK_IMAGE_STOCK) %s on %p", name, mappedSize, (stockFound ? "STOCK" : "local"), widget ); - } - } else if ( type == GTK_IMAGE_ICON_NAME ) { + if ( type == GTK_IMAGE_ICON_NAME ) { widget = GTK_WIDGET(img); - img = 0; + img = NULL; // Add a hook to render if set visible before prerender is done. g_signal_connect( G_OBJECT(widget), "map", G_CALLBACK(imageMapNamedCB), GINT_TO_POINTER(0) ); @@ -813,16 +819,16 @@ GtkWidget *IconImpl::newFull( Inkscape::IconSize lsize, gchar const *name ) } } else { if ( dump ) { - g_message( "skipped gtk '%s' %d (not GTK_IMAGE_STOCK)", name, lsize ); + g_message( "skipped gtk '%s' %d (not GTK_IMAGE_ICON_NAME)", name, lsize ); } - //g_object_unref( (GObject *)img ); - img = 0; + //g_object_unref(G_OBJECT(img)); + img = NULL; } } if ( !widget ) { //g_message("Creating an SPIcon instance for %s:%d", name, (int)lsize); - SPIcon *icon = (SPIcon *)g_object_new(SP_TYPE_ICON, NULL); + SPIcon *icon = SP_ICON(g_object_new(SP_TYPE_ICON, NULL)); icon->lsize = lsize; icon->name = g_strdup(name); icon->psize = getPhysSize(lsize); @@ -839,10 +845,17 @@ GtkWidget *sp_icon_new( Inkscape::IconSize lsize, gchar const *name ) return IconImpl::newFull( lsize, name ); } +// PUBLIC CALL for when you REALLY need a pixbuf +GdkPixbuf *sp_pixbuf_new( Inkscape::IconSize lsize, gchar const *name ) +{ + int psize = IconImpl::getPhysSize(lsize); + return IconImpl::renderup(name, lsize, psize); +} + // PUBLIC CALL: Gtk::Widget *sp_icon_get_icon( Glib::ustring const &oid, Inkscape::IconSize size ) { - Gtk::Widget *result = 0; + Gtk::Widget *result = NULL; GtkWidget *widget = IconImpl::newFull( static_cast<Inkscape::IconSize>(Inkscape::getRegisteredIconSize(size)), oid.c_str() ); if ( widget ) { @@ -972,7 +985,7 @@ int IconImpl::getPhysSize(int size) "inkscape-decoration" }; - GtkWidget *icon = (GtkWidget *)g_object_new(SP_TYPE_ICON, NULL); + GtkWidget *icon = GTK_WIDGET(g_object_new(SP_TYPE_ICON, NULL)); for (unsigned i = 0; i < G_N_ELEMENTS(gtkSizes); ++i) { guint const val_ix = (gtkSizes[i] <= GTK_ICON_SIZE_DIALOG) ? (guint)gtkSizes[i] : (guint)Inkscape::ICON_SIZE_DECORATION; @@ -997,7 +1010,7 @@ int IconImpl::getPhysSize(int size) // "The rendered pixbuf may not even correspond to the width/height returned by // gtk_icon_size_lookup(), because themes are free to render the pixbuf however // they like, including changing the usual size." - gchar const *id = GTK_STOCK_OPEN; + gchar const *id = INKSCAPE_ICON("document-open"); GdkPixbuf *pb = gtk_widget_render_icon( icon, id, gtkSizes[i], NULL); if (pb) { width = gdk_pixbuf_get_width(pb); @@ -1021,52 +1034,11 @@ int IconImpl::getPhysSize(int size) return vals[size]; } -void IconImpl::paint(SPIcon *icon, GdkRectangle const */*area*/) -{ - GtkWidget &widget = *GTK_WIDGET(icon); - GdkPixbuf *image = icon->pb; - bool unref_image = false; - /* copied from the expose function of GtkImage */ - if (gtk_widget_get_state (GTK_WIDGET(icon)) != GTK_STATE_NORMAL && image) { - GtkIconSource *source = gtk_icon_source_new(); - gtk_icon_source_set_pixbuf(source, icon->pb); - gtk_icon_source_set_size(source, GTK_ICON_SIZE_SMALL_TOOLBAR); // note: this is boilerplate and not used - gtk_icon_source_set_size_wildcarded(source, FALSE); - image = gtk_style_render_icon(gtk_widget_get_style(&widget), source, - gtk_widget_get_direction(&widget), - (GtkStateType) gtk_widget_get_state(&widget), - (GtkIconSize)-1, &widget, "gtk-image"); - gtk_icon_source_free(source); - unref_image = true; - } - - if (image) { - GtkAllocation allocation; - GtkRequisition requisition; - gtk_widget_get_allocation(&widget, &allocation); - gtk_widget_get_requisition(&widget, &requisition); - int x = floor(allocation.x + ((allocation.width - requisition.width) * 0.5)); - int y = floor(allocation.y + ((allocation.height - requisition.height) * 0.5)); - int width = gdk_pixbuf_get_width(image); - int height = gdk_pixbuf_get_height(image); - // Limit drawing to when we actually have something. Avoids some crashes. - if ( (width > 0) && (height > 0) ) { - gdk_draw_pixbuf(GDK_DRAWABLE(gtk_widget_get_window(&widget)), - gtk_widget_get_style(&widget)->black_gc, image, - 0, 0, x, y, width, height, - GDK_RGB_DITHER_NORMAL, x, y); - } - } - - if (unref_image) { - g_object_unref(G_OBJECT(image)); - } -} GdkPixbuf *IconImpl::loadPixmap(gchar const *name, unsigned /*lsize*/, unsigned psize) { - gchar *path = (gchar *) g_strdup_printf("%s/%s.png", INKSCAPE_PIXMAPDIR, name); + gchar *path = g_strdup_printf("%s/%s.png", INKSCAPE_PIXMAPDIR, name); // TODO: bulia, please look over gsize bytesRead = 0; gsize bytesWritten = 0; @@ -1080,7 +1052,7 @@ GdkPixbuf *IconImpl::loadPixmap(gchar const *name, unsigned /*lsize*/, unsigned g_free(localFilename); g_free(path); if (!pb) { - path = (gchar *) g_strdup_printf("%s/%s.xpm", INKSCAPE_PIXMAPDIR, name); + path = g_strdup_printf("%s/%s.xpm", INKSCAPE_PIXMAPDIR, name); // TODO: bulia, please look over gsize bytesRead = 0; gsize bytesWritten = 0; @@ -1143,7 +1115,7 @@ sp_icon_doc_icon( SPDocument *doc, Inkscape::Drawing &drawing, if ( object->parent == NULL ) { dbox = Geom::Rect(Geom::Point(0, 0), - Geom::Point(doc->getWidth(), doc->getHeight())); + Geom::Point(doc->getWidth().value("px"), doc->getHeight().value("px"))); } /* This is in document coordinates, i.e. pixels */ @@ -1218,9 +1190,9 @@ sp_icon_doc_icon( SPDocument *doc, Inkscape::Drawing &drawing, /* Render */ cairo_surface_t *s = cairo_image_surface_create_for_data(px, CAIRO_FORMAT_ARGB32, psize, psize, stride); - Inkscape::DrawingContext ct(s, ua.min()); + Inkscape::DrawingContext dc(s, ua.min()); - drawing.render(ct, ua); + drawing.render(dc, ua); cairo_surface_destroy(s); // convert to GdkPixbuf format @@ -1270,7 +1242,7 @@ Glib::ustring icon_cache_key(Glib::ustring const & name, unsigned psize) } GdkPixbuf *get_cached_pixbuf(Glib::ustring const &key) { - GdkPixbuf* pb = 0; + GdkPixbuf* pb = NULL; std::map<Glib::ustring, GdkPixbuf *>::iterator found = pb_cache.find(key); if ( found != pb_cache.end() ) { pb = found->second; @@ -1304,7 +1276,7 @@ guchar *IconImpl::load_svg_pixels(std::list<Glib::ustring> const &names, guchar *px = NULL; for (std::list<gchar*>::iterator i = sources.begin(); (i != sources.end()) && !px; ++i) { gchar *doc_filename = *i; - SVGDocCache *info = 0; + SVGDocCache *info = NULL; // Did we already load this doc? Glib::ustring key(doc_filename); @@ -1338,11 +1310,11 @@ guchar *IconImpl::load_svg_pixels(std::list<Glib::ustring> const &names, } static void addToIconSet(GdkPixbuf* pb, gchar const* name, GtkIconSize lsize, unsigned psize) { - static bool dump = Inkscape::Preferences::get()->getBool("/debug/icons/dumpGtk"); - GtkStockItem stock; - gboolean stockFound = gtk_stock_lookup( name, &stock ); - if ( !stockFound ) { + Glib::RefPtr<Gtk::IconTheme> icon_theme = Gtk::IconTheme::get_default(); + bool icon_found = icon_theme->has_icon(name); + if ( !icon_found ) { Gtk::IconTheme::add_builtin_icon( name, psize, Glib::wrap(pb) ); + static bool dump = Inkscape::Preferences::get()->getBool("/debug/icons/dumpGtk"); if (dump) { g_message(" set in a builtin for %s:%d:%d", name, lsize, psize); } @@ -1351,10 +1323,8 @@ static void addToIconSet(GdkPixbuf* pb, gchar const* name, GtkIconSize lsize, un void Inkscape::queueIconPrerender( Glib::ustring const &name, Inkscape::IconSize lsize ) { - GtkStockItem stock; - gboolean stockFound = gtk_stock_lookup( name.c_str(), &stock ); gboolean themedFound = gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), name.c_str()); - if (!stockFound && !themedFound ) { + if ( !themedFound ) { gint trySize = CLAMP( static_cast<gint>(lsize), 0, static_cast<gint>(G_N_ELEMENTS(iconSizeLookup) - 1) ); if ( !sizeMapDone ) { IconImpl::injectCustomSize(); @@ -1384,7 +1354,6 @@ static std::string getDestDir( unsigned psize ) bool IconImpl::prerenderIcon(gchar const *name, GtkIconSize lsize, unsigned psize) { bool loadNeeded = false; - static bool dump = Inkscape::Preferences::get()->getBool("/debug/icons/dumpGtk"); static bool useCache = Inkscape::Preferences::get()->getBool("/debug/icons/useCache", true); static bool cacheValidated = false; if (!cacheValidated) { @@ -1396,6 +1365,7 @@ bool IconImpl::prerenderIcon(gchar const *name, GtkIconSize lsize, unsigned psiz Glib::ustring key = icon_cache_key(name, psize); if ( !get_cached_pixbuf(key) ) { + static bool dump = Inkscape::Preferences::get()->getBool("/debug/icons/dumpGtk"); if ((internalNames.find(name) != internalNames.end()) || (!gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), name))) { if (dump) { @@ -1620,9 +1590,9 @@ gboolean IconImpl::prerenderTask(gpointer /*data*/) { void IconImpl::imageMapCB(GtkWidget* widget, gpointer user_data) { - gchar* id = 0; + gchar const* id = NULL; GtkIconSize size = GTK_ICON_SIZE_INVALID; - gtk_image_get_stock(GTK_IMAGE(widget), &id, &size); + gtk_image_get_icon_name(GTK_IMAGE(widget), &id, &size); GtkIconSize lsize = static_cast<GtkIconSize>(GPOINTER_TO_INT(user_data)); if ( id ) { int psize = getPhysSize(lsize); @@ -1647,33 +1617,34 @@ void IconImpl::imageMapCB(GtkWidget* widget, gpointer user_data) void IconImpl::imageMapNamedCB(GtkWidget* widget, gpointer user_data) { GtkImage* img = GTK_IMAGE(widget); - gchar const* iconName = 0; + gchar const* iconName = NULL; GtkIconSize size = GTK_ICON_SIZE_INVALID; gtk_image_get_icon_name(img, &iconName, &size); if ( iconName ) { GtkImageType type = gtk_image_get_storage_type( GTK_IMAGE(img) ); if ( type == GTK_IMAGE_ICON_NAME ) { - gint iconSize = 0; - gchar* iconName = 0; + GtkIconSize iconSize = GTK_ICON_SIZE_INVALID; + gchar const* iconName_two = NULL; { g_object_get(G_OBJECT(widget), - "icon-name", &iconName, + "icon-name", &iconName_two, "icon-size", &iconSize, NULL); } for ( std::vector<preRenderItem>::iterator it = pendingRenders.begin(); it != pendingRenders.end(); ++it ) { - if ( (it->_name == iconName) && (it->_lsize == size) ) { - int psize = getPhysSize(size); - prerenderIcon(iconName, size, psize); + /// @todo fix pointer string comparison here!!! "it->_name == iconName_two", that seems very bug-prone + if ( (it->_name == iconName_two) && (it->_lsize == iconSize) ) { + int psize = getPhysSize(iconSize); + prerenderIcon(iconName_two, iconSize, psize); pendingRenders.erase(it); break; } } - gtk_image_set_from_icon_name(img, "", (GtkIconSize)iconSize); - gtk_image_set_from_icon_name(img, iconName, (GtkIconSize)iconSize); + gtk_image_set_from_icon_name(img, "", iconSize); + gtk_image_set_from_icon_name(img, iconName_two, iconSize); } else { g_warning("UNEXPECTED TYPE of %d", (int)type); } diff --git a/src/widgets/icon.h b/src/widgets/icon.h index 3f6aa2455..e1dae0d6a 100644 --- a/src/widgets/icon.h +++ b/src/widgets/icon.h @@ -14,10 +14,18 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + #include <gtkmm/widget.h> #include "icon-size.h" -#define SP_TYPE_ICON SPIcon::getType() +#define SP_TYPE_ICON sp_icon_get_type() #define SP_ICON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_ICON, SPIcon)) #define SP_IS_ICON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_ICON)) @@ -29,6 +37,8 @@ struct SPIconClass { GtkWidgetClass parent_class; }; +GType sp_icon_get_type() G_GNUC_CONST; + struct SPIcon { GtkWidget widget; @@ -38,14 +48,12 @@ struct SPIcon { GdkPixbuf *pb; - static GType getType(void); - friend class SPIconImpl; }; GtkWidget *sp_icon_new( Inkscape::IconSize size, const gchar *name ); - +GdkPixbuf *sp_pixbuf_new( Inkscape::IconSize size, const gchar *name ); // Might return a wrapped SPIcon, or Gtk::Image Gtk::Widget *sp_icon_get_icon( const Glib::ustring &oid, Inkscape::IconSize size = Inkscape::ICON_SIZE_BUTTON ); diff --git a/src/widgets/lpe-toolbar.cpp b/src/widgets/lpe-toolbar.cpp new file mode 100644 index 000000000..e9e5af912 --- /dev/null +++ b/src/widgets/lpe-toolbar.cpp @@ -0,0 +1,427 @@ +/** + * @file + * LPE aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "live_effects/lpe-line_segment.h" +#include "lpe-toolbar.h" +#include "connection-pool.h" +#include "desktop-handles.h" +#include "desktop.h" +#include "document-undo.h" +#include "ege-select-one-action.h" +#include "helper/action-context.h" +#include "helper/action.h" +#include "ink-action.h" +#include "live_effects/effect.h" +#include "preferences.h" +#include "selection.h" +#include "sp-namedview.h" +#include "tools-switch.h" +#include "ui/tools/lpe-tool.h" +#include "ui/widget/unit-tracker.h" +#include "util/units.h" +#include "verbs.h" + +using Inkscape::UI::Widget::UnitTracker; +using Inkscape::Util::Unit; +using Inkscape::Util::Quantity; +using Inkscape::DocumentUndo; +using Inkscape::UI::Tools::ToolBase; +using Inkscape::UI::Tools::LpeTool; + + +//######################## +//## LPETool ## +//######################## + +// the subtools from which the toolbar is built automatically are listed in lpe-tool-context.h + +// this is called when the mode is changed via the toolbar (i.e., one of the subtool buttons is pressed) +static void sp_lpetool_mode_changed(EgeSelectOneAction *act, GObject *tbl) +{ + using namespace Inkscape::LivePathEffect; + + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(tbl, "desktop")); + ToolBase *ec = desktop->event_context; + if (!SP_IS_LPETOOL_CONTEXT(ec)) { + return; + } + + // only take action if run by the attr_changed listener + if (!g_object_get_data(tbl, "freeze")) { + // in turn, prevent listener from responding + g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE)); + + gint mode = ege_select_one_action_get_active(act); + EffectType type = lpesubtools[mode].type; + + LpeTool *lc = SP_LPETOOL_CONTEXT(desktop->event_context); + bool success = lpetool_try_construction(lc, type); + if (success) { + // since the construction was already performed, we set the state back to inactive + ege_select_one_action_set_active(act, 0); + mode = 0; + } else { + // switch to the chosen subtool + SP_LPETOOL_CONTEXT(desktop->event_context)->mode = type; + } + + if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt( "/tools/lpetool/mode", mode ); + } + + g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE)); + } +} + +static void sp_lpetool_toolbox_sel_modified(Inkscape::Selection *selection, guint /*flags*/, GObject * /*tbl*/) +{ + ToolBase *ec = selection->desktop()->event_context; + if (SP_IS_LPETOOL_CONTEXT(ec)) { + lpetool_update_measuring_items(SP_LPETOOL_CONTEXT(ec)); + } +} + +static void sp_lpetool_toolbox_sel_changed(Inkscape::Selection *selection, GObject *tbl) +{ + using namespace Inkscape::LivePathEffect; + ToolBase *ec = selection->desktop()->event_context; + if (!SP_IS_LPETOOL_CONTEXT(ec)) { + return; + } + LpeTool *lc = SP_LPETOOL_CONTEXT(ec); + + lpetool_delete_measuring_items(lc); + lpetool_create_measuring_items(lc, selection); + + // activate line segment combo box if a single item with LPELineSegment is selected + GtkAction* w = GTK_ACTION(g_object_get_data(tbl, "lpetool_line_segment_action")); + SPItem *item = selection->singleItem(); + if (item && SP_IS_LPE_ITEM(item) && lpetool_item_has_construction(lc, item)) { + SPLPEItem *lpeitem = SP_LPE_ITEM(item); + Effect* lpe = lpeitem->getCurrentLPE(); + if (lpe && lpe->effectType() == LINE_SEGMENT) { + LPELineSegment *lpels = static_cast<LPELineSegment*>(lpe); + g_object_set_data(tbl, "currentlpe", lpe); + g_object_set_data(tbl, "currentlpeitem", lpeitem); + gtk_action_set_sensitive(w, TRUE); + ege_select_one_action_set_active(EGE_SELECT_ONE_ACTION(w), lpels->end_type.get_value()); + } else { + g_object_set_data(tbl, "currentlpe", NULL); + g_object_set_data(tbl, "currentlpeitem", NULL); + gtk_action_set_sensitive(w, FALSE); + } + } else { + g_object_set_data(tbl, "currentlpe", NULL); + g_object_set_data(tbl, "currentlpeitem", NULL); + gtk_action_set_sensitive(w, FALSE); + } +} + +static void lpetool_toggle_show_bbox(GtkToggleAction *act, gpointer data) { + SPDesktop *desktop = static_cast<SPDesktop *>(data); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + bool show = gtk_toggle_action_get_active( act ); + prefs->setBool("/tools/lpetool/show_bbox", show); + + if (tools_isactive(desktop, TOOLS_LPETOOL)) { + LpeTool *lc = SP_LPETOOL_CONTEXT(desktop->event_context); + lpetool_context_reset_limiting_bbox(lc); + } +} + +static void lpetool_toggle_show_measuring_info(GtkToggleAction *act, GObject *tbl) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(tbl, "desktop")); + if (!tools_isactive(desktop, TOOLS_LPETOOL)) { + return; + } + + GtkAction *unitact = static_cast<GtkAction*>(g_object_get_data(tbl, "lpetool_units_action")); + LpeTool *lc = SP_LPETOOL_CONTEXT(desktop->event_context); + if (tools_isactive(desktop, TOOLS_LPETOOL)) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool show = gtk_toggle_action_get_active( act ); + prefs->setBool("/tools/lpetool/show_measuring_info", show); + lpetool_show_measuring_info(lc, show); + gtk_action_set_sensitive(GTK_ACTION(unitact), show); + } +} + +static void lpetool_unit_changed(GtkAction* /*act*/, GObject* tbl) +{ + UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker")); + Unit const *unit = tracker->getActiveUnit(); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString("/tools/lpetool/unit", unit->abbr); + + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + if (SP_IS_LPETOOL_CONTEXT(desktop->event_context)) { + LpeTool *lc = SP_LPETOOL_CONTEXT(desktop->event_context); + lpetool_delete_measuring_items(lc); + lpetool_create_measuring_items(lc); + } +} + +static void lpetool_toggle_set_bbox(GtkToggleAction *act, gpointer data) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(data); + Inkscape::Selection *selection = desktop->selection; + + Geom::OptRect bbox = selection->visualBounds(); + + if (bbox) { + Geom::Point A(bbox->min()); + Geom::Point B(bbox->max()); + + A *= desktop->doc2dt(); + B *= desktop->doc2dt(); + + // TODO: should we provide a way to store points in prefs? + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/tools/lpetool/bbox_upperleftx", A[Geom::X]); + prefs->setDouble("/tools/lpetool/bbox_upperlefty", A[Geom::Y]); + prefs->setDouble("/tools/lpetool/bbox_lowerrightx", B[Geom::X]); + prefs->setDouble("/tools/lpetool/bbox_lowerrighty", B[Geom::Y]); + + lpetool_context_reset_limiting_bbox(SP_LPETOOL_CONTEXT(desktop->event_context)); + } + + gtk_toggle_action_set_active(act, false); +} + +static void sp_line_segment_build_list(GObject *tbl) +{ + g_object_set_data(tbl, "line_segment_list_blocked", GINT_TO_POINTER(TRUE)); + + EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "lpetool_line_segment_action")); + GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector)); + gtk_list_store_clear (model); + + // TODO: we add the entries of rht combo box manually; later this should be done automatically + { + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, 0, _("Closed"), 1, 0, -1 ); + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, 0, _("Open start"), 1, 1, -1 ); + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, 0, _("Open end"), 1, 2, -1 ); + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, 0, _("Open both"), 1, 3, -1 ); + } + + g_object_set_data(tbl, "line_segment_list_blocked", GINT_TO_POINTER(FALSE)); +} + +static void sp_lpetool_change_line_segment_type(EgeSelectOneAction* act, GObject* tbl) +{ + using namespace Inkscape::LivePathEffect; + + // quit if run by the attr_changed listener + if (g_object_get_data(tbl, "freeze")) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE)); + + LPELineSegment *lpe = static_cast<LPELineSegment *>(g_object_get_data(tbl, "currentlpe")); + SPLPEItem *lpeitem = static_cast<SPLPEItem *>(g_object_get_data(tbl, "currentlpeitem")); + if (lpeitem) { + SPLPEItem *lpeitem = static_cast<SPLPEItem *>(g_object_get_data(tbl, "currentlpeitem")); + lpe->end_type.param_set_value(static_cast<Inkscape::LivePathEffect::EndType>(ege_select_one_action_get_active(act))); + sp_lpe_item_update_patheffect(lpeitem, true, true); + } + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void lpetool_open_lpe_dialog(GtkToggleAction *act, gpointer data) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(data); + + if (tools_isactive(desktop, TOOLS_LPETOOL)) { + sp_action_perform(Inkscape::Verb::get(SP_VERB_DIALOG_LIVE_PATH_EFFECT)->get_action(Inkscape::ActionContext(desktop)), NULL); + } + gtk_toggle_action_set_active(act, false); +} + +void sp_lpetool_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + UnitTracker* tracker = new UnitTracker(Inkscape::Util::UNIT_TYPE_LINEAR); + tracker->setActiveUnit(sp_desktop_namedview(desktop)->doc_units); + g_object_set_data(holder, "tracker", tracker); + Unit const *unit = tracker->getActiveUnit(); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString("/tools/lpetool/unit", unit->abbr); + + /** Automatically create a list of LPEs that get added to the toolbar **/ + { + GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); + + GtkTreeIter iter; + + // the first toggle button represents the state that no subtool is active (remove this when + // this can be modeled by EgeSelectOneAction or some other action) + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("All inactive"), + 1, _("No geometric tool is active"), + 2, "draw-geometry-inactive", + -1 ); + + Inkscape::LivePathEffect::EffectType type; + for (int i = 1; i < num_subtools; ++i) { // we start with i = 1 because INVALID_LPE was already added + type = lpesubtools[i].type; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str(), + 1, Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str(), + 2, lpesubtools[i].icon_name, + -1 ); + } + + EgeSelectOneAction* act = ege_select_one_action_new( "LPEToolModeAction", (""), (""), NULL, GTK_TREE_MODEL(model) ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "lpetool_mode_action", act ); + + ege_select_one_action_set_appearance( act, "full" ); + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); + ege_select_one_action_set_icon_column( act, 2 ); + ege_select_one_action_set_tooltip_column( act, 1 ); + + gint lpeToolMode = prefs->getInt("/tools/lpetool/mode", 0); + ege_select_one_action_set_active( act, lpeToolMode ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_lpetool_mode_changed), holder ); + } + + /* Show limiting bounding box */ + { + InkToggleAction* act = ink_toggle_action_new( "LPEShowBBoxAction", + _("Show limiting bounding box"), + _("Show bounding box (used to cut infinite lines)"), + "show-bounding-box", + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_show_bbox), desktop ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/lpetool/show_bbox", true ) ); + } + + /* Set limiting bounding box to bbox of current selection */ + { + InkToggleAction* act = ink_toggle_action_new( "LPEBBoxFromSelectionAction", + _("Get limiting bounding box from selection"), + _("Set limiting bounding box (used to cut infinite lines) to the bounding box of current selection"), + "draw-geometry-set-bounding-box", + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_set_bbox), desktop ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), FALSE ); + } + + + /* Combo box to choose line segment type */ + { + GtkListStore* model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT); + EgeSelectOneAction* act = ege_select_one_action_new ("LPELineSegmentAction", "" , (_("Choose a line segment type")), NULL, GTK_TREE_MODEL(model)); + ege_select_one_action_set_appearance (act, "compact"); + g_object_set_data (holder, "lpetool_line_segment_action", act ); + + g_object_set_data(holder, "line_segment_list_blocked", GINT_TO_POINTER(FALSE)); + + sp_line_segment_build_list (holder); + + g_signal_connect(G_OBJECT(act), "changed", G_CALLBACK(sp_lpetool_change_line_segment_type), holder); + gtk_action_set_sensitive( GTK_ACTION(act), FALSE ); + gtk_action_group_add_action(mainActions, GTK_ACTION(act)); + } + + /* Display measuring info for selected items */ + { + InkToggleAction* act = ink_toggle_action_new( "LPEMeasuringAction", + _("Display measuring info"), + _("Display measuring info for selected items"), + "draw-geometry-show-measuring-info", + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_show_measuring_info), holder ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/lpetool/show_measuring_info", true ) ); + } + + // add the units menu + { + GtkAction* act = tracker->createAction( "LPEToolUnitsAction", _("Units"), ("") ); + gtk_action_group_add_action( mainActions, act ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(lpetool_unit_changed), holder ); + g_object_set_data(holder, "lpetool_units_action", act); + gtk_action_set_sensitive(act, prefs->getBool("/tools/lpetool/show_measuring_info", true)); + } + + /* Open LPE dialog (to adapt parameters numerically) */ + { + InkToggleAction* act = ink_toggle_action_new( "LPEOpenLPEDialogAction", + _("Open LPE dialog"), + _("Open LPE dialog (to adapt parameters numerically)"), + "dialog-geometry", + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_open_lpe_dialog), desktop ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), FALSE ); + } + + //watch selection + Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISNodeToolbox"); + + sigc::connection *c_selection_modified = + new sigc::connection (sp_desktop_selection (desktop)->connectModified + (sigc::bind (sigc::ptr_fun (sp_lpetool_toolbox_sel_modified), holder))); + pool->add_connection ("selection-modified", c_selection_modified); + + sigc::connection *c_selection_changed = + new sigc::connection (sp_desktop_selection (desktop)->connectChanged + (sigc::bind (sigc::ptr_fun(sp_lpetool_toolbox_sel_changed), holder))); + pool->add_connection ("selection-changed", c_selection_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:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/lpe-toolbar.h b/src/widgets/lpe-toolbar.h new file mode 100644 index 000000000..3db2bcb65 --- /dev/null +++ b/src/widgets/lpe-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_LPE_TOOLBAR_H +#define SEEN_LPE_TOOLBAR_H + +/** + * @file + * LPE aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_lpetool_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_LPE_TOOLBAR_H */ diff --git a/src/widgets/measure-toolbar.cpp b/src/widgets/measure-toolbar.cpp new file mode 100644 index 000000000..46d3bd4e0 --- /dev/null +++ b/src/widgets/measure-toolbar.cpp @@ -0,0 +1,123 @@ +/** + * @file + * Measure aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glibmm/i18n.h> + +#include "measure-toolbar.h" +#include "desktop-handles.h" +#include "desktop.h" +#include "document-undo.h" +#include "ege-adjustment-action.h" +#include "ege-output-action.h" +#include "preferences.h" +#include "toolbox.h" +#include "ui/widget/unit-tracker.h" + +using Inkscape::UI::Widget::UnitTracker; +using Inkscape::Util::Unit; +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; + +//######################## +//## Measure Toolbox ## +//######################## + +static void +sp_measure_fontsize_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + + if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt(Glib::ustring("/tools/measure/fontsize"), + gtk_adjustment_get_value(adj)); + } +} + +static void measure_unit_changed(GtkAction* /*act*/, GObject* tbl) +{ + UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker")); + Glib::ustring const unit = tracker->getActiveUnit()->abbr; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString("/tools/measure/unit", unit); +} + +void sp_measure_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObject* holder) +{ + UnitTracker* tracker = new UnitTracker(Inkscape::Util::UNIT_TYPE_LINEAR); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + tracker->setActiveUnitByAbbr(prefs->getString("/tools/measure/unit").c_str()); + + g_object_set_data( holder, "tracker", tracker ); + + EgeAdjustmentAction *eact = 0; + + /* Font Size */ + { + eact = create_adjustment_action( "MeasureFontSizeAction", + _("Font Size"), _("Font Size:"), + _("The font size to be used in the measurement labels"), + "/tools/measure/fontsize", 0.0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 10, 36, 1.0, 4.0, + 0, 0, 0, + sp_measure_fontsize_value_changed); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + + // units label + { + EgeOutputAction* act = ege_output_action_new( "measure_units_label", _("Units:"), _("The units to be used for the measurements"), 0 ); + ege_output_action_set_use_markup( act, TRUE ); + g_object_set( act, "visible-overflown", FALSE, NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + } + + // units menu + { + GtkAction* act = tracker->createAction( "MeasureUnitsAction", _("Units:"), _("The units to be used for the measurements") ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(measure_unit_changed), holder ); + gtk_action_group_add_action( mainActions, act ); + } +} // end of sp_measure_toolbox_prep() + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/measure-toolbar.h b/src/widgets/measure-toolbar.h new file mode 100644 index 000000000..aff0a209b --- /dev/null +++ b/src/widgets/measure-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_MEASURE_TOOLBAR_H +#define SEEN_MEASURE_TOOLBAR_H + +/** + * @file + * Measue aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_measure_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_MEASURE_TOOLBAR_H */ diff --git a/src/widgets/mesh-toolbar.cpp b/src/widgets/mesh-toolbar.cpp new file mode 100644 index 000000000..15dda94f0 --- /dev/null +++ b/src/widgets/mesh-toolbar.cpp @@ -0,0 +1,366 @@ +/* + * Gradient aux toolbar + * + * Authors: + * bulia byak <bulia@dr.com> + * Johan Engelen <j.b.c.engelen@ewi.utwente.nl> + * Abhishek Sharma + * Tavmjong Bah <tavjong@free.fr> + * + * Copyright (C) 2012 Tavmjong Bah + * Copyright (C) 2007 Johan Engelen + * Copyright (C) 2005 authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +// REVIEW THESE AT END OF REWRITE +#include "ui/widget/color-preview.h" +#include "toolbox.h" +#include "mesh-toolbar.h" + +#include "verbs.h" + +#include "macros.h" +#include "widgets/button.h" +#include "widgets/widget-sizes.h" +#include "widgets/spw-utilities.h" +#include "widgets/spinbutton-events.h" +#include "widgets/gradient-vector.h" +#include "widgets/gradient-image.h" +#include "style.h" + +#include "preferences.h" +#include "document-private.h" +#include "document-undo.h" +#include "desktop.h" +#include "desktop-handles.h" +#include <glibmm/i18n.h> + +#include "ui/tools/gradient-tool.h" +#include "gradient-drag.h" +#include "sp-mesh-gradient.h" +#include "gradient-chemistry.h" +#include "gradient-selector.h" +#include "selection.h" +#include "ui/icon-names.h" + +#include "../ege-adjustment-action.h" +#include "../ege-output-action.h" +#include "../ege-select-one-action.h" +#include "../ink-action.h" +#include "../ink-comboboxentry-action.h" + +#include "sp-stop.h" +#include "svg/css-ostringstream.h" +#include "svg/svg-color.h" +#include "desktop-style.h" +#include "ui/tools/gradient-tool.h" + +#include "toolbox.h" + +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; + +static gboolean blocked = FALSE; + +//######################## +//## Mesh ## +//######################## + +/* + * Core function, setup all the widgets whenever something changes on the desktop + */ +static void ms_tb_selection_changed(Inkscape::Selection * /*selection*/, gpointer /*data*/) +{ + // DOES NOTHING AT MOMENT + + // std::cout << "ms_tb_selection_changed" << std::endl; + + // if (blocked) + // return; + + // GtkWidget *widget = GTK_WIDGET(data); + + // SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(G_OBJECT(widget), "desktop")); + // if (!desktop) { + // return; + // } + + // Inkscape::Selection *selection = sp_desktop_selection(desktop); // take from desktop, not from args + // if (selection) { + // ToolBase *ev = sp_desktop_event_context(desktop); + // GrDrag *drag = NULL; + // if (ev) { + // drag = ev->get_drag(); + // // Hide/show handles? + // } + + // } +} + + +static void ms_tb_selection_modified(Inkscape::Selection *selection, guint /*flags*/, gpointer data) +{ + ms_tb_selection_changed(selection, data); +} + +static void ms_drag_selection_changed(gpointer /*dragger*/, gpointer data) +{ + ms_tb_selection_changed(NULL, data); + +} + +static void ms_defs_release(SPObject * /*defs*/, GtkWidget *widget) +{ + ms_tb_selection_changed(NULL, widget); +} + +static void ms_defs_modified(SPObject * /*defs*/, guint /*flags*/, GtkWidget *widget) +{ + ms_tb_selection_changed(NULL, (gpointer) widget); +} + +static void ms_disconnect_sigc(GObject * /*obj*/, sigc::connection *connection) { + connection->disconnect(); + delete connection; +} + + +/* + * Callback functions for user actions + */ + +static void ms_new_type_changed( EgeSelectOneAction *act, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gint typemode = ege_select_one_action_get_active( act ) == 0 ? SP_GRADIENT_MESH_TYPE_NORMAL : SP_GRADIENT_MESH_TYPE_CONICAL; + prefs->setInt("/tools/mesh/mesh_type", typemode); +} + +static void ms_new_fillstroke_changed( EgeSelectOneAction *act, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Inkscape::PaintTarget fsmode = (ege_select_one_action_get_active( act ) == 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; + prefs->setInt("/tools/gradient/newfillorstroke", (fsmode == Inkscape::FOR_FILL) ? 1 : 0); +} + +static void ms_row_changed(GtkAdjustment *adj, GObject * /*tbl*/ ) +{ + if (blocked) { + return; + } + + blocked = TRUE; + + int rows = gtk_adjustment_get_value(adj); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + prefs->setInt("/tools/mesh/mesh_rows", rows); + + blocked = FALSE; +} + +static void ms_col_changed(GtkAdjustment *adj, GObject * /*tbl*/ ) +{ + if (blocked) { + return; + } + + blocked = TRUE; + + int cols = gtk_adjustment_get_value(adj); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + prefs->setInt("/tools/mesh/mesh_cols", cols); + + blocked = FALSE; +} + +/** + * Mesh auxiliary toolbar construction and setup. + * + */ +void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObject* holder) +{ + Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); + + EgeAdjustmentAction* eact = 0; + + /* New mesh: normal or conical */ + { + GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); + + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("normal"), 1, _("Create mesh gradient"), 2, INKSCAPE_ICON("paint-gradient-mesh"), -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("conical"), 1, _("Create conical gradient"), 2, INKSCAPE_ICON("paint-gradient-conical"), -1 ); + + EgeSelectOneAction* act = ege_select_one_action_new( "MeshNewTypeAction", (""), (""), NULL, GTK_TREE_MODEL(model) ); + g_object_set( act, "short_label", _("New:"), NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "mesh_new_type_action", act ); + + ege_select_one_action_set_appearance( act, "full" ); + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); + ege_select_one_action_set_icon_column( act, 2 ); + ege_select_one_action_set_tooltip_column( act, 1 ); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gint mode = prefs->getInt("/tools/mesh/mesh_type", SP_GRADIENT_MESH_TYPE_NORMAL) != SP_GRADIENT_MESH_TYPE_NORMAL; + ege_select_one_action_set_active( act, mode ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(ms_new_type_changed), holder ); + } + + /* New gradient on fill or stroke*/ + { + GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); + + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("fill"), 1, _("Create gradient in the fill"), 2, INKSCAPE_ICON("object-fill"), -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("stroke"), 1, _("Create gradient in the stroke"), 2, INKSCAPE_ICON("object-stroke"), -1 ); + + EgeSelectOneAction* act = ege_select_one_action_new( "MeshNewFillStrokeAction", (""), (""), NULL, GTK_TREE_MODEL(model) ); + g_object_set( act, "short_label", _("on:"), NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "mesh_new_fillstroke_action", act ); + + ege_select_one_action_set_appearance( act, "full" ); + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); + ege_select_one_action_set_icon_column( act, 2 ); + ege_select_one_action_set_tooltip_column( act, 1 ); + + /// @todo Convert to boolean? + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool fillstrokemode = !prefs->getBool("/tools/gradient/newfillorstroke", true); + ege_select_one_action_set_active( act, fillstrokemode ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(ms_new_fillstroke_changed), holder ); + } + + /* Number of mesh rows */ + { + gchar const* labels[] = {}; + gdouble values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + eact = create_adjustment_action( "MeshRowAction", + _("Rows"), _("Rows:"), _("Number of rows in new mesh"), + "/tools/mesh/mesh_rows", 1, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 1, 20, 1, 1, + labels, values, G_N_ELEMENTS(labels), + ms_row_changed, NULL /*unit tracker*/, + 1.0, 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + /* Number of mesh columns */ + { + gchar const* labels[] = {}; + gdouble values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + eact = create_adjustment_action( "MeshColumnAction", + _("Columns"), _("Columns:"), _("Number of columns in new mesh"), + "/tools/mesh/mesh_cols", 1, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 1, 20, 1, 1, + labels, values, G_N_ELEMENTS(labels), + ms_col_changed, NULL /*unit tracker*/, + 1.0, 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + /* Edit fill mesh */ + { + InkToggleAction* act = ink_toggle_action_new( "MeshEditFillAction", + _("Edit Fill"), + _("Edit fill mesh"), + INKSCAPE_ICON("object-fill"), + secondarySize ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/mesh/edit_fill"); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + } + + /* Edit stroke mesh */ + { + InkToggleAction* act = ink_toggle_action_new( "MeshEditStrokeAction", + _("Edit Stroke"), + _("Edit stroke mesh"), + INKSCAPE_ICON("object-stroke"), + secondarySize ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/mesh/edit_stroke"); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + } + + /* Show/hide side and tensor handles */ + { + InkToggleAction* act = ink_toggle_action_new( "MeshShowHandlesAction", + _("Show Handles"), + _("Show side and tensor handles"), + INKSCAPE_ICON("show-node-handles"), + secondarySize ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/mesh/show_handles"); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + } + + + Inkscape::Selection *selection = sp_desktop_selection (desktop); + SPDocument *document = sp_desktop_document (desktop); + + g_object_set_data(holder, "desktop", desktop); + + // connect to selection modified and changed signals + sigc::connection *conn1 = new sigc::connection( + selection->connectChanged(sigc::bind(sigc::ptr_fun(&ms_tb_selection_changed), (gpointer) holder))); + sigc::connection *conn2 = new sigc::connection( + selection->connectModified(sigc::bind(sigc::ptr_fun(&ms_tb_selection_modified), (gpointer) holder))); + sigc::connection *conn3 = new sigc::connection( + desktop->connectToolSubselectionChanged( sigc::bind(sigc::ptr_fun(&ms_drag_selection_changed), (gpointer) holder))); + + // when holder is destroyed, disconnect + g_signal_connect(G_OBJECT(holder), "destroy", G_CALLBACK(ms_disconnect_sigc), conn1); + g_signal_connect(G_OBJECT(holder), "destroy", G_CALLBACK(ms_disconnect_sigc), conn2); + g_signal_connect(G_OBJECT(holder), "destroy", G_CALLBACK(ms_disconnect_sigc), conn3); + + // connect to release and modified signals of the defs (i.e. when someone changes mesh) + sigc::connection *release_connection = new sigc::connection(); + *release_connection = document->getDefs()->connectRelease(sigc::bind<1>(sigc::ptr_fun(&ms_defs_release), GTK_WIDGET(holder))); + sigc::connection *modified_connection = new sigc::connection(); + *modified_connection = document->getDefs()->connectModified(sigc::bind<2>(sigc::ptr_fun(&ms_defs_modified), GTK_WIDGET(holder))); + + // when holder is destroyed, disconnect + g_signal_connect(G_OBJECT(holder), "destroy", G_CALLBACK(ms_disconnect_sigc), release_connection); + g_signal_connect(G_OBJECT(holder), "destroy", G_CALLBACK(ms_disconnect_sigc), modified_connection); + +} + +/* + 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 : diff --git a/src/widgets/mesh-toolbar.h b/src/widgets/mesh-toolbar.h new file mode 100644 index 000000000..fd3f4b4b7 --- /dev/null +++ b/src/widgets/mesh-toolbar.h @@ -0,0 +1,24 @@ +#ifndef SEEN_MESH_TOOLBAR_H +#define SEEN_MESH_TOOLBAR_H + +/* + * Mesh aux toolbar + * + * Authors: + * bulia byak <bulia@dr.com> + * Tavmjong Bah <tavmjong@free.fr> + * + * Copyright (C) 2012 authors + * Copyright (C) 2005 authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_mesh_toolbox_prep( SPDesktop * /*desktop*/, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_MESH_TOOLBAR_H */ diff --git a/src/widgets/node-toolbar.cpp b/src/widgets/node-toolbar.cpp new file mode 100644 index 000000000..53161857a --- /dev/null +++ b/src/widgets/node-toolbar.cpp @@ -0,0 +1,654 @@ +/** + * @file + * Node aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ui/tool/multi-path-manipulator.h" +#include <glibmm/i18n.h> +#include "node-toolbar.h" +#include "connection-pool.h" +#include "desktop-handles.h" +#include "desktop.h" +#include "document-undo.h" +#include "ege-adjustment-action.h" +#include "ink-action.h" +#include "inkscape.h" +#include "preferences.h" +#include "selection-chemistry.h" +#include "selection.h" +#include "sp-namedview.h" +#include "toolbox.h" +#include "ui/icon-names.h" +#include "ui/tool/control-point-selection.h" +#include "ui/tools/node-tool.h" +#include "ui/widget/unit-tracker.h" +#include "util/units.h" +#include "verbs.h" +#include "widgets/widget-sizes.h" + +using Inkscape::UI::Widget::UnitTracker; +using Inkscape::Util::Unit; +using Inkscape::Util::Quantity; +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; +using Inkscape::Util::unit_table; +using Inkscape::UI::Tools::NodeTool; + +//#################################### +//# node editing callbacks +//#################################### + +/** Temporary hack: Returns the node tool in the active desktop. + * Will go away during tool refactoring. */ +static NodeTool *get_node_tool() +{ + NodeTool *tool = 0; + if (SP_ACTIVE_DESKTOP ) { + Inkscape::UI::Tools::ToolBase *ec = SP_ACTIVE_DESKTOP->event_context; + if (INK_IS_NODE_TOOL(ec)) { + tool = static_cast<NodeTool*>(ec); + } + } + return tool; +} + +static void sp_node_path_edit_add(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->insertNodes(); + } +} + +static void sp_node_path_edit_add_min_x(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->insertNodesAtExtrema(Inkscape::UI::PointManipulator::EXTR_MIN_X); + } +} +static void sp_node_path_edit_add_max_x(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->insertNodesAtExtrema(Inkscape::UI::PointManipulator::EXTR_MAX_X); + } +} +static void sp_node_path_edit_add_min_y(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->insertNodesAtExtrema(Inkscape::UI::PointManipulator::EXTR_MIN_Y); + } +} +static void sp_node_path_edit_add_max_y(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->insertNodesAtExtrema(Inkscape::UI::PointManipulator::EXTR_MAX_Y); + } +} + +static void sp_node_path_edit_delete(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + nt->_multipath->deleteNodes(prefs->getBool("/tools/nodes/delete_preserves_shape", true)); + } +} + +static void sp_node_path_edit_delete_segment(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->deleteSegments(); + } +} + +static void sp_node_path_edit_break(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->breakNodes(); + } +} + +static void sp_node_path_edit_join(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->joinNodes(); + } +} + +static void sp_node_path_edit_join_segment(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->joinSegments(); + } +} + +static void sp_node_path_edit_toline(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->setSegmentType(Inkscape::UI::SEGMENT_STRAIGHT); + } +} + +static void sp_node_path_edit_tocurve(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->setSegmentType(Inkscape::UI::SEGMENT_CUBIC_BEZIER); + } +} + +static void sp_node_path_edit_cusp(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->setNodeType(Inkscape::UI::NODE_CUSP); + } +} + +static void sp_node_path_edit_smooth(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->setNodeType(Inkscape::UI::NODE_SMOOTH); + } +} + +static void sp_node_path_edit_symmetrical(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->setNodeType(Inkscape::UI::NODE_SYMMETRIC); + } +} + +static void sp_node_path_edit_auto(void) +{ + NodeTool *nt = get_node_tool(); + if (nt) { + nt->_multipath->setNodeType(Inkscape::UI::NODE_AUTO); + } +} + +static void sp_node_path_edit_nextLPEparam(GtkAction * /*act*/, gpointer data) { + sp_selection_next_patheffect_param( reinterpret_cast<SPDesktop*>(data) ); +} + +/* is called when the node selection is modified */ +static void sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl) +{ + GtkAction* xact = GTK_ACTION( g_object_get_data( tbl, "nodes_x_action" ) ); + GtkAction* yact = GTK_ACTION( g_object_get_data( tbl, "nodes_y_action" ) ); + GtkAdjustment *xadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(xact)); + GtkAdjustment *yadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(yact)); + + // quit if run by the attr_changed listener + if (g_object_get_data( tbl, "freeze" )) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE)); + + UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) ); + if (!tracker) { + return; + } + Unit const *unit = tracker->getActiveUnit(); + + NodeTool *nt = get_node_tool(); + if (!nt || !(nt->_selected_nodes) ||nt->_selected_nodes->empty()) { + // no path selected + gtk_action_set_sensitive(xact, FALSE); + gtk_action_set_sensitive(yact, FALSE); + } else { + gtk_action_set_sensitive(xact, TRUE); + gtk_action_set_sensitive(yact, TRUE); + Geom::Coord oldx = Quantity::convert(gtk_adjustment_get_value(xadj), unit, "px"); + Geom::Coord oldy = Quantity::convert(gtk_adjustment_get_value(yadj), unit, "px"); + Geom::Point mid = nt->_selected_nodes->pointwiseBounds()->midpoint(); + + if (oldx != mid[Geom::X]) { + gtk_adjustment_set_value(xadj, Quantity::convert(mid[Geom::X], "px", unit)); + } + if (oldy != mid[Geom::Y]) { + gtk_adjustment_set_value(yadj, Quantity::convert(mid[Geom::Y], "px", unit)); + } + } + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, Geom::Dim2 d) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" )); + if (!tracker) { + return; + } + Unit const *unit = tracker->getActiveUnit(); + + if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { + prefs->setDouble(Glib::ustring("/tools/nodes/") + (d == Geom::X ? "x" : "y"), + Quantity::convert(gtk_adjustment_get_value(adj), unit, "px")); + } + + // quit if run by the attr_changed listener + if (g_object_get_data( tbl, "freeze" )) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE)); + + NodeTool *nt = get_node_tool(); + if (nt && !nt->_selected_nodes->empty()) { + double val = Quantity::convert(gtk_adjustment_get_value(adj), unit, "px"); + double oldval = nt->_selected_nodes->pointwiseBounds()->midpoint()[d]; + Geom::Point delta(0,0); + delta[d] = val - oldval; + nt->_multipath->move(delta); + } + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_node_path_x_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + sp_node_path_value_changed(adj, tbl, Geom::X); +} + +static void sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + sp_node_path_value_changed(adj, tbl, Geom::Y); +} + +static void sp_node_toolbox_sel_changed(Inkscape::Selection *selection, GObject *tbl) +{ + { + GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_lpeedit" ) ); + SPItem *item = selection->singleItem(); + if (item && SP_IS_LPE_ITEM(item)) { + if (SP_LPE_ITEM(item)->hasPathEffect()) { + gtk_action_set_sensitive(w, TRUE); + } else { + gtk_action_set_sensitive(w, FALSE); + } + } else { + gtk_action_set_sensitive(w, FALSE); + } + } +} + +static void sp_node_toolbox_sel_modified(Inkscape::Selection *selection, guint /*flags*/, GObject *tbl) +{ + sp_node_toolbox_sel_changed (selection, tbl); +} + + + +//################################ +//## Node Editing Toolbox ## +//################################ + +void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + UnitTracker* tracker = new UnitTracker(Inkscape::Util::UNIT_TYPE_LINEAR); + Unit doc_units = *sp_desktop_namedview(desktop)->doc_units; + tracker->setActiveUnit(&doc_units); + g_object_set_data( holder, "tracker", tracker ); + + Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); + + { + InkToolMenuAction* inky = ink_tool_menu_action_new( "NodeInsertAction", + _("Insert node"), + _("Insert new nodes into selected segments"), + INKSCAPE_ICON("node-add"), + secondarySize ); + g_object_set( INK_ACTION(inky), "short_label", _("Insert"), NULL ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + GtkToolItem *menu_tool_button = gtk_menu_tool_button_new (NULL, NULL); + gtk_activatable_set_related_action (GTK_ACTIVATABLE (menu_tool_button), GTK_ACTION(inky)); + // also create dummy menu action: + gtk_action_group_add_action( mainActions, gtk_action_new("NodeInsertActionMenu", NULL, NULL, NULL) ); + } + + { + InkAction* inky = ink_action_new( "NodeInsertActionMinX", + _("Insert node at min X"), + _("Insert new nodes at min X into selected segments"), + INKSCAPE_ICON("node_insert_min_x"), + secondarySize ); + g_object_set( inky, "short_label", _("Insert min X"), NULL ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add_min_x), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + { + InkAction* inky = ink_action_new( "NodeInsertActionMaxX", + _("Insert node at max X"), + _("Insert new nodes at max X into selected segments"), + INKSCAPE_ICON("node_insert_max_x"), + secondarySize ); + g_object_set( inky, "short_label", _("Insert max X"), NULL ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add_max_x), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + { + InkAction* inky = ink_action_new( "NodeInsertActionMinY", + _("Insert node at min Y"), + _("Insert new nodes at min Y into selected segments"), + INKSCAPE_ICON("node_insert_min_y"), + secondarySize ); + g_object_set( inky, "short_label", _("Insert min Y"), NULL ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add_min_y), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + { + InkAction* inky = ink_action_new( "NodeInsertActionMaxY", + _("Insert node at max Y"), + _("Insert new nodes at max Y into selected segments"), + INKSCAPE_ICON("node_insert_max_y"), + secondarySize ); + g_object_set( inky, "short_label", _("Insert max Y"), NULL ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add_max_y), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + { + InkAction* inky = ink_action_new( "NodeDeleteAction", + _("Delete node"), + _("Delete selected nodes"), + INKSCAPE_ICON("node-delete"), + secondarySize ); + g_object_set( inky, "short_label", _("Delete"), NULL ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + { + InkAction* inky = ink_action_new( "NodeJoinAction", + _("Join nodes"), + _("Join selected nodes"), + INKSCAPE_ICON("node-join"), + secondarySize ); + g_object_set( inky, "short_label", _("Join"), NULL ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + { + InkAction* inky = ink_action_new( "NodeBreakAction", + _("Break nodes"), + _("Break path at selected nodes"), + INKSCAPE_ICON("node-break"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + + { + InkAction* inky = ink_action_new( "NodeJoinSegmentAction", + _("Join with segment"), + _("Join selected endnodes with a new segment"), + INKSCAPE_ICON("node-join-segment"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + { + InkAction* inky = ink_action_new( "NodeDeleteSegmentAction", + _("Delete segment"), + _("Delete segment between two non-endpoint nodes"), + INKSCAPE_ICON("node-delete-segment"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + { + InkAction* inky = ink_action_new( "NodeCuspAction", + _("Node Cusp"), + _("Make selected nodes corner"), + INKSCAPE_ICON("node-type-cusp"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + { + InkAction* inky = ink_action_new( "NodeSmoothAction", + _("Node Smooth"), + _("Make selected nodes smooth"), + INKSCAPE_ICON("node-type-smooth"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + { + InkAction* inky = ink_action_new( "NodeSymmetricAction", + _("Node Symmetric"), + _("Make selected nodes symmetric"), + INKSCAPE_ICON("node-type-symmetric"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + { + InkAction* inky = ink_action_new( "NodeAutoAction", + _("Node Auto"), + _("Make selected nodes auto-smooth"), + INKSCAPE_ICON("node-type-auto-smooth"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_auto), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + { + InkAction* inky = ink_action_new( "NodeLineAction", + _("Node Line"), + _("Make selected segments lines"), + INKSCAPE_ICON("node-segment-line"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + { + InkAction* inky = ink_action_new( "NodeCurveAction", + _("Node Curve"), + _("Make selected segments curves"), + INKSCAPE_ICON("node-segment-curve"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + { + InkToggleAction* act = ink_toggle_action_new( "NodesShowTransformHandlesAction", + _("Show Transform Handles"), + _("Show transformation handles for selected nodes"), + "node-transform", + secondarySize ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/nodes/show_transform_handles"); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + } + + { + InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction", + _("Show Handles"), + _("Show Bezier handles of selected nodes"), + INKSCAPE_ICON("show-node-handles"), + secondarySize ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/nodes/show_handles"); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + } + + { + InkToggleAction* act = ink_toggle_action_new( "NodesShowHelperpath", + _("Show Outline"), + _("Show path outline (without path effects)"), + INKSCAPE_ICON("show-path-outline"), + secondarySize ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/nodes/show_outline"); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + } + + { + Inkscape::Verb* verb = Inkscape::Verb::get(SP_VERB_EDIT_NEXT_PATHEFFECT_PARAMETER); + InkAction* inky = ink_action_new( verb->get_id(), + verb->get_name(), + verb->get_tip(), + INKSCAPE_ICON("path-effect-parameter-next"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_nextLPEparam), desktop ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + g_object_set_data( holder, "nodes_lpeedit", inky); + } + + { + InkToggleAction* inky = ink_toggle_action_new( "ObjectEditClipPathAction", + _("Edit clipping paths"), + _("Show clipping path(s) of selected object(s)"), + INKSCAPE_ICON("path-clip-edit"), + secondarySize ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(inky), "/tools/nodes/edit_clipping_paths"); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + } + + { + InkToggleAction* inky = ink_toggle_action_new( "ObjectEditMaskPathAction", + _("Edit masks"), + _("Show mask(s) of selected object(s)"), + INKSCAPE_ICON("path-mask-edit"), + secondarySize ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(inky), "/tools/nodes/edit_masks"); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + } + + /* X coord of selected node(s) */ + { + EgeAdjustmentAction* eact = 0; + gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500}; + eact = create_adjustment_action( "NodeXAction", + _("X coordinate:"), _("X:"), _("X coordinate of selected node(s)"), + "/tools/nodes/Xcoord", 0, + GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-nodes", + -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP, + labels, values, G_N_ELEMENTS(labels), + sp_node_path_x_value_changed, tracker ); + tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); + g_object_set_data( holder, "nodes_x_action", eact ); + gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + /* Y coord of selected node(s) */ + { + EgeAdjustmentAction* eact = 0; + gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500}; + eact = create_adjustment_action( "NodeYAction", + _("Y coordinate:"), _("Y:"), _("Y coordinate of selected node(s)"), + "/tools/nodes/Ycoord", 0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP, + labels, values, G_N_ELEMENTS(labels), + sp_node_path_y_value_changed, tracker ); + tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); + g_object_set_data( holder, "nodes_y_action", eact ); + gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + // add the units menu + { + GtkAction* act = tracker->createAction( "NodeUnitsAction", _("Units"), ("") ); + gtk_action_group_add_action( mainActions, act ); + } + + + sp_node_toolbox_sel_changed(sp_desktop_selection(desktop), holder); + + //watch selection + Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISNodeToolbox"); + + sigc::connection *c_selection_changed = + new sigc::connection (sp_desktop_selection (desktop)->connectChanged + (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_changed), holder))); + pool->add_connection ("selection-changed", c_selection_changed); + + sigc::connection *c_selection_modified = + new sigc::connection (sp_desktop_selection (desktop)->connectModified + (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_modified), holder))); + pool->add_connection ("selection-modified", c_selection_modified); + + sigc::connection *c_subselection_changed = + new sigc::connection (desktop->connectToolSubselectionChanged + (sigc::bind (sigc::ptr_fun (sp_node_toolbox_coord_changed), holder))); + pool->add_connection ("tool-subselection-changed", c_subselection_changed); + + Inkscape::ConnectionPool::connect_destroy (G_OBJECT (holder), pool); + + g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); +} // end of sp_node_toolbox_prep() + + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/node-toolbar.h b/src/widgets/node-toolbar.h new file mode 100644 index 000000000..1f2a3f6b7 --- /dev/null +++ b/src/widgets/node-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_NODE_TOOLBAR_H +#define SEEN_NODE_TOOLBAR_H + +/** + * @file + * Node aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_SELECT_TOOLBAR_H */ diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index c1147f9b0..9466c875e 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -24,6 +24,9 @@ #include <cstring> #include <string> +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif #include "widgets/swatch-selector.h" #include "../sp-pattern.h" @@ -33,8 +36,8 @@ #include "xml/repr.h" #include "sp-color-notebook.h" -#include "sp-linear-gradient-fns.h" -#include "sp-radial-gradient-fns.h" +#include "sp-linear-gradient.h" +#include "sp-radial-gradient.h" /* fixme: Move it from dialogs to here */ #include "gradient-selector.h" #include <inkscape.h> @@ -70,7 +73,7 @@ enum { static void sp_paint_selector_class_init(SPPaintSelectorClass *klass); static void sp_paint_selector_init(SPPaintSelector *slider); -static void sp_paint_selector_destroy(GtkObject *object); +static void sp_paint_selector_dispose(GObject *object); static GtkWidget *sp_paint_selector_style_button_add(SPPaintSelector *psel, gchar const *px, SPPaintSelector::Mode mode, gchar const *tip); static void sp_paint_selector_style_button_toggled(GtkToggleButton *tb, SPPaintSelector *psel); @@ -157,54 +160,54 @@ GType sp_paint_selector_get_type(void) static void sp_paint_selector_class_init(SPPaintSelectorClass *klass) { - GtkObjectClass *object_class = (GtkObjectClass *) klass; + GObjectClass *object_class = G_OBJECT_CLASS(klass); - parent_class = (GtkVBoxClass*)g_type_class_peek_parent(klass); + parent_class = GTK_VBOX_CLASS(g_type_class_peek_parent(klass)); psel_signals[MODE_CHANGED] = g_signal_new("mode_changed", G_TYPE_FROM_CLASS(object_class), (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), G_STRUCT_OFFSET(SPPaintSelectorClass, mode_changed), - NULL, NULL, + NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); psel_signals[GRABBED] = g_signal_new("grabbed", G_TYPE_FROM_CLASS(object_class), (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), G_STRUCT_OFFSET(SPPaintSelectorClass, grabbed), - NULL, NULL, + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); psel_signals[DRAGGED] = g_signal_new("dragged", G_TYPE_FROM_CLASS(object_class), (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), G_STRUCT_OFFSET(SPPaintSelectorClass, dragged), - NULL, NULL, + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); psel_signals[RELEASED] = g_signal_new("released", G_TYPE_FROM_CLASS(object_class), (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), G_STRUCT_OFFSET(SPPaintSelectorClass, released), - NULL, NULL, + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); psel_signals[CHANGED] = g_signal_new("changed", G_TYPE_FROM_CLASS(object_class), (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), G_STRUCT_OFFSET(SPPaintSelectorClass, changed), - NULL, NULL, + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); psel_signals[FILLRULE_CHANGED] = g_signal_new("fillrule_changed", G_TYPE_FROM_CLASS(object_class), (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), G_STRUCT_OFFSET(SPPaintSelectorClass, fillrule_changed), - NULL, NULL, + NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); - object_class->destroy = sp_paint_selector_destroy; + object_class->dispose = sp_paint_selector_dispose; } #define XPAD 4 @@ -245,8 +248,8 @@ sp_paint_selector_init(SPPaintSelector *psel) /* Fillrule */ { #if GTK_CHECK_VERSION(3,0,0) - psel->fillrulebox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_set_homogeneous(GTK_BOX(psel->fillrulebox), FALSE); + psel->fillrulebox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_set_homogeneous(GTK_BOX(psel->fillrulebox), FALSE); #else psel->fillrulebox = gtk_hbox_new(FALSE, 0); #endif @@ -304,16 +307,15 @@ sp_paint_selector_init(SPPaintSelector *psel) psel->alpha = 1.0; } -static void -sp_paint_selector_destroy(GtkObject *object) +static void sp_paint_selector_dispose(GObject *object) { SPPaintSelector *psel = SP_PAINT_SELECTOR(object); // clean up our long-living pattern menu g_object_set_data(G_OBJECT(psel),"patternmenu",NULL); - if (((GtkObjectClass *) parent_class)->destroy) - (* ((GtkObjectClass *) parent_class)->destroy)(object); + if ((G_OBJECT_CLASS(parent_class))->dispose) + (* (G_OBJECT_CLASS(parent_class))->dispose)(object); } static GtkWidget *sp_paint_selector_style_button_add(SPPaintSelector *psel, @@ -360,7 +362,7 @@ sp_paint_selector_fillrule_toggled(GtkToggleButton *tb, SPPaintSelector *psel) } } -void +static void sp_paint_selector_show_fillrule(SPPaintSelector *psel, bool is_fill) { if (psel->fillrulebox) { @@ -656,15 +658,15 @@ static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelec if ((psel->mode == SPPaintSelector::MODE_COLOR_RGB) || (psel->mode == SPPaintSelector::MODE_COLOR_CMYK)) { /* Already have color selector */ - csel = (GtkWidget*)g_object_get_data(G_OBJECT(psel->selector), "color-selector"); + csel = GTK_WIDGET(g_object_get_data(G_OBJECT(psel->selector), "color-selector")); } else { sp_paint_selector_clear_frame(psel); /* Create new color selector */ /* Create vbox */ #if GTK_CHECK_VERSION(3,0,0) - GtkWidget *vb = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); - gtk_box_set_homogeneous(GTK_BOX(vb), FALSE); + GtkWidget *vb = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); + gtk_box_set_homogeneous(GTK_BOX(vb), FALSE); #else GtkWidget *vb = gtk_vbox_new(FALSE, 4); #endif @@ -733,7 +735,7 @@ static void sp_paint_selector_set_mode_gradient(SPPaintSelector *psel, SPPaintSe if ((psel->mode == SPPaintSelector::MODE_GRADIENT_LINEAR) || (psel->mode == SPPaintSelector::MODE_GRADIENT_RADIAL)) { /* Already have gradient selector */ - gsel = (GtkWidget*)g_object_get_data(G_OBJECT(psel->selector), "gradient-selector"); + gsel = GTK_WIDGET(g_object_get_data(G_OBJECT(psel->selector), "gradient-selector")); } else { sp_paint_selector_clear_frame(psel); /* Create new gradient selector */ @@ -792,7 +794,7 @@ static void sp_psel_pattern_change(GtkWidget * /*widget*/, SPPaintSelector *psel * Returns a list of patterns in the defs of the given source document as a GSList object * Returns NULL if there are no patterns in the document. */ -GSList * +static GSList * ink_pattern_list_get (SPDocument *source) { if (source == NULL) @@ -800,7 +802,7 @@ ink_pattern_list_get (SPDocument *source) GSList *pl = NULL; GSList const *patterns = source->getResourceList("pattern"); - for (GSList *l = (GSList *) patterns; l != NULL; l = l->next) { + for (GSList *l = const_cast<GSList *>(patterns); l != NULL; l = l->next) { if (SP_PATTERN(l->data) == pattern_getroot(SP_PATTERN(l->data))) { // only if this is a root pattern pl = g_slist_prepend(pl, l->data); } @@ -996,14 +998,14 @@ static void sp_paint_selector_set_mode_pattern(SPPaintSelector *psel, SPPaintSel if (psel->mode == SPPaintSelector::MODE_PATTERN) { /* Already have pattern menu */ - tbl = (GtkWidget*)g_object_get_data(G_OBJECT(psel->selector), "pattern-selector"); + tbl = GTK_WIDGET(g_object_get_data(G_OBJECT(psel->selector), "pattern-selector")); } else { sp_paint_selector_clear_frame(psel); /* Create vbox */ #if GTK_CHECK_VERSION(3,0,0) - tbl = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); - gtk_box_set_homogeneous(GTK_BOX(tbl), FALSE); + tbl = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); + gtk_box_set_homogeneous(GTK_BOX(tbl), FALSE); #else tbl = gtk_vbox_new(FALSE, 4); #endif @@ -1082,7 +1084,7 @@ SPPattern *SPPaintSelector::getPattern() SPPattern *pat = 0; g_return_val_if_fail((mode == MODE_PATTERN) , NULL); - GtkWidget *combo = (GtkWidget *) g_object_get_data(G_OBJECT(this), "patternmenu"); + GtkWidget *combo = GTK_WIDGET(g_object_get_data(G_OBJECT(this), "patternmenu")); /* no pattern menu if we were just selected */ if ( combo == NULL ) { @@ -1108,14 +1110,18 @@ SPPattern *SPPaintSelector::getPattern() if (strcmp(patid, "none")){ - gchar *paturn = g_strdup(patid); - if (stockid) { + gchar *paturn; + if (stockid) { paturn = g_strconcat("urn:inkscape:pattern:",patid,NULL); } + else { + paturn = g_strdup(patid); + } SPObject *pat_obj = get_stock_item(paturn); if (pat_obj) { pat = SP_PATTERN(pat_obj); } + g_free(paturn); } else { pat = pattern_getroot(SP_PATTERN(patid)); } @@ -1135,10 +1141,8 @@ static void sp_paint_selector_set_mode_swatch(SPPaintSelector *psel, SPPaintSele gtk_widget_set_sensitive(psel->style, TRUE); - SwatchSelector *swatchsel = 0; - if (psel->mode == SPPaintSelector::MODE_SWATCH){ - swatchsel = static_cast<SwatchSelector*>(g_object_get_data(G_OBJECT(psel->selector), "swatch-selector")); + // swatchsel = static_cast<SwatchSelector*>(g_object_get_data(G_OBJECT(psel->selector), "swatch-selector")); } else { sp_paint_selector_clear_frame(psel); // Create new gradient selector diff --git a/src/widgets/paint-selector.h b/src/widgets/paint-selector.h index d6ad3f50c..d3b3f4116 100644 --- a/src/widgets/paint-selector.h +++ b/src/widgets/paint-selector.h @@ -23,7 +23,7 @@ class SPGradient; class SPDesktop; class SPPattern; -class SPStyle; +struct SPStyle; #define SP_TYPE_PAINT_SELECTOR (sp_paint_selector_get_type ()) #define SP_PAINT_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_PAINT_SELECTOR, SPPaintSelector)) diff --git a/src/widgets/paintbucket-toolbar.cpp b/src/widgets/paintbucket-toolbar.cpp new file mode 100644 index 000000000..e20811de8 --- /dev/null +++ b/src/widgets/paintbucket-toolbar.cpp @@ -0,0 +1,231 @@ +/** + * @file + * Paint bucket aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glibmm/i18n.h> + +#include "paintbucket-toolbar.h" +#include "desktop.h" +#include "document-undo.h" +#include "ege-adjustment-action.h" +#include "ege-select-one-action.h" +#include "preferences.h" +#include "toolbox.h" +#include "ui/icon-names.h" +#include "ui/tools/flood-tool.h" +#include "ui/uxmanager.h" +#include "ui/widget/unit-tracker.h" +#include "util/units.h" + +using Inkscape::UI::Widget::UnitTracker; +using Inkscape::UI::UXManager; +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; +using Inkscape::Util::unit_table; + + +//######################### +//## Paintbucket ## +//######################### + +static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/) +{ + gint channels = ege_select_one_action_get_active( act ); + //flood_channels_set_channels( channels ); + Inkscape::UI::Tools::FloodTool::set_channels(channels); +} + +static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject * /*tbl*/) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt("/tools/paintbucket/threshold", (gint)gtk_adjustment_get_value(adj)); +} + +static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject * /*tbl*/) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/paintbucket/autogap", ege_select_one_action_get_active( act )); +} + +static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl) +{ + UnitTracker* tracker = static_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" )); + Unit const *unit = tracker->getActiveUnit(); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + // Don't adjust the offset value because we're saving the + // unit and it'll be correctly handled on load. + prefs->setDouble("/tools/paintbucket/offset", (gdouble)gtk_adjustment_get_value(adj)); + prefs->setString("/tools/paintbucket/offsetunits", unit->abbr); +} + +static void paintbucket_defaults(GtkWidget *, GObject *tbl) +{ + // FIXME: make defaults settable via Inkscape Options + struct KeyValue { + char const *key; + double value; + } const key_values[] = { + {"threshold", 15}, + {"offset", 0.0} + }; + + for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) { + KeyValue const &kv = key_values[i]; + GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(tbl, kv.key)); + if ( adj ) { + gtk_adjustment_set_value(adj, kv.value); + } + } + + EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "channels_action" ) ); + ege_select_one_action_set_active( channels_action, Inkscape::UI::Tools::FLOOD_CHANNELS_RGB ); + EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "autogap_action" ) ); + ege_select_one_action_set_active( autogap_action, 0 ); +} + +void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + EgeAdjustmentAction* eact = 0; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + { + GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); + + GList* items = 0; + gint count = 0; + for ( items = Inkscape::UI::Tools::flood_channels_dropdown_items_list(); items ; items = g_list_next(items) ) + { + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 ); + count++; + } + g_list_free( items ); + items = 0; + EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) ); + g_object_set( act1, "short_label", _("Fill by:"), NULL ); + ege_select_one_action_set_appearance( act1, "compact" ); + ege_select_one_action_set_active( act1, prefs->getInt("/tools/paintbucket/channels", 0) ); + g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act1) ); + g_object_set_data( holder, "channels_action", act1 ); + } + + // Spacing spinbox + { + eact = create_adjustment_action( + "ThresholdAction", + _("Fill Threshold"), _("Threshold:"), + _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"), + "/tools/paintbucket/threshold", 5, GTK_WIDGET(desktop->canvas), holder, TRUE, + "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0, + 0, 0, 0, + paintbucket_threshold_changed, NULL /*unit tracker*/, 1, 0 ); + + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + // Create the units menu. + UnitTracker* tracker = new UnitTracker(Inkscape::Util::UNIT_TYPE_LINEAR); + Glib::ustring stored_unit = prefs->getString("/tools/paintbucket/offsetunits"); + if (!stored_unit.empty()) { + Unit const *u = unit_table.getUnit(stored_unit); + tracker->setActiveUnit(u); + } + g_object_set_data( holder, "tracker", tracker ); + { + GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), ("") ); + gtk_action_group_add_action( mainActions, act ); + } + + // Offset spinbox + { + eact = create_adjustment_action( + "OffsetAction", + _("Grow/shrink by"), _("Grow/shrink by:"), + _("The amount to grow (positive) or shrink (negative) the created fill path"), + "/tools/paintbucket/offset", 0, GTK_WIDGET(desktop->canvas), holder, TRUE, + "inkscape:paintbucket-offset", -1e4, 1e4, 0.1, 0.5, + 0, 0, 0, + paintbucket_offset_changed, tracker, 1, 2); + tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); + + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + /* Auto Gap */ + { + GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); + + GList* items = 0; + gint count = 0; + for ( items = Inkscape::UI::Tools::flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) ) + { + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 ); + count++; + } + g_list_free( items ); + items = 0; + EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) ); + g_object_set( act2, "short_label", _("Close gaps:"), NULL ); + ege_select_one_action_set_appearance( act2, "compact" ); + ege_select_one_action_set_active( act2, prefs->getBool("/tools/paintbucket/autogap") ); + g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act2) ); + g_object_set_data( holder, "autogap_action", act2 ); + } + + /* Reset */ + { + GtkAction* act = gtk_action_new( "PaintbucketResetAction", + _("Defaults"), + _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), + INKSCAPE_ICON("edit-clear")); + g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder ); + gtk_action_group_add_action( mainActions, act ); + gtk_action_set_sensitive( act, 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/paintbucket-toolbar.h b/src/widgets/paintbucket-toolbar.h new file mode 100644 index 000000000..9e6d6194a --- /dev/null +++ b/src/widgets/paintbucket-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_PAINTBUCKET_TOOLBAR_H +#define SEEN_PAINTBUCKET_TOOLBAR_H + +/** + * @file + * Paintbucket aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_PAINTBUCKET_TOOLBAR_H */ diff --git a/src/widgets/pencil-toolbar.cpp b/src/widgets/pencil-toolbar.cpp new file mode 100644 index 000000000..6598e995a --- /dev/null +++ b/src/widgets/pencil-toolbar.cpp @@ -0,0 +1,322 @@ +/** + * @file + * Pencil aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glibmm/i18n.h> + +#include "pencil-toolbar.h" +#include "desktop.h" +#include "document-undo.h" +#include "ege-adjustment-action.h" +#include "ege-select-one-action.h" +#include "ink-action.h" +#include "preferences.h" +#include "toolbox.h" +#include "tools-switch.h" +#include "ui/icon-names.h" +#include "ui/tools/pen-tool.h" +#include "ui/uxmanager.h" +#include "widgets/spinbutton-events.h" + +using Inkscape::UI::UXManager; +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; + +//######################## +//## Pen/Pencil ## +//######################## + +/* This is used in generic functions below to share large portions of code between pen and pencil tool */ +static Glib::ustring const freehand_tool_name(GObject *dataKludge) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(dataKludge, "desktop")); + return ( tools_isactive(desktop, TOOLS_FREEHAND_PEN) + ? "/tools/freehand/pen" + : "/tools/freehand/pencil" ); +} + +static void freehand_mode_changed(EgeSelectOneAction* act, GObject* tbl) +{ + gint mode = ege_select_one_action_get_active(act); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt(freehand_tool_name(tbl) + "/freehand-mode", mode); + + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(tbl, "desktop")); + + // in pen tool we have more options than in pencil tool; if one of them was chosen, we do any + // preparatory work here + //if (SP_IS_PEN_CONTEXT(desktop->event_context)) { + // Inkscape::UI::Tools::PenTool *pc = SP_PEN_CONTEXT(desktop->event_context); + // sp_pen_context_set_polyline_mode(pc); + //} + + using namespace Inkscape::UI; + using Inkscape::UI::Tools::PenTool; + + if (Tool::is_a<PenTool>(desktop->event_context)) { + PenTool* pc = Tool::to<PenTool>(desktop->event_context); + pc->setPolylineMode(); + } +} + +static void sp_add_freehand_mode_toggle(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil) +{ + /* Freehand mode toggle buttons */ + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + guint freehandMode = prefs->getInt(( tool_is_pencil ? "/tools/freehand/pencil/freehand-mode" : "/tools/freehand/pen/freehand-mode" ), 0); + Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); + + { + GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); + + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Bezier"), + 1, _("Create regular Bezier path"), + 2, INKSCAPE_ICON("path-mode-bezier"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Spiro"), + 1, _("Create Spiro path"), + 2, INKSCAPE_ICON("path-mode-spiro"), + -1 ); + + if (!tool_is_pencil) { + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Zigzag"), + 1, _("Create a sequence of straight line segments"), + 2, INKSCAPE_ICON("path-mode-polyline"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Paraxial"), + 1, _("Create a sequence of paraxial line segments"), + 2, INKSCAPE_ICON("path-mode-polyline-paraxial"), + -1 ); + } + + EgeSelectOneAction* act = ege_select_one_action_new(tool_is_pencil ? + "FreehandModeActionPencil" : + "FreehandModeActionPen", + (_("Mode:")), (_("Mode of new lines drawn by this tool")), NULL, GTK_TREE_MODEL(model) ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + + ege_select_one_action_set_appearance( act, "full" ); + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); + ege_select_one_action_set_icon_column( act, 2 ); + ege_select_one_action_set_icon_size( act, secondarySize ); + ege_select_one_action_set_tooltip_column( act, 1 ); + + ege_select_one_action_set_active( act, freehandMode); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(freehand_mode_changed), holder); + } + } +} + +static void freehand_change_shape(EgeSelectOneAction* act, GObject *dataKludge) { + gint shape = ege_select_one_action_get_active( act ); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt(freehand_tool_name(dataKludge) + "/shape", shape); +} + +/** + * Generate the list of freehand advanced shape option entries. + */ +static GList * freehand_shape_dropdown_items_list() { + GList *glist = NULL; + + glist = g_list_append (glist, _("None")); + glist = g_list_append (glist, _("Triangle in")); + glist = g_list_append (glist, _("Triangle out")); + glist = g_list_append (glist, _("Ellipse")); + glist = g_list_append (glist, _("From clipboard")); + + return glist; +} + +static void freehand_add_advanced_shape_options(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil) +{ + /*advanced shape options */ + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); + + GList* items = 0; + gint count = 0; + for ( items = freehand_shape_dropdown_items_list(); items ; items = g_list_next(items) ) + { + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 ); + count++; + } + g_list_free( items ); + items = 0; + EgeSelectOneAction* act1 = ege_select_one_action_new( + tool_is_pencil ? "SetPencilShapeAction" : "SetPenShapeAction", + _("Shape:"), (_("Shape of new paths drawn by this tool")), NULL, GTK_TREE_MODEL(model)); + g_object_set( act1, "short_label", _("Shape:"), NULL ); + ege_select_one_action_set_appearance( act1, "compact" ); + ege_select_one_action_set_active( act1, prefs->getInt(( tool_is_pencil ? "/tools/freehand/pencil/shape" : "/tools/freehand/pen/shape" ), 0) ); + g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(freehand_change_shape), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act1) ); + g_object_set_data( holder, "shape_action", act1 ); + } +} + +void sp_pen_toolbox_prep(SPDesktop * /*desktop*/, GtkActionGroup* mainActions, GObject* holder) +{ + sp_add_freehand_mode_toggle(mainActions, holder, false); + freehand_add_advanced_shape_options(mainActions, holder, false); +} + + +static void sp_pencil_tb_defaults(GtkWidget * /*widget*/, GObject *obj) +{ + GtkWidget *tbl = GTK_WIDGET(obj); + + GtkAdjustment *adj; + + // fixme: make settable + gdouble tolerance = 4; + + adj = GTK_ADJUSTMENT(g_object_get_data(obj, "tolerance")); + gtk_adjustment_set_value(adj, tolerance); + gtk_adjustment_value_changed(adj); + + spinbutton_defocus(tbl); +} + +static void sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + // quit if run by the attr_changed listener + if (g_object_get_data( tbl, "freeze" )) { + return; + } + // in turn, prevent listener from responding + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + prefs->setDouble("/tools/freehand/pencil/tolerance", + gtk_adjustment_get_value(adj)); + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +/* +class PencilToleranceObserver : public Inkscape::Preferences::Observer { +public: + PencilToleranceObserver(Glib::ustring const &path, GObject *x) : Observer(path), _obj(x) + { + g_object_set_data(_obj, "prefobserver", this); + } + virtual ~PencilToleranceObserver() { + if (g_object_get_data(_obj, "prefobserver") == this) { + g_object_set_data(_obj, "prefobserver", NULL); + } + } + virtual void notify(Inkscape::Preferences::Entry const &val) { + GObject* tbl = _obj; + if (g_object_get_data( tbl, "freeze" )) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + GtkAdjustment * adj = GTK_ADJUSTMENT(g_object_get_data(tbl, "tolerance")); + + double v = val.getDouble(adj->value); + gtk_adjustment_set_value(adj, v); + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); + } +private: + GObject *_obj; +}; +*/ + +void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + sp_add_freehand_mode_toggle(mainActions, holder, true); + + EgeAdjustmentAction* eact = 0; + + /* Tolerance */ + { + gchar const* labels[] = {_("(many nodes, rough)"), _("(default)"), 0, 0, 0, 0, _("(few nodes, smooth)")}; + gdouble values[] = {1, 10, 20, 30, 50, 75, 100}; + eact = create_adjustment_action( "PencilToleranceAction", + _("Smoothing:"), _("Smoothing: "), + _("How much smoothing (simplifying) is applied to the line"), + "/tools/freehand/pencil/tolerance", + 3.0, + GTK_WIDGET(desktop->canvas), + holder, TRUE, "altx-pencil", + 1, 100.0, 0.5, 1.0, + labels, values, G_N_ELEMENTS(labels), + sp_pencil_tb_tolerance_value_changed, + NULL /*unit tracker*/, + 1, 2); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + /* advanced shape options */ + freehand_add_advanced_shape_options(mainActions, holder, true); + + /* Reset */ + { + InkAction* inky = ink_action_new( "PencilResetAction", + _("Defaults"), + _("Reset pencil parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), + INKSCAPE_ICON("edit-clear"), + Inkscape::ICON_SIZE_SMALL_TOOLBAR ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_pencil_tb_defaults), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); + +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/pencil-toolbar.h b/src/widgets/pencil-toolbar.h new file mode 100644 index 000000000..c01b7d591 --- /dev/null +++ b/src/widgets/pencil-toolbar.h @@ -0,0 +1,38 @@ +#ifndef SEEN_PENCIL_TOOLBAR_H +#define SEEN_PENCIL_TOOLBAR_H + +/** + * @file + * Pencil aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); +void sp_pen_toolbox_prep(SPDesktop * /*desktop*/, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_PENCIL_TOOLBAR_H */ diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp new file mode 100644 index 000000000..6996786e3 --- /dev/null +++ b/src/widgets/rect-toolbar.cpp @@ -0,0 +1,412 @@ +/** + * @file + * Rect aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glibmm/i18n.h> + +#include "rect-toolbar.h" +#include "desktop-handles.h" +#include "desktop.h" +#include "document-undo.h" +#include "ege-adjustment-action.h" +#include "ege-output-action.h" +#include "ink-action.h" +#include "inkscape.h" +#include "preferences.h" +#include "selection.h" +#include "sp-namedview.h" +#include "sp-rect.h" +#include "toolbox.h" +#include "ui/icon-names.h" +#include "ui/uxmanager.h" +#include "ui/widget/unit-tracker.h" +#include "util/units.h" +#include "verbs.h" +#include "widgets/widget-sizes.h" +#include "xml/node-event-vector.h" +#include "xml/repr.h" + +using Inkscape::UI::Widget::UnitTracker; +using Inkscape::UI::UXManager; +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; +using Inkscape::Util::Unit; +using Inkscape::Util::Quantity; +using Inkscape::Util::unit_table; + + +//######################## +//## Rect ## +//######################## + +static void sp_rtb_sensitivize( GObject *tbl ) +{ + GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") ); + GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") ); + GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") ); + + if (gtk_adjustment_get_value(adj1) == 0 && gtk_adjustment_get_value(adj2) == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now) + gtk_action_set_sensitive( not_rounded, FALSE ); + } else { + gtk_action_set_sensitive( not_rounded, TRUE ); + } +} + + +static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, + void (SPRect::*setter)(gdouble)) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + + UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" )); + Unit const *unit = tracker->getActiveUnit(); + + if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble(Glib::ustring("/tools/shapes/rect/") + value_name, + Quantity::convert(gtk_adjustment_get_value(adj), unit, "px")); + } + + // quit if run by the attr_changed listener + if (g_object_get_data( tbl, "freeze" )) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE)); + + bool modmade = false; + Inkscape::Selection *selection = sp_desktop_selection(desktop); + for (GSList const *items = selection->itemList(); items != NULL; items = items->next) { + if (SP_IS_RECT(items->data)) { + if (gtk_adjustment_get_value(adj) != 0) { + (SP_RECT(items->data)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, sp_desktop_namedview(desktop)->doc_units)); + } else { + SP_OBJECT(items->data)->getRepr()->setAttribute(value_name, NULL); + } + modmade = true; + } + } + + sp_rtb_sensitivize( tbl ); + + if (modmade) { + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT, + _("Change rectangle")); + } + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + sp_rtb_value_changed(adj, tbl, "rx", &SPRect::setVisibleRx); +} + +static void sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + sp_rtb_value_changed(adj, tbl, "ry", &SPRect::setVisibleRy); +} + +static void sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + sp_rtb_value_changed(adj, tbl, "width", &SPRect::setVisibleWidth); +} + +static void sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + sp_rtb_value_changed(adj, tbl, "height", &SPRect::setVisibleHeight); +} + + + +static void sp_rtb_defaults( GtkWidget * /*widget*/, GObject *obj) +{ + GtkAdjustment *adj = 0; + + adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") ); + gtk_adjustment_set_value(adj, 0.0); + // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects + gtk_adjustment_value_changed(adj); + + adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") ); + gtk_adjustment_set_value(adj, 0.0); + gtk_adjustment_value_changed(adj); + + sp_rtb_sensitivize( obj ); +} + +static void rect_tb_event_attr_changed(Inkscape::XML::Node * /*repr*/, gchar const * /*name*/, + gchar const * /*old_value*/, gchar const * /*new_value*/, + bool /*is_interactive*/, gpointer data) +{ + GObject *tbl = G_OBJECT(data); + + // quit if run by the _changed callbacks + if (g_object_get_data( tbl, "freeze" )) { + return; + } + + // in turn, prevent callbacks from responding + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) ); + Unit const *unit = tracker->getActiveUnit(); + Unit const *doc_unit = sp_desktop_namedview(SP_ACTIVE_DESKTOP)->doc_units; + + gpointer item = g_object_get_data( tbl, "item" ); + if (item && SP_IS_RECT(item)) { + { + GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) ); + + gdouble rx = SP_RECT(item)->getVisibleRx(); + gtk_adjustment_set_value(adj, Quantity::convert(rx, doc_unit, unit)); + } + + { + GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) ); + + gdouble ry = SP_RECT(item)->getVisibleRy(); + gtk_adjustment_set_value(adj, Quantity::convert(ry, doc_unit, unit)); + } + + { + GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) ); + + gdouble width = SP_RECT(item)->getVisibleWidth(); + gtk_adjustment_set_value(adj, Quantity::convert(width, doc_unit, unit)); + } + + { + GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) ); + + gdouble height = SP_RECT(item)->getVisibleHeight(); + gtk_adjustment_set_value(adj, Quantity::convert(height, doc_unit, unit)); + } + } + + sp_rtb_sensitivize( tbl ); + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + + +static Inkscape::XML::NodeEventVector rect_tb_repr_events = { + NULL, /* child_added */ + NULL, /* child_removed */ + rect_tb_event_attr_changed, + NULL, /* content_changed */ + NULL /* order_changed */ +}; + +/** + * \param selection should not be NULL. + */ +static void sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) +{ + int n_selected = 0; + Inkscape::XML::Node *repr = NULL; + SPItem *item = NULL; + + if ( g_object_get_data( tbl, "repr" ) ) { + g_object_set_data( tbl, "item", NULL ); + } + purge_repr_listener( tbl, tbl ); + + for (GSList const *items = selection->itemList(); + items != NULL; + items = items->next) { + if (SP_IS_RECT(reinterpret_cast<SPItem *>(items->data))) { + n_selected++; + item = reinterpret_cast<SPItem *>(items->data); + repr = item->getRepr(); + } + } + + EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) ); + + g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) ); + + if (n_selected == 0) { + g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL ); + + GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) ); + gtk_action_set_sensitive(w, FALSE); + GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) ); + gtk_action_set_sensitive(h, FALSE); + + } else if (n_selected == 1) { + g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); + g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) ); + + GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) ); + gtk_action_set_sensitive(w, TRUE); + GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) ); + gtk_action_set_sensitive(h, TRUE); + + if (repr) { + g_object_set_data( tbl, "repr", repr ); + g_object_set_data( tbl, "item", item ); + Inkscape::GC::anchor(repr); + sp_repr_add_listener(repr, &rect_tb_repr_events, tbl); + sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl); + } + } else { + // FIXME: implement averaging of all parameters for multiple selected + //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>")); + g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); + sp_rtb_sensitivize( tbl ); + } +} + + +void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + EgeAdjustmentAction* eact = 0; + Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); + + { + EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 ); + ege_output_action_set_use_markup( act, TRUE ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_object_set_data( holder, "mode_action", act ); + } + + // rx/ry units menu: create + UnitTracker* tracker = new UnitTracker(Inkscape::Util::UNIT_TYPE_LINEAR); + //tracker->addUnit( SP_UNIT_PERCENT, 0 ); + // fixme: add % meaning per cent of the width/height + tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units ); + g_object_set_data( holder, "tracker", tracker ); + + /* W */ + { + gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500}; + eact = create_adjustment_action( "RectWidthAction", + _("Width"), _("W:"), _("Width of rectangle"), + "/tools/shapes/rect/width", 0, + GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-rect", + 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, + labels, values, G_N_ELEMENTS(labels), + sp_rtb_width_value_changed, tracker); + tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); + g_object_set_data( holder, "width_action", eact ); + gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + /* H */ + { + gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500}; + eact = create_adjustment_action( "RectHeightAction", + _("Height"), _("H:"), _("Height of rectangle"), + "/tools/shapes/rect/height", 0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, + labels, values, G_N_ELEMENTS(labels), + sp_rtb_height_value_changed, tracker); + tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); + g_object_set_data( holder, "height_action", eact ); + gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + /* rx */ + { + gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0}; + gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100}; + eact = create_adjustment_action( "RadiusXAction", + _("Horizontal radius"), _("Rx:"), _("Horizontal radius of rounded corners"), + "/tools/shapes/rect/rx", 0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, + labels, values, G_N_ELEMENTS(labels), + sp_rtb_rx_value_changed, tracker); + tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + /* ry */ + { + gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0}; + gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100}; + eact = create_adjustment_action( "RadiusYAction", + _("Vertical radius"), _("Ry:"), _("Vertical radius of rounded corners"), + "/tools/shapes/rect/ry", 0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, + labels, values, G_N_ELEMENTS(labels), + sp_rtb_ry_value_changed, tracker); + tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + // add the units menu + { + GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), ("") ); + gtk_action_group_add_action( mainActions, act ); + } + + /* Reset */ + { + InkAction* inky = ink_action_new( "RectResetAction", + _("Not rounded"), + _("Make corners sharp"), + INKSCAPE_ICON("rectangle-make-corners-sharp"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + gtk_action_set_sensitive( GTK_ACTION(inky), TRUE ); + g_object_set_data( holder, "not_rounded", inky ); + } + + g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) ); + sp_rtb_sensitivize( holder ); + + sigc::connection *connection = new sigc::connection( + sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), holder)) + ); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection ); + g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/rect-toolbar.h b/src/widgets/rect-toolbar.h new file mode 100644 index 000000000..f89903c6c --- /dev/null +++ b/src/widgets/rect-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_RECT_TOOLBAR_H +#define SEEN_RECT_TOOLBAR_H + +/** + * @file + * Rect aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_RECT_TOOLBAR_H */ diff --git a/src/widgets/ruler.cpp b/src/widgets/ruler.cpp index 845d56e1c..5d5151343 100644 --- a/src/widgets/ruler.cpp +++ b/src/widgets/ruler.cpp @@ -1,5 +1,18 @@ /* - * Customized ruler class for inkscape + * Customized ruler class for inkscape. Note that this is a fork of + * the GimpRuler widget from GIMP: libgimpwidgets/gimpruler.c. + * The GIMP code is released under the GPL 3. The GIMP code itself + * is a fork of the now-obsolete GtkRuler widget from GTK+ 2. + * + * Major differences between implementations in Inkscape and GIMP are + * as follows: + * - We use a 1,2,4,8... scale for inches and 1,2,5,10... for everything + * else. GIMP uses 1,2,5,10... for everything. + * + * - We use a default font size of PANGO_SCALE_X_SMALL for labels, + * GIMP uses PANGO_SCALE_SMALL (i.e., a bit larger than ours). + * + * - We abbreviate large numbers in tick-labels (e.g., 10000 -> 10k) * * Authors: * Lauris Kaplinski <lauris@kaplinski.com> @@ -7,6 +20,7 @@ * bulia byak <buliabyak@users.sf.net> * Diederik van Lierop <mail@diedenrezi.nl> * Jon A. Cruz <jon@joncruz.org> + * Alex Valavanis <valavanisalex@gmail.com> * * Copyright (C) 1999-2011 authors * @@ -18,121 +32,178 @@ #include <cstdio> #include "widget-sizes.h" -#include "desktop-widget.h" #include "ruler.h" -#include "unit-constants.h" #include "round.h" #include <glibmm/i18n.h> +#include "util/units.h" + +#define ROUND(x) ((int) ((x) + 0.5)) #define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB -#define MINIMUM_INCR 5 -#define MAXIMUM_SUBDIVIDE 5 -#define MAXIMUM_SCALES 10 +#define DEFAULT_RULER_FONT_SCALE PANGO_SCALE_X_SMALL +#define MINIMUM_INCR 5 -#define ROUND(x) ((int) ((x) + 0.5)) +using Inkscape::Util::unit_table; enum { PROP_0, PROP_ORIENTATION, + PROP_UNIT, PROP_LOWER, PROP_UPPER, PROP_POSITION, - PROP_MAX_SIZE, - PROP_METRIC + PROP_MAX_SIZE }; -typedef struct _GtkDeprecatedRulerPrivate GtkDeprecatedRulerPrivate; -struct _GtkDeprecatedRulerPrivate +/* All distances below are in 1/72nd's of an inch. (According to + * Adobe, that's a point, but points are really 1/72.27 in.) + */ +typedef struct +{ + GtkOrientation orientation; + Inkscape::Util::Unit const *unit; + gdouble lower; + gdouble upper; + gdouble position; + gdouble max_size; + + GdkWindow *input_window; + cairo_surface_t *backing_store; + PangoLayout *layout; + gdouble font_scale; + + gint xsrc; + gint ysrc; + + GList *track_widgets; +} SPRulerPrivate; + +#define SP_RULER_GET_PRIVATE(ruler) \ + G_TYPE_INSTANCE_GET_PRIVATE (ruler, SP_TYPE_RULER, SPRulerPrivate) + + +struct SPRulerMetric { - GtkOrientation orientation; + gdouble ruler_scale[16]; + gint subdivide[5]; +}; + +// Ruler metric for general use. +static SPRulerMetric const ruler_metric_general = { + { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000, 25000, 50000, 100000 }, + { 1, 5, 10, 50, 100 } }; -static void gtk_deprecated_ruler_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_deprecated_ruler_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gtk_deprecated_ruler_realize (GtkWidget *widget); -static void gtk_deprecated_ruler_unrealize (GtkWidget *widget); -static void gtk_deprecated_ruler_size_request (GtkWidget *widget, - GtkRequisition *requisition); +// Ruler metric for inch scales. +static SPRulerMetric const ruler_metric_inches = { + { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 }, + { 1, 2, 4, 8, 16 } +}; + +static void sp_ruler_dispose (GObject *object); +static void sp_ruler_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void sp_ruler_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static void sp_ruler_realize (GtkWidget *widget); +static void sp_ruler_unrealize (GtkWidget *widget); +static void sp_ruler_map (GtkWidget *widget); +static void sp_ruler_unmap (GtkWidget *widget); +static void sp_ruler_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); #if GTK_CHECK_VERSION(3,0,0) -static void gtk_deprecated_ruler_get_preferred_width(GtkWidget *widget, - gint *minimal_width, - gint *natural_width); +static void sp_ruler_get_preferred_width (GtkWidget *widget, + gint *minimum_width, + gint *natural_width); + +static void sp_ruler_get_preferred_height (GtkWidget *widget, + gint *minimum_height, + gint *natural_height); +static void sp_ruler_style_updated (GtkWidget *widget); +#else +static void sp_ruler_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void sp_ruler_style_set (GtkWidget *widget, + GtkStyle *prev_style); +#endif -static void gtk_deprecated_ruler_get_preferred_height(GtkWidget *widget, - gint *minimal_height, - gint *natural_height); +static gboolean sp_ruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static gboolean sp_ruler_draw (GtkWidget *widget, + cairo_t *cr); +#if !GTK_CHECK_VERSION(3,0,0) +static gboolean sp_ruler_expose (GtkWidget *widget, + GdkEventExpose *event); #endif +static void sp_ruler_draw_ticks (SPRuler *ruler); +static void sp_ruler_draw_pos (SPRuler *ruler); +static void sp_ruler_make_pixmap (SPRuler *ruler); + +static PangoLayout * sp_ruler_get_layout (GtkWidget *widget, + const gchar *text); -static void gtk_deprecated_ruler_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static gboolean gtk_deprecated_ruler_motion_notify (GtkWidget *widget, - GdkEventMotion *event); -static gboolean gtk_deprecated_ruler_expose (GtkWidget *widget, - GdkEventExpose *event); -static void gtk_deprecated_ruler_make_pixmap (GtkDeprecatedRuler *ruler); -static void gtk_deprecated_ruler_real_draw_ticks (GtkDeprecatedRuler *ruler); -static void gtk_deprecated_ruler_real_draw_pos (GtkDeprecatedRuler *ruler); - - -#define GTK_DEPRECATED_RULER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_DEPRECATED_TYPE_RULER, GtkDeprecatedRulerPrivate)) - -// Note: const casts are due to GtkDeprecatedRuler being const-broken and not scheduled for any more fixes. -/// Ruler metrics. -static GtkDeprecatedRulerMetric const sp_ruler_metrics[] = { - // NOTE: the order of records in this struct must correspond to the SPMetric enum. - {const_cast<gchar*>("NONE"), const_cast<gchar*>(""), 1, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, - {const_cast<gchar*>("millimeters"), const_cast<gchar*>("mm"), PX_PER_MM, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, - {const_cast<gchar*>("centimeters"), const_cast<gchar*>("cm"), PX_PER_CM, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, - {const_cast<gchar*>("inches"), const_cast<gchar*>("in"), PX_PER_IN, { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }, { 1, 2, 4, 8, 16 }}, - {const_cast<gchar*>("feet"), const_cast<gchar*>("ft"), PX_PER_FT, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, - {const_cast<gchar*>("points"), const_cast<gchar*>("pt"), PX_PER_PT, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, - {const_cast<gchar*>("picas"), const_cast<gchar*>("pc"), PX_PER_PC, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, - {const_cast<gchar*>("pixels"), const_cast<gchar*>("px"), PX_PER_PX, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, - {const_cast<gchar*>("meters"), const_cast<gchar*>("m"), PX_PER_M, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, -}; -G_DEFINE_TYPE_WITH_CODE (GtkDeprecatedRuler, gtk_deprecated_ruler, GTK_TYPE_WIDGET, - G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, - NULL)) +G_DEFINE_TYPE (SPRuler, sp_ruler, GTK_TYPE_WIDGET) + +#define parent_class sp_ruler_parent_class + static void -gtk_deprecated_ruler_class_init (GtkDeprecatedRulerClass *klass) +sp_ruler_class_init (SPRulerClass *klass) { - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - gobject_class->set_property = gtk_deprecated_ruler_set_property; - gobject_class->get_property = gtk_deprecated_ruler_get_property; + object_class->dispose = sp_ruler_dispose; + object_class->set_property = sp_ruler_set_property; + object_class->get_property = sp_ruler_get_property; - widget_class->realize = gtk_deprecated_ruler_realize; - widget_class->unrealize = gtk_deprecated_ruler_unrealize; + widget_class->realize = sp_ruler_realize; + widget_class->unrealize = sp_ruler_unrealize; + widget_class->map = sp_ruler_map; + widget_class->unmap = sp_ruler_unmap; + widget_class->size_allocate = sp_ruler_size_allocate; #if GTK_CHECK_VERSION(3,0,0) - widget_class->get_preferred_width = gtk_deprecated_ruler_get_preferred_width; - widget_class->get_preferred_height = gtk_deprecated_ruler_get_preferred_height; + widget_class->get_preferred_width = sp_ruler_get_preferred_width; + widget_class->get_preferred_height = sp_ruler_get_preferred_height; + widget_class->style_updated = sp_ruler_style_updated; + widget_class->draw = sp_ruler_draw; #else - widget_class->size_request = gtk_deprecated_ruler_size_request; + widget_class->size_request = sp_ruler_size_request; + widget_class->style_set = sp_ruler_style_set; + widget_class->expose_event = sp_ruler_expose; #endif - widget_class->size_allocate = gtk_deprecated_ruler_size_allocate; - widget_class->motion_notify_event = gtk_deprecated_ruler_motion_notify; - widget_class->expose_event = gtk_deprecated_ruler_expose; - - klass->draw_ticks = gtk_deprecated_ruler_real_draw_ticks; - klass->draw_pos = gtk_deprecated_ruler_real_draw_pos; - - g_object_class_override_property (gobject_class, - PROP_ORIENTATION, - "orientation"); - - g_object_class_install_property (gobject_class, + widget_class->motion_notify_event = sp_ruler_motion_notify; + + g_type_class_add_private (object_class, sizeof (SPRulerPrivate)); + + g_object_class_install_property (object_class, + PROP_ORIENTATION, + g_param_spec_enum ("orientation", + _("Orientation"), + _("The orientation of the ruler"), + GTK_TYPE_ORIENTATION, + GTK_ORIENTATION_HORIZONTAL, + static_cast<GParamFlags>(GTK_PARAM_READWRITE))); + + /* FIXME: Should probably use g_param_spec_enum */ + g_object_class_install_property (object_class, + PROP_UNIT, + g_param_spec_string ("unit", + _("Unit"), + _("Unit of the ruler"), + "px", + static_cast<GParamFlags>(GTK_PARAM_READWRITE))); + + g_object_class_install_property (object_class, PROP_LOWER, g_param_spec_double ("lower", _("Lower"), @@ -142,7 +213,7 @@ gtk_deprecated_ruler_class_init (GtkDeprecatedRulerClass *klass) 0.0, static_cast<GParamFlags>(GTK_PARAM_READWRITE))); - g_object_class_install_property (gobject_class, + g_object_class_install_property (object_class, PROP_UPPER, g_param_spec_double ("upper", _("Upper"), @@ -152,7 +223,7 @@ gtk_deprecated_ruler_class_init (GtkDeprecatedRulerClass *klass) 0.0, static_cast<GParamFlags>(GTK_PARAM_READWRITE))); - g_object_class_install_property (gobject_class, + g_object_class_install_property (object_class, PROP_POSITION, g_param_spec_double ("position", _("Position"), @@ -162,7 +233,7 @@ gtk_deprecated_ruler_class_init (GtkDeprecatedRulerClass *klass) 0.0, static_cast<GParamFlags>(GTK_PARAM_READWRITE))); - g_object_class_install_property (gobject_class, + g_object_class_install_property (object_class, PROP_MAX_SIZE, g_param_spec_double ("max-size", _("Max Size"), @@ -171,131 +242,148 @@ gtk_deprecated_ruler_class_init (GtkDeprecatedRulerClass *klass) G_MAXDOUBLE, 0.0, static_cast<GParamFlags>(GTK_PARAM_READWRITE))); - /** - * GtkDeprecatedRuler:metric: - * - * The metric used for the ruler. - * - * TODO: This should probably use g_param_spec_enum - */ - g_object_class_install_property (gobject_class, - PROP_METRIC, - g_param_spec_uint("metric", - _("Metric"), - _("The metric used for the ruler"), - 0, 8, - SP_PX, - static_cast<GParamFlags>(GTK_PARAM_READWRITE))); - - g_type_class_add_private (gobject_class, sizeof (GtkDeprecatedRulerPrivate)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_double ("font-scale", + NULL, NULL, + 0.0, + G_MAXDOUBLE, + DEFAULT_RULER_FONT_SCALE, + G_PARAM_READABLE)); } static void -gtk_deprecated_ruler_init (GtkDeprecatedRuler *ruler) +sp_ruler_init (SPRuler *ruler) { - GtkDeprecatedRulerPrivate *priv = GTK_DEPRECATED_RULER_GET_PRIVATE (ruler); + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler); + + gtk_widget_set_has_window (GTK_WIDGET (ruler), FALSE); + + priv->orientation = GTK_ORIENTATION_HORIZONTAL; + priv->unit = unit_table.getUnit("px"); + priv->lower = 0; + priv->upper = 0; + priv->position = 0; + priv->max_size = 0; + priv->backing_store = NULL; + priv->font_scale = DEFAULT_RULER_FONT_SCALE; - priv->orientation = GTK_ORIENTATION_HORIZONTAL; +#if GTK_CHECK_VERSION(3,0,0) + #if GTK_CHECK_VERSION(3,8,0) + const gchar *str = + "SPRuler {\n" + " background-color: @theme_bg_color;\n" + "}\n"; + #else + const gchar *str = + "SPRuler {\n" + " background-color: @bg_color;\n" + "}\n"; + #endif + GtkCssProvider *css = gtk_css_provider_new (); + gtk_css_provider_load_from_data (css, str, -1, NULL); + gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (ruler)), + GTK_STYLE_PROVIDER (css), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_object_unref (css); +#endif +} + +static void +sp_ruler_dispose (GObject *object) +{ + SPRuler *ruler = SP_RULER (object); + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler); - ruler->backing_store = NULL; - ruler->xsrc = 0; - ruler->ysrc = 0; - ruler->slider_size = 0; - ruler->lower = 0; - ruler->upper = 0; - ruler->position = 0; - ruler->max_size = 0; + while (priv->track_widgets) + sp_ruler_remove_track_widget (ruler, GTK_WIDGET(priv->track_widgets->data)); - sp_ruler_set_metric(ruler, SP_PX); + G_OBJECT_CLASS (parent_class)->dispose (object); } /** - * gtk_deprecated_ruler_set_range: - * @ruler: the gtkdeprecatedruler + * sp_ruler_set_range: + * @ruler: the SPRuler * @lower: the lower limit of the ruler * @upper: the upper limit of the ruler - * @position: the mark on the ruler * @max_size: the maximum size of the ruler used when calculating the space to * leave for the text * * This sets the range of the ruler. */ void -gtk_deprecated_ruler_set_range (GtkDeprecatedRuler *ruler, - gdouble lower, - gdouble upper, - gdouble position, - gdouble max_size) +sp_ruler_set_range (SPRuler *ruler, + gdouble lower, + gdouble upper, + gdouble max_size) { - g_return_if_fail (GTK_DEPRECATED_IS_RULER (ruler)); + SPRulerPrivate *priv; + + g_return_if_fail (SP_IS_RULER (ruler)); + + priv = SP_RULER_GET_PRIVATE (ruler); g_object_freeze_notify (G_OBJECT (ruler)); - if (ruler->lower != lower) + if (priv->lower != lower) { - ruler->lower = lower; + priv->lower = lower; g_object_notify (G_OBJECT (ruler), "lower"); } - if (ruler->upper != upper) + if (priv->upper != upper) { - ruler->upper = upper; + priv->upper = upper; g_object_notify (G_OBJECT (ruler), "upper"); } - if (ruler->position != position) - { - ruler->position = position; - g_object_notify (G_OBJECT (ruler), "position"); - } - if (ruler->max_size != max_size) + if (priv->max_size != max_size) { - ruler->max_size = max_size; + priv->max_size = max_size; g_object_notify (G_OBJECT (ruler), "max-size"); } g_object_thaw_notify (G_OBJECT (ruler)); - if (gtk_widget_is_drawable (GTK_WIDGET (ruler))) - gtk_widget_queue_draw (GTK_WIDGET (ruler)); + gtk_widget_queue_draw (GTK_WIDGET (ruler)); } /** - * gtk_deprecated_ruler_get_range: - * @ruler: a #GtkDeprecatedRuler + * sp_ruler_get_range: + * @ruler: a #SPRuler * @lower: (allow-none): location to store lower limit of the ruler, or %NULL * @upper: (allow-none): location to store upper limit of the ruler, or %NULL - * @position: (allow-none): location to store the current position of the mark on the ruler, or %NULL * @max_size: location to store the maximum size of the ruler used when calculating * the space to leave for the text, or %NULL. * - * Retrieves values indicating the range and current position of a #GtkDeprecatedRuler. - * See gtk_deprecated_ruler_set_range(). + * Retrieves values indicating the range and current position of a #SPRuler. + * See sp_ruler_set_range(). **/ void -gtk_deprecated_ruler_get_range (GtkDeprecatedRuler *ruler, +sp_ruler_get_range (SPRuler *ruler, gdouble *lower, gdouble *upper, - gdouble *position, gdouble *max_size) { - g_return_if_fail (GTK_DEPRECATED_IS_RULER (ruler)); + SPRulerPrivate *priv; + + g_return_if_fail (SP_IS_RULER (ruler)); + + priv = SP_RULER_GET_PRIVATE (ruler); if (lower) - *lower = ruler->lower; + *lower = priv->lower; if (upper) - *upper = ruler->upper; - if (position) - *position = ruler->position; + *upper = priv->upper; if (max_size) - *max_size = ruler->max_size; + *max_size = priv->max_size; } static void -gtk_deprecated_ruler_set_property (GObject *object, +sp_ruler_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - GtkDeprecatedRuler *ruler = GTK_DEPRECATED_RULER (object); - GtkDeprecatedRulerPrivate *priv = GTK_DEPRECATED_RULER_GET_PRIVATE (ruler); + SPRuler *ruler = SP_RULER (object); + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler); switch (prop_id) { @@ -303,25 +391,35 @@ gtk_deprecated_ruler_set_property (GObject *object, priv->orientation = static_cast<GtkOrientation>(g_value_get_enum (value)); gtk_widget_queue_resize (GTK_WIDGET (ruler)); break; + + case PROP_UNIT: + sp_ruler_set_unit (ruler, unit_table.getUnit(g_value_get_string (value))); + break; + case PROP_LOWER: - gtk_deprecated_ruler_set_range (ruler, g_value_get_double (value), ruler->upper, - ruler->position, ruler->max_size); + sp_ruler_set_range (ruler, + g_value_get_double (value), + priv->upper, + priv->max_size); break; case PROP_UPPER: - gtk_deprecated_ruler_set_range (ruler, ruler->lower, g_value_get_double (value), - ruler->position, ruler->max_size); + sp_ruler_set_range (ruler, + priv->lower, + g_value_get_double (value), + priv->max_size); break; + case PROP_POSITION: - gtk_deprecated_ruler_set_range (ruler, ruler->lower, ruler->upper, - g_value_get_double (value), ruler->max_size); + sp_ruler_set_position (ruler, g_value_get_double (value)); break; + case PROP_MAX_SIZE: - gtk_deprecated_ruler_set_range (ruler, ruler->lower, ruler->upper, - ruler->position, g_value_get_double (value)); - break; - case PROP_METRIC: - sp_ruler_set_metric(ruler, static_cast<SPMetric>(g_value_get_enum (value))); + sp_ruler_set_range (ruler, + priv->lower, + priv->upper, + g_value_get_double (value)); break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -329,33 +427,34 @@ gtk_deprecated_ruler_set_property (GObject *object, } static void -gtk_deprecated_ruler_get_property (GObject *object, +sp_ruler_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - GtkDeprecatedRuler *ruler = GTK_DEPRECATED_RULER (object); - GtkDeprecatedRulerPrivate *priv = GTK_DEPRECATED_RULER_GET_PRIVATE (ruler); + SPRuler *ruler = SP_RULER (object); + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler); switch (prop_id) { case PROP_ORIENTATION: g_value_set_enum (value, priv->orientation); break; + + case PROP_UNIT: + g_value_set_string (value, priv->unit->abbr.c_str()); + break; case PROP_LOWER: - g_value_set_double (value, ruler->lower); + g_value_set_double (value, priv->lower); break; case PROP_UPPER: - g_value_set_double (value, ruler->upper); + g_value_set_double (value, priv->upper); break; case PROP_POSITION: - g_value_set_double (value, ruler->position); + g_value_set_double (value, priv->position); break; case PROP_MAX_SIZE: - g_value_set_double (value, ruler->max_size); - break; - case PROP_METRIC: - g_value_set_enum(value, sp_ruler_get_metric(ruler)); + g_value_set_double (value, priv->max_size); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -363,971 +462,1042 @@ gtk_deprecated_ruler_get_property (GObject *object, } } - -/** - * sp_ruler_get_metric: - * @ruler: a #GtkDeprecatedRuler - * - * Gets the units used for a #GtkDeprecatedRuler. See sp_ruler_set_metric(). - * - * Return value: the units currently used for @ruler - **/ -SPMetric sp_ruler_get_metric(GtkDeprecatedRuler *ruler) +static void +sp_ruler_realize (GtkWidget *widget) { - g_return_val_if_fail(GTK_DEPRECATED_IS_RULER(ruler), static_cast<SPMetric>(0)); - - for (size_t i = 0; i < G_N_ELEMENTS(sp_ruler_metrics); i++) { - if (ruler->metric == &sp_ruler_metrics[i]) { - return static_cast<SPMetric>(i); - } - } + SPRuler *ruler = SP_RULER (widget); + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler); + GtkAllocation allocation; + GdkWindowAttr attributes; + gint attributes_mask; - g_assert_not_reached (); + GTK_WIDGET_CLASS (sp_ruler_parent_class)->realize (widget); + + gtk_widget_get_allocation (widget, &allocation); - return static_cast<SPMetric>(0); -} + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.wclass = GDK_INPUT_ONLY; +#if GTK_CHECK_VERSION(3,0,0) + attributes.event_mask = (gtk_widget_get_events (widget) | + GDK_EXPOSURE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); +#else + attributes.event_mask = (gtk_widget_get_events (widget) | + GDK_EXPOSURE_MASK | + GDK_POINTER_MOTION_MASK); +#endif + attributes_mask = GDK_WA_X | GDK_WA_Y; -void -gtk_deprecated_ruler_draw_ticks (GtkDeprecatedRuler *ruler) -{ - g_return_if_fail (GTK_DEPRECATED_IS_RULER (ruler)); + priv->input_window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gdk_window_set_user_data (priv->input_window, ruler); - if (GTK_DEPRECATED_RULER_GET_CLASS (ruler)->draw_ticks) - GTK_DEPRECATED_RULER_GET_CLASS (ruler)->draw_ticks (ruler); + sp_ruler_make_pixmap (ruler); } -void -gtk_deprecated_ruler_draw_pos (GtkDeprecatedRuler *ruler) +static void +sp_ruler_unrealize(GtkWidget *widget) { - g_return_if_fail (GTK_DEPRECATED_IS_RULER (ruler)); + SPRuler *ruler = SP_RULER (widget); + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler); - if (GTK_DEPRECATED_RULER_GET_CLASS (ruler)->draw_pos) - GTK_DEPRECATED_RULER_GET_CLASS (ruler)->draw_pos (ruler); -} + if (priv->backing_store) + { + cairo_surface_destroy (priv->backing_store); + priv->backing_store = NULL; + } + + if (priv->layout) + { + g_object_unref (priv->layout); + priv->layout = NULL; + } + + if (priv->input_window) + { + gdk_window_destroy (priv->input_window); + priv->input_window = NULL; + } + GTK_WIDGET_CLASS (sp_ruler_parent_class)->unrealize (widget); +} static void -gtk_deprecated_ruler_realize (GtkWidget *widget) +sp_ruler_map (GtkWidget *widget) { - GtkAllocation allocation; - GtkDeprecatedRuler *ruler; - GdkWindow *window; - GdkWindowAttr attributes; - gint attributes_mask; + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (widget); - ruler = GTK_DEPRECATED_RULER (widget); + GTK_WIDGET_CLASS (sp_ruler_parent_class)->map (widget); - gtk_widget_set_realized (widget, TRUE); + if (priv->input_window) + gdk_window_show (priv->input_window); +} - gtk_widget_get_allocation(widget, &allocation); +static void +sp_ruler_unmap (GtkWidget *widget) +{ + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (widget); - attributes.window_type = GDK_WINDOW_CHILD; - attributes.x = allocation.x; - attributes.y = allocation.y; - attributes.width = allocation.width; - attributes.height = allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); - attributes.event_mask = gtk_widget_get_events (widget); - attributes.event_mask |= (GDK_EXPOSURE_MASK | - GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - - window = gdk_window_new(gtk_widget_get_parent_window (widget), - &attributes, attributes_mask); - gtk_widget_set_window(widget, window); - gdk_window_set_user_data(window, ruler); - - gtk_widget_style_attach(widget); - gtk_style_set_background(gtk_widget_get_style(widget), - window, GTK_STATE_ACTIVE); - - gtk_deprecated_ruler_make_pixmap (ruler); + if (priv->input_window) + gdk_window_hide (priv->input_window); + + GTK_WIDGET_CLASS (sp_ruler_parent_class)->unmap (widget); } static void -gtk_deprecated_ruler_unrealize (GtkWidget *widget) +sp_ruler_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) { - GtkDeprecatedRuler *ruler = GTK_DEPRECATED_RULER (widget); + SPRuler *ruler = SP_RULER(widget); + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler); + GtkAllocation widget_allocation; + gboolean resized; + + gtk_widget_get_allocation (widget, &widget_allocation); + + resized = (widget_allocation.width != allocation->width || + widget_allocation.height != allocation->height); + + gtk_widget_set_allocation(widget, allocation); - if (ruler->backing_store) + if (gtk_widget_get_realized (widget)) { - g_object_unref (ruler->backing_store); - ruler->backing_store = NULL; + gdk_window_move_resize (priv->input_window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + if (resized) + sp_ruler_make_pixmap (ruler); } - - GTK_WIDGET_CLASS (gtk_deprecated_ruler_parent_class)->unrealize (widget); } static void -gtk_deprecated_ruler_size_request (GtkWidget *widget, - GtkRequisition *requisition) +sp_ruler_size_request (GtkWidget *widget, + GtkRequisition *requisition) { - GtkDeprecatedRulerPrivate *priv = GTK_DEPRECATED_RULER_GET_PRIVATE (widget); - GtkStyle *style = gtk_widget_get_style(widget); + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (widget); + PangoLayout *layout; + PangoRectangle ink_rect; + gint size; + + layout = sp_ruler_get_layout (widget, "0123456789"); + pango_layout_get_pixel_extents (layout, &ink_rect, NULL); + + size = 2 + ink_rect.height * 1.7; + +#if GTK_CHECK_VERSION(3,0,0) + GtkStyleContext *context = gtk_widget_get_style_context (widget); + GtkBorder border; + + gtk_style_context_get_border (context, static_cast<GtkStateFlags>(0), &border); + + requisition->width = border.left + border.right; + requisition->height = border.top + border.bottom; +#else + GtkStyle *style = gtk_widget_get_style(widget); +#endif if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) { +#if GTK_CHECK_VERSION(3,0,0) + requisition->width += 1; + requisition->height += size; +#else requisition->width = style->xthickness * 2 + 1; - requisition->height = style->ythickness * 2 + RULER_WIDTH; + requisition->height = style->ythickness * 2 + size; +#endif } else { - requisition->width = style->xthickness * 2 + RULER_WIDTH; +#if GTK_CHECK_VERSION(3,0,0) + requisition->width += size; + requisition->height += 1; +#else + requisition->width = style->xthickness * 2 + size; requisition->height = style->ythickness * 2 + 1; +#endif } } +static void #if GTK_CHECK_VERSION(3,0,0) -static void gtk_deprecated_ruler_get_preferred_width(GtkWidget *widget, gint *minimal_width, gint *natural_width) +sp_ruler_style_updated (GtkWidget *widget) +#else +sp_ruler_style_set (GtkWidget *widget, + GtkStyle *prev_style) +#endif { - GtkRequisition requisition; - gtk_deprecated_ruler_size_request(widget, &requisition); - *minimal_width = *natural_width = requisition.width; -} + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (widget); -static void gtk_deprecated_ruler_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height) -{ - GtkRequisition requisition; - gtk_deprecated_ruler_size_request(widget, &requisition); - *minimal_height = *natural_height = requisition.height; -} +#if GTK_CHECK_VERSION(3,0,0) + GTK_WIDGET_CLASS (sp_ruler_parent_class)->style_updated (widget); +#else + GTK_WIDGET_CLASS (sp_ruler_parent_class)->style_set (widget, prev_style); #endif -static void -gtk_deprecated_ruler_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - GtkDeprecatedRuler *ruler = GTK_DEPRECATED_RULER (widget); - - gtk_widget_set_allocation(widget, allocation); + gtk_widget_style_get (widget, + "font-scale", &priv->font_scale, + NULL); - if (gtk_widget_get_realized (widget)) + if (priv->layout) { - gdk_window_move_resize(gtk_widget_get_window(widget), - allocation->x, allocation->y, - allocation->width, allocation->height); - - gtk_deprecated_ruler_make_pixmap (ruler); + g_object_unref (priv->layout); + priv->layout = NULL; } } -static gboolean -gtk_deprecated_ruler_motion_notify (GtkWidget *widget, - GdkEventMotion *event) +#if GTK_CHECK_VERSION(3,0,0) +static void +sp_ruler_get_preferred_width (GtkWidget *widget, + gint *minimum_width, + gint *natural_width) { - GtkAllocation allocation; - GtkDeprecatedRuler *ruler = GTK_DEPRECATED_RULER (widget); - GtkDeprecatedRulerPrivate *priv = GTK_DEPRECATED_RULER_GET_PRIVATE (widget); - gint x; - gint y; + GtkRequisition requisition; - gdk_event_request_motions (event); - x = event->x; - y = event->y; + sp_ruler_size_request (widget, &requisition); - gtk_widget_get_allocation(widget, &allocation); + *minimum_width = *natural_width = requisition.width; +} - if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) - ruler->position = ruler->lower + ((ruler->upper - ruler->lower) * x) / allocation.width; - else - ruler->position = ruler->lower + ((ruler->upper - ruler->lower) * y) / allocation.height; +static void +sp_ruler_get_preferred_height (GtkWidget *widget, + gint *minimum_height, + gint *natural_height) +{ + GtkRequisition requisition; + + sp_ruler_size_request(widget, &requisition); + + *minimum_height = *natural_height = requisition.height; +} +#else +static gboolean +sp_ruler_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget)); + GtkAllocation allocation; + + gdk_cairo_region (cr, event->region); + cairo_clip (cr); - g_object_notify (G_OBJECT (ruler), "position"); + gtk_widget_get_allocation (widget, &allocation); + cairo_translate (cr, allocation.x, allocation.y); - /* Make sure the ruler has been allocated already */ - if (ruler->backing_store != NULL) - gtk_deprecated_ruler_draw_pos (ruler); + gboolean result = sp_ruler_draw (widget, cr); - return FALSE; + cairo_destroy (cr); + + return result; } +#endif static gboolean -gtk_deprecated_ruler_expose (GtkWidget *widget, - GdkEventExpose *event) +sp_ruler_draw (GtkWidget *widget, + cairo_t *cr) { - if (gtk_widget_is_drawable (widget)) - { - GtkDeprecatedRuler *ruler = GTK_DEPRECATED_RULER (widget); - cairo_t *cr; + SPRuler *ruler = SP_RULER (widget); + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler); - gtk_deprecated_ruler_draw_ticks (ruler); - - cr = gdk_cairo_create(gtk_widget_get_window(widget)); - gdk_cairo_set_source_pixmap (cr, ruler->backing_store, 0, 0); - gdk_cairo_rectangle (cr, &event->area); - cairo_fill (cr); - cairo_destroy (cr); - - gtk_deprecated_ruler_draw_pos (ruler); - } + sp_ruler_draw_ticks (ruler); + + cairo_set_source_surface(cr, priv->backing_store, 0, 0); + cairo_paint(cr); + + sp_ruler_draw_pos (ruler); return FALSE; } static void -gtk_deprecated_ruler_make_pixmap (GtkDeprecatedRuler *ruler) +sp_ruler_make_pixmap (SPRuler *ruler) { - GtkAllocation allocation; - GtkWidget *widget; - gint width; - gint height; - - widget = GTK_WIDGET (ruler); + GtkWidget *widget = GTK_WIDGET (ruler); + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler); + GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); - if (ruler->backing_store) - { - gdk_drawable_get_size (ruler->backing_store, &width, &height); - if ((width == allocation.width) && - (height == allocation.height)) - return; - - g_object_unref (ruler->backing_store); - } - - ruler->backing_store = gdk_pixmap_new (gtk_widget_get_window(widget), - allocation.width, - allocation.height, - -1); + if (priv->backing_store) + cairo_surface_destroy (priv->backing_store); - ruler->xsrc = 0; - ruler->ysrc = 0; + priv->backing_store = + gdk_window_create_similar_surface (gtk_widget_get_window (widget), + CAIRO_CONTENT_COLOR, + allocation.width, + allocation.height); } static void -gtk_deprecated_ruler_real_draw_ticks (GtkDeprecatedRuler *ruler) +sp_ruler_draw_pos (SPRuler *ruler) { - GtkAllocation allocation; - GtkWidget *widget = GTK_WIDGET (ruler); - GtkDeprecatedRulerPrivate *priv = GTK_DEPRECATED_RULER_GET_PRIVATE (ruler); - GtkStyle *style; - cairo_t *cr; - gint i, j; - gint width, height; - gint xthickness; - gint ythickness; - gint length, ideal_length; - gdouble lower, upper; /* Upper and lower limits, in ruler units */ - gdouble increment; /* Number of pixels per unit */ - gint scale; /* Number of units per major unit */ - gdouble subd_incr; - gdouble start, end, cur; - gchar unit_str[32]; - gint digit_height; - gint digit_offset; - gint text_width; - gint text_height; - gint pos; - PangoLayout *layout; - PangoRectangle logical_rect, ink_rect; - - if (!gtk_widget_is_drawable (widget)) - return; - - style = gtk_widget_get_style(widget); + GtkWidget *widget = GTK_WIDGET (ruler); + +#if GTK_CHECK_VERSION(3,0,0) + GtkStyleContext *context = gtk_widget_get_style_context (widget); + GtkBorder border; + GdkRGBA color; +#else + GtkStyle *style = gtk_widget_get_style (widget); + GtkStateType state = gtk_widget_get_state (widget); + gint xthickness; + gint ythickness; +#endif + + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler); + GtkAllocation allocation; + gint x, y; + gint width, height; + gint bs_width, bs_height; + + if (! gtk_widget_is_drawable (widget)) + return; + gtk_widget_get_allocation(widget, &allocation); +#if GTK_CHECK_VERSION(3,0,0) + gtk_style_context_get_border (context, static_cast<GtkStateFlags>(0), &border); +#else xthickness = style->xthickness; ythickness = style->ythickness; - - layout = gtk_widget_create_pango_layout (widget, "012456789"); - pango_layout_get_extents (layout, &ink_rect, &logical_rect); - - digit_height = PANGO_PIXELS (ink_rect.height) + 2; - digit_offset = ink_rect.y; +#endif if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) { - width = allocation.width; + width = allocation.width; +#if GTK_CHECK_VERSION(3,0,0) + height = allocation.height - (border.top + border.bottom); +#else height = allocation.height - ythickness * 2; - } - else - { - width = allocation.height; - height = allocation.width - ythickness * 2; - } - -#define DETAILE(priv) (priv->orientation == GTK_ORIENTATION_HORIZONTAL ? "hruler" : "vruler"); - - gtk_paint_box (style, ruler->backing_store, - GTK_STATE_NORMAL, GTK_SHADOW_OUT, - NULL, widget, - priv->orientation == GTK_ORIENTATION_HORIZONTAL ? - "hruler" : "vruler", - 0, 0, - allocation.width, allocation.height); - - cr = gdk_cairo_create (ruler->backing_store); - gdk_cairo_set_source_color (cr, &style->fg[gtk_widget_get_state(widget)]); +#endif - if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) - { - cairo_rectangle (cr, - xthickness, - height + ythickness, - allocation.width - 2 * xthickness, - 1); + bs_width = height / 2 + 2; + bs_width |= 1; /* make sure it's odd */ + bs_height = bs_width / 2 + 1; } else { - cairo_rectangle (cr, - height + xthickness, - ythickness, - 1, - allocation.height - 2 * ythickness); - } +#if GTK_CHECK_VERSION(3,0,0) + width = allocation.width - (border.left + border.right); +#else + width = allocation.width - xthickness * 2; +#endif + height = allocation.height; - upper = ruler->upper / ruler->metric->pixels_per_unit; - lower = ruler->lower / ruler->metric->pixels_per_unit; + bs_height = width / 2 + 2; + bs_height |= 1; /* make sure it's odd */ + bs_width = bs_height / 2 + 1; + } - if ((upper - lower) == 0) - goto out; + if ((bs_width > 0) && (bs_height > 0)) + { + cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (widget)); + gdouble lower; + gdouble upper; + gdouble position; + gdouble increment; - increment = (gdouble) width / (upper - lower); + cairo_rectangle (cr, + allocation.x, allocation.y, + allocation.width, allocation.height); + cairo_clip (cr); - /* determine the scale H - * We calculate the text size as for the vruler instead of using - * text_width = gdk_string_width(font, unit_str), so that the result - * for the scale looks consistent with an accompanying vruler - */ - /* determine the scale V - * use the maximum extents of the ruler to determine the largest - * possible number to be displayed. Calculate the height in pixels - * of this displayed text. Use this height to find a scale which - * leaves sufficient room for drawing the ruler. - */ - scale = ceil (ruler->max_size / ruler->metric->pixels_per_unit); - g_snprintf (unit_str, sizeof (unit_str), "%d", scale); + cairo_translate (cr, allocation.x, allocation.y); - if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) - { - text_width = strlen (unit_str) * digit_height + 1; + /* If a backing store exists, restore the ruler */ + if (priv->backing_store) + { + cairo_set_source_surface (cr, priv->backing_store, 0, 0); + cairo_rectangle (cr, priv->xsrc, priv->ysrc, bs_width, bs_height); + cairo_fill (cr); + } - for (scale = 0; scale < MAXIMUM_SCALES; scale++) - if (ruler->metric->ruler_scale[scale] * fabs(increment) > 2 * text_width) - break; - } - else - { - text_height = strlen (unit_str) * digit_height + 1; + position = sp_ruler_get_position (ruler); - for (scale = 0; scale < MAXIMUM_SCALES; scale++) - if (ruler->metric->ruler_scale[scale] * fabs(increment) > 2 * text_height) - break; - } + sp_ruler_get_range (ruler, &lower, &upper, NULL); - if (scale == MAXIMUM_SCALES) - scale = MAXIMUM_SCALES - 1; + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + increment = (gdouble) width / (upper - lower); - /* drawing starts here */ - length = 0; - for (i = MAXIMUM_SUBDIVIDE - 1; i >= 0; i--) - { - subd_incr = (gdouble) ruler->metric->ruler_scale[scale] / - (gdouble) ruler->metric->subdivide[i]; - if (subd_incr * fabs(increment) <= MINIMUM_INCR) - continue; - - /* Calculate the length of the tickmarks. Make sure that - * this length increases for each set of ticks - */ - ideal_length = height / (i + 1) - 1; - if (ideal_length > ++length) - length = ideal_length; - - if (lower < upper) - { - start = floor (lower / subd_incr) * subd_incr; - end = ceil (upper / subd_incr) * subd_incr; - } +#if GTK_CHECK_VERSION(3,0,0) + x = ROUND ((position - lower) * increment) + (border.left - bs_width) / 2 - 1; + y = (height + bs_height) / 2 + border.top; +#else + x = ROUND ((position - lower) * increment) + (xthickness - bs_width) / 2 - 1; + y = (height + bs_height) / 2 + ythickness; +#endif + } else - { - start = floor (upper / subd_incr) * subd_incr; - end = ceil (lower / subd_incr) * subd_incr; - } - - for (cur = start; cur <= end; cur += subd_incr) - { - pos = ROUND ((cur - lower) * increment); - - if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) - { - cairo_rectangle (cr, - pos, height + ythickness - length, - 1, length); - } - else - { - cairo_rectangle (cr, - height + xthickness - length, pos, - length, 1); - } - - /* draw label */ - if (i == 0) - { - g_snprintf (unit_str, sizeof (unit_str), "%d", (int) cur); - - if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) - { - pango_layout_set_text (layout, unit_str, -1); - pango_layout_get_extents (layout, &logical_rect, NULL); - - gtk_paint_layout (style, - ruler->backing_store, - gtk_widget_get_state (widget), - FALSE, - NULL, - widget, - "hruler", - pos + 2, ythickness + PANGO_PIXELS (logical_rect.y - digit_offset), - layout); - } - else - { - for (j = 0; j < (int) strlen (unit_str); j++) - { - pango_layout_set_text (layout, unit_str + j, 1); - pango_layout_get_extents (layout, NULL, &logical_rect); - - gtk_paint_layout (style, - ruler->backing_store, - gtk_widget_get_state (widget), - FALSE, - NULL, - widget, - "vruler", - xthickness + 1, - pos + digit_height * j + 2 + PANGO_PIXELS (logical_rect.y - digit_offset), - layout); - } - } - } - } - } - - cairo_fill (cr); -out: - cairo_destroy (cr); + { + increment = (gdouble) height / (upper - lower); - g_object_unref (layout); -} +#if GTK_CHECK_VERSION(3,0,0) + x = (width + bs_width) / 2 + border.left; + y = ROUND ((position - lower) * increment) + (border.top - bs_height) / 2 - 1; +#else + x = (width + bs_width) / 2 + xthickness; + y = ROUND ((position - lower) * increment) + (ythickness - bs_height) / 2 - 1; +#endif + } -static void -gtk_deprecated_ruler_real_draw_pos (GtkDeprecatedRuler *ruler) -{ - GtkAllocation allocation; - GtkWidget *widget = GTK_WIDGET (ruler); - GtkDeprecatedRulerPrivate *priv = GTK_DEPRECATED_RULER_GET_PRIVATE (ruler); - GtkStyle *style; - gint x, y; - gint width, height; - gint bs_width, bs_height; - gint xthickness; - gint ythickness; - gdouble increment; - - if (gtk_widget_is_drawable (widget)) - { - style = gtk_widget_get_style(widget); - gtk_widget_get_allocation(widget, &allocation); +#if GTK_CHECK_VERSION(3,0,0) + gtk_style_context_get_color (context, gtk_widget_get_state_flags (widget), + &color); + gdk_cairo_set_source_rgba (cr, &color); +#else + gdk_cairo_set_source_color (cr, &style->fg[state]); +#endif - xthickness = style->xthickness; - ythickness = style->ythickness; - width = allocation.width; - height = allocation.height; + cairo_move_to (cr, x, y); if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) { - height -= ythickness * 2; - - bs_width = height / 2 + 2; - bs_width |= 1; /* make sure it's odd */ - bs_height = bs_width / 2 + 1; + cairo_line_to (cr, x + bs_width / 2.0, y + bs_height); + cairo_line_to (cr, x + bs_width, y); } else { - width -= xthickness * 2; - - bs_height = width / 2 + 2; - bs_height |= 1; /* make sure it's odd */ - bs_width = bs_height / 2 + 1; + cairo_line_to (cr, x + bs_width, y + bs_height / 2.0); + cairo_line_to (cr, x, y + bs_height); } - if ((bs_width > 0) && (bs_height > 0)) - { - GdkWindow *window = gtk_widget_get_window(widget); - cairo_t *cr = gdk_cairo_create(window); - - /* If a backing store exists, restore the ruler */ - if (ruler->backing_store) - { - cairo_t *cr = gdk_cairo_create(window); - - gdk_cairo_set_source_pixmap (cr, ruler->backing_store, 0, 0); - cairo_rectangle (cr, ruler->xsrc, ruler->ysrc, bs_width, bs_height); - cairo_fill (cr); + cairo_fill (cr); - cairo_destroy (cr); - } + cairo_destroy (cr); - if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) - { - increment = (gdouble) width / (ruler->upper - ruler->lower); + priv->xsrc = x; + priv->ysrc = y; + } +} - x = ROUND ((ruler->position - ruler->lower) * increment) + (xthickness - bs_width) / 2 - 1; - y = (height + bs_height) / 2 + ythickness; - } - else - { - increment = (gdouble) height / (ruler->upper - ruler->lower); +/** + * sp_ruler_new: + * @orientation: the ruler's orientation + * + * Creates a new ruler. + * + * Return value: a new #SPRuler widget. + */ +GtkWidget * +sp_ruler_new (GtkOrientation orientation) +{ + return GTK_WIDGET (g_object_new (SP_TYPE_RULER, + "orientation", orientation, + NULL)); +} - x = (width + bs_width) / 2 + xthickness; - y = ROUND ((ruler->position - ruler->lower) * increment) + (ythickness - bs_height) / 2 - 1; - } +static void +sp_ruler_update_position (SPRuler *ruler, + gdouble x, + gdouble y) +{ + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler); + GtkAllocation allocation; + gdouble lower; + gdouble upper; - gdk_cairo_set_source_color(cr, &style->fg[gtk_widget_get_state(widget)]); + gtk_widget_get_allocation (GTK_WIDGET (ruler), &allocation); + sp_ruler_get_range (ruler, &lower, &upper, NULL); - cairo_move_to (cr, x, y); + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + sp_ruler_set_position (ruler, + lower + + (upper - lower) * x / allocation.width); + } + else + { + sp_ruler_set_position (ruler, + lower + + (upper - lower) * y / allocation.height); + } +} - if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) - { - cairo_line_to (cr, x + bs_width / 2.0, y + bs_height); - cairo_line_to (cr, x + bs_width, y); - } - else - { - cairo_line_to (cr, x + bs_width, y + bs_height / 2.0); - cairo_line_to (cr, x, y + bs_height); - } +/* Returns TRUE if a translation should be done */ +static gboolean +gtk_widget_get_translation_to_window (GtkWidget *widget, + GdkWindow *window, + int *x, + int *y) +{ + GdkWindow *w, *widget_window; - cairo_fill (cr); + if (! gtk_widget_get_has_window (widget)) + { + GtkAllocation allocation; - cairo_destroy (cr); + gtk_widget_get_allocation (widget, &allocation); - ruler->xsrc = x; - ruler->ysrc = y; - } + *x = -allocation.x; + *y = -allocation.y; + } + else + { + *x = 0; + *y = 0; } -} - - + widget_window = gtk_widget_get_window (widget); + for (w = window; + w && w != widget_window; + w = gdk_window_get_effective_parent (w)) + { + gdouble px, py; -#define UNUSED_PIXELS 2 // There appear to be two pixels that are not being used at each end of the ruler + gdk_window_coords_to_parent (w, *x, *y, &px, &py); -static void sp_ruler_common_draw_ticks (GtkDeprecatedRuler *ruler); + *x += px; + *y += px; + } -static void sp_hruler_class_init (SPHRulerClass *klass); -static void sp_hruler_init (SPHRuler *hruler); -static gint sp_hruler_motion_notify (GtkWidget *widget, GdkEventMotion *event); + if (w == NULL) + { + *x = 0; + *y = 0; + return FALSE; + } -static GtkWidgetClass *hruler_parent_class; + return TRUE; +} -GType -sp_hruler_get_type (void) +static void +sp_ruler_event_to_widget_coords (GtkWidget *widget, + GdkWindow *window, + gdouble event_x, + gdouble event_y, + gint *widget_x, + gint *widget_y) { - static GType hruler_type = 0; + gint tx, ty; - if (!hruler_type) + if (gtk_widget_get_translation_to_window (widget, window, &tx, &ty)) { - static const GTypeInfo hruler_info = { - sizeof (SPHRulerClass), - NULL, NULL, - (GClassInitFunc) sp_hruler_class_init, - NULL, NULL, - sizeof (SPHRuler), - 0, - (GInstanceInitFunc) sp_hruler_init, - NULL - }; - - hruler_type = g_type_register_static (gtk_deprecated_ruler_get_type (), "SPHRuler", &hruler_info, (GTypeFlags)0); + event_x += tx; + event_y += ty; } - return hruler_type; + *widget_x = event_x; + *widget_y = event_y; } -static void -sp_hruler_class_init (SPHRulerClass *klass) +static gboolean +sp_ruler_track_widget_motion_notify (GtkWidget *widget, + GdkEventMotion *mevent, + SPRuler *ruler) { - GtkWidgetClass *widget_class; - GtkDeprecatedRulerClass *ruler_class; + gint widget_x; + gint widget_y; + gint ruler_x; + gint ruler_y; - hruler_parent_class = (GtkWidgetClass *) g_type_class_peek_parent (klass); + widget = gtk_get_event_widget (reinterpret_cast<GdkEvent *>(mevent)); - widget_class = (GtkWidgetClass*) klass; - ruler_class = (GtkDeprecatedRulerClass*) klass; + sp_ruler_event_to_widget_coords (widget, mevent->window, + mevent->x, mevent->y, + &widget_x, &widget_y); - widget_class->motion_notify_event = sp_hruler_motion_notify; + if (gtk_widget_translate_coordinates (widget, GTK_WIDGET (ruler), + widget_x, widget_y, + &ruler_x, &ruler_y)) + { + sp_ruler_update_position (ruler, ruler_x, ruler_y); + } - ruler_class->draw_ticks = sp_ruler_common_draw_ticks; + return FALSE; } -static void -sp_hruler_init (SPHRuler *hruler) +void +sp_ruler_add_track_widget (SPRuler *ruler, + GtkWidget *widget) { - GtkWidget *widget; - GtkRequisition requisition; - GtkStyle *style; - - widget = GTK_WIDGET (hruler); - gtk_widget_get_requisition (widget, &requisition); - style = gtk_widget_get_style (widget); - requisition.width = style->xthickness * 2 + 1; - requisition.height = style->ythickness * 2 + RULER_HEIGHT; -} - + SPRulerPrivate *priv; -GtkWidget* -sp_hruler_new (void) -{ - return GTK_WIDGET (g_object_new (sp_hruler_get_type (), NULL)); -} + g_return_if_fail (SP_IS_RULER (ruler)); + g_return_if_fail (GTK_IS_WIDGET (ruler)); -static gint -sp_hruler_motion_notify (GtkWidget *widget, - GdkEventMotion *event) -{ - GtkDeprecatedRuler *ruler; - gdouble lower, upper, max_size; - GtkAllocation allocation; + priv = SP_RULER_GET_PRIVATE (ruler); - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (SP_IS_HRULER (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); + g_return_if_fail (g_list_find (priv->track_widgets, widget) == NULL); - ruler = GTK_DEPRECATED_RULER (widget); - gtk_deprecated_ruler_get_range (ruler, &lower, &upper, NULL, &max_size); - gtk_widget_get_allocation (widget, &allocation); - double x = event->x; //Although event->x is double according to the docs, it only appears to return integers - double pos = lower + (upper - lower) * (x + UNUSED_PIXELS) / (allocation.width + 2*UNUSED_PIXELS); - - gtk_deprecated_ruler_set_range(ruler, lower, upper, pos, max_size); + priv->track_widgets = g_list_prepend (priv->track_widgets, widget); - return FALSE; + g_signal_connect (widget, "motion-notify-event", + G_CALLBACK (sp_ruler_track_widget_motion_notify), + ruler); + g_signal_connect (widget, "destroy", + G_CALLBACK (sp_ruler_remove_track_widget), + ruler); } -// vruler +/** + * sp_ruler_remove_track_widget: + * @ruler: an #SPRuler + * @widget: the track widget to remove + * + * Removes a previously added track widget from the ruler. See + * sp_ruler_add_track_widget(). + */ +void +sp_ruler_remove_track_widget (SPRuler *ruler, + GtkWidget *widget) +{ + SPRulerPrivate *priv; + + g_return_if_fail (SP_IS_RULER (ruler)); + g_return_if_fail (GTK_IS_WIDGET (ruler)); -static void sp_vruler_class_init (SPVRulerClass *klass); -static void sp_vruler_init (SPVRuler *vruler); -static gint sp_vruler_motion_notify (GtkWidget *widget, - GdkEventMotion *event); -static void sp_vruler_size_request (GtkWidget *widget, GtkRequisition *requisition); + priv = SP_RULER_GET_PRIVATE (ruler); -#if GTK_CHECK_VERSION(3,0,0) -static void sp_vruler_get_preferred_width(GtkWidget *widget, - gint *minimal_width, - gint *natural_width); + g_return_if_fail (g_list_find (priv->track_widgets, widget) != NULL); -static void sp_vruler_get_preferred_height(GtkWidget *widget, - gint *minimal_height, - gint *natural_height); -#endif + priv->track_widgets = g_list_remove (priv->track_widgets, widget); -static GtkWidgetClass *vruler_parent_class; + g_signal_handlers_disconnect_by_func (widget, + (gpointer) G_CALLBACK (sp_ruler_track_widget_motion_notify), + ruler); + g_signal_handlers_disconnect_by_func (widget, + (gpointer) G_CALLBACK (sp_ruler_remove_track_widget), + ruler); +} -GType -sp_vruler_get_type (void) +/** + * sp_ruler_set_unit: + * @ruler: a #SPRuler + * @unit: the #SPMetric to set the ruler to + * + * This sets the unit of the ruler. + */ +void +sp_ruler_set_unit (SPRuler *ruler, + Inkscape::Util::Unit const *unit) { - static GType vruler_type = 0; + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler); + + g_return_if_fail (SP_IS_RULER (ruler)); - if (!vruler_type) + if (*priv->unit != *unit) { - static const GTypeInfo vruler_info = { - sizeof (SPVRulerClass), - NULL, NULL, - (GClassInitFunc) sp_vruler_class_init, - NULL, NULL, - sizeof (SPVRuler), - 0, - (GInstanceInitFunc) sp_vruler_init, - NULL - }; - - vruler_type = g_type_register_static (gtk_deprecated_ruler_get_type (), "SPVRuler", &vruler_info, (GTypeFlags)0); - } + priv->unit = unit; + g_object_notify(G_OBJECT(ruler), "unit"); - return vruler_type; + gtk_widget_queue_draw (GTK_WIDGET (ruler)); + } } -static void -sp_vruler_class_init (SPVRulerClass *klass) +/** + * sp_ruler_get_unit: + * @ruler: a #SPRuler + * + * Return value: the unit currently used in the @ruler widget. + **/ +Inkscape::Util::Unit const* +sp_ruler_get_unit (SPRuler *ruler) { - GtkWidgetClass *widget_class; - GtkDeprecatedRulerClass *ruler_class; - - vruler_parent_class = (GtkWidgetClass *) g_type_class_peek_parent (klass); - - widget_class = (GtkWidgetClass*) klass; - ruler_class = (GtkDeprecatedRulerClass*) klass; - - widget_class->motion_notify_event = sp_vruler_motion_notify; - -#if GTK_CHECK_VERSION(3,0,0) - widget_class->get_preferred_width = sp_vruler_get_preferred_width; - widget_class->get_preferred_height = sp_vruler_get_preferred_height; -#else - widget_class->size_request = sp_vruler_size_request; -#endif - - ruler_class->draw_ticks = sp_ruler_common_draw_ticks; + return SP_RULER_GET_PRIVATE (ruler)->unit; } -static void -sp_vruler_init (SPVRuler *vruler) +/** + * sp_ruler_set_position: + * @ruler: a #SPRuler + * @position: the position to set the ruler to + * + * This sets the position of the ruler. + */ +void +sp_ruler_set_position (SPRuler *ruler, + gdouble position) { - GtkWidget *widget; - GtkRequisition requisition; - GtkStyle *style; + SPRulerPrivate *priv; - widget = GTK_WIDGET (vruler); - gtk_widget_get_requisition (widget, &requisition); - style = gtk_widget_get_style (widget); - requisition.width = style->xthickness * 2 + RULER_WIDTH; - requisition.height = style->ythickness * 2 + 1; + g_return_if_fail (SP_IS_RULER (ruler)); + + priv = SP_RULER_GET_PRIVATE (ruler); + + if (priv->position != position) + { + priv->position = position; + g_object_notify (G_OBJECT (ruler), "position"); - g_object_set(G_OBJECT(vruler), "orientation", GTK_ORIENTATION_VERTICAL, NULL); + sp_ruler_draw_pos (ruler); + } } -GtkWidget* -sp_vruler_new (void) +/** + * sp_ruler_get_position: + * @ruler: a #SPRuler + * + * Return value: the current position of the @ruler widget. + */ +gdouble +sp_ruler_get_position (SPRuler *ruler) { - return GTK_WIDGET (g_object_new (sp_vruler_get_type (), NULL)); -} + g_return_val_if_fail (SP_IS_RULER (ruler), 0.0); + return SP_RULER_GET_PRIVATE (ruler)->position; +} -static gint -sp_vruler_motion_notify (GtkWidget *widget, - GdkEventMotion *event) +static gboolean +sp_ruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event) { - GtkDeprecatedRuler *ruler; - gdouble lower, upper, max_size; - GtkAllocation allocation; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (SP_IS_VRULER (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - ruler = GTK_DEPRECATED_RULER (widget); - gtk_deprecated_ruler_get_range (ruler, &lower, &upper, NULL, &max_size); - gtk_widget_get_allocation (widget, &allocation); - double y = event->y; //Although event->y is double according to the docs, it only appears to return integers - double pos = lower + (upper - lower) * (y + UNUSED_PIXELS) / (allocation.height + 2*UNUSED_PIXELS); + SPRuler *ruler = SP_RULER(widget); - gtk_deprecated_ruler_set_range(ruler, lower, upper, pos, max_size); + sp_ruler_update_position (ruler, event->x, event->y); return FALSE; } static void -sp_vruler_size_request (GtkWidget *widget, GtkRequisition *requisition) +sp_ruler_draw_ticks (SPRuler *ruler) { - GtkStyle *style = gtk_widget_get_style (widget); - requisition->width = style->xthickness * 2 + RULER_WIDTH; -} + GtkWidget *widget = GTK_WIDGET (ruler); #if GTK_CHECK_VERSION(3,0,0) -static void sp_vruler_get_preferred_width(GtkWidget *widget, gint *minimal_width, gint *natural_width) -{ - GtkRequisition requisition; - sp_vruler_size_request(widget, &requisition); - *minimal_width = *natural_width = requisition.width; -} - -static void sp_vruler_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height) -{ - GtkRequisition requisition; - sp_vruler_size_request(widget, &requisition); - *minimal_height = *natural_height = requisition.height; -} + GtkStyleContext *context = gtk_widget_get_style_context (widget); + GtkBorder border; + GdkRGBA color; +#else + GtkStyle *style = gtk_widget_get_style (widget); + GtkStateType state = gtk_widget_get_state (widget); + gint xthickness; + gint ythickness; #endif -static void -sp_ruler_common_draw_ticks(GtkDeprecatedRuler *ruler) -{ - gint width = 0; - gint height = 0; - gchar unit_str[32]; - gchar digit_str[2] = { '\0', '\0' }; - GtkOrientation orientation; - GtkAllocation allocation; - - g_return_if_fail (ruler != NULL); - - if (!gtk_widget_is_drawable (GTK_WIDGET (ruler))) - return; - - g_object_get(G_OBJECT(ruler), "orientation", &orientation, NULL); - GtkWidget *widget = GTK_WIDGET (ruler); - GtkStyle *style = gtk_widget_get_style (widget); - GdkGC *gc = style->fg_gc[GTK_STATE_NORMAL]; - - PangoContext *pango_context = gtk_widget_get_pango_context (widget); - PangoLayout *pango_layout = pango_layout_new (pango_context); - PangoFontDescription *fs = pango_font_description_new (); - pango_font_description_set_size (fs, RULER_FONT_SIZE); - pango_layout_set_font_description (pango_layout, fs); - pango_font_description_free (fs); - - gint digit_height = (int) floor (RULER_FONT_SIZE * RULER_FONT_VERTICAL_SPACING / PANGO_SCALE + 0.5); - gint xthickness = style->xthickness; - gint ythickness = style->ythickness; + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler); + GtkAllocation allocation; + cairo_t *cr; + gint i; + gint width, height; + gint length, ideal_length; + gdouble lower, upper; /* Upper and lower limits, in ruler units */ + gdouble increment; /* Number of pixels per unit */ + guint scale; /* Number of units per major unit */ + gdouble start, end, cur; + gchar unit_str[32]; + gint digit_height; + gint digit_offset; + gchar digit_str[2] = { '\0', '\0' }; + gint text_size; + gint pos; + gdouble max_size; + Inkscape::Util::Unit const *unit = NULL; + SPRulerMetric ruler_metric = ruler_metric_general; /* The metric to use for this unit system */ + PangoLayout *layout; + PangoRectangle logical_rect, ink_rect; + + if (! gtk_widget_is_drawable (widget)) + return; gtk_widget_get_allocation (widget, &allocation); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_style_context_get_border (context, static_cast<GtkStateFlags>(0), &border); +#else + xthickness = style->xthickness; + ythickness = style->ythickness; +#endif + + layout = sp_ruler_get_layout (widget, "0123456789"); + pango_layout_get_extents (layout, &ink_rect, &logical_rect); - if (orientation == GTK_ORIENTATION_HORIZONTAL) { - width = allocation.width; // in pixels; is apparently 2 pixels shorter than the canvas at each end - height = allocation.height; - } else { + digit_height = PANGO_PIXELS (ink_rect.height) + 2; + digit_offset = ink_rect.y; + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + width = allocation.width; +#if GTK_CHECK_VERSION(3,0,0) + height = allocation.height - (border.top + border.bottom); +#else + height = allocation.height - ythickness * 2; +#endif + } + else + { width = allocation.height; - height = allocation.width; - } +#if GTK_CHECK_VERSION(3,0,0) + height = allocation.width - (border.top + border.bottom); +#else + height = allocation.width - ythickness * 2; +#endif + } + + cr = cairo_create (priv->backing_store); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_render_background (context, cr, 0, 0, allocation.width, allocation.height); + gtk_render_frame (context, cr, 0, 0, allocation.width, allocation.height); + + gtk_style_context_get_color (context, gtk_widget_get_state_flags (widget), + &color); + gdk_cairo_set_source_rgba (cr, &color); + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + cairo_rectangle (cr, + border.left, + height + border.top, + allocation.width - (border.left + border.right), + 1); + } + else + { + cairo_rectangle (cr, + height + border.left, + border.top, + 1, + allocation.height - (border.top + border.bottom)); + } +#else + gdk_cairo_set_source_color (cr, &style->bg[state]); + + cairo_paint (cr); + + gdk_cairo_set_source_color(cr, &style->fg[state]); + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + cairo_rectangle (cr, + xthickness, + height + ythickness, + allocation.width - 2 * xthickness, + 1); + } + else + { + cairo_rectangle (cr, + height + xthickness, + ythickness, + 1, + allocation.height - 2 * ythickness); + } +#endif - gtk_paint_box (style, ruler->backing_store, - GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, widget, - orientation == GTK_ORIENTATION_HORIZONTAL ? "hruler" : "vruler", - 0, 0, - allocation.width, allocation.height); - - gdouble ruler_upper = 0; - gdouble ruler_lower = 0; - gdouble max_size = 0; - gtk_deprecated_ruler_get_range(ruler, &ruler_lower, &ruler_upper, NULL, &max_size); - gdouble upper = ruler_upper / ruler->metric->pixels_per_unit; // upper and lower are expressed in ruler units - gdouble lower = ruler_lower / ruler->metric->pixels_per_unit; - /* "pixels_per_unit" should be "points_per_unit". This is the size of the unit - * in 1/72nd's of an inch and has nothing to do with screen pixels */ + sp_ruler_get_range (ruler, &lower, &upper, &max_size); if ((upper - lower) == 0) - return; + goto out; - double increment = (double) (width + 2*UNUSED_PIXELS) / (upper - lower); // screen pixels per ruler unit + increment = (gdouble) width / (upper - lower); /* determine the scale - * For vruler, use the maximum extents of the ruler to determine the largest - * possible number to be displayed. Calculate the height in pixels - * of this displayed text. Use this height to find a scale which - * leaves sufficient room for drawing the ruler. - * For hruler, we calculate the text size as for the vruler instead of using - * text_width = gdk_string_width(font, unit_str), so that the result - * for the scale looks consistent with an accompanying vruler + * Use the maximum extents of the ruler to determine the largest + * possible number to be displayed. Calculate the height in pixels + * of this displayed text. Use this height to find a scale which + * leaves sufficient room for drawing the ruler. + * + * We calculate the text size as for the vruler instead of + * actually measuring the text width, so that the result for the + * scale looks consistent with an accompanying vruler */ - gint scale = (int)(ceil(max_size / ruler->metric->pixels_per_unit)); + scale = ceil (priv->max_size); sprintf (unit_str, "%d", scale); - gint text_dimension = strlen (unit_str) * digit_height + 1; + text_size = strlen (unit_str) * digit_height + 1; + + /* Inkscape change to ruler: Use a 1,2,4,8... scale for inches + * or a 1,2,5,10... scale for everything else */ + if (*sp_ruler_get_unit (ruler) == *unit_table.getUnit("in")) + ruler_metric = ruler_metric_inches; - for (scale = 0; scale < MAXIMUM_SCALES; scale++) - if (ruler->metric->ruler_scale[scale] * fabs(increment) > 2 * text_dimension) + for (scale = 0; scale < G_N_ELEMENTS (ruler_metric.ruler_scale); scale++) + if (ruler_metric.ruler_scale[scale] * fabs (increment) > 2 * text_size) break; - if (scale == MAXIMUM_SCALES) - scale = MAXIMUM_SCALES - 1; + if (scale == G_N_ELEMENTS (ruler_metric.ruler_scale)) + scale = G_N_ELEMENTS (ruler_metric.ruler_scale) - 1; + + unit = sp_ruler_get_unit (ruler); /* drawing starts here */ - gint length = 0; - for (gint i = MAXIMUM_SUBDIVIDE - 1; i >= 0; i--) { - double subd_incr = ruler->metric->ruler_scale[scale] / - ruler->metric->subdivide[i]; - if (subd_incr * fabs(increment) <= MINIMUM_INCR) + length = 0; + for (i = G_N_ELEMENTS (ruler_metric.subdivide) - 1; i >= 0; i--) + { + gdouble subd_incr; + + /* hack to get proper subdivisions at full pixels */ + if (*unit == *unit_table.getUnit("px") && scale == 1 && i == 1) + subd_incr = 1.0; + else + subd_incr = ((gdouble) ruler_metric.ruler_scale[scale] / + (gdouble) ruler_metric.subdivide[i]); + + if (subd_incr * fabs (increment) <= MINIMUM_INCR) continue; /* Calculate the length of the tickmarks. Make sure that * this length increases for each set of ticks */ - gint ideal_length = height / (i + 1) - 1; + ideal_length = height / (i + 1) - 1; if (ideal_length > ++length) length = ideal_length; - gdouble start = 0; - gdouble end = 0; - if (lower < upper) { + if (lower < upper) + { start = floor (lower / subd_incr) * subd_incr; end = ceil (upper / subd_incr) * subd_incr; - } else { + } + else + { start = floor (upper / subd_incr) * subd_incr; end = ceil (lower / subd_incr) * subd_incr; - } + } gint tick_index = 0; - gdouble cur = start; // location (in ruler units) of the first invisible tick at the left side of the canvas - while (cur <= end) { + for (cur = start; cur <= end; cur += subd_incr) + { // due to the typical values for cur, lower and increment, pos will often end up to // be e.g. 641.50000000000; rounding behaviour is not defined in such a case (see round.h) // and jitter will be apparent (upon redrawing some of the lines on the ruler might jump a // by a pixel, and jump back on the next redraw). This is suppressed by adding 1e-9 (that's only one nanopixel ;-)) - gint pos = int(Inkscape::round((cur - lower) * increment + 1e-12)) - UNUSED_PIXELS; - - if (orientation == GTK_ORIENTATION_HORIZONTAL) { - gdk_draw_line (ruler->backing_store, gc, - pos, height + ythickness, - pos, height - length + ythickness); - } else { - gdk_draw_line (ruler->backing_store, gc, - height + xthickness - length, pos, - height + xthickness, pos); - } + pos = gint(Inkscape::round((cur - lower) * increment + 1e-12)); + +#if GTK_CHECK_VERSION(3,0,0) + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + cairo_rectangle (cr, + pos, height + border.top - length, + 1, length); + } + else + { + cairo_rectangle (cr, + height + border.left - length, pos, + length, 1); + } +#else + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + cairo_rectangle (cr, + pos, height + ythickness - length, + 1, length); + } + else + { + cairo_rectangle (cr, + height + xthickness - length, pos, + length, 1); + } +#endif /* draw label */ - double label_spacing_px = fabs((increment*(double)ruler->metric->ruler_scale[scale])/ruler->metric->subdivide[i]); + double label_spacing_px = fabs(increment*(double)ruler_metric.ruler_scale[scale]/ruler_metric.subdivide[i]); if (i == 0 && (label_spacing_px > 6*digit_height || tick_index%2 == 0 || cur == 0) && (label_spacing_px > 3*digit_height || tick_index%4 == 0 || cur == 0)) - { + { if (fabs((int)cur) >= 2000 && (((int) cur)/1000)*1000 == ((int) cur)) sprintf (unit_str, "%dk", ((int) cur)/1000); else sprintf (unit_str, "%d", (int) cur); - if (orientation == GTK_ORIENTATION_HORIZONTAL) { - pango_layout_set_text (pango_layout, unit_str, -1); - gdk_draw_layout (ruler->backing_store, gc, - pos + 2, 0, pango_layout); - } else { - for (gint j = 0; j < (int) strlen (unit_str); j++) { + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + pango_layout_set_text (layout, unit_str, -1); + pango_layout_get_extents (layout, &logical_rect, NULL); + +#if GTK_CHECK_VERSION(3,0,0) + cairo_move_to (cr, + pos + 2, + border.top + PANGO_PIXELS (logical_rect.y - digit_offset)); +#else + cairo_move_to (cr, + pos + 2, + ythickness + PANGO_PIXELS (logical_rect.y - digit_offset)); +#endif + + pango_cairo_show_layout(cr, layout); + } + else + { + gint j; + + for (j = 0; j < (int) strlen (unit_str); j++) + { digit_str[0] = unit_str[j]; - pango_layout_set_text (pango_layout, digit_str, 1); - - gdk_draw_layout (ruler->backing_store, gc, - xthickness + 1, - pos + digit_height * (j) + 1, - pango_layout); - } - } - } - /* Calculate cur from start rather than incrementing by subd_incr - * in each iteration. This is to avoid propagation of floating point - * errors in subd_incr. - */ + pango_layout_set_text (layout, digit_str, 1); + pango_layout_get_extents (layout, NULL, &logical_rect); + +#if GTK_CHECK_VERSION(3,0,0) + cairo_move_to (cr, + border.left + 1, + pos + digit_height * j + 2 + PANGO_PIXELS (logical_rect.y - digit_offset)); +#else + cairo_move_to (cr, + xthickness + 1, + pos + digit_height * j + 2 + PANGO_PIXELS (logical_rect.y - digit_offset)); +#endif + pango_cairo_show_layout (cr, layout); + } + } + } + ++tick_index; - cur = start + tick_index * subd_incr; - } - } -} + } + } + + cairo_fill (cr); +out: + cairo_destroy (cr); +} -void sp_ruler_set_metric(GtkDeprecatedRuler *ruler, SPMetric metric) +static PangoLayout* +sp_ruler_create_layout (GtkWidget *widget, + const gchar *text) { - g_return_if_fail(ruler != NULL); - g_return_if_fail(GTK_DEPRECATED_IS_RULER (ruler)); - g_return_if_fail((unsigned) metric < G_N_ELEMENTS(sp_ruler_metrics)); + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (widget); + PangoLayout *layout; + PangoAttrList *attrs; + PangoAttribute *attr; + + layout = gtk_widget_create_pango_layout (widget, text); + + attrs = pango_attr_list_new (); + + attr = pango_attr_scale_new (priv->font_scale); + attr->start_index = 0; + attr->end_index = -1; + pango_attr_list_insert (attrs, attr); + + pango_layout_set_attributes (layout, attrs); + pango_attr_list_unref (attrs); + + return layout; +} - if (metric == 0) - return; +static PangoLayout * +sp_ruler_get_layout (GtkWidget *widget, + const gchar *text) +{ + SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (widget); - ruler->metric = const_cast<GtkDeprecatedRulerMetric *>(&sp_ruler_metrics[metric]); + if (priv->layout) + { + pango_layout_set_text (priv->layout, text, -1); + return priv->layout; + } - if (gtk_widget_is_drawable(GTK_WIDGET(ruler))) - gtk_widget_queue_draw(GTK_WIDGET(ruler)); + priv->layout = sp_ruler_create_layout (widget, text); - g_object_notify(G_OBJECT(ruler), "metric"); + return priv->layout; } + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/ruler.h b/src/widgets/ruler.h index 210a65bed..ed529d082 100644 --- a/src/widgets/ruler.h +++ b/src/widgets/ruler.h @@ -14,138 +14,63 @@ */ #include <gtk/gtk.h> -#include "sp-metric.h" #include <iostream> #include <glib.h> -#define GTK_DEPRECATED_TYPE_RULER (gtk_deprecated_ruler_get_type ()) -#define GTK_DEPRECATED_RULER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_DEPRECATED_TYPE_RULER, GtkDeprecatedRuler)) -#define GTK_DEPRECATED_RULER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_DEPRECATED_TYPE_RULER, GtkDeprecatedRulerClass)) -#define GTK_DEPRECATED_IS_RULER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_DEPRECATED_TYPE_RULER)) -#define GTK_DEPRECATED_IS_RULER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_DEPRECATED_TYPE_RULER)) -#define GTK_DEPRECATED_RULER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_DEPRECATED_TYPE_RULER, GtkDeprecatedRulerClass)) +namespace Inkscape { + namespace Util { + class Unit; + } +} +G_BEGIN_DECLS -typedef struct _GtkDeprecatedRuler GtkDeprecatedRuler; -typedef struct _GtkDeprecatedRulerClass GtkDeprecatedRulerClass; -typedef struct _GtkDeprecatedRulerMetric GtkDeprecatedRulerMetric; +#define SP_TYPE_RULER (sp_ruler_get_type ()) +#define SP_RULER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_RULER, SPRuler)) +#define SP_RULER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_RULER, SPRulerClass)) +#define SP_IS_RULER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_RULER)) +#define SP_IS_RULER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_RULER)) +#define SP_RULER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SP_TYPE_RULER, SPRulerClass)) -/* All distances below are in 1/72nd's of an inch. (According to - * Adobe that's a point, but points are really 1/72.27 in.) - */ -struct _GtkDeprecatedRuler -{ - GtkWidget widget; - - GdkPixmap *backing_store; - GdkGC *non_gr_exp_gc; /* unused */ - GtkDeprecatedRulerMetric *metric; - gint xsrc; - gint ysrc; - gint slider_size; - - /* The upper limit of the ruler (in points) */ - gdouble lower; - /* The lower limit of the ruler */ - gdouble upper; - /* The position of the mark on the ruler */ - gdouble position; - /* The maximum size of the ruler */ - gdouble max_size; -}; - -struct _GtkDeprecatedRulerClass -{ - GtkWidgetClass parent_class; - - void (* draw_ticks) (GtkDeprecatedRuler *ruler); - void (* draw_pos) (GtkDeprecatedRuler *ruler); - - /* Padding for future expansion */ - void (*_gtk_reserved1) (void); - void (*_gtk_reserved2) (void); - void (*_gtk_reserved3) (void); - void (*_gtk_reserved4) (void); -}; +typedef struct _SPRuler SPRuler; +typedef struct _SPRulerClass SPRulerClass; -struct _GtkDeprecatedRulerMetric +struct _SPRuler { - gchar const *metric_name; - gchar const *abbrev; - /* This should be points_per_unit. This is the size of the unit - * in 1/72nd's of an inch and has nothing to do with screen pixels */ - gdouble pixels_per_unit; - gdouble ruler_scale[10]; - gint subdivide[5]; /* five possible modes of subdivision */ + GtkWidget parent_instance; }; - -GType gtk_deprecated_ruler_get_type (void) G_GNUC_CONST; -void gtk_deprecated_ruler_set_range (GtkDeprecatedRuler *ruler, - gdouble lower, - gdouble upper, - gdouble position, - gdouble max_size); -void gtk_deprecated_ruler_get_range (GtkDeprecatedRuler *ruler, - gdouble *lower, - gdouble *upper, - gdouble *position, - gdouble *max_size); - -void gtk_deprecated_ruler_draw_ticks (GtkDeprecatedRuler *ruler); -void gtk_deprecated_ruler_draw_pos (GtkDeprecatedRuler *ruler); - - -void sp_ruler_set_metric (GtkDeprecatedRuler * ruler, SPMetric metric); -SPMetric sp_ruler_get_metric (GtkDeprecatedRuler *ruler); - - -#define SP_HRULER(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, sp_hruler_get_type (), SPHRuler) -#define SP_HRULER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, sp_hruler_get_type (), SPHRulerClass) -#define SP_IS_HRULER(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, sp_hruler_get_type ()) - - -struct SPHRuler +struct _SPRulerClass { - GtkDeprecatedRuler ruler; -}; - -struct SPHRulerClass -{ - GtkDeprecatedRulerClass parent_class; -}; - - -GType sp_hruler_get_type (void); -GtkWidget* sp_hruler_new (void); - - - -// vruler - - - -#define SP_VRULER(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, sp_vruler_get_type (), SPVRuler) -#define SP_VRULER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, sp_vruler_get_type (), SPVRulerClass) -#define SP_IS_VRULER(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, sp_vruler_get_type ()) - - -struct SPVRuler -{ - GtkDeprecatedRuler ruler; + GtkWidgetClass parent_class; }; -struct SPVRulerClass -{ - GtkDeprecatedRulerClass parent_class; -}; +GType sp_ruler_get_type (void) G_GNUC_CONST; -GType sp_vruler_get_type (void); -GtkWidget* sp_vruler_new (void); +GtkWidget* sp_ruler_new (GtkOrientation orientation); +void sp_ruler_add_track_widget (SPRuler *ruler, + GtkWidget *widget); +void sp_ruler_remove_track_widget (SPRuler *ruler, + GtkWidget *widget); +void sp_ruler_set_unit (SPRuler *ruler, + const Inkscape::Util::Unit *unit); +Inkscape::Util::Unit const * sp_ruler_get_unit (SPRuler *ruler); +void sp_ruler_set_position (SPRuler *ruler, + gdouble set_position); +gdouble sp_ruler_get_position (SPRuler *ruler); +void sp_ruler_set_range (SPRuler *ruler, + gdouble lower, + gdouble upper, + gdouble max_size); +void sp_ruler_get_range (SPRuler *ruler, + gdouble *lower, + gdouble *upper, + gdouble *max_size); +G_END_DECLS #endif /* __SP_RULER_H__ */ diff --git a/src/widgets/select-toolbar.cpp b/src/widgets/select-toolbar.cpp index 4378bc19d..284e436bf 100644 --- a/src/widgets/select-toolbar.cpp +++ b/src/widgets/select-toolbar.cpp @@ -16,45 +16,42 @@ # include "config.h" #endif -#include "ui/widget/spinbutton.h" -#include <gtk/gtk.h> - -#include "widgets/button.h" -#include "widgets/spw-utilities.h" -#include "widgets/widget-sizes.h" -#include "widgets/spinbutton-events.h" -#include "widgets/icon.h" -#include "widgets/sp-widget.h" +#include <2geom/rect.h> -#include "preferences.h" -#include "selection-chemistry.h" -#include "document.h" -#include "document-undo.h" -#include "inkscape.h" -#include "desktop-style.h" -#include "desktop.h" -#include "desktop-handles.h" -#include "sp-namedview.h" -#include "toolbox.h" +#include "ui/widget/spinbutton.h" #include <glibmm/i18n.h> -#include "helper/unit-menu.h" -#include "helper/units.h" -#include "inkscape.h" -#include "verbs.h" -#include "selection.h" -#include "selection-chemistry.h" -#include "sp-item-transform.h" -#include "message-stack.h" +#include "select-toolbar.h" +#include "desktop-handles.h" +#include "desktop.h" #include "display/sp-canvas.h" -#include "helper/unit-tracker.h" +#include "document-undo.h" +#include "document.h" #include "ege-adjustment-action.h" -#include "ege-output-action.h" +#include "helper/action-context.h" +#include "helper/action.h" #include "ink-action.h" -#include <2geom/rect.h> +#include "inkscape.h" +#include "message-stack.h" +#include "preferences.h" +#include "selection-chemistry.h" +#include "selection.h" +#include "sp-item-transform.h" +#include "sp-namedview.h" +#include "toolbox.h" #include "ui/icon-names.h" +#include "ui/widget/unit-tracker.h" +#include "util/units.h" +#include "verbs.h" +#include "widgets/icon.h" +#include "widgets/sp-widget.h" +#include "widgets/spw-utilities.h" +#include "widgets/widget-sizes.h" -using Inkscape::UnitTracker; +using Inkscape::UI::Widget::UnitTracker; +using Inkscape::Util::Unit; +using Inkscape::Util::Quantity; using Inkscape::DocumentUndo; +using Inkscape::Util::unit_table; static void sp_selection_layout_widget_update(SPWidget *spw, Inkscape::Selection *sel) @@ -75,7 +72,7 @@ sp_selection_layout_widget_update(SPWidget *spw, Inkscape::Selection *sel) Geom::OptRect const bbox(sel->bounds(bbox_type)); if ( bbox ) { UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(G_OBJECT(spw), "tracker")); - SPUnit const &unit = *tracker->getActiveUnit(); + Unit const *unit = tracker->getActiveUnit(); struct { char const *key; double val; } const keyval[] = { { "X", bbox->min()[X] }, @@ -84,17 +81,17 @@ sp_selection_layout_widget_update(SPWidget *spw, Inkscape::Selection *sel) { "height", bbox->dimensions()[Y] } }; - if (unit.base == SP_UNIT_DIMENSIONLESS) { - double const val = 1. / unit.unittobase; + if (unit->type == Inkscape::Util::UNIT_TYPE_DIMENSIONLESS) { + double const val = unit->factor * 100; for (unsigned i = 0; i < G_N_ELEMENTS(keyval); ++i) { - GtkAdjustment *a = (GtkAdjustment *) g_object_get_data(G_OBJECT(spw), keyval[i].key); + GtkAdjustment *a = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(spw), keyval[i].key)); gtk_adjustment_set_value(a, val); tracker->setFullVal( a, keyval[i].val ); } } else { for (unsigned i = 0; i < G_N_ELEMENTS(keyval); ++i) { - GtkAdjustment *a = (GtkAdjustment *) g_object_get_data(G_OBJECT(spw), keyval[i].key); - gtk_adjustment_set_value(a, sp_pixels_get_units(keyval[i].val, unit)); + GtkAdjustment *a = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(spw), keyval[i].key)); + gtk_adjustment_set_value(a, Quantity::convert(keyval[i].val, "px", unit)); } } } @@ -180,28 +177,28 @@ sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw) gdouble y1 = 0; gdouble xrel = 0; gdouble yrel = 0; - SPUnit const &unit = *tracker->getActiveUnit(); + Unit const *unit = tracker->getActiveUnit(); GtkAdjustment* a_x = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "X" ) ); GtkAdjustment* a_y = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "Y" ) ); GtkAdjustment* a_w = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "width" ) ); GtkAdjustment* a_h = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "height" ) ); - if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) { - x0 = sp_units_get_pixels (gtk_adjustment_get_value (a_x), unit); - y0 = sp_units_get_pixels (gtk_adjustment_get_value (a_y), unit); - x1 = x0 + sp_units_get_pixels (gtk_adjustment_get_value (a_w), unit); - xrel = sp_units_get_pixels (gtk_adjustment_get_value (a_w), unit) / bbox_user->dimensions()[Geom::X]; - y1 = y0 + sp_units_get_pixels (gtk_adjustment_get_value (a_h), unit); - yrel = sp_units_get_pixels (gtk_adjustment_get_value (a_h), unit) / bbox_user->dimensions()[Geom::Y]; + if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) { + x0 = Quantity::convert(gtk_adjustment_get_value(a_x), unit, "px"); + y0 = Quantity::convert(gtk_adjustment_get_value(a_y), unit, "px"); + x1 = x0 + Quantity::convert(gtk_adjustment_get_value(a_w), unit, "px"); + xrel = Quantity::convert(gtk_adjustment_get_value(a_w), unit, "px") / bbox_user->dimensions()[Geom::X]; + y1 = y0 + Quantity::convert(gtk_adjustment_get_value(a_h), unit, "px");; + yrel = Quantity::convert(gtk_adjustment_get_value(a_h), unit, "px") / bbox_user->dimensions()[Geom::Y]; } else { - double const x0_propn = gtk_adjustment_get_value (a_x) * unit.unittobase; + double const x0_propn = gtk_adjustment_get_value (a_x) / 100 / unit->factor; x0 = bbox_user->min()[Geom::X] * x0_propn; - double const y0_propn = gtk_adjustment_get_value (a_y) * unit.unittobase; + double const y0_propn = gtk_adjustment_get_value (a_y) / 100 / unit->factor; y0 = y0_propn * bbox_user->min()[Geom::Y]; - xrel = gtk_adjustment_get_value (a_w) * unit.unittobase; + xrel = gtk_adjustment_get_value (a_w) / (100 / unit->factor); x1 = x0 + xrel * bbox_user->dimensions()[Geom::X]; - yrel = gtk_adjustment_get_value (a_h) * unit.unittobase; + yrel = gtk_adjustment_get_value (a_h) / (100 / unit->factor); y1 = y0 + yrel * bbox_user->dimensions()[Geom::Y]; } @@ -222,11 +219,11 @@ sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw) double sv = fabs(y1 - bbox_user->max()[Geom::Y]); // unless the unit is %, convert the scales and moves to the unit - if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) { - mh = sp_pixels_get_units (mh, unit); - sh = sp_pixels_get_units (sh, unit); - mv = sp_pixels_get_units (mv, unit); - sv = sp_pixels_get_units (sv, unit); + if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) { + mh = Quantity::convert(mh, "px", unit); + sh = Quantity::convert(sh, "px", unit); + mv = Quantity::convert(mv, "px", unit); + sv = Quantity::convert(sv, "px", unit); } // do the action only if one of the scales/moves is greater than half the last significant @@ -244,17 +241,18 @@ sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw) // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed sp_desktop_canvas(desktop)->forceFullRedrawAfterInterruptions(0); - int transform_stroke = prefs->getBool("/options/transform/stroke", true) ? 1 : 0; + bool transform_stroke = prefs->getBool("/options/transform/stroke", true); + bool preserve = prefs->getBool("/options/preservetransform/value", false); Geom::Affine scaler; if (bbox_type == SPItem::VISUAL_BBOX) { - scaler = get_scale_transform_for_variable_stroke (*bbox_vis, *bbox_geom, transform_stroke, x0, y0, x1, y1); + scaler = get_scale_transform_for_variable_stroke (*bbox_vis, *bbox_geom, transform_stroke, preserve, x0, y0, x1, y1); } else { // 1) We could have use the newer get_scale_transform_for_variable_stroke() here, but to avoid regressions // we'll just use the old get_scale_transform_for_uniform_stroke() for now. // 2) get_scale_transform_for_uniform_stroke() is intended for visual bounding boxes, not geometrical ones! // we'll trick it into using a geometric bounding box though, by setting the stroke width to zero - scaler = get_scale_transform_for_uniform_stroke (*bbox_geom, 0, false, x0, y0, x1, y1); + scaler = get_scale_transform_for_uniform_stroke (*bbox_geom, 0, 0, false, false, x0, y0, x1, y1); } sp_selection_apply_affine(selection, scaler); @@ -268,7 +266,7 @@ sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw) g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE)); } -static GtkWidget* createCustomSlider( GtkAdjustment *adjustment, gdouble climbRate, guint digits ) +static GtkWidget* createCustomSlider( GtkAdjustment *adjustment, gdouble climbRate, guint digits, Inkscape::UI::Widget::UnitTracker *unit_tracker ) { #if WITH_GTKMM_3_0 Glib::RefPtr<Gtk::Adjustment> adj = Glib::wrap(adjustment, true); @@ -276,6 +274,7 @@ static GtkWidget* createCustomSlider( GtkAdjustment *adjustment, gdouble climbRa #else Inkscape::UI::Widget::SpinButton *inkSpinner = new Inkscape::UI::Widget::SpinButton(*Glib::wrap(adjustment, true), climbRate, digits); #endif + inkSpinner->addUnitTracker(unit_tracker); inkSpinner = Gtk::manage( inkSpinner ); GtkWidget *widget = GTK_WIDGET( inkSpinner->gobj() ); return widget; @@ -308,7 +307,7 @@ static EgeAdjustmentAction * create_adjustment_action( gchar const *name, g_object_set_data( G_OBJECT(spw), data, adj ); } - EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, Q_(label), tooltip, 0, SPIN_STEP, 3 ); + EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, Q_(label), tooltip, 0, SPIN_STEP, 3, tracker ); if ( shortLabel ) { g_object_set( act, "short_label", Q_(shortLabel), NULL ); } @@ -412,7 +411,7 @@ static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::Vi { GtkAction* act = 0; - SPAction* targetAction = verb->get_action(view); + SPAction* targetAction = verb->get_action(Inkscape::ActionContext(view)); InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size ); act = GTK_ACTION(inky); @@ -485,8 +484,8 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb gtk_container_add(GTK_CONTAINER(spw), vb); // Create the units menu. - UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE ); - tracker->addUnit( SP_UNIT_PERCENT, 0 ); + UnitTracker* tracker = new UnitTracker(Inkscape::Util::UNIT_TYPE_LINEAR); + tracker->addUnit(unit_table.getUnit("%")); tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units ); g_object_set_data( G_OBJECT(spw), "tracker", tracker ); @@ -497,7 +496,7 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb // four spinbuttons eact = create_adjustment_action( "XAction", C_("Select toolbar", "X position"), C_("Select toolbar", "X:"), "X", - -1e6, GTK_WIDGET(desktop->canvas), tracker, spw, + -1e6, GTK_WIDGET(desktop->canvas), tracker, spw, _("Horizontal coordinate of selection"), TRUE ); gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) ); contextActions->push_back( GTK_ACTION(eact) ); @@ -509,7 +508,7 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb contextActions->push_back( GTK_ACTION(eact) ); eact = create_adjustment_action( "WidthAction", C_("Select toolbar", "Width"), C_("Select toolbar", "W:"), "width", - 1e-3, GTK_WIDGET(desktop->canvas), tracker, spw, + 0.0, GTK_WIDGET(desktop->canvas), tracker, spw, _("Width of selection"), FALSE ); gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) ); contextActions->push_back( GTK_ACTION(eact) ); @@ -528,7 +527,7 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb } eact = create_adjustment_action( "HeightAction", C_("Select toolbar", "Height"), C_("Select toolbar", "H:"), "height", - 1e-3, GTK_WIDGET(desktop->canvas), tracker, spw, + 0.0, GTK_WIDGET(desktop->canvas), tracker, spw, _("Height of selection"), FALSE ); gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) ); contextActions->push_back( GTK_ACTION(eact) ); diff --git a/src/widgets/select-toolbar.h b/src/widgets/select-toolbar.h index e3573da66..b900a0615 100644 --- a/src/widgets/select-toolbar.h +++ b/src/widgets/select-toolbar.h @@ -14,9 +14,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <gtk/gtk.h> class SPDesktop; +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); diff --git a/src/widgets/shrink-wrap-button.cpp b/src/widgets/shrink-wrap-button.cpp index 8d5bad21c..3558780ed 100644 --- a/src/widgets/shrink-wrap-button.cpp +++ b/src/widgets/shrink-wrap-button.cpp @@ -9,40 +9,49 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + #include <gtkmm/button.h> #include <gtk/gtk.h> +#include "shrink-wrap-button.h" + namespace Inkscape { namespace Widgets { -namespace { +void shrink_wrap_button(Gtk::Button &button) { + button.set_border_width(0); + button.set_can_focus(false); + button.set_can_default(false); -void minimum_size(GtkWidget *widget, GtkRequisition *requisition, void *) { - GtkWidget *child(gtk_bin_get_child(GTK_BIN(widget))); + Gtk::Widget* child = button.get_child(); + Gtk::Requisition req_min; if (child) { -#if GTK_CHECK_VERSION(3,0,0) - gtk_widget_get_preferred_size(child, requisition, NULL); +#if WITH_GTKMM_3_0 + Gtk::Requisition req_nat; + child->get_preferred_size(req_min, req_nat); #else - gtk_widget_size_request(child, requisition); + req_min = child->size_request(); #endif } else { - requisition->width = 0; - requisition->height = 0; + req_min.width = 0; + req_min.height = 0; } - requisition->width += 2 + 2 * std::max(2, widget->style->xthickness); - requisition->height += 2 + 2 * std::max(2, widget->style->ythickness); -} - -} + // TODO: Use Gtk::StyleContext instead + GtkStyle* style = gtk_widget_get_style(GTK_WIDGET(button.gobj())); + + req_min.width += 2 + 2 * std::max(2, style->xthickness); + req_min.height += 2 + 2 * std::max(2, style->ythickness); -void shrink_wrap_button(Gtk::Button &button) { - button.set_border_width(0); - button.set_can_focus(false); - button.set_can_default(false); - g_signal_connect_after(G_OBJECT(button.gobj()), "size_request", - G_CALLBACK(minimum_size), NULL); + button.set_size_request(req_min.width, req_min.height); } } diff --git a/src/widgets/sp-attribute-widget.cpp b/src/widgets/sp-attribute-widget.cpp index a1702a864..fb7eb1420 100644 --- a/src/widgets/sp-attribute-widget.cpp +++ b/src/widgets/sp-attribute-widget.cpp @@ -12,9 +12,18 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include "sp-attribute-widget.h" + #include <glibmm/i18n.h> #include <gtkmm/entry.h> #include <gtkmm/label.h> + +#if WITH_GTKMM_3_0 +# include <gtkmm/grid.h> +#else +# include <gtkmm/table.h> +#endif + #include <sigc++/functors/ptr_fun.h> #include <sigc++/adaptors/bind.h> @@ -24,7 +33,6 @@ #include "document.h" #include "document-undo.h" #include "verbs.h" -#include "sp-attribute-widget.h" using Inkscape::DocumentUndo; @@ -93,14 +101,12 @@ SPAttributeTable::~SPAttributeTable () void SPAttributeTable::clear(void) { - Gtk::Widget *w; - if (table) { std::vector<Gtk::Widget*> ch = table->get_children(); for (int i = (ch.size())-1; i >=0 ; i--) { - w = ch[i]; + Gtk::Widget *w = ch[i]; ch.pop_back(); if (w != NULL) { @@ -150,11 +156,14 @@ void SPAttributeTable::set_object(SPObject *object, release_connection = object->connectRelease (sigc::bind<1>(sigc::ptr_fun(&sp_attribute_table_object_release), this)); // Create table - table = new Gtk::Table (attributes.size(), 2, false); +#if WITH_GTKMM_3_0 + table = new Gtk::Grid(); +#else + table = new Gtk::Table(attributes.size(), 2, false); +#endif + if (!(parent == NULL)) - { - gtk_container_add (GTK_CONTAINER (parent),(GtkWidget*)table->gobj()); - } + gtk_container_add(GTK_CONTAINER(parent), (GtkWidget*)table->gobj()); // Fill rows _attributes = attributes; @@ -162,18 +171,41 @@ void SPAttributeTable::set_object(SPObject *object, Gtk::Label *ll = new Gtk::Label (_(labels[i].c_str())); ll->show(); ll->set_alignment (1.0, 0.5); + +#if WITH_GTKMM_3_0 + ll->set_vexpand(); + ll->set_margin_left(XPAD); + ll->set_margin_right(XPAD); + ll->set_margin_top(XPAD); + ll->set_margin_bottom(XPAD); + table->attach(*ll, 0, i, 1, 1); +#else table->attach (*ll, 0, 1, i, i + 1, Gtk::FILL, (Gtk::EXPAND | Gtk::FILL), XPAD, YPAD ); +#endif + Gtk::Entry *ee = new Gtk::Entry(); ee->show(); const gchar *val = object->getRepr()->attribute(attributes[i].c_str()); ee->set_text (val ? val : (const gchar *) ""); + +#if WITH_GTKMM_3_0 + ee->set_hexpand(); + ee->set_vexpand(); + ee->set_margin_left(XPAD); + ee->set_margin_right(XPAD); + ee->set_margin_top(XPAD); + ee->set_margin_bottom(XPAD); + table->attach(*ee, 1, i, 1, 1); +#else table->attach (*ee, 1, 2, i, i + 1, (Gtk::EXPAND | Gtk::FILL), (Gtk::EXPAND | Gtk::FILL), XPAD, YPAD ); +#endif + _entries.push_back(ee); g_signal_connect ( ee->gobj(), "changed", G_CALLBACK (sp_attribute_table_entry_changed), @@ -227,7 +259,7 @@ static void sp_attribute_table_object_modified ( SPObject */*object*/, guint flags, SPAttributeTable *spat ) { - if (flags && SP_OBJECT_MODIFIED_FLAG) + if (flags & SP_OBJECT_MODIFIED_FLAG) { std::vector<Glib::ustring> attributes = spat->get_attributes(); std::vector<Gtk::Entry *> entries = spat->get_entries(); @@ -238,7 +270,7 @@ static void sp_attribute_table_object_modified ( SPObject */*object*/, text = e->get_text (); if (val || !text.empty()) { if (text != val) { - /* We are different */ + // We are different spat->blocked = true; e->set_text (val ? val : (const gchar *) ""); spat->blocked = false; diff --git a/src/widgets/sp-attribute-widget.h b/src/widgets/sp-attribute-widget.h index fb8a74632..4bd6c6959 100644 --- a/src/widgets/sp-attribute-widget.h +++ b/src/widgets/sp-attribute-widget.h @@ -15,13 +15,26 @@ #ifndef SEEN_DIALOGS_SP_ATTRIBUTE_WIDGET_H #define SEEN_DIALOGS_SP_ATTRIBUTE_WIDGET_H -#include <gtkmm/table.h> +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + #include <gtkmm/widget.h> #include <stddef.h> #include <sigc++/connection.h> namespace Gtk { class Entry; + +#if WITH_GTKMM_3_0 +class Grid; +#else +class Table; +#endif } namespace Inkscape { @@ -126,12 +139,16 @@ public: bool blocked; private: - /** + /** * Container widget for the dynamically created child widgets (labels and entry boxes). */ +#if WITH_GTKMM_3_0 + Gtk::Grid *table; +#else Gtk::Table *table; +#endif - /** + /** * List of attributes. * * _attributes stores the attribute names of the selected object that diff --git a/src/widgets/sp-color-gtkselector.cpp b/src/widgets/sp-color-gtkselector.cpp deleted file mode 100644 index 5766e84c0..000000000 --- a/src/widgets/sp-color-gtkselector.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include <glibmm/i18n.h> -#include "sp-color-gtkselector.h" - - -static void sp_color_gtkselector_class_init (SPColorGtkselectorClass *klass); -static void sp_color_gtkselector_init (SPColorGtkselector *csel); -static void sp_color_gtkselector_destroy (GtkObject *object); - -static void sp_color_gtkselector_show_all (GtkWidget *widget); -static void sp_color_gtkselector_hide_all (GtkWidget *widget); - - -static SPColorSelectorClass *parent_class; - -#define XPAD 4 -#define YPAD 1 - -GType -sp_color_gtkselector_get_type (void) -{ - static GType type = 0; - if (!type) { - static const GTypeInfo info = { - sizeof (SPColorGtkselectorClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) sp_color_gtkselector_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (SPColorGtkselector), - 0, /* n_preallocs */ - (GInstanceInitFunc) sp_color_gtkselector_init, - NULL, - }; - - type = g_type_register_static (SP_TYPE_COLOR_SELECTOR, - "SPColorGtkselector", - &info, - static_cast< GTypeFlags > (0) ); - } - return type; -} - -static void -sp_color_gtkselector_class_init (SPColorGtkselectorClass *klass) -{ - static const gchar* nameset[] = {N_("System"), 0}; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - SPColorSelectorClass *selector_class; - - object_class = (GtkObjectClass *) klass; - widget_class = (GtkWidgetClass *) klass; - selector_class = SP_COLOR_SELECTOR_CLASS (klass); - - parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass)); - - selector_class->name = nameset; - selector_class->submode_count = 1; - - object_class->destroy = sp_color_gtkselector_destroy; - - widget_class->show_all = sp_color_gtkselector_show_all; - widget_class->hide_all = sp_color_gtkselector_hide_all; -} - -void sp_color_gtkselector_init (SPColorGtkselector *csel) -{ - SP_COLOR_SELECTOR(csel)->base = new ColorGtkselector( SP_COLOR_SELECTOR(csel) ); - - if ( SP_COLOR_SELECTOR(csel)->base ) - { - SP_COLOR_SELECTOR(csel)->base->init(); - } -} - -void ColorGtkselector::init() -{ - GtkWidget *gtksel; - - gtksel = gtk_color_selection_new(); - gtk_widget_show (gtksel); - _gtkThing = GTK_COLOR_SELECTION (gtksel); - gtk_box_pack_start (GTK_BOX (_csel), gtksel, TRUE, TRUE, 0); - - _sigId = g_signal_connect( GTK_OBJECT(gtksel), "color-changed", G_CALLBACK( _gtkChanged ), _csel); -} - -static void -sp_color_gtkselector_destroy (GtkObject *object) -{ - if (((GtkObjectClass *) (parent_class))->destroy) - (* ((GtkObjectClass *) (parent_class))->destroy) (object); -} - -static void -sp_color_gtkselector_show_all (GtkWidget *widget) -{ - gtk_widget_show (widget); -} - -static void -sp_color_gtkselector_hide_all (GtkWidget *widget) -{ - gtk_widget_hide (widget); -} - -GtkWidget * -sp_color_gtkselector_new( GType ) -{ - SPColorGtkselector *csel; - - csel = (SPColorGtkselector*)g_object_new (SP_TYPE_COLOR_GTKSELECTOR, NULL); - - return GTK_WIDGET (csel); -} - -ColorGtkselector::ColorGtkselector( SPColorSelector* csel ) - : ColorSelector( csel ), - _gtkThing(0) -{ -} - -ColorGtkselector::~ColorGtkselector() -{ -} - -void ColorGtkselector::_colorChanged() -{ - GdkColor gcolor; - - gcolor.pixel = 0; - gcolor.red = static_cast< guint16 >(_color.v.c[0] * 65535); - gcolor.green = static_cast< guint16 >(_color.v.c[1] * 65535); - gcolor.blue = static_cast< guint16 >(_color.v.c[2] * 65535); - -// g_message( "***** _colorChanged %04x %04x %04x", gcolor.red, gcolor.green, gcolor.blue ); - g_signal_handler_block( _gtkThing, _sigId ); - gtk_color_selection_set_current_alpha( _gtkThing, static_cast<guint16>(65535 * _alpha) ); - gtk_color_selection_set_current_color( _gtkThing, &gcolor ); - g_signal_handler_unblock(_gtkThing, _sigId ); -} - -void ColorGtkselector::_gtkChanged( GtkColorSelection *colorselection, SPColorGtkselector *gtksel ) -{ - GdkColor color; - gtk_color_selection_get_current_color (colorselection, &color); - - guint16 alpha = gtk_color_selection_get_current_alpha (colorselection); - - SPColor ourColor( (color.red / 65535.0), (color.green / 65535.0), (color.blue / 65535.0) ); - -// g_message( "***** _gtkChanged %04x %04x %04x", color.red, color.green, color.blue ); - - ColorGtkselector* gtkInst = static_cast<ColorGtkselector *>(SP_COLOR_SELECTOR(gtksel)->base); - gtkInst->_updateInternals( ourColor, static_cast< gfloat > (alpha) / 65535.0, gtk_color_selection_is_adjusting(colorselection) ); -} diff --git a/src/widgets/sp-color-gtkselector.h b/src/widgets/sp-color-gtkselector.h deleted file mode 100644 index 3142406c1..000000000 --- a/src/widgets/sp-color-gtkselector.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef SEEN_SP_COLOR_GTKSELECTOR_H -#define SEEN_SP_COLOR_GTKSELECTOR_H - -#include <gtk/gtk.h> -#include "../color.h" -#include "sp-color-selector.h" - -#include <glib.h> - - - -struct SPColorGtkselector; - - - -class ColorGtkselector: public ColorSelector -{ -public: - ColorGtkselector( SPColorSelector* csel ); - virtual ~ColorGtkselector(); - - virtual void init(); - -protected: - static void _gtkChanged( GtkColorSelection *colorselection, SPColorGtkselector *gtksel ); - - virtual void _colorChanged(); - - GtkColorSelection* _gtkThing; - gulong _sigId; -}; - - - -#define SP_TYPE_COLOR_GTKSELECTOR (sp_color_gtkselector_get_type ()) -#define SP_COLOR_GTKSELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_COLOR_GTKSELECTOR, SPColorGtkselector)) -#define SP_COLOR_GTKSELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_COLOR_GTKSELECTOR, SPColorGtkselectorClass)) -#define SP_IS_COLOR_GTKSELECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_COLOR_GTKSELECTOR)) -#define SP_IS_COLOR_GTKSELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_COLOR_GTKSELECTOR)) - -struct SPColorGtkselector { - SPColorSelector base; -}; - -struct SPColorGtkselectorClass { - SPColorSelectorClass parent_class; -}; - -GType sp_color_gtkselector_get_type (void); - -GtkWidget *sp_color_gtkselector_new( GType selector_type ); - - - -#endif // SEEN_SP_COLOR_GTKSELECTOR_H diff --git a/src/widgets/sp-color-icc-selector.cpp b/src/widgets/sp-color-icc-selector.cpp index 844ba0020..53e73dd57 100644 --- a/src/widgets/sp-color-icc-selector.cpp +++ b/src/widgets/sp-color-icc-selector.cpp @@ -1,13 +1,21 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif + +#include "gradient-vector.h" #include <math.h> #include <gtk/gtk.h> #include <glibmm/i18n.h> +#include <map> +#include <set> +#include <vector> + #include "../dialogs/dialog-events.h" #include "sp-color-icc-selector.h" #include "sp-color-scales.h" +#include "sp-color-slider.h" #include "svg/svg-icc-color.h" +#include "colorspace.h" #include "document.h" #include "inkscape.h" #include "profile-manager.h" @@ -61,35 +69,179 @@ G_BEGIN_DECLS static void sp_color_icc_selector_class_init (SPColorICCSelectorClass *klass); static void sp_color_icc_selector_init (SPColorICCSelector *cs); -static void sp_color_icc_selector_destroy (GtkObject *object); +static void sp_color_icc_selector_dispose(GObject *object); static void sp_color_icc_selector_show_all (GtkWidget *widget); -static void sp_color_icc_selector_hide_all (GtkWidget *widget); - +static void sp_color_icc_selector_hide(GtkWidget *widget); G_END_DECLS +/** + * Class containing the parts for a single color component's UI presence. + */ +class ComponentUI +{ +public: + ComponentUI() : + _component(), + _adj(0), + _slider(0), + _btn(0), + _label(0), + _map(0) + { + } + + ComponentUI(colorspace::Component const &component) : + _component(component), + _adj(0), + _slider(0), + _btn(0), + _label(0), + _map(0) + { + } + + colorspace::Component _component; + GtkAdjustment *_adj; // Component adjustment + GtkWidget *_slider; + GtkWidget *_btn; // spinbutton + GtkWidget *_label; // Label + guchar *_map; +}; + +/** + * Class that implements the internals of the selector. + */ +class ColorICCSelectorImpl +{ +public: + + ColorICCSelectorImpl( ColorICCSelector *owner); + + ~ColorICCSelectorImpl(); + + static void _adjustmentChanged ( GtkAdjustment *adjustment, SPColorICCSelector *cs ); + + static void _sliderGrabbed( SPColorSlider *slider, SPColorICCSelector *cs ); + static void _sliderReleased( SPColorSlider *slider, SPColorICCSelector *cs ); + static void _sliderChanged( SPColorSlider *slider, SPColorICCSelector *cs ); + + static void _profileSelected( GtkWidget* src, gpointer data ); + static void _fixupHit( GtkWidget* src, gpointer data ); + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + void _setProfile( SVGICCColor* profile ); + void _switchToProfile( gchar const* name ); +#endif + void _updateSliders( gint ignore ); + void _profilesChanged( std::string const & name ); + + ColorICCSelector *_owner; + + gboolean _updating : 1; + gboolean _dragging : 1; + + guint32 _fixupNeeded; + GtkWidget* _fixupBtn; + GtkWidget* _profileSel; + + std::vector<ComponentUI> _compUI; + + GtkAdjustment* _adj; // Channel adjustment + GtkWidget* _slider; + GtkWidget* _sbtn; // Spinbutton + GtkWidget* _label; // Label + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + std::string _profileName; + Inkscape::ColorProfile* _prof; + guint _profChannelCount; + gulong _profChangedID; +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +}; + + static SPColorSelectorClass *parent_class; #define XPAD 4 #define YPAD 1 -GType -sp_color_icc_selector_get_type (void) +namespace +{ + +size_t maxColorspaceComponentCount = 0; + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + +/** + * Internal variable to track all known colorspaces. + */ +std::set<cmsUInt32Number> knownColorspaces; + +#endif + + +/** + * Simple helper to allow bitwise or on GtkAttachOptions. + */ +GtkAttachOptions operator|(GtkAttachOptions lhs, GtkAttachOptions rhs) +{ + return static_cast<GtkAttachOptions>(static_cast<int>(lhs) | static_cast<int>(rhs)); +} + +/** + * Helper function to handle GTK2/GTK3 attachment #ifdef code. + */ +void attachToGridOrTable(GtkWidget *parent, + GtkWidget *child, + guint left, + guint top, + guint width, + guint height, + bool hexpand = false, + bool centered = false, + guint xpadding = XPAD, + guint ypadding = YPAD) +{ +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left( child, xpadding ); + gtk_widget_set_margin_right( child, xpadding ); + gtk_widget_set_margin_top( child, ypadding ); + gtk_widget_set_margin_bottom( child, ypadding ); + if (hexpand) { + gtk_widget_set_hexpand(child, TRUE); + } + if (centered) { + gtk_widget_set_halign( child, GTK_ALIGN_CENTER ); + gtk_widget_set_valign( child, GTK_ALIGN_CENTER ); + } + gtk_grid_attach( GTK_GRID(parent), child, left, top, width, height ); +#else + GtkAttachOptions xoptions = centered ? static_cast<GtkAttachOptions>(0) : hexpand ? (GTK_EXPAND | GTK_FILL) : GTK_FILL; + GtkAttachOptions yoptions = centered ? static_cast<GtkAttachOptions>(0) : GTK_FILL; + + gtk_table_attach( GTK_TABLE(parent), child, left, left + width, top, top + height, xoptions, yoptions, xpadding, ypadding ); +#endif +} + +} // namespace + +GType sp_color_icc_selector_get_type(void) { static GType type = 0; if (!type) { static const GTypeInfo info = { sizeof (SPColorICCSelectorClass), - NULL, /* base_init */ - NULL, /* base_finalize */ + NULL, // base_init + NULL, // base_finalize (GClassInitFunc) sp_color_icc_selector_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ + NULL, // class_finalize + NULL, // class_data sizeof (SPColorICCSelector), - 0, /* n_preallocs */ + 0, // n_preallocs (GInstanceInitFunc) sp_color_icc_selector_init, - 0, /* value_table */ + 0, // value_table }; type = g_type_register_static (SP_TYPE_COLOR_SELECTOR, @@ -100,66 +252,41 @@ sp_color_icc_selector_get_type (void) return type; } -static void -sp_color_icc_selector_class_init (SPColorICCSelectorClass *klass) +static void sp_color_icc_selector_class_init(SPColorICCSelectorClass *klass) { static const gchar* nameset[] = {N_("CMS"), 0}; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - SPColorSelectorClass *selector_class; - - object_class = (GtkObjectClass *) klass; - widget_class = (GtkWidgetClass *) klass; - selector_class = SP_COLOR_SELECTOR_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + SPColorSelectorClass *selector_class = SP_COLOR_SELECTOR_CLASS (klass); parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass)); selector_class->name = nameset; selector_class->submode_count = 1; - object_class->destroy = sp_color_icc_selector_destroy; + object_class->dispose = sp_color_icc_selector_dispose; widget_class->show_all = sp_color_icc_selector_show_all; - widget_class->hide_all = sp_color_icc_selector_hide_all; + widget_class->hide = sp_color_icc_selector_hide; } ColorICCSelector::ColorICCSelector( SPColorSelector* csel ) : ColorSelector( csel ), - _updating( FALSE ), - _dragging( FALSE ), - _fixupNeeded(0), - _fixupBtn(0), - _profileSel(0), - _fooCount(0), - _fooScales(0), - _fooAdj(0), - _fooSlider(0), - _fooBtn(0), - _fooLabel(0), - _fooMap(0), - _adj(0), - _slider(0), - _sbtn(0), - _label(0) -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - , - _profileName(""), - _prof(), - _profChannelCount(0), - _profChangedID(0) -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + _impl(NULL) { } ColorICCSelector::~ColorICCSelector() { - _adj = 0; - _sbtn = 0; - _label = 0; + if (_impl) + { + delete _impl; + _impl = 0; + } } -void sp_color_icc_selector_init (SPColorICCSelector *cs) +void sp_color_icc_selector_init(SPColorICCSelector *cs) { SP_COLOR_SELECTOR(cs)->base = new ColorICCSelector( SP_COLOR_SELECTOR(cs) ); @@ -188,246 +315,293 @@ static cmsUInt16Number* getScratch() { return scritch; } -struct MapMap { - cmsUInt32Number space; - cmsUInt32Number inForm; -}; +colorspace::Component::Component() : + name(), + tip(), + scale(1) +{ +} + +colorspace::Component::Component(std::string const &name, std::string const &tip, guint scale) : + name(name), + tip(tip), + scale(scale) +{ +} + +std::vector<colorspace::Component> colorspace::getColorSpaceInfo( uint32_t space ) +{ + static std::map<cmsUInt32Number, std::vector<Component> > sets; + if (sets.empty()) + { + sets[cmsSigXYZData].push_back(Component("_X", "X", 2)); // TYPE_XYZ_16 + sets[cmsSigXYZData].push_back(Component("_Y", "Y", 1)); + sets[cmsSigXYZData].push_back(Component("_Z", "Z", 2)); + + sets[cmsSigLabData].push_back(Component("_L", "L", 100)); // TYPE_Lab_16 + sets[cmsSigLabData].push_back(Component("_a", "a", 256)); + sets[cmsSigLabData].push_back(Component("_b", "b", 256)); -void getThings( cmsUInt32Number space, gchar const**& namers, gchar const**& tippies, guint const*& scalies ) { - MapMap possible[] = { - {cmsSigXYZData, TYPE_XYZ_16}, - {cmsSigLabData, TYPE_Lab_16}, //cmsSigLuvData - {cmsSigYCbCrData, TYPE_YCbCr_16}, - {cmsSigYxyData, TYPE_Yxy_16}, - {cmsSigRgbData, TYPE_RGB_16}, - {cmsSigGrayData, TYPE_GRAY_16}, - {cmsSigHsvData, TYPE_HSV_16}, - {cmsSigHlsData, TYPE_HLS_16}, - {cmsSigCmykData, TYPE_CMYK_16}, - {cmsSigCmyData, TYPE_CMY_16}, - }; - - static gchar const *names[][6] = { - {"_X", "_Y", "_Z", "", "", ""}, - {"_L", "_a", "_b", "", "", ""}, - // - {"_Y", "C_b", "C_r", "", "", ""}, - {"_Y", "_x", "y", "", "", ""}, - {_("_R:"), _("_G:"), _("_B:"), "", "", ""}, - {_("_G:"), "", "", "", "", ""}, - {_("_H:"), _("_S:"), "_V:", "", "", ""}, - {_("_H:"), _("_L:"), _("_S:"), "", "", ""}, - {_("_C:"), _("_M:"), _("_Y:"), _("_K:"), "", ""}, - {_("_C:"), _("_M:"), _("_Y:"), "", "", ""}, - }; - - static gchar const *tips[][6] = { - {"X", "Y", "Z", "", "", ""}, - {"L", "a", "b", "", "", ""}, - // - {"Y", "Cb", "Cr", "", "", ""}, - {"Y", "x", "y", "", "", ""}, - {_("Red"), _("Green"), _("Blue"), "", "", ""}, - {_("Gray"), "", "", "", "", ""}, - {_("Hue"), _("Saturation"), "Value", "", "", ""}, - {_("Hue"), _("Lightness"), _("Saturation"), "", "", ""}, - {_("Cyan"), _("Magenta"), _("Yellow"), _("Black"), "", ""}, - {_("Cyan"), _("Magenta"), _("Yellow"), "", "", ""}, - }; - - static guint scales[][6] = { - {2, 1, 2, 1, 1, 1}, - {100, 256, 256, 1, 1, 1}, - // - {1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1}, - {360, 1, 1, 1, 1, 1}, - {360, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1}, - }; - - int index = 0; - for ( guint i = 0; i < G_N_ELEMENTS(possible); i++ ) { - if ( possible[i].space == space ) { - index = i; - break; + + sets[cmsSigYCbCrData].push_back(Component("_Y", "Y", 1)); // TYPE_YCbCr_16 + sets[cmsSigYCbCrData].push_back(Component("C_b", "Cb", 1)); + sets[cmsSigYCbCrData].push_back(Component("C_r", "Cr", 1)); + + sets[cmsSigYxyData].push_back(Component("_Y", "Y", 1)); // TYPE_Yxy_16 + sets[cmsSigYxyData].push_back(Component("_x", "x", 1)); + sets[cmsSigYxyData].push_back(Component("y", "y", 1)); + + sets[cmsSigRgbData].push_back(Component(_("_R:"), _("Red"), 1)); // TYPE_RGB_16 + sets[cmsSigRgbData].push_back(Component(_("_G:"), _("Green"), 1)); + sets[cmsSigRgbData].push_back(Component(_("_B:"), _("Blue"), 1)); + + sets[cmsSigGrayData].push_back(Component(_("G:"), _("Gray"), 1)); // TYPE_GRAY_16 + + sets[cmsSigHsvData].push_back(Component(_("_H:"), _("Hue"), 360)); // TYPE_HSV_16 + sets[cmsSigHsvData].push_back(Component(_("_S:"), _("Saturation"), 1)); + sets[cmsSigHsvData].push_back(Component("_V:", "Value", 1)); + + sets[cmsSigHlsData].push_back(Component(_("_H:"), _("Hue"), 360)); // TYPE_HLS_16 + sets[cmsSigHlsData].push_back(Component(_("_L:"), _("Lightness"), 1)); + sets[cmsSigHlsData].push_back(Component(_("_S:"), _("Saturation"), 1)); + + sets[cmsSigCmykData].push_back(Component(_("_C:"), _("Cyan"), 1)); // TYPE_CMYK_16 + sets[cmsSigCmykData].push_back(Component(_("_M:"), _("Magenta"), 1)); + sets[cmsSigCmykData].push_back(Component(_("_Y:"), _("Yellow"), 1)); + sets[cmsSigCmykData].push_back(Component(_("_K:"), _("Black"), 1)); + + sets[cmsSigCmyData].push_back(Component(_("_C:"), _("Cyan"), 1)); // TYPE_CMY_16 + sets[cmsSigCmyData].push_back(Component(_("_M:"), _("Magenta"), 1)); + sets[cmsSigCmyData].push_back(Component(_("_Y:"), _("Yellow"), 1)); + + for (std::map<cmsUInt32Number, std::vector<Component> >::iterator it = sets.begin(); it != sets.end(); ++it) + { + knownColorspaces.insert(it->first); + maxColorspaceComponentCount = std::max(maxColorspaceComponentCount, it->second.size()); } } - namers = names[index]; - tippies = tips[index]; - scalies = scales[index]; + std::vector<Component> target; + + if (sets.find(space) != sets.end()) + { + target = sets[space]; + } + return target; } -void getThings( Inkscape::ColorProfile *prof, gchar const**& namers, gchar const**& tippies, guint const*& scalies ) { - getThings( asICColorSpaceSig(prof->getColorSpace()), namers, tippies, scalies ); +std::vector<colorspace::Component> colorspace::getColorSpaceInfo( Inkscape::ColorProfile *prof ) +{ + return getColorSpaceInfo( asICColorSpaceSig(prof->getColorSpace()) ); } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +ColorICCSelectorImpl::ColorICCSelectorImpl(ColorICCSelector *owner) : + _owner(owner), + _updating( FALSE ), + _dragging( FALSE ), + _fixupNeeded(0), + _fixupBtn(0), + _profileSel(0), + _compUI(), + _adj(0), + _slider(0), + _sbtn(0), + _label(0) +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + , + _profileName(), + _prof(0), + _profChannelCount(0), + _profChangedID(0) +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +{ +} + +ColorICCSelectorImpl::~ColorICCSelectorImpl() +{ + _adj = 0; + _sbtn = 0; + _label = 0; +} void ColorICCSelector::init() { - GtkWidget *t; + if (_impl) delete(_impl); + _impl = new ColorICCSelectorImpl(this); gint row = 0; - _updating = FALSE; - _dragging = FALSE; + _impl->_updating = FALSE; + _impl->_dragging = FALSE; + +#if GTK_CHECK_VERSION(3,0,0) + GtkWidget *t = gtk_grid_new(); +#else + GtkWidget *t = gtk_table_new(5, 3, FALSE); +#endif - t = gtk_table_new (5, 3, FALSE); gtk_widget_show (t); - gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 4); -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - //guint partCount = _cmsChannelsOf( icSigRgbData ); - gchar const** names = 0; - gchar const** tips = 0; - getThings( cmsSigRgbData, names, tips, _fooScales ); -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + _impl->_compUI.clear(); - /* Create components */ + // Create components row = 0; - _fixupBtn = gtk_button_new_with_label(_("Fix")); - g_signal_connect( G_OBJECT(_fixupBtn), "clicked", G_CALLBACK(_fixupHit), (gpointer)this ); - gtk_widget_set_sensitive( _fixupBtn, FALSE ); - gtk_widget_set_tooltip_text( _fixupBtn, _("Fix RGB fallback to match icc-color() value.") ); - //gtk_misc_set_alignment( GTK_MISC (_fixupBtn), 1.0, 0.5 ); - gtk_widget_show( _fixupBtn ); - gtk_table_attach( GTK_TABLE (t), _fixupBtn, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD ); + _impl->_fixupBtn = gtk_button_new_with_label(_("Fix")); + g_signal_connect( G_OBJECT(_impl->_fixupBtn), "clicked", G_CALLBACK(ColorICCSelectorImpl::_fixupHit), (gpointer)_impl ); + gtk_widget_set_sensitive( _impl->_fixupBtn, FALSE ); + gtk_widget_set_tooltip_text( _impl->_fixupBtn, _("Fix RGB fallback to match icc-color() value.") ); + //gtk_misc_set_alignment( GTK_MISC (_impl->_fixupBtn), 1.0, 0.5 ); + gtk_widget_show( _impl->_fixupBtn ); + attachToGridOrTable(t, _impl->_fixupBtn, 0, row, 1, 1); -#if GTK_CHECK_VERSION(2,24,0) - _profileSel = gtk_combo_box_text_new(); - gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(_profileSel), _("<none>") ); -#else - _profileSel = gtk_combo_box_new_text(); - gtk_combo_box_append_text( GTK_COMBO_BOX(_profileSel), _("<none>") ); -#endif - gtk_widget_show( _profileSel ); - gtk_combo_box_set_active( GTK_COMBO_BOX(_profileSel), 0 ); - gtk_table_attach( GTK_TABLE(t), _profileSel, 1, 2, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD ); + // Combobox and store with 2 columns : label (0) and full name (1) + GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + _impl->_profileSel = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)); + + GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(_impl->_profileSel), renderer, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(_impl->_profileSel), renderer, "text", 0, NULL); + + GtkTreeIter iter; + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, _("<none>"), 1, _("<none>"), -1); + + gtk_widget_show( _impl->_profileSel ); + gtk_combo_box_set_active( GTK_COMBO_BOX(_impl->_profileSel), 0 ); + + attachToGridOrTable(t, _impl->_profileSel, 1, row, 1, 1); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - _profChangedID = g_signal_connect( G_OBJECT(_profileSel), "changed", G_CALLBACK(_profileSelected), (gpointer)this ); + _impl->_profChangedID = g_signal_connect( G_OBJECT(_impl->_profileSel), "changed", G_CALLBACK(ColorICCSelectorImpl::_profileSelected), (gpointer)_impl ); #else - gtk_widget_set_sensitive( _profileSel, false ); + gtk_widget_set_sensitive( _impl->_profileSel, false ); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) row++; - _fooCount = 4; - _fooAdj = new GtkAdjustment*[_fooCount]; - _fooSlider = new GtkWidget*[_fooCount]; - _fooBtn = new GtkWidget*[_fooCount]; - _fooLabel = new GtkWidget*[_fooCount]; - _fooMap = new guchar*[_fooCount]; + // populate the data for colorspaces and channels: +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + std::vector<colorspace::Component> things = colorspace::getColorSpaceInfo( cmsSigRgbData ); +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - for ( guint i = 0; i < _fooCount; i++ ) { - /* Label */ + for ( size_t i = 0; i < maxColorspaceComponentCount; i++ ) { #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - _fooLabel[i] = gtk_label_new_with_mnemonic( names[i] ); + if (i < things.size()) { + _impl->_compUI.push_back(ComponentUI(things[i])); + } else { + _impl->_compUI.push_back(ComponentUI()); + } + + std::string labelStr = (i < things.size()) ? things[i].name.c_str() : ""; #else - _fooLabel[i] = gtk_label_new_with_mnemonic( "." ); -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - gtk_misc_set_alignment( GTK_MISC (_fooLabel[i]), 1.0, 0.5 ); - gtk_widget_show( _fooLabel[i] ); - gtk_table_attach( GTK_TABLE (t), _fooLabel[i], 0, 1, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD ); + _impl->_compUI.push_back(ComponentUI()); + + std::string labelStr = "."; +#endif + + _impl->_compUI[i]._label = gtk_label_new_with_mnemonic( labelStr.c_str() ); + gtk_misc_set_alignment( GTK_MISC (_impl->_compUI[i]._label), 1.0, 0.5 ); + gtk_widget_show( _impl->_compUI[i]._label ); - /* Adjustment */ - gdouble step = static_cast<gdouble>(_fooScales[i]) / 100.0; - gdouble page = static_cast<gdouble>(_fooScales[i]) / 10.0; + attachToGridOrTable(t, _impl->_compUI[i]._label, 0, row, 1, 1); + + // Adjustment + guint scaleValue = _impl->_compUI[i]._component.scale; + gdouble step = static_cast<gdouble>(scaleValue) / 100.0; + gdouble page = static_cast<gdouble>(scaleValue) / 10.0; gint digits = (step > 0.9) ? 0 : 2; - _fooAdj[i] = GTK_ADJUSTMENT( gtk_adjustment_new( 0.0, 0.0, _fooScales[i], step, page, page ) ); + _impl->_compUI[i]._adj = GTK_ADJUSTMENT( gtk_adjustment_new( 0.0, 0.0, scaleValue, step, page, page ) ); - /* Slider */ - _fooSlider[i] = sp_color_slider_new( _fooAdj[i] ); + // Slider + _impl->_compUI[i]._slider = sp_color_slider_new( _impl->_compUI[i]._adj ); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - gtk_widget_set_tooltip_text( _fooSlider[i], tips[i] ); + gtk_widget_set_tooltip_text( _impl->_compUI[i]._slider, (i < things.size()) ? things[i].tip.c_str() : "" ); #else - gtk_widget_set_tooltip_text( _fooSlider[i], "." ); + gtk_widget_set_tooltip_text( _impl->_compUI[i]._slider, "." ); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - gtk_widget_show( _fooSlider[i] ); - gtk_table_attach( GTK_TABLE (t), _fooSlider[i], 1, 2, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)GTK_FILL, XPAD, YPAD ); + gtk_widget_show( _impl->_compUI[i]._slider ); + + attachToGridOrTable(t, _impl->_compUI[i]._slider, 1, row, 1, 1, true); - _fooBtn[i] = gtk_spin_button_new( _fooAdj[i], step, digits ); + _impl->_compUI[i]._btn = gtk_spin_button_new( _impl->_compUI[i]._adj, step, digits ); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - gtk_widget_set_tooltip_text( _fooBtn[i], tips[i] ); + gtk_widget_set_tooltip_text( _impl->_compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : "" ); #else - gtk_widget_set_tooltip_text( _fooBtn[i], "." ); + gtk_widget_set_tooltip_text( _impl->_compUI[i]._btn, "." ); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - sp_dialog_defocus_on_enter( _fooBtn[i] ); - gtk_label_set_mnemonic_widget( GTK_LABEL(_fooLabel[i]), _fooBtn[i] ); - gtk_widget_show( _fooBtn[i] ); - gtk_table_attach( GTK_TABLE (t), _fooBtn[i], 2, 3, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, XPAD, YPAD ); + sp_dialog_defocus_on_enter( _impl->_compUI[i]._btn ); + gtk_label_set_mnemonic_widget( GTK_LABEL(_impl->_compUI[i]._label), _impl->_compUI[i]._btn ); + gtk_widget_show( _impl->_compUI[i]._btn ); + + attachToGridOrTable(t, _impl->_compUI[i]._btn, 2, row, 1, 1, false, true); - _fooMap[i] = g_new( guchar, 4 * 1024 ); - memset( _fooMap[i], 0x0ff, 1024 * 4 ); + _impl->_compUI[i]._map = g_new( guchar, 4 * 1024 ); + memset( _impl->_compUI[i]._map, 0x0ff, 1024 * 4 ); - /* Signals */ - g_signal_connect( G_OBJECT( _fooAdj[i] ), "value_changed", G_CALLBACK( _adjustmentChanged ), _csel ); + // Signals + g_signal_connect( G_OBJECT( _impl->_compUI[i]._adj ), "value_changed", G_CALLBACK( ColorICCSelectorImpl::_adjustmentChanged ), _csel ); - g_signal_connect( G_OBJECT( _fooSlider[i] ), "grabbed", G_CALLBACK( _sliderGrabbed ), _csel ); - g_signal_connect( G_OBJECT( _fooSlider[i] ), "released", G_CALLBACK( _sliderReleased ), _csel ); - g_signal_connect( G_OBJECT( _fooSlider[i] ), "changed", G_CALLBACK( _sliderChanged ), _csel ); + g_signal_connect( G_OBJECT( _impl->_compUI[i]._slider ), "grabbed", G_CALLBACK( ColorICCSelectorImpl::_sliderGrabbed ), _csel ); + g_signal_connect( G_OBJECT( _impl->_compUI[i]._slider ), "released", G_CALLBACK( ColorICCSelectorImpl::_sliderReleased ), _csel ); + g_signal_connect( G_OBJECT( _impl->_compUI[i]._slider ), "changed", G_CALLBACK( ColorICCSelectorImpl::_sliderChanged ), _csel ); row++; } - /* Label */ - _label = gtk_label_new_with_mnemonic (_("_A:")); - gtk_misc_set_alignment (GTK_MISC (_label), 1.0, 0.5); - gtk_widget_show (_label); - gtk_table_attach (GTK_TABLE (t), _label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); + // Label + _impl->_label = gtk_label_new_with_mnemonic(_("_A:")); + gtk_misc_set_alignment(GTK_MISC(_impl->_label), 1.0, 0.5); + gtk_widget_show(_impl->_label); + + attachToGridOrTable(t, _impl->_label, 0, row, 1, 1); + + // Adjustment + _impl->_adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 255.0, 1.0, 10.0, 10.0)); - /* Adjustment */ - _adj = (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 10.0, 10.0); + // Slider + _impl->_slider = sp_color_slider_new(_impl->_adj); + gtk_widget_set_tooltip_text(_impl->_slider, _("Alpha (opacity)")); + gtk_widget_show(_impl->_slider); - /* Slider */ - _slider = sp_color_slider_new (_adj); - gtk_widget_set_tooltip_text (_slider, _("Alpha (opacity)")); - gtk_widget_show (_slider); - gtk_table_attach (GTK_TABLE (t), _slider, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)GTK_FILL, XPAD, YPAD); + attachToGridOrTable(t, _impl->_slider, 1, row, 1, 1, true); - sp_color_slider_set_colors( SP_COLOR_SLIDER( _slider ), + sp_color_slider_set_colors( SP_COLOR_SLIDER( _impl->_slider ), SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.0 ), SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.5 ), SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 1.0 ) ); - /* Spinbutton */ - _sbtn = gtk_spin_button_new (GTK_ADJUSTMENT (_adj), 1.0, 0); - gtk_widget_set_tooltip_text (_sbtn, _("Alpha (opacity)")); - sp_dialog_defocus_on_enter (_sbtn); - gtk_label_set_mnemonic_widget (GTK_LABEL(_label), _sbtn); - gtk_widget_show (_sbtn); - gtk_table_attach (GTK_TABLE (t), _sbtn, 2, 3, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, XPAD, YPAD); + // Spinbutton + _impl->_sbtn = gtk_spin_button_new(GTK_ADJUSTMENT(_impl->_adj), 1.0, 0); + gtk_widget_set_tooltip_text(_impl->_sbtn, _("Alpha (opacity)")); + sp_dialog_defocus_on_enter(_impl->_sbtn); + gtk_label_set_mnemonic_widget(GTK_LABEL(_impl->_label), _impl->_sbtn); + gtk_widget_show(_impl->_sbtn); - /* Signals */ - g_signal_connect (G_OBJECT (_adj), "value_changed", - G_CALLBACK (_adjustmentChanged), _csel); + attachToGridOrTable(t, _impl->_sbtn, 2, row, 1, 1, false, true); - g_signal_connect (G_OBJECT (_slider), "grabbed", - G_CALLBACK (_sliderGrabbed), _csel); - g_signal_connect (G_OBJECT (_slider), "released", - G_CALLBACK (_sliderReleased), _csel); - g_signal_connect (G_OBJECT (_slider), "changed", - G_CALLBACK (_sliderChanged), _csel); + // Signals + g_signal_connect(G_OBJECT(_impl->_adj), "value_changed", G_CALLBACK(ColorICCSelectorImpl::_adjustmentChanged), _csel); + + g_signal_connect(G_OBJECT(_impl->_slider), "grabbed", G_CALLBACK(ColorICCSelectorImpl::_sliderGrabbed), _csel); + g_signal_connect(G_OBJECT(_impl->_slider), "released", G_CALLBACK(ColorICCSelectorImpl::_sliderReleased), _csel); + g_signal_connect(G_OBJECT(_impl->_slider), "changed", G_CALLBACK(ColorICCSelectorImpl::_sliderChanged), _csel); } -static void -sp_color_icc_selector_destroy (GtkObject *object) +static void sp_color_icc_selector_dispose(GObject *object) { - if (((GtkObjectClass *) (parent_class))->destroy) - (* ((GtkObjectClass *) (parent_class))->destroy) (object); + if ((G_OBJECT_CLASS(parent_class))->dispose) { + (* (G_OBJECT_CLASS(parent_class))->dispose)(object); + } } static void @@ -436,10 +610,9 @@ sp_color_icc_selector_show_all (GtkWidget *widget) gtk_widget_show (widget); } -static void -sp_color_icc_selector_hide_all (GtkWidget *widget) +static void sp_color_icc_selector_hide(GtkWidget *widget) { - gtk_widget_hide (widget); + gtk_widget_hide(widget); } GtkWidget * @@ -447,41 +620,45 @@ sp_color_icc_selector_new (void) { SPColorICCSelector *csel; - csel = (SPColorICCSelector*)g_object_new (SP_TYPE_COLOR_ICC_SELECTOR, NULL); + csel = static_cast<SPColorICCSelector*>(g_object_new (SP_TYPE_COLOR_ICC_SELECTOR, NULL)); return GTK_WIDGET (csel); } -void ColorICCSelector::_fixupHit( GtkWidget* /*src*/, gpointer data ) +void ColorICCSelectorImpl::_fixupHit( GtkWidget* /*src*/, gpointer data ) { - ColorICCSelector* self = reinterpret_cast<ColorICCSelector*>(data); + ColorICCSelectorImpl* self = reinterpret_cast<ColorICCSelectorImpl*>(data); gtk_widget_set_sensitive( self->_fixupBtn, FALSE ); - self->_adjustmentChanged( self->_fooAdj[0], SP_COLOR_ICC_SELECTOR(self->_csel) ); + self->_adjustmentChanged( self->_compUI[0]._adj, SP_COLOR_ICC_SELECTOR(self->_owner->_csel) ); } #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelector::_profileSelected( GtkWidget* /*src*/, gpointer data ) +void ColorICCSelectorImpl::_profileSelected( GtkWidget* /*src*/, gpointer data ) { - ColorICCSelector* self = reinterpret_cast<ColorICCSelector*>(data); - gint activeIndex = gtk_combo_box_get_active( GTK_COMBO_BOX(self->_profileSel) ); -#if GTK_CHECK_VERSION(2,24,0) - gchar* name = (activeIndex != 0) ? gtk_combo_box_text_get_active_text( GTK_COMBO_BOX_TEXT(self->_profileSel) ) : 0; -#else - gchar* name = (activeIndex != 0) ? gtk_combo_box_get_active_text( GTK_COMBO_BOX(self->_profileSel) ) : 0; -#endif //GTK_CHECK_VERSION - self->_switchToProfile( name ); - if ( name ) { - g_free( name ); + ColorICCSelectorImpl* self = reinterpret_cast<ColorICCSelectorImpl*>(data); + + GtkTreeIter iter; + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(self->_profileSel), &iter)) { + GtkTreeModel *store = gtk_combo_box_get_model(GTK_COMBO_BOX(self->_profileSel)); + gchar* name = 0; + + gtk_tree_model_get(store, &iter, 1, &name, -1); + self->_switchToProfile( name ); + gtk_widget_set_tooltip_text(self->_profileSel, name ); + + if ( name ) { + g_free( name ); + } } } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelector::_switchToProfile( gchar const* name ) +void ColorICCSelectorImpl::_switchToProfile( gchar const* name ) { bool dirty = false; - SPColor tmp( _color ); + SPColor tmp( _owner->_color ); if ( name ) { if ( tmp.icc && tmp.icc->colorProfile == name ) { @@ -502,11 +679,11 @@ void ColorICCSelector::_switchToProfile( gchar const* name ) if ( newProf ) { cmsHTRANSFORM trans = newProf->getTransfFromSRGB8(); if ( trans ) { - guint32 val = _color.toRGBA32(0); + guint32 val = _owner->_color.toRGBA32(0); guchar pre[4] = { - SP_RGBA32_R_U(val), - SP_RGBA32_G_U(val), - SP_RGBA32_B_U(val), + static_cast<guchar>(SP_RGBA32_R_U(val)), + static_cast<guchar>(SP_RGBA32_G_U(val)), + static_cast<guchar>(SP_RGBA32_B_U(val)), 255}; #ifdef DEBUG_LCMS g_message("Shoving in [%02x] [%02x] [%02x]", pre[0], pre[1], pre[2]); @@ -522,15 +699,12 @@ void ColorICCSelector::_switchToProfile( gchar const* name ) guint count = cmsChannelsOf( asICColorSpaceSig(newProf->getColorSpace()) ); #endif - gchar const** names = 0; - gchar const** tips = 0; - guint const* scales = 0; - getThings( asICColorSpaceSig(newProf->getColorSpace()), names, tips, scales ); + std::vector<colorspace::Component> things = colorspace::getColorSpaceInfo(asICColorSpaceSig(newProf->getColorSpace())); for ( guint i = 0; i < count; i++ ) { - gdouble val = (((gdouble)post[i])/65535.0) * (gdouble)scales[i]; + gdouble val = (((gdouble)post[i])/65535.0) * (gdouble)((i < things.size()) ? things[i].scale : 1); #ifdef DEBUG_LCMS - g_message(" scaled %d by %d to be %f", i, scales[i], val); + g_message(" scaled %d by %d to be %f", i, ((i < things.size()) ? things[i].scale : 1), val); #endif // DEBUG_LCMS tmp.icc->colors.push_back(val); } @@ -568,8 +742,8 @@ void ColorICCSelector::_switchToProfile( gchar const* name ) g_message("+ new color is [%s]", tmp.toString().c_str()); #endif // DEBUG_LCMS _setProfile( tmp.icc ); - //_adjustmentChanged( _fooAdj[0], SP_COLOR_ICC_SELECTOR(_csel) ); - setColorAlpha( tmp, _alpha, true ); + //_adjustmentChanged( _compUI[0]._adj, SP_COLOR_ICC_SELECTOR(_csel) ); + _owner->setColorAlpha( tmp, _owner->_alpha, true ); #ifdef DEBUG_LCMS g_message("+_________________"); #endif // DEBUG_LCMS @@ -578,27 +752,18 @@ void ColorICCSelector::_switchToProfile( gchar const* name ) #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelector::_profilesChanged( std::string const & name ) +void ColorICCSelectorImpl::_profilesChanged( std::string const & name ) { GtkComboBox* combo = GTK_COMBO_BOX(_profileSel); g_signal_handler_block( G_OBJECT(_profileSel), _profChangedID ); - GtkTreeModel* model = gtk_combo_box_get_model( combo ); - GtkTreeIter iter; - while ( gtk_tree_model_get_iter_first( model, &iter ) ) { -#if GTK_CHECK_VERSION(2,24,0) - gtk_combo_box_text_remove( GTK_COMBO_BOX_TEXT(combo), 0 ); -#else - gtk_combo_box_remove_text( combo, 0 ); -#endif - } + GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(combo)); + gtk_list_store_clear(store); -#if GTK_CHECK_VERSION(2,24,0) - gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(combo), _("<none>")); -#else - gtk_combo_box_append_text( combo, _("<none>")); -#endif + GtkTreeIter iter; + gtk_list_store_append (store, &iter); + gtk_list_store_set(store, &iter, 0, _("<none>"), 1, _("<none>"), -1); gtk_combo_box_set_active( combo, 0 ); @@ -607,13 +772,13 @@ void ColorICCSelector::_profilesChanged( std::string const & name ) while ( current ) { SPObject* obj = SP_OBJECT(current->data); Inkscape::ColorProfile* prof = reinterpret_cast<Inkscape::ColorProfile*>(obj); -#if GTK_CHECK_VERSION(2,24,0) - gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(combo), prof->name ); -#else - gtk_combo_box_append_text( combo, prof->name ); -#endif + + gtk_list_store_append (store, &iter); + gtk_list_store_set(store, &iter, 0, gr_ellipsize_text(prof->name, 25).c_str(), 1, prof->name, -1); + if ( name == prof->name ) { gtk_combo_box_set_active( combo, index ); + gtk_widget_set_tooltip_text(_profileSel, prof->name ); } index++; @@ -623,16 +788,16 @@ void ColorICCSelector::_profilesChanged( std::string const & name ) g_signal_handler_unblock( G_OBJECT(_profileSel), _profChangedID ); } #else -void ColorICCSelector::_profilesChanged( std::string const & /*name*/ ) +void ColorICCSelectorImpl::_profilesChanged( std::string const & /*name*/ ) { } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -/* Helpers for setting color value */ +// Helpers for setting color value void ColorICCSelector::_colorChanged() { - _updating = TRUE; + _impl->_updating = TRUE; //sp_color_icc_set_color( SP_COLOR_ICC( _icc ), &color ); #ifdef DEBUG_LCMS @@ -645,55 +810,57 @@ void ColorICCSelector::_colorChanged() g_message("FLIPPIES!!!! %p '%s'", _color.icc, (_color.icc ? _color.icc->colorProfile.c_str():"<null>")); #endif // DEBUG_LCMS - _profilesChanged( (_color.icc) ? _color.icc->colorProfile : std::string("") ); - ColorScales::setScaled( _adj, _alpha ); + _impl->_profilesChanged( (_color.icc) ? _color.icc->colorProfile : std::string("") ); + ColorScales::setScaled( _impl->_adj, _alpha ); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - _setProfile( _color.icc ); - _fixupNeeded = 0; - gtk_widget_set_sensitive( _fixupBtn, FALSE ); - - if ( _prof && _prof->getTransfToSRGB8() ) { - cmsUInt16Number tmp[4]; - for ( guint i = 0; i < _profChannelCount; i++ ) { - gdouble val = 0.0; - if ( _color.icc->colors.size() > i ) { - if ( _fooScales[i] == 256 ) { - val = (_color.icc->colors[i] + 128.0) / static_cast<gdouble>(_fooScales[i]); - } else { - val = _color.icc->colors[i] / static_cast<gdouble>(_fooScales[i]); + _impl->_setProfile( _color.icc ); + _impl->_fixupNeeded = 0; + gtk_widget_set_sensitive( _impl->_fixupBtn, FALSE ); + + if (_impl->_prof) { + if (_impl->_prof->getTransfToSRGB8() ) { + cmsUInt16Number tmp[4]; + for ( guint i = 0; i < _impl->_profChannelCount; i++ ) { + gdouble val = 0.0; + if ( _color.icc->colors.size() > i ) { + if ( _impl->_compUI[i]._component.scale == 256 ) { + val = (_color.icc->colors[i] + 128.0) / static_cast<gdouble>(_impl->_compUI[i]._component.scale); + } else { + val = _color.icc->colors[i] / static_cast<gdouble>(_impl->_compUI[i]._component.scale); + } } + tmp[i] = val * 0x0ffff; } - tmp[i] = val * 0x0ffff; - } - guchar post[4] = {0,0,0,0}; - cmsHTRANSFORM trans = _prof->getTransfToSRGB8(); - if ( trans ) { - cmsDoTransform( trans, tmp, post, 1 ); - guint32 other = SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255 ); - if ( other != _color.toRGBA32(255) ) { - _fixupNeeded = other; - gtk_widget_set_sensitive( _fixupBtn, TRUE ); + guchar post[4] = {0,0,0,0}; + cmsHTRANSFORM trans = _impl->_prof->getTransfToSRGB8(); + if ( trans ) { + cmsDoTransform( trans, tmp, post, 1 ); + guint32 other = SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255 ); + if ( other != _color.toRGBA32(255) ) { + _impl->_fixupNeeded = other; + gtk_widget_set_sensitive( _impl->_fixupBtn, TRUE ); #ifdef DEBUG_LCMS - g_message("Color needs to change 0x%06x to 0x%06x", _color.toRGBA32(255) >> 8, other >> 8 ); + g_message("Color needs to change 0x%06x to 0x%06x", _color.toRGBA32(255) >> 8, other >> 8 ); #endif // DEBUG_LCMS + } } } } #else //(void)color; #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - _updateSliders( -1 ); + _impl->_updateSliders( -1 ); - _updating = FALSE; + _impl->_updating = FALSE; #ifdef DEBUG_LCMS g_message( "\\_________ %p::_colorChanged()", this ); #endif // DEBUG_LCMS } #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelector::_setProfile( SVGICCColor* profile ) +void ColorICCSelectorImpl::_setProfile( SVGICCColor* profile ) { #ifdef DEBUG_LCMS g_message( "/^^^^^^^^^ %p::_setProfile(%s)", this, @@ -711,10 +878,10 @@ void ColorICCSelector::_setProfile( SVGICCColor* profile ) profChanged = true; } - for ( guint i = 0; i < _fooCount; i++ ) { - gtk_widget_hide( _fooLabel[i] ); - gtk_widget_hide( _fooSlider[i] ); - gtk_widget_hide( _fooBtn[i] ); + for ( size_t i = 0; i < _compUI.size(); i++ ) { + gtk_widget_hide( _compUI[i]._label ); + gtk_widget_hide( _compUI[i]._slider ); + gtk_widget_hide( _compUI[i]._btn ); } if ( profile ) { @@ -726,39 +893,41 @@ void ColorICCSelector::_setProfile( SVGICCColor* profile ) _profChannelCount = cmsChannelsOf( asICColorSpaceSig(_prof->getColorSpace()) ); #endif - gchar const** names = 0; - gchar const** tips = 0; - getThings( asICColorSpaceSig(_prof->getColorSpace()), names, tips, _fooScales ); - if ( profChanged ) { + std::vector<colorspace::Component> things = colorspace::getColorSpaceInfo(asICColorSpaceSig(_prof->getColorSpace())); + for (size_t i = 0; (i < things.size()) && (i < _profChannelCount); ++i) + { + _compUI[i]._component = things[i]; + } + for ( guint i = 0; i < _profChannelCount; i++ ) { - gtk_label_set_text_with_mnemonic( GTK_LABEL(_fooLabel[i]), names[i]); + gtk_label_set_text_with_mnemonic( GTK_LABEL(_compUI[i]._label), (i < things.size()) ? things[i].name.c_str() : ""); - gtk_widget_set_tooltip_text( _fooSlider[i], tips[i] ); - gtk_widget_set_tooltip_text( _fooBtn[i], tips[i] ); + gtk_widget_set_tooltip_text( _compUI[i]._slider, (i < things.size()) ? things[i].tip.c_str() : "" ); + gtk_widget_set_tooltip_text( _compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : "" ); - sp_color_slider_set_colors( SP_COLOR_SLIDER(_fooSlider[i]), + sp_color_slider_set_colors( SP_COLOR_SLIDER(_compUI[i]._slider), SPColor(0.0, 0.0, 0.0).toRGBA32(0xff), SPColor(0.5, 0.5, 0.5).toRGBA32(0xff), SPColor(1.0, 1.0, 1.0).toRGBA32(0xff) ); /* - _fooAdj[i] = GTK_ADJUSTMENT( gtk_adjustment_new( val, 0.0, _fooScales[i], step, page, page ) ); - g_signal_connect( G_OBJECT( _fooAdj[i] ), "value_changed", G_CALLBACK( _adjustmentChanged ), _csel ); + _compUI[i]._adj = GTK_ADJUSTMENT( gtk_adjustment_new( val, 0.0, _fooScales[i], step, page, page ) ); + g_signal_connect( G_OBJECT( _compUI[i]._adj ), "value_changed", G_CALLBACK( _adjustmentChanged ), _csel ); - sp_color_slider_set_adjustment( SP_COLOR_SLIDER(_fooSlider[i]), _fooAdj[i] ); - gtk_spin_button_set_adjustment( GTK_SPIN_BUTTON(_fooBtn[i]), _fooAdj[i] ); - gtk_spin_button_set_digits( GTK_SPIN_BUTTON(_fooBtn[i]), digits ); + sp_color_slider_set_adjustment( SP_COLOR_SLIDER(_compUI[i]._slider), _compUI[i]._adj ); + gtk_spin_button_set_adjustment( GTK_SPIN_BUTTON(_compUI[i]._btn), _compUI[i]._adj ); + gtk_spin_button_set_digits( GTK_SPIN_BUTTON(_compUI[i]._btn), digits ); */ - gtk_widget_show( _fooLabel[i] ); - gtk_widget_show( _fooSlider[i] ); - gtk_widget_show( _fooBtn[i] ); - //gtk_adjustment_set_value( _fooAdj[i], 0.0 ); - //gtk_adjustment_set_value( _fooAdj[i], val ); + gtk_widget_show( _compUI[i]._label ); + gtk_widget_show( _compUI[i]._slider ); + gtk_widget_show( _compUI[i]._btn ); + //gtk_adjustment_set_value( _compUI[i]._adj, 0.0 ); + //gtk_adjustment_set_value( _compUI[i]._adj, val ); } - for ( guint i = _profChannelCount; i < _fooCount; i++ ) { - gtk_widget_hide( _fooLabel[i] ); - gtk_widget_hide( _fooSlider[i] ); - gtk_widget_hide( _fooBtn[i] ); + for ( size_t i = _profChannelCount; i < _compUI.size(); i++ ) { + gtk_widget_hide( _compUI[i]._label ); + gtk_widget_hide( _compUI[i]._slider ); + gtk_widget_hide( _compUI[i]._btn ); } } } else { @@ -773,47 +942,49 @@ void ColorICCSelector::_setProfile( SVGICCColor* profile ) } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelector::_updateSliders( gint ignore ) +void ColorICCSelectorImpl::_updateSliders( gint ignore ) { #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - if ( _color.icc ) + if ( _owner->_color.icc ) { for ( guint i = 0; i < _profChannelCount; i++ ) { gdouble val = 0.0; - if ( _color.icc->colors.size() > i ) { - if ( _fooScales[i] == 256 ) { - val = (_color.icc->colors[i] + 128.0) / static_cast<gdouble>(_fooScales[i]); + if ( _owner->_color.icc->colors.size() > i ) { + if ( _compUI[i]._component.scale == 256 ) { + val = (_owner->_color.icc->colors[i] + 128.0) / static_cast<gdouble>(_compUI[i]._component.scale); } else { - val = _color.icc->colors[i] / static_cast<gdouble>(_fooScales[i]); + val = _owner->_color.icc->colors[i] / static_cast<gdouble>(_compUI[i]._component.scale); } } - gtk_adjustment_set_value( _fooAdj[i], val ); + gtk_adjustment_set_value( _compUI[i]._adj, val ); } - if ( _prof && _prof->getTransfToSRGB8() ) { - for ( guint i = 0; i < _profChannelCount; i++ ) { - if ( static_cast<gint>(i) != ignore ) { - cmsUInt16Number* scratch = getScratch(); - cmsUInt16Number filler[4] = {0, 0, 0, 0}; - for ( guint j = 0; j < _profChannelCount; j++ ) { - filler[j] = 0x0ffff * ColorScales::getScaled( _fooAdj[j] ); - } - - cmsUInt16Number* p = scratch; - for ( guint x = 0; x < 1024; x++ ) { + if ( _prof ) { + if ( _prof->getTransfToSRGB8() ) { + for ( guint i = 0; i < _profChannelCount; i++ ) { + if ( static_cast<gint>(i) != ignore ) { + cmsUInt16Number* scratch = getScratch(); + cmsUInt16Number filler[4] = {0, 0, 0, 0}; for ( guint j = 0; j < _profChannelCount; j++ ) { - if ( j == i ) { - *p++ = x * 0x0ffff / 1024; - } else { - *p++ = filler[j]; + filler[j] = 0x0ffff * ColorScales::getScaled( _compUI[j]._adj ); + } + + cmsUInt16Number* p = scratch; + for ( guint x = 0; x < 1024; x++ ) { + for ( guint j = 0; j < _profChannelCount; j++ ) { + if ( j == i ) { + *p++ = x * 0x0ffff / 1024; + } else { + *p++ = filler[j]; + } } } - } - - cmsHTRANSFORM trans = _prof->getTransfToSRGB8(); - if ( trans ) { - cmsDoTransform( trans, scratch, _fooMap[i], 1024 ); - sp_color_slider_set_map( SP_COLOR_SLIDER(_fooSlider[i]), _fooMap[i] ); + + cmsHTRANSFORM trans = _prof->getTransfToSRGB8(); + if ( trans ) { + cmsDoTransform( trans, scratch, _compUI[i]._map, 1024 ); + sp_color_slider_set_map( SP_COLOR_SLIDER(_compUI[i]._slider), _compUI[i]._map ); + } } } } @@ -823,16 +994,15 @@ void ColorICCSelector::_updateSliders( gint ignore ) (void)ignore; #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - guint32 start = _color.toRGBA32( 0x00 ); - guint32 mid = _color.toRGBA32( 0x7f ); - guint32 end = _color.toRGBA32( 0xff ); + guint32 start = _owner->_color.toRGBA32( 0x00 ); + guint32 mid = _owner->_color.toRGBA32( 0x7f ); + guint32 end = _owner->_color.toRGBA32( 0xff ); sp_color_slider_set_colors( SP_COLOR_SLIDER(_slider), start, mid, end ); - } -void ColorICCSelector::_adjustmentChanged( GtkAdjustment *adjustment, SPColorICCSelector *cs ) +void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, SPColorICCSelector *cs ) { // // TODO check this. It looks questionable: // // if a value is entered between 0 and 1 exclusive, normalize it to (int) 0..255 or 0..100 @@ -845,24 +1015,24 @@ void ColorICCSelector::_adjustmentChanged( GtkAdjustment *adjustment, SPColorICC #endif // DEBUG_LCMS ColorICCSelector* iccSelector = static_cast<ColorICCSelector*>(SP_COLOR_SELECTOR(cs)->base); - if (iccSelector->_updating) { + if (iccSelector->_impl->_updating) { return; } - iccSelector->_updating = TRUE; + iccSelector->_impl->_updating = TRUE; gint match = -1; SPColor newColor( iccSelector->_color ); - gfloat scaled = ColorScales::getScaled( iccSelector->_adj ); - if ( iccSelector->_adj == adjustment ) { + gfloat scaled = ColorScales::getScaled( iccSelector->_impl->_adj ); + if ( iccSelector->_impl->_adj == adjustment ) { #ifdef DEBUG_LCMS g_message("ALPHA"); #endif // DEBUG_LCMS } else { #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - for ( guint i = 0; i < iccSelector->_fooCount; i++ ) { - if ( iccSelector->_fooAdj[i] == adjustment ) { + for ( size_t i = 0; i < iccSelector->_impl->_compUI.size(); i++ ) { + if ( iccSelector->_impl->_compUI[i]._adj == adjustment ) { match = i; break; } @@ -876,11 +1046,11 @@ void ColorICCSelector::_adjustmentChanged( GtkAdjustment *adjustment, SPColorICC cmsUInt16Number tmp[4]; for ( guint i = 0; i < 4; i++ ) { - tmp[i] = ColorScales::getScaled( iccSelector->_fooAdj[i] ) * 0x0ffff; + tmp[i] = ColorScales::getScaled( iccSelector->_impl->_compUI[i]._adj ) * 0x0ffff; } guchar post[4] = {0,0,0,0}; - cmsHTRANSFORM trans = iccSelector->_prof->getTransfToSRGB8(); + cmsHTRANSFORM trans = iccSelector->_impl->_prof->getTransfToSRGB8(); if ( trans ) { cmsDoTransform( trans, tmp, post, 1 ); } @@ -901,41 +1071,39 @@ void ColorICCSelector::_adjustmentChanged( GtkAdjustment *adjustment, SPColorICC #endif // DEBUG_LCMS newColor = other; newColor.icc->colors.clear(); - for ( guint i = 0; i < iccSelector->_profChannelCount; i++ ) { - gdouble val = ColorScales::getScaled( iccSelector->_fooAdj[i] ); - if ( iccSelector->_fooScales ) { - val *= iccSelector->_fooScales[i]; - if ( iccSelector->_fooScales[i] == 256 ) { - val -= 128; - } + for ( guint i = 0; i < iccSelector->_impl->_profChannelCount; i++ ) { + gdouble val = ColorScales::getScaled( iccSelector->_impl->_compUI[i]._adj ); + val *= iccSelector->_impl->_compUI[i]._component.scale; + if ( iccSelector->_impl->_compUI[i]._component.scale == 256 ) { + val -= 128; } newColor.icc->colors.push_back( val ); } } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) } - iccSelector->_updateInternals( newColor, scaled, iccSelector->_dragging ); - iccSelector->_updateSliders( match ); + iccSelector->_updateInternals( newColor, scaled, iccSelector->_impl->_dragging ); + iccSelector->_impl->_updateSliders( match ); - iccSelector->_updating = FALSE; + iccSelector->_impl->_updating = FALSE; #ifdef DEBUG_LCMS g_message( "\\_________ %p::_adjustmentChanged()", cs ); #endif // DEBUG_LCMS } -void ColorICCSelector::_sliderGrabbed( SPColorSlider */*slider*/, SPColorICCSelector */*cs*/ ) +void ColorICCSelectorImpl::_sliderGrabbed( SPColorSlider * /*slider*/, SPColorICCSelector * /*cs*/ ) { -// ColorICCSelector* iccSelector = (ColorICCSelector*)(SP_COLOR_SELECTOR(cs)->base); +// ColorICCSelector* iccSelector = dynamic_cast<ColorICCSelector*>(SP_COLOR_SELECTOR(cs)->base); // if (!iccSelector->_dragging) { // iccSelector->_dragging = TRUE; // iccSelector->_grabbed(); -// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_adj ), iccSelector->_dragging ); +// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_impl->_adj ), iccSelector->_dragging ); // } } -void ColorICCSelector::_sliderReleased( SPColorSlider */*slider*/, SPColorICCSelector */*cs*/ ) +void ColorICCSelectorImpl::_sliderReleased( SPColorSlider * /*slider*/, SPColorICCSelector * /*cs*/ ) { -// ColorICCSelector* iccSelector = (ColorICCSelector*)(SP_COLOR_SELECTOR(cs)->base); +// ColorICCSelector* iccSelector = dynamic_cast<ColorICCSelector*>(SP_COLOR_SELECTOR(cs)->base); // if (iccSelector->_dragging) { // iccSelector->_dragging = FALSE; // iccSelector->_released(); @@ -944,15 +1112,15 @@ void ColorICCSelector::_sliderReleased( SPColorSlider */*slider*/, SPColorICCSel } #ifdef DEBUG_LCMS -void ColorICCSelector::_sliderChanged( SPColorSlider *slider, SPColorICCSelector *cs ) +void ColorICCSelectorImpl::_sliderChanged( SPColorSlider *slider, SPColorICCSelector *cs ) #else -void ColorICCSelector::_sliderChanged( SPColorSlider */*slider*/, SPColorICCSelector */*cs*/ ) +void ColorICCSelectorImpl::_sliderChanged( SPColorSlider * /*slider*/, SPColorICCSelector * /*cs*/ ) #endif // DEBUG_LCMS { #ifdef DEBUG_LCMS g_message("Changed %p and %p", slider, cs ); #endif // DEBUG_LCMS -// ColorICCSelector* iccSelector = (ColorICCSelector*)(SP_COLOR_SELECTOR(cs)->base); +// ColorICCSelector* iccSelector = dynamic_cast<ColorICCSelector*>(SP_COLOR_SELECTOR(cs)->base); // iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_adj ), iccSelector->_dragging ); } diff --git a/src/widgets/sp-color-icc-selector.h b/src/widgets/sp-color-icc-selector.h index 67fedf590..f63ab0853 100644 --- a/src/widgets/sp-color-icc-selector.h +++ b/src/widgets/sp-color-icc-selector.h @@ -4,17 +4,16 @@ #include <glib.h> #include <gtk/gtk.h> -#include "../color.h" -#include "sp-color-slider.h" #include "sp-color-selector.h" namespace Inkscape { -struct ColorProfile; +class ColorProfile; } struct SPColorICCSelector; struct SPColorICCSelectorClass; +class ColorICCSelectorImpl; class ColorICCSelector: public ColorSelector { @@ -27,63 +26,25 @@ public: protected: virtual void _colorChanged(); - static void _adjustmentChanged ( GtkAdjustment *adjustment, SPColorICCSelector *cs ); - - static void _sliderGrabbed( SPColorSlider *slider, SPColorICCSelector *cs ); - static void _sliderReleased( SPColorSlider *slider, SPColorICCSelector *cs ); - static void _sliderChanged( SPColorSlider *slider, SPColorICCSelector *cs ); - - static void _fixupHit( GtkWidget* src, gpointer data ); - static void _profileSelected( GtkWidget* src, gpointer data ); - void _recalcColor( gboolean changing ); -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - void _setProfile( SVGICCColor* profile ); - void _switchToProfile( gchar const* name ); -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - void _updateSliders( gint ignore ); - void _profilesChanged( std::string const & name ); - - gboolean _updating : 1; - gboolean _dragging : 1; - - guint32 _fixupNeeded; - GtkWidget* _fixupBtn; - GtkWidget* _profileSel; - - guint _fooCount; - guint const* _fooScales; - GtkAdjustment** _fooAdj; - GtkWidget** _fooSlider; - GtkWidget** _fooBtn; - GtkWidget** _fooLabel; - guchar** _fooMap; - - GtkAdjustment* _adj; /* Channel adjustment */ - GtkWidget* _slider; - GtkWidget* _sbtn; /* Spinbutton */ - GtkWidget* _label; /* Label */ - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - std::string _profileName; - Inkscape::ColorProfile* _prof; - guint _profChannelCount; - gulong _profChangedID; -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) private: + friend class ColorICCSelectorImpl; + // By default, disallow copy constructor and assignment operator ColorICCSelector( const ColorICCSelector& obj ); ColorICCSelector& operator=( const ColorICCSelector& obj ); + + ColorICCSelectorImpl *_impl; }; -#define SP_TYPE_COLOR_ICC_SELECTOR (sp_color_icc_selector_get_type ()) -#define SP_COLOR_ICC_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_COLOR_ICC_SELECTOR, SPColorICCSelector)) -#define SP_COLOR_ICC_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_COLOR_ICC_SELECTOR, SPColorICCSelectorClass)) -#define SP_IS_COLOR_ICC_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_COLOR_ICC_SELECTOR)) -#define SP_IS_COLOR_ICC_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_COLOR_ICC_SELECTOR)) +#define SP_TYPE_COLOR_ICC_SELECTOR (sp_color_icc_selector_get_type()) +#define SP_COLOR_ICC_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_COLOR_ICC_SELECTOR, SPColorICCSelector)) +#define SP_COLOR_ICC_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_COLOR_ICC_SELECTOR, SPColorICCSelectorClass)) +#define SP_IS_COLOR_ICC_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_COLOR_ICC_SELECTOR)) +#define SP_IS_COLOR_ICC_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_COLOR_ICC_SELECTOR)) struct SPColorICCSelector { SPColorSelector parent; @@ -93,9 +54,9 @@ struct SPColorICCSelectorClass { SPColorSelectorClass parent_class; }; -GType sp_color_icc_selector_get_type (void); +GType sp_color_icc_selector_get_type(void); -GtkWidget *sp_color_icc_selector_new (void); +GtkWidget *sp_color_icc_selector_new(void); diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index 863e8b762..e081f98e0 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -17,6 +17,7 @@ # include "config.h" #endif +#include "widgets/icon.h" #include <cstring> #include <string> #include <cstdlib> @@ -37,6 +38,8 @@ #include "../profile-manager.h" #include "color-profile.h" #include "cms-system.h" +#include "tools-switch.h" +#include "ui/tools/tool-base.h" using Inkscape::CMSSystem; @@ -52,10 +55,10 @@ struct SPColorNotebookTracker { static void sp_color_notebook_class_init (SPColorNotebookClass *klass); static void sp_color_notebook_init (SPColorNotebook *colorbook); -static void sp_color_notebook_destroy (GtkObject *object); +static void sp_color_notebook_dispose(GObject *object); static void sp_color_notebook_show_all (GtkWidget *widget); -static void sp_color_notebook_hide_all (GtkWidget *widget); +static void sp_color_notebook_hide(GtkWidget *widget); static SPColorSelectorClass *parent_class; @@ -85,15 +88,15 @@ GType sp_color_notebook_get_type(void) static void sp_color_notebook_class_init(SPColorNotebookClass *klass) { - GtkObjectClass *object_class = reinterpret_cast<GtkObjectClass *>(klass); + GObjectClass *object_class = reinterpret_cast<GObjectClass *>(klass); GtkWidgetClass *widget_class = reinterpret_cast<GtkWidgetClass *>(klass); parent_class = SP_COLOR_SELECTOR_CLASS(g_type_class_peek_parent(klass)); - object_class->destroy = sp_color_notebook_destroy; + object_class->dispose = sp_color_notebook_dispose; widget_class->show_all = sp_color_notebook_show_all; - widget_class->hide_all = sp_color_notebook_hide_all; + widget_class->hide = sp_color_notebook_hide; } static void @@ -104,7 +107,7 @@ sp_color_notebook_switch_page(GtkNotebook *notebook, { if ( colorbook ) { - ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base); + ColorNotebook* nb = dynamic_cast<ColorNotebook*>(SP_COLOR_SELECTOR(colorbook)->base); nb->switchPage( notebook, page, page_num ); // remember the page we switched to @@ -126,7 +129,7 @@ void ColorNotebook::switchPage(GtkNotebook*, csel->base->getColorAlpha(_color, _alpha); } widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), page_num); - if ( widget && SP_IS_COLOR_SELECTOR (widget) ) + if ( widget && SP_IS_COLOR_SELECTOR(widget) ) { csel = SP_COLOR_SELECTOR (widget); csel->base->setColorAlpha( _color, _alpha ); @@ -141,7 +144,7 @@ static gint sp_color_notebook_menu_handler( GtkWidget *widget, GdkEvent *event ) if (event->type == GDK_BUTTON_PRESS) { SPColorSelector* csel = SP_COLOR_SELECTOR(widget); - ((ColorNotebook*)(csel->base))->menuHandler( event ); + (dynamic_cast<ColorNotebook*>(csel->base))->menuHandler( event ); /* Tell calling code that we have handled this event; the buck * stops here. */ @@ -162,19 +165,17 @@ gint ColorNotebook::menuHandler( GdkEvent* event ) static void sp_color_notebook_menuitem_response (GtkMenuItem *menuitem, gpointer user_data) { - gboolean active = FALSE; - - active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)); + gboolean active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)); SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (user_data); if ( entry ) { if ( active ) { - ((ColorNotebook*)(SP_COLOR_SELECTOR(entry->backPointer)->base))->addPage(entry->type, entry->submode); + (dynamic_cast<ColorNotebook*>(SP_COLOR_SELECTOR(entry->backPointer)->base))->addPage(entry->type, entry->submode); } else { - ((ColorNotebook*)(SP_COLOR_SELECTOR(entry->backPointer)->base))->removePage(entry->type, entry->submode); + (dynamic_cast<ColorNotebook*>(SP_COLOR_SELECTOR(entry->backPointer)->base))->removePage(entry->type, entry->submode); } } } @@ -192,7 +193,6 @@ sp_color_notebook_init (SPColorNotebook *colorbook) void ColorNotebook::init() { - GtkWidget* table = 0; guint row = 0; guint i = 0; guint j = 0; @@ -220,6 +220,10 @@ void ColorNotebook::init() _book = gtk_notebook_new (); gtk_widget_show (_book); + // Dont show the notebook tabs, use radiobuttons instead + gtk_notebook_set_show_border (GTK_NOTEBOOK (_book), false); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (_book), false); + selector_types = g_type_children (SP_TYPE_COLOR_SELECTOR, &selector_type_count); for ( i = 0; i < selector_type_count; i++ ) @@ -228,7 +232,7 @@ void ColorNotebook::init() { guint howmany = 1; gpointer klass = g_type_class_ref (selector_types[i]); - if ( klass && SP_IS_COLOR_SELECTOR_CLASS (klass) ) + if ( klass && SP_IS_COLOR_SELECTOR_CLASS(klass) ) { SPColorSelectorClass *ck = SP_COLOR_SELECTOR_CLASS (klass); howmany = MAX (1, ck->submode_count); @@ -252,6 +256,16 @@ void ColorNotebook::init() } } +#if GTK_CHECK_VERSION(3,0,0) + _buttonbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2); + gtk_box_set_homogeneous(GTK_BOX(_buttonbox), TRUE); +#else + _buttonbox = gtk_hbox_new (TRUE, 2); +#endif + + gtk_widget_show (_buttonbox); + _buttons = new GtkWidget *[_trackerList->len]; + for ( i = 0; i < _trackerList->len; i++ ) { SPColorNotebookTracker *entry = @@ -262,19 +276,53 @@ void ColorNotebook::init() } } - table = gtk_table_new (2, 3, FALSE); +#if GTK_CHECK_VERSION(3,0,0) + GtkWidget* table = gtk_grid_new(); +#else + GtkWidget* table = gtk_table_new(2, 3, FALSE); +#endif + gtk_widget_show (table); gtk_box_pack_start (GTK_BOX (_csel), table, TRUE, TRUE, 0); + sp_set_font_size_smaller (_buttonbox); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_buttonbox, XPAD); + gtk_widget_set_margin_right(_buttonbox, XPAD); + gtk_widget_set_margin_top(_buttonbox, YPAD); + gtk_widget_set_margin_bottom(_buttonbox, YPAD); + gtk_widget_set_hexpand(_buttonbox, TRUE); + gtk_widget_set_valign(_buttonbox, GTK_ALIGN_CENTER); + gtk_grid_attach(GTK_GRID(table), _buttonbox, 0, row, 2, 1); +#else + gtk_table_attach (GTK_TABLE (table), _buttonbox, 0, 2, row, row + 1, + static_cast<GtkAttachOptions>(GTK_EXPAND|GTK_FILL), + static_cast<GtkAttachOptions>(0), + XPAD, YPAD); +#endif + + row++; + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_book, XPAD*2); + gtk_widget_set_margin_right(_book, XPAD*2); + gtk_widget_set_margin_top(_book, YPAD); + gtk_widget_set_margin_bottom(_book, YPAD); + gtk_widget_set_hexpand(_book, TRUE); + gtk_widget_set_vexpand(_book, TRUE); + gtk_grid_attach(GTK_GRID(table), _book, 0, row, 2, 1); +#else gtk_table_attach (GTK_TABLE (table), _book, 0, 2, row, row + 1, static_cast<GtkAttachOptions>(GTK_EXPAND|GTK_FILL), static_cast<GtkAttachOptions>(GTK_EXPAND|GTK_FILL), - XPAD, YPAD); + XPAD*2, YPAD); +#endif // restore the last active page Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gtk_notebook_set_current_page (GTK_NOTEBOOK (_book), prefs->getInt("/colorselector/page", 0)); + _setCurrentPage(prefs->getInt("/colorselector/page", 0)); { gboolean found = FALSE; @@ -325,7 +373,6 @@ void ColorNotebook::init() #if GTK_CHECK_VERSION(3,0,0) GtkWidget *rgbabox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_set_homogeneous(GTK_BOX(rgbabox), FALSE); #else GtkWidget *rgbabox = gtk_hbox_new (FALSE, 0); #endif @@ -352,9 +399,19 @@ void ColorNotebook::init() gtk_widget_set_tooltip_text (_box_toomuchink, _("Too much ink!")); gtk_widget_set_sensitive (_box_toomuchink, false); gtk_box_pack_start(GTK_BOX(rgbabox), _box_toomuchink, FALSE, FALSE, 2); - #endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + + /* Color picker */ + GtkWidget *picker = gtk_image_new_from_icon_name ("color-picker", GTK_ICON_SIZE_SMALL_TOOLBAR); + _btn_picker = gtk_button_new (); + gtk_button_set_relief(GTK_BUTTON(_btn_picker), GTK_RELIEF_NONE); + gtk_widget_show (_btn); + gtk_container_add (GTK_CONTAINER (_btn_picker), picker); + gtk_widget_set_tooltip_text (_btn_picker, _("Pick colors from image")); + gtk_box_pack_start(GTK_BOX(rgbabox), _btn_picker, FALSE, FALSE, 2); + g_signal_connect(G_OBJECT(_btn_picker), "clicked", G_CALLBACK(ColorNotebook::_picker_clicked), _csel); + /* Create RGBA entry and color preview */ _rgbal = gtk_label_new_with_mnemonic (_("RGBA_:")); gtk_misc_set_alignment (GTK_MISC (_rgbal), 1.0, 0.5); @@ -376,7 +433,15 @@ void ColorNotebook::init() gtk_widget_hide(GTK_WIDGET(_box_toomuchink)); #endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(rgbabox, XPAD); + gtk_widget_set_margin_right(rgbabox, XPAD); + gtk_widget_set_margin_top(rgbabox, YPAD); + gtk_widget_set_margin_bottom(rgbabox, YPAD); + gtk_grid_attach(GTK_GRID(table), rgbabox, 0, row, 2, 1); +#else gtk_table_attach (GTK_TABLE (table), rgbabox, 0, 2, row, row + 1, GTK_FILL, GTK_SHRINK, XPAD, YPAD); +#endif #ifdef SPCS_PREVIEW _p = sp_color_preview_new (0xffffffff); @@ -390,11 +455,10 @@ void ColorNotebook::init() _entryId = g_signal_connect (G_OBJECT (_rgbae), "changed", G_CALLBACK (ColorNotebook::_rgbaEntryChangedHook), _csel); } -static void -sp_color_notebook_destroy (GtkObject *object) +static void sp_color_notebook_dispose(GObject *object) { - if (((GtkObjectClass *) (parent_class))->destroy) - (* ((GtkObjectClass *) (parent_class))->destroy) (object); + if (((GObjectClass *) (parent_class))->dispose) + (* ((GObjectClass *) (parent_class))->dispose) (object); } ColorNotebook::~ColorNotebook() @@ -413,6 +477,13 @@ ColorNotebook::~ColorNotebook() _switchId = 0; } } + + if ( _buttons ) + { + delete [] _buttons; + _buttons = 0; + } + } static void @@ -421,20 +492,16 @@ sp_color_notebook_show_all (GtkWidget *widget) gtk_widget_show (widget); } -static void -sp_color_notebook_hide_all (GtkWidget *widget) +static void sp_color_notebook_hide(GtkWidget *widget) { - gtk_widget_hide (widget); + gtk_widget_hide(widget); } -GtkWidget * -sp_color_notebook_new (void) +GtkWidget *sp_color_notebook_new() { - SPColorNotebook *colorbook; - - colorbook = (SPColorNotebook*)g_object_new (SP_TYPE_COLOR_NOTEBOOK, NULL); + SPColorNotebook *colorbook = SP_COLOR_NOTEBOOK(g_object_new (SP_TYPE_COLOR_NOTEBOOK, NULL)); - return GTK_WIDGET (colorbook); + return GTK_WIDGET(colorbook); } ColorNotebook::ColorNotebook( SPColorSelector* csel ) @@ -470,9 +537,17 @@ void ColorNotebook::_colorChanged() _updateRgbaEntry( _color, _alpha ); } +void ColorNotebook::_picker_clicked(GtkWidget * /*widget*/, SPColorNotebook * /*colorbook*/) +{ + // Set the dropper into a "one click" mode, so it reverts to the previous tool after a click + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/dropper/onetimepick", true); + Inkscape::UI::Tools::sp_toggle_dropper(SP_ACTIVE_DESKTOP); +} + void ColorNotebook::_rgbaEntryChangedHook(GtkEntry *entry, SPColorNotebook *colorbook) { - ((ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base))->_rgbaEntryChanged( entry ); + (dynamic_cast<ColorNotebook*>(SP_COLOR_SELECTOR(colorbook)->base))->_rgbaEntryChanged( entry ); } void ColorNotebook::_rgbaEntryChanged(GtkEntry* entry) @@ -574,16 +649,40 @@ void ColorNotebook::_updateRgbaEntry( const SPColor& color, gfloat alpha ) } } +void ColorNotebook::_setCurrentPage(int i) +{ + gtk_notebook_set_current_page(GTK_NOTEBOOK(_book), i); + + if (_buttons && _trackerList && (static_cast<size_t>(i) < _trackerList->len) ) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_buttons[i]), TRUE); + } +} + +void ColorNotebook::_buttonClicked(GtkWidget *widget, SPColorNotebook *colorbook) +{ + ColorNotebook* nb = dynamic_cast<ColorNotebook*>(SP_COLOR_SELECTOR(colorbook)->base); + + if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget))) { + return; + } + + for(gint i = 0; i < gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb->_book)); i++) { + if (nb->_buttons[i] == widget) { + gtk_notebook_set_current_page (GTK_NOTEBOOK (nb->_book), i); + } + } +} + void ColorNotebook::_entryGrabbed (SPColorSelector *, SPColorNotebook *colorbook) { - ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base); + ColorNotebook* nb = dynamic_cast<ColorNotebook*>(SP_COLOR_SELECTOR(colorbook)->base); nb->_grabbed(); } void ColorNotebook::_entryDragged (SPColorSelector *csel, SPColorNotebook *colorbook) { gboolean oldState; - ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base); + ColorNotebook* nb = dynamic_cast<ColorNotebook*>(SP_COLOR_SELECTOR(colorbook)->base); oldState = nb->_dragging; @@ -595,14 +694,14 @@ void ColorNotebook::_entryDragged (SPColorSelector *csel, SPColorNotebook *color void ColorNotebook::_entryReleased (SPColorSelector *, SPColorNotebook *colorbook) { - ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base); + ColorNotebook* nb = dynamic_cast<ColorNotebook*>(SP_COLOR_SELECTOR(colorbook)->base); nb->_released(); } void ColorNotebook::_entryChanged (SPColorSelector *csel, SPColorNotebook *colorbook) { gboolean oldState; - ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base); + ColorNotebook* nb = dynamic_cast<ColorNotebook*>(SP_COLOR_SELECTOR(colorbook)->base); oldState = nb->_dragging; @@ -619,7 +718,7 @@ void ColorNotebook::_entryModified (SPColorSelector *csel, SPColorNotebook *colo g_return_if_fail (csel != NULL); g_return_if_fail (SP_IS_COLOR_SELECTOR (csel)); - ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base); + ColorNotebook* nb = dynamic_cast<ColorNotebook*>(SP_COLOR_SELECTOR(colorbook)->base); SPColor color; gfloat alpha = 1.0; @@ -648,7 +747,19 @@ GtkWidget* ColorNotebook::addPage(GType page_type, guint submode) const gchar* str = _(SP_COLOR_SELECTOR_GET_CLASS (csel)->name[index]); // g_message( "Hitting up for tab for '%s'", str ); tab_label = gtk_label_new(_(str)); - gtk_notebook_append_page( GTK_NOTEBOOK (_book), page, tab_label ); + gint pageNum = gtk_notebook_append_page( GTK_NOTEBOOK (_book), page, tab_label ); + + // Add a button for each page + _buttons[pageNum] = gtk_radio_button_new_with_label(NULL, _(str)); + gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(_buttons[pageNum]), FALSE); + if (pageNum > 0) { + GSList *group = gtk_radio_button_get_group (GTK_RADIO_BUTTON(_buttons[0])); + gtk_radio_button_set_group (GTK_RADIO_BUTTON(_buttons[pageNum]), group); + } + gtk_widget_show (_buttons[pageNum]); + gtk_box_pack_start (GTK_BOX (_buttonbox), _buttons[pageNum], TRUE, TRUE, 0); + + g_signal_connect (G_OBJECT (_buttons[pageNum]), "clicked", G_CALLBACK (_buttonClicked), _csel); g_signal_connect (G_OBJECT (page), "grabbed", G_CALLBACK (_entryGrabbed), _csel); g_signal_connect (G_OBJECT (page), "dragged", G_CALLBACK (_entryDragged), _csel); g_signal_connect (G_OBJECT (page), "released", G_CALLBACK (_entryReleased), _csel); diff --git a/src/widgets/sp-color-notebook.h b/src/widgets/sp-color-notebook.h index 8ea8464a9..6e5111132 100644 --- a/src/widgets/sp-color-notebook.h +++ b/src/widgets/sp-color-notebook.h @@ -46,11 +46,14 @@ protected: static void _entryReleased( SPColorSelector *csel, SPColorNotebook *colorbook ); static void _entryChanged( SPColorSelector *csel, SPColorNotebook *colorbook ); static void _entryModified( SPColorSelector *csel, SPColorNotebook *colorbook ); + static void _buttonClicked(GtkWidget *widget, SPColorNotebook *colorbook); + static void _picker_clicked(GtkWidget *widget, SPColorNotebook *colorbook); virtual void _colorChanged(); void _rgbaEntryChanged( GtkEntry* entry ); void _updateRgbaEntry( const SPColor& color, gfloat alpha ); + void _setCurrentPage(int i); gboolean _updating : 1; gboolean _updatingrgba : 1; @@ -58,10 +61,13 @@ protected: gulong _switchId; gulong _entryId; GtkWidget *_book; + GtkWidget *_buttonbox; + GtkWidget **_buttons; GtkWidget *_rgbal, *_rgbae; /* RGBA entry */ #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) GtkWidget *_box_outofgamut, *_box_colormanaged, *_box_toomuchink; #endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + GtkWidget *_btn_picker; GtkWidget *_p; /* Color preview */ GtkWidget *_btn; GtkWidget *_popup; diff --git a/src/widgets/sp-color-scales.cpp b/src/widgets/sp-color-scales.cpp index 262e199e9..c3f9d511c 100644 --- a/src/widgets/sp-color-scales.cpp +++ b/src/widgets/sp-color-scales.cpp @@ -32,10 +32,10 @@ G_BEGIN_DECLS static void sp_color_scales_class_init (SPColorScalesClass *klass); static void sp_color_scales_init (SPColorScales *cs); -static void sp_color_scales_destroy (GtkObject *object); +static void sp_color_scales_dispose(GObject *object); static void sp_color_scales_show_all (GtkWidget *widget); -static void sp_color_scales_hide_all (GtkWidget *widget); +static void sp_color_scales_hide(GtkWidget *widget); static const gchar *sp_color_scales_hue_map (void); @@ -78,23 +78,19 @@ static void sp_color_scales_class_init (SPColorScalesClass *klass) { static const gchar* nameset[] = {N_("RGB"), N_("HSL"), N_("CMYK"), 0}; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - SPColorSelectorClass *selector_class; - - object_class = (GtkObjectClass *) klass; - widget_class = (GtkWidgetClass *) klass; - selector_class = SP_COLOR_SELECTOR_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + SPColorSelectorClass *selector_class = SP_COLOR_SELECTOR_CLASS (klass); parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass)); selector_class->name = nameset; selector_class->submode_count = 3; - object_class->destroy = sp_color_scales_destroy; + object_class->dispose = sp_color_scales_dispose; widget_class->show_all = sp_color_scales_show_all; - widget_class->hide_all = sp_color_scales_hide_all; + widget_class->hide = sp_color_scales_hide; } ColorScales::ColorScales( SPColorSelector* csel ) @@ -134,15 +130,18 @@ void sp_color_scales_init (SPColorScales *cs) void ColorScales::init() { - GtkWidget *t; gint i; _updating = FALSE; _dragging = FALSE; - t = gtk_table_new (5, 3, FALSE); +#if GTK_CHECK_VERSION(3,0,0) + GtkWidget *t = gtk_grid_new(); +#else + GtkWidget *t = gtk_table_new (5, 3, FALSE); +#endif gtk_widget_show (t); - gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 4); /* Create components */ for (i = 0; i < static_cast< gint > (G_N_ELEMENTS(_a)) ; i++) { @@ -150,20 +149,51 @@ void ColorScales::init() _l[i] = gtk_label_new(""); gtk_misc_set_alignment (GTK_MISC (_l[i]), 1.0, 0.5); gtk_widget_show (_l[i]); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_l[i], XPAD); + gtk_widget_set_margin_right(_l[i], XPAD); + gtk_widget_set_margin_top(_l[i], YPAD); + gtk_widget_set_margin_bottom(_l[i], YPAD); + gtk_grid_attach(GTK_GRID(t), _l[i], 0, i, 1, 1); +#else gtk_table_attach (GTK_TABLE (t), _l[i], 0, 1, i, i + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); +#endif + /* Adjustment */ - _a[i] = (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, _rangeLimit, 1.0, 10.0, 10.0); + _a[i] = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, _rangeLimit, 1.0, 10.0, 10.0)); /* Slider */ _s[i] = sp_color_slider_new (_a[i]); gtk_widget_show (_s[i]); - gtk_table_attach (GTK_TABLE (t), _s[i], 1, 2, i, i + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)GTK_FILL, XPAD, YPAD); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_s[i], XPAD); + gtk_widget_set_margin_right(_s[i], XPAD); + gtk_widget_set_margin_top(_s[i], YPAD); + gtk_widget_set_margin_bottom(_s[i], YPAD); + gtk_widget_set_hexpand(_s[i], TRUE); + gtk_grid_attach(GTK_GRID(t), _s[i], 1, i, 1, 1); +#else + gtk_table_attach (GTK_TABLE (t), _s[i], 1, 2, i, i + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, XPAD, YPAD); +#endif /* Spinbutton */ _b[i] = gtk_spin_button_new (GTK_ADJUSTMENT (_a[i]), 1.0, 0); sp_dialog_defocus_on_enter (_b[i]); gtk_label_set_mnemonic_widget (GTK_LABEL(_l[i]), _b[i]); gtk_widget_show (_b[i]); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_b[i], XPAD); + gtk_widget_set_margin_right(_b[i], XPAD); + gtk_widget_set_margin_top(_b[i], YPAD); + gtk_widget_set_margin_bottom(_b[i], YPAD); + gtk_widget_set_halign(_b[i], GTK_ALIGN_CENTER); + gtk_widget_set_valign(_b[i], GTK_ALIGN_CENTER); + gtk_grid_attach(GTK_GRID(t), _b[i], 2, i, 1, 1); +#else gtk_table_attach (GTK_TABLE (t), _b[i], 2, 3, i, i + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, XPAD, YPAD); +#endif /* Attach channel value to adjustment */ g_object_set_data (G_OBJECT (_a[i]), "channel", GINT_TO_POINTER (i)); @@ -182,11 +212,10 @@ void ColorScales::init() setMode(SP_COLOR_SCALES_MODE_RGB); } -static void -sp_color_scales_destroy (GtkObject *object) +static void sp_color_scales_dispose(GObject *object) { - if (((GtkObjectClass *) (parent_class))->destroy) - (* ((GtkObjectClass *) (parent_class))->destroy) (object); + if ((G_OBJECT_CLASS(parent_class))->dispose) + (* (G_OBJECT_CLASS(parent_class))->dispose) (object); } static void @@ -195,18 +224,14 @@ sp_color_scales_show_all (GtkWidget *widget) gtk_widget_show (widget); } -static void -sp_color_scales_hide_all (GtkWidget *widget) +static void sp_color_scales_hide(GtkWidget *widget) { - gtk_widget_hide (widget); + gtk_widget_hide(widget); } -GtkWidget * -sp_color_scales_new (void) +GtkWidget *sp_color_scales_new() { - SPColorScales *csel; - - csel = (SPColorScales*)g_object_new (SP_TYPE_COLOR_SCALES, NULL); + SPColorScales *csel = SP_COLOR_SCALES(g_object_new (SP_TYPE_COLOR_SCALES, NULL)); return GTK_WIDGET (csel); } @@ -438,7 +463,7 @@ void ColorScales::setMode(SPColorScalesMode mode) gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_A:")); gtk_widget_set_tooltip_text (_s[3], _("Alpha (opacity)")); gtk_widget_set_tooltip_text (_b[3], _("Alpha (opacity)")); - sp_color_slider_set_map (SP_COLOR_SLIDER (_s[0]), (guchar*)sp_color_scales_hue_map ()); + sp_color_slider_set_map (SP_COLOR_SLIDER (_s[0]), (guchar *)(sp_color_scales_hue_map())); gtk_widget_hide (_l[4]); gtk_widget_hide (_s[4]); gtk_widget_hide (_b[4]); diff --git a/src/widgets/sp-color-selector.cpp b/src/widgets/sp-color-selector.cpp index 96cae3a35..6d62acecd 100644 --- a/src/widgets/sp-color-selector.cpp +++ b/src/widgets/sp-color-selector.cpp @@ -24,10 +24,10 @@ enum { static void sp_color_selector_class_init( SPColorSelectorClass *klass ); static void sp_color_selector_init( SPColorSelector *csel ); -static void sp_color_selector_destroy( GtkObject *object ); +static void sp_color_selector_dispose(GObject *object); static void sp_color_selector_show_all( GtkWidget *widget ); -static void sp_color_selector_hide_all( GtkWidget *widget ); +static void sp_color_selector_hide( GtkWidget *widget ); static GtkVBoxClass *parent_class; static guint csel_signals[LAST_SIGNAL] = {0}; @@ -62,10 +62,8 @@ GType sp_color_selector_get_type( void ) void sp_color_selector_class_init( SPColorSelectorClass *klass ) { static const gchar* nameset[] = {N_("Unnamed"), 0}; - GtkObjectClass *object_class; + GObjectClass *object_class = G_OBJECT_CLASS(klass); GtkWidgetClass *widget_class; - - object_class = GTK_OBJECT_CLASS(klass); widget_class = GTK_WIDGET_CLASS(klass); parent_class = GTK_VBOX_CLASS( g_type_class_peek_parent(klass) ); @@ -102,10 +100,10 @@ void sp_color_selector_class_init( SPColorSelectorClass *klass ) klass->name = nameset; klass->submode_count = 1; - object_class->destroy = sp_color_selector_destroy; + object_class->dispose = sp_color_selector_dispose; widget_class->show_all = sp_color_selector_show_all; - widget_class->hide_all = sp_color_selector_hide_all; + widget_class->hide = sp_color_selector_hide; } @@ -118,7 +116,7 @@ void sp_color_selector_init( SPColorSelector *csel ) /* g_signal_connect(G_OBJECT(csel->rgbae), "changed", G_CALLBACK(sp_color_selector_rgba_entry_changed), csel); */ } -void sp_color_selector_destroy( GtkObject *object ) +void sp_color_selector_dispose(GObject *object) { SPColorSelector *csel = SP_COLOR_SELECTOR( object ); if ( csel->base ) @@ -127,8 +125,8 @@ void sp_color_selector_destroy( GtkObject *object ) csel->base = 0; } - if ( (GTK_OBJECT_CLASS(parent_class))->destroy ) { - (* (GTK_OBJECT_CLASS(parent_class))->destroy)(object); + if ( (G_OBJECT_CLASS(parent_class))->dispose ) { + (* (G_OBJECT_CLASS(parent_class))->dispose)(object); } } @@ -137,7 +135,7 @@ void sp_color_selector_show_all( GtkWidget *widget ) gtk_widget_show( widget ); } -void sp_color_selector_hide_all( GtkWidget *widget ) +void sp_color_selector_hide(GtkWidget *widget) { gtk_widget_hide( widget ); } diff --git a/src/widgets/sp-color-slider.cpp b/src/widgets/sp-color-slider.cpp index 3b690afc9..9b13ba1c5 100644 --- a/src/widgets/sp-color-slider.cpp +++ b/src/widgets/sp-color-slider.cpp @@ -28,7 +28,7 @@ enum { static void sp_color_slider_class_init (SPColorSliderClass *klass); static void sp_color_slider_init (SPColorSlider *slider); -static void sp_color_slider_destroy (GtkObject *object); +static void sp_color_slider_dispose(GObject *object); static void sp_color_slider_realize (GtkWidget *widget); static void sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); @@ -41,14 +41,14 @@ static void sp_color_slider_get_preferred_width(GtkWidget *widget, static void sp_color_slider_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height); +#else +static gboolean sp_color_slider_expose(GtkWidget *widget, GdkEventExpose *event); #endif static void sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); -/* static void sp_color_slider_draw (GtkWidget *widget, GdkRectangle *area); */ -/* static void sp_color_slider_draw_focus (GtkWidget *widget); */ -/* static void sp_color_slider_draw_default (GtkWidget *widget); */ -static gint sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event); +static gboolean sp_color_slider_draw(GtkWidget *widget, cairo_t *cr); + static gint sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event); static gint sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event); static gint sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); @@ -56,7 +56,6 @@ static gint sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *ev static void sp_color_slider_adjustment_changed (GtkAdjustment *adjustment, SPColorSlider *slider); static void sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider); -static void sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area); static const guchar *sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height, gint c[], gint dc[], guint b0, guint b1, guint mask); static const guchar *sp_color_slider_render_map (gint x0, gint y0, gint width, gint height, @@ -85,16 +84,12 @@ sp_color_slider_get_type (void) return type; } -static void -sp_color_slider_class_init (SPColorSliderClass *klass) +static void sp_color_slider_class_init(SPColorSliderClass *klass) { - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; + GObjectClass *object_class = G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); - object_class = (GtkObjectClass *) klass; - widget_class = (GtkWidgetClass *) klass; - - parent_class = (GtkWidgetClass*)g_type_class_peek_parent (klass); + parent_class = GTK_WIDGET_CLASS(g_type_class_peek_parent(klass)); slider_signals[GRABBED] = g_signal_new ("grabbed", G_TYPE_FROM_CLASS(object_class), @@ -125,21 +120,21 @@ sp_color_slider_class_init (SPColorSliderClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - object_class->destroy = sp_color_slider_destroy; + object_class->dispose = sp_color_slider_dispose; widget_class->realize = sp_color_slider_realize; #if GTK_CHECK_VERSION(3,0,0) widget_class->get_preferred_width = sp_color_slider_get_preferred_width; widget_class->get_preferred_height = sp_color_slider_get_preferred_height; + widget_class->draw = sp_color_slider_draw; #else widget_class->size_request = sp_color_slider_size_request; + widget_class->expose_event = sp_color_slider_expose; #endif widget_class->size_allocate = sp_color_slider_size_allocate; -/* widget_class->draw = sp_color_slider_draw; */ /* widget_class->draw_focus = sp_color_slider_draw_focus; */ /* widget_class->draw_default = sp_color_slider_draw_default; */ - widget_class->expose_event = sp_color_slider_expose; widget_class->button_press_event = sp_color_slider_button_press; widget_class->button_release_event = sp_color_slider_button_release; widget_class->motion_notify_event = sp_color_slider_motion_notify; @@ -178,12 +173,9 @@ sp_color_slider_init (SPColorSlider *slider) slider->map = NULL; } -static void -sp_color_slider_destroy (GtkObject *object) +static void sp_color_slider_dispose(GObject *object) { - SPColorSlider *slider; - - slider = SP_COLOR_SLIDER (object); + SPColorSlider *slider = SP_COLOR_SLIDER (object); if (slider->adjustment) { g_signal_handlers_disconnect_matched (G_OBJECT (slider->adjustment), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, slider); @@ -191,8 +183,8 @@ sp_color_slider_destroy (GtkObject *object) slider->adjustment = NULL; } - if (((GtkObjectClass *) (parent_class))->destroy) - (* ((GtkObjectClass *) (parent_class))->destroy) (object); + if ((G_OBJECT_CLASS(parent_class))->dispose) + (* (G_OBJECT_CLASS(parent_class))->dispose) (object); } static void @@ -212,7 +204,11 @@ sp_color_slider_realize (GtkWidget *widget) attributes.height = allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gdk_screen_get_system_visual(gdk_screen_get_default()); + +#if !GTK_CHECK_VERSION(3,0,0) attributes.colormap = gdk_screen_get_system_colormap(gdk_screen_get_default()); +#endif + attributes.event_mask = gtk_widget_get_events (widget); attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | @@ -220,7 +216,11 @@ sp_color_slider_realize (GtkWidget *widget) GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); +#if GTK_CHECK_VERSION(3,0,0) + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; +#else attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; +#endif gtk_widget_set_window(widget, gdk_window_new(gtk_widget_get_parent_window(widget), @@ -228,9 +228,12 @@ sp_color_slider_realize (GtkWidget *widget) gdk_window_set_user_data(gtk_widget_get_window(widget), widget); +#if !GTK_CHECK_VERSION(3,0,0) + // This doesn't do anything in GTK+ 3 gtk_widget_set_style(widget, - gtk_style_attach(gtk_widget_get_style(widget), - gtk_widget_get_window(widget))); + gtk_style_attach(gtk_widget_get_style(widget), + gtk_widget_get_window(widget))); +#endif } static void @@ -270,19 +273,21 @@ sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation) } } -static gint -sp_color_slider_expose (GtkWidget *widget, GdkEventExpose *event) +#if !GTK_CHECK_VERSION(3,0,0) +static gboolean sp_color_slider_expose(GtkWidget *widget, GdkEventExpose * /*event*/) { - SPColorSlider *slider; + gboolean result = FALSE; - slider = SP_COLOR_SLIDER (widget); - - if (gtk_widget_is_drawable (widget)) { - sp_color_slider_paint (slider, &event->area); + if (gtk_widget_is_drawable(widget)) { + GdkWindow *window = gtk_widget_get_window(widget); + cairo_t *cr = gdk_cairo_create(window); + result = sp_color_slider_draw(widget, cr); + cairo_destroy(cr); } - return FALSE; + return result; } +#endif static gint sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event) @@ -302,10 +307,20 @@ sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event) slider->oldvalue = slider->value; ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); g_signal_emit (G_OBJECT (slider), slider_signals[DRAGGED], 0); + +#if GTK_CHECK_VERSION(3,0,0) + gdk_device_grab(gdk_event_get_device(reinterpret_cast<GdkEvent *>(event)), + gtk_widget_get_window(widget), + GDK_OWNERSHIP_NONE, + FALSE, + static_cast<GdkEventMask>(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), + NULL, + event->time); +#else gdk_pointer_grab(gtk_widget_get_window(widget), FALSE, - (GdkEventMask)(GDK_POINTER_MOTION_MASK | - GDK_BUTTON_RELEASE_MASK), + static_cast<GdkEventMask>(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), NULL, NULL, event->time); +#endif } return FALSE; @@ -319,7 +334,14 @@ sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event) slider = SP_COLOR_SLIDER (widget); if (event->button == 1) { + +#if GTK_CHECK_VERSION(3,0,0) + gdk_device_ungrab(gdk_event_get_device(reinterpret_cast<GdkEvent *>(event)), + gdk_event_get_time(reinterpret_cast<GdkEvent *>(event))); +#else gdk_pointer_ungrab (event->time); +#endif + slider->dragging = FALSE; g_signal_emit (G_OBJECT (slider), slider_signals[RELEASED], 0); if (slider->value != slider->oldvalue) g_signal_emit (G_OBJECT (slider), slider_signals[CHANGED], 0); @@ -348,12 +370,9 @@ sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event) return FALSE; } -GtkWidget * -sp_color_slider_new (GtkAdjustment *adjustment) +GtkWidget *sp_color_slider_new(GtkAdjustment *adjustment) { - SPColorSlider *slider; - - slider = (SPColorSlider*)g_object_new (SP_TYPE_COLOR_SLIDER, NULL); + SPColorSlider *slider = SP_COLOR_SLIDER(g_object_new(SP_TYPE_COLOR_SLIDER, NULL)); sp_color_slider_set_adjustment (slider, adjustment); @@ -366,7 +385,7 @@ void sp_color_slider_set_adjustment(SPColorSlider *slider, GtkAdjustment *adjust g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); if (!adjustment) { - adjustment = (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 1.0, 0.01, 0.0, 0.0); + adjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.0, 0.0)); } else { gtk_adjustment_set_page_increment(adjustment, 0.0); gtk_adjustment_set_page_size(adjustment, 0.0); @@ -426,7 +445,7 @@ sp_color_slider_set_map (SPColorSlider *slider, const guchar *map) g_return_if_fail (slider != NULL); g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); - slider->map = (guchar *) map; + slider->map = const_cast<guchar *>(map); gtk_widget_queue_draw (GTK_WIDGET (slider)); } @@ -483,191 +502,167 @@ sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlid } } -static void -sp_color_slider_paint (SPColorSlider *slider, GdkRectangle *area) +static gboolean sp_color_slider_draw(GtkWidget *widget, cairo_t *cr) { - GtkWidget *widget; - GdkRectangle warea, carea, aarea; - GdkRectangle wpaint, cpaint, apaint; - const guchar *b; - gint w, x, y1, y2; + SPColorSlider *slider = SP_COLOR_SLIDER(widget); + gboolean colorsOnTop = Inkscape::Preferences::get()->getBool("/options/workarounds/colorsontop", false); - - widget = GTK_WIDGET (slider); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); - GtkStyle *style = gtk_widget_get_style(widget); + +#if GTK_CHECK_VERSION(3,0,0) + GtkStyleContext *context = gtk_widget_get_style_context(widget); +#else GdkWindow *window = gtk_widget_get_window(widget); + GtkStyle *style = gtk_widget_get_style(widget); +#endif + + // Draw shadow + if (colorsOnTop) { +#if GTK_CHECK_VERSION(3,0,0) + gtk_render_frame(context, + cr, + 0, 0, + allocation.width, allocation.height); +#else + gtk_paint_shadow( style, window, + gtk_widget_get_state(widget), GTK_SHADOW_IN, + NULL, widget, "colorslider", + 0, 0, + allocation.width, allocation.height); +#endif + } - /* Widget area */ - warea.x = 0; - warea.y = 0; - warea.width = allocation.width; - warea.height = allocation.height; + /* Paintable part of color gradient area */ + GdkRectangle carea; - /* Color gradient area */ +#if GTK_CHECK_VERSION(3,0,0) + GtkBorder padding; + + gtk_style_context_get_padding(context, + gtk_widget_get_state_flags(widget), + &padding); + + carea.x = padding.left; + carea.y = padding.top; +#else carea.x = style->xthickness; carea.y = style->ythickness; +#endif + carea.width = allocation.width - 2 * carea.x; carea.height = allocation.height - 2 * carea.y; - /* Arrow area */ - aarea.x = (int)(slider->value * (carea.width - 1) - ARROW_SIZE / 2 + carea.x); - aarea.width = ARROW_SIZE; - aarea.y = carea.y; - aarea.height = carea.height; + if (slider->map) { + /* Render map pixelstore */ + gint d = (1024 << 16) / carea.width; + gint s = 0; - /* Actual paintable area */ - if (!gdk_rectangle_intersect (area, &warea, &wpaint)) { - return; - } + const guchar *b = sp_color_slider_render_map(0, 0, carea.width, carea.height, + slider->map, s, d, + slider->b0, slider->b1, slider->bmask); - b = NULL; + if (b != NULL && carea.width > 0) { + GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, + 0, 8, carea.width, carea.height, carea.width * 3, NULL, NULL); - // Draw shadow - if (colorsOnTop) { - gtk_paint_shadow( style, window, - gtk_widget_get_state(widget), GTK_SHADOW_IN, - area, widget, "colorslider", - 0, 0, - warea.width, warea.height); - } + gdk_cairo_set_source_pixbuf(cr, pb, carea.x, carea.y); + cairo_paint(cr); + g_object_unref(pb); + } - /* Paintable part of color gradient area */ - if (gdk_rectangle_intersect (area, &carea, &cpaint)) { - if (slider->map) { - gint s, d; - /* Render map pixelstore */ - d = (1024 << 16) / carea.width; - s = (cpaint.x - carea.x) * d; - b = sp_color_slider_render_map (cpaint.x - carea.x, cpaint.y - carea.y, cpaint.width, cpaint.height, - slider->map, s, d, - slider->b0, slider->b1, slider->bmask); - if (b != NULL && cpaint.width > 0) { - - GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, - 0, 8, cpaint.width, cpaint.height, cpaint.width * 3, NULL, NULL); - - cairo_t *ct = gdk_cairo_create(window); - gdk_cairo_set_source_pixbuf (ct, pb, cpaint.x, cpaint.y); - cairo_paint(ct); - cairo_destroy(ct); - - g_object_unref(pb); + } else { + gint c[4], dc[4]; + + /* Render gradient */ + // part 1: from c0 to cm + if (carea.width > 0) { + for (gint i = 0; i < 4; i++) { + c[i] = slider->c0[i] << 16; + dc[i] = ((slider->cm[i] << 16) - c[i]) / (carea.width/2); } + guint wi = carea.width/2; + const guchar *b = sp_color_slider_render_gradient(0, 0, wi, carea.height, + c, dc, slider->b0, slider->b1, slider->bmask); + + /* Draw pixelstore 1 */ + if (b != NULL && wi > 0) { + GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, + 0, 8, wi, carea.height, wi * 3, NULL, NULL); + + gdk_cairo_set_source_pixbuf(cr, pb, carea.x, carea.y); + cairo_paint(cr); + g_object_unref(pb); + } + } - } else { - gint c[4], dc[4]; - gint i; - /* Render gradient */ - - // part 1: from c0 to cm - if ((cpaint.x - carea.x) <= carea.width/2) { - for (i = 0; i < 4; i++) { - c[i] = slider->c0[i] << 16; - dc[i] = ((slider->cm[i] << 16) - c[i]) / (carea.width/2); - c[i] += (cpaint.x - carea.x) * dc[i]; - } - guint wi = MIN(cpaint.x - carea.x + cpaint.width, carea.width/2) - (cpaint.x - carea.x); - b = sp_color_slider_render_gradient (cpaint.x - carea.x, cpaint.y - carea.y, wi, cpaint.height, - c, dc, - slider->b0, slider->b1, slider->bmask); - - /* Draw pixelstore 1 */ - if (b != NULL && wi > 0) { - - GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, - 0, 8, wi, cpaint.height, wi * 3, NULL, NULL); - - cairo_t *ct = gdk_cairo_create(window); - gdk_cairo_set_source_pixbuf (ct, pb, cpaint.x, cpaint.y); - cairo_paint(ct); - cairo_destroy(ct); - - g_object_unref(pb); - } + // part 2: from cm to c1 + if (carea.width > 0) { + for (gint i = 0; i < 4; i++) { + c[i] = slider->cm[i] << 16; + dc[i] = ((slider->c1[i] << 16) - c[i]) / (carea.width/2); } + guint wi = carea.width/2; + const guchar *b = sp_color_slider_render_gradient(carea.width/2, 0, wi, carea.height, + c, dc, + slider->b0, slider->b1, slider->bmask); - // part 2: from cm to c1 - if ((cpaint.x - carea.x + cpaint.width) > carea.width/2) { - for (i = 0; i < 4; i++) { - c[i] = slider->cm[i] << 16; - dc[i] = ((slider->c1[i] << 16) - c[i]) / (carea.width/2); - if ((cpaint.x - carea.x) > carea.width/2) - c[i] += (cpaint.x - carea.x - carea.width/2) * dc[i]; - } - guint wi = cpaint.width - MAX(0, (carea.width/2 - (cpaint.x - carea.x))); - b = sp_color_slider_render_gradient (MAX(cpaint.x - carea.x, carea.width/2), cpaint.y - carea.y, wi, cpaint.height, - c, dc, - slider->b0, slider->b1, slider->bmask); - - /* Draw pixelstore 2 */ - if (b != NULL && wi > 0) { - - GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, - 0, 8, wi, cpaint.height, wi * 3, NULL, NULL); - - cairo_t *ct = gdk_cairo_create(window); - gdk_cairo_set_source_pixbuf (ct, pb, MAX(cpaint.x, carea.width/2 + carea.x), cpaint.y); - cairo_paint(ct); - cairo_destroy(ct); - - g_object_unref(pb); - } + /* Draw pixelstore 2 */ + if (b != NULL && wi > 0) { + GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, + 0, 8, wi, carea.height, wi * 3, NULL, NULL); + + gdk_cairo_set_source_pixbuf(cr, pb, carea.width/2 + carea.x, carea.y); + cairo_paint(cr); + + g_object_unref(pb); } } } - /* Draw shadow */ + /* Draw shadow */ if (!colorsOnTop) { +#if GTK_CHECK_VERSION(3,0,0) + gtk_render_frame(context, + cr, + 0, 0, + allocation.width, allocation.height); +#else gtk_paint_shadow( style, window, gtk_widget_get_state(widget), GTK_SHADOW_IN, - area, widget, "colorslider", + NULL, widget, "colorslider", 0, 0, - warea.width, warea.height); + allocation.width, allocation.height); +#endif } - - if (gdk_rectangle_intersect (area, &aarea, &apaint)) { - /* Draw arrow */ - gdk_rectangle_intersect (&carea, &apaint, &apaint); - cairo_t* cr = gdk_cairo_create(window); - gdk_cairo_rectangle(cr, &apaint); - cairo_clip(cr); - - x = aarea.x; - y1 = carea.y; - y2 = aarea.y + aarea.height - 1; - w = aarea.width; - cairo_set_line_width(cr, 1.0); - - while ( w > 0 ) - { - gdk_cairo_set_source_color(cr, &style->white); - cairo_move_to(cr, x - 0.5, y1 + 0.5); - cairo_line_to(cr, x + w - 1 + 0.5, y1 + 0.5); - cairo_move_to(cr, x - 0.5, y2 + 0.5); - cairo_line_to(cr, x + w - 1 + 0.5, y2 + 0.5); - cairo_stroke(cr); - w -=2; - x++; - if ( w > 0 ) - { - gdk_cairo_set_source_color(cr, &style->black); - cairo_move_to(cr, x - 0.5, y1 + 0.5); - cairo_line_to(cr, x + w - 1 + 0.5, y1 + 0.5); - cairo_move_to(cr, x - 0.5, y2 + 0.5); - cairo_line_to(cr, x + w - 1 + 0.5, y2 + 0.5); - cairo_stroke(cr); - } - y1++; - y2--; - } - - cairo_destroy(cr); - } + /* Draw arrow */ + gint x = (int)(slider->value * (carea.width - 1) - ARROW_SIZE / 2 + carea.x); + gint y1 = carea.y; + gint y2 = carea.y + carea.height - 1; + cairo_set_line_width(cr, 1.0); + + // Define top arrow + cairo_move_to(cr, x - 0.5, y1 + 0.5); + cairo_line_to(cr, x + ARROW_SIZE - 0.5, y1 + 0.5); + cairo_line_to(cr, x + (ARROW_SIZE-1)/2.0, y1 + ARROW_SIZE/2.0 + 0.5); + cairo_line_to(cr, x - 0.5, y1 + 0.5); + + // Define bottom arrow + cairo_move_to(cr, x - 0.5, y2 + 0.5); + cairo_line_to(cr, x + ARROW_SIZE - 0.5, y2 + 0.5); + cairo_line_to(cr, x + (ARROW_SIZE-1)/2.0, y2 - ARROW_SIZE/2.0 + 0.5); + cairo_line_to(cr, x - 0.5, y2 + 0.5); + + // Render both arrows + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + cairo_stroke_preserve(cr); + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + cairo_fill(cr); + + return FALSE; } /* Colors are << 16 */ @@ -734,7 +729,7 @@ sp_color_slider_render_map (gint x0, gint y0, gint width, gint height, { static guchar *buf = NULL; static gint bs = 0; - guchar *dp, *sp; + guchar *dp; gint x, y; if (buf && (bs < width * height)) { @@ -749,13 +744,12 @@ sp_color_slider_render_map (gint x0, gint y0, gint width, gint height, dp = buf; for (x = x0; x < x0 + width; x++) { gint cr, cg, cb, ca; - guchar *d; - sp = map + 4 * (start >> 16); + guchar *d = dp; + guchar *sp = map + 4 * (start >> 16); cr = *sp++; cg = *sp++; cb = *sp++; ca = *sp++; - d = dp; for (y = y0; y < y0 + height; y++) { guint bg, fc; /* Background value */ diff --git a/src/widgets/sp-color-wheel-selector.cpp b/src/widgets/sp-color-wheel-selector.cpp index 7baafb4b3..7c8bb1df7 100644 --- a/src/widgets/sp-color-wheel-selector.cpp +++ b/src/widgets/sp-color-wheel-selector.cpp @@ -9,15 +9,16 @@ #include "sp-color-scales.h" #include "sp-color-icc-selector.h" #include "../svg/svg-icc-color.h" +#include "ui/widget/gimpcolorwheel.h" G_BEGIN_DECLS static void sp_color_wheel_selector_class_init (SPColorWheelSelectorClass *klass); static void sp_color_wheel_selector_init (SPColorWheelSelector *cs); -static void sp_color_wheel_selector_destroy (GtkObject *object); +static void sp_color_wheel_selector_dispose(GObject *object); static void sp_color_wheel_selector_show_all (GtkWidget *widget); -static void sp_color_wheel_selector_hide_all (GtkWidget *widget); +static void sp_color_wheel_selector_hide(GtkWidget *widget); G_END_DECLS @@ -53,27 +54,22 @@ sp_color_wheel_selector_get_type (void) return type; } -static void -sp_color_wheel_selector_class_init (SPColorWheelSelectorClass *klass) +static void sp_color_wheel_selector_class_init(SPColorWheelSelectorClass *klass) { static const gchar* nameset[] = {N_("Wheel"), 0}; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - SPColorSelectorClass *selector_class; - - object_class = (GtkObjectClass *) klass; - widget_class = (GtkWidgetClass *) klass; - selector_class = SP_COLOR_SELECTOR_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + SPColorSelectorClass *selector_class = SP_COLOR_SELECTOR_CLASS (klass); parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass)); selector_class->name = nameset; selector_class->submode_count = 1; - object_class->destroy = sp_color_wheel_selector_destroy; + object_class->dispose = sp_color_wheel_selector_dispose; widget_class->show_all = sp_color_wheel_selector_show_all; - widget_class->hide_all = sp_color_wheel_selector_hide_all; + widget_class->hide = sp_color_wheel_selector_hide; } ColorWheelSelector::ColorWheelSelector( SPColorSelector* csel ) @@ -106,64 +102,37 @@ void sp_color_wheel_selector_init (SPColorWheelSelector *cs) } } -static void resizeHSVWheel( GtkHSV *hsv, GtkAllocation *allocation ) -{ - gint diam = std::min(allocation->width, allocation->height); - - // drop a little for resizing - diam -= 4; - - GtkStyle *style = gtk_widget_get_style( GTK_WIDGET(hsv) ); - if ( style ) { - gint thick = std::max(style->xthickness, style->ythickness); - if (thick > 0) { - diam -= thick * 2; - } - } - gint padding = -1; - gtk_widget_style_get( GTK_WIDGET(hsv), - "focus-padding", &padding, - NULL ); - if (padding > 0) { - diam -= padding * 2; - } - - diam = std::max(20, diam); - gint ring = static_cast<gint>( static_cast<gdouble>(diam) / (4.0 * 1.618) ); - gtk_hsv_set_metrics( hsv, diam, ring ); -} - -static void handleWheelStyleSet(GtkHSV *hsv, GtkStyle* /*previous*/, gpointer /*userData*/) -{ - GtkAllocation allocation = {0, 0, 0, 0}; - gtk_widget_get_allocation( GTK_WIDGET(hsv), &allocation ); - resizeHSVWheel( hsv, &allocation ); -} - -static void handleWheelAllocation(GtkHSV *hsv, GtkAllocation *allocation, gpointer /*userData*/) -{ - resizeHSVWheel( hsv, allocation ); -} - void ColorWheelSelector::init() { - GtkWidget *t; gint row = 0; _updating = FALSE; _dragging = FALSE; - t = gtk_table_new (5, 3, FALSE); +#if GTK_CHECK_VERSION(3,0,0) + GtkWidget *t = gtk_grid_new(); +#else + GtkWidget *t = gtk_table_new (5, 3, FALSE); +#endif + gtk_widget_show (t); gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 0); /* Create components */ row = 0; - _wheel = gtk_hsv_new(); - gtk_hsv_set_metrics( GTK_HSV(_wheel), 48, 8 ); + _wheel = gimp_color_wheel_new(); gtk_widget_show( _wheel ); - gtk_table_attach( GTK_TABLE(t), _wheel, 0, 3, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), XPAD, YPAD); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_halign(_wheel, GTK_ALIGN_FILL); + gtk_widget_set_valign(_wheel, GTK_ALIGN_FILL); + gtk_widget_set_hexpand(_wheel, TRUE); + gtk_widget_set_vexpand(_wheel, TRUE); + gtk_grid_attach(GTK_GRID(t), _wheel, 0, row, 3, 1); +#else + gtk_table_attach(GTK_TABLE(t), _wheel, 0, 3, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0); +#endif row++; @@ -171,16 +140,39 @@ void ColorWheelSelector::init() _label = gtk_label_new_with_mnemonic (_("_A:")); gtk_misc_set_alignment (GTK_MISC (_label), 1.0, 0.5); gtk_widget_show (_label); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_label, XPAD); + gtk_widget_set_margin_right(_label, XPAD); + gtk_widget_set_margin_top(_label, YPAD); + gtk_widget_set_margin_bottom(_label, YPAD); + gtk_widget_set_halign(_label, GTK_ALIGN_FILL); + gtk_widget_set_valign(_label, GTK_ALIGN_FILL); + gtk_grid_attach(GTK_GRID(t), _label, 0, row, 1, 1); +#else gtk_table_attach (GTK_TABLE (t), _label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); +#endif /* Adjustment */ - _adj = (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 10.0, 10.0); + _adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 255.0, 1.0, 10.0, 10.0)); /* Slider */ _slider = sp_color_slider_new (_adj); gtk_widget_set_tooltip_text (_slider, _("Alpha (opacity)")); gtk_widget_show (_slider); - gtk_table_attach (GTK_TABLE (t), _slider, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)GTK_FILL, XPAD, YPAD); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_slider, XPAD); + gtk_widget_set_margin_right(_slider, XPAD); + gtk_widget_set_margin_top(_slider, YPAD); + gtk_widget_set_margin_bottom(_slider, YPAD); + gtk_widget_set_hexpand(_slider, TRUE); + gtk_widget_set_halign(_slider, GTK_ALIGN_FILL); + gtk_widget_set_valign(_slider, GTK_ALIGN_FILL); + gtk_grid_attach(GTK_GRID(t), _slider, 1, row, 1, 1); +#else + gtk_table_attach(GTK_TABLE (t), _slider, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, XPAD, YPAD); +#endif sp_color_slider_set_colors (SP_COLOR_SLIDER (_slider), SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.0), @@ -194,7 +186,18 @@ void ColorWheelSelector::init() sp_dialog_defocus_on_enter (_sbtn); gtk_label_set_mnemonic_widget (GTK_LABEL(_label), _sbtn); gtk_widget_show (_sbtn); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_sbtn, XPAD); + gtk_widget_set_margin_right(_sbtn, XPAD); + gtk_widget_set_margin_top(_sbtn, YPAD); + gtk_widget_set_margin_bottom(_sbtn, YPAD); + gtk_widget_set_halign(_sbtn, GTK_ALIGN_CENTER); + gtk_widget_set_valign(_sbtn, GTK_ALIGN_CENTER); + gtk_grid_attach(GTK_GRID(t), _sbtn, 2, row, 1, 1); +#else gtk_table_attach (GTK_TABLE (t), _sbtn, 2, 3, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, XPAD, YPAD); +#endif /* Signals */ g_signal_connect (G_OBJECT (_adj), "value_changed", @@ -209,20 +212,12 @@ void ColorWheelSelector::init() g_signal_connect( G_OBJECT(_wheel), "changed", G_CALLBACK (_wheelChanged), _csel ); - - - // GTK does not automatically scale the color wheel, so we have to add that in: - g_signal_connect( G_OBJECT (_wheel), "size-allocate", - G_CALLBACK (handleWheelAllocation), _csel ); - g_signal_connect( G_OBJECT (_wheel), "style-set", - G_CALLBACK (handleWheelStyleSet), _csel ); } -static void -sp_color_wheel_selector_destroy (GtkObject *object) +static void sp_color_wheel_selector_dispose(GObject *object) { - if (((GtkObjectClass *) (parent_class))->destroy) - (* ((GtkObjectClass *) (parent_class))->destroy) (object); + if ((G_OBJECT_CLASS(parent_class))->dispose) + (* (G_OBJECT_CLASS(parent_class))->dispose) (object); } static void @@ -231,18 +226,14 @@ sp_color_wheel_selector_show_all (GtkWidget *widget) gtk_widget_show (widget); } -static void -sp_color_wheel_selector_hide_all (GtkWidget *widget) +static void sp_color_wheel_selector_hide(GtkWidget *widget) { - gtk_widget_hide (widget); + gtk_widget_hide(widget); } -GtkWidget * -sp_color_wheel_selector_new (void) +GtkWidget *sp_color_wheel_selector_new() { - SPColorWheelSelector *csel; - - csel = (SPColorWheelSelector*)g_object_new (SP_TYPE_COLOR_WHEEL_SELECTOR, NULL); + SPColorWheelSelector *csel = SP_COLOR_WHEEL_SELECTOR(g_object_new (SP_TYPE_COLOR_WHEEL_SELECTOR, NULL)); return GTK_WIDGET (csel); } @@ -261,11 +252,9 @@ void ColorWheelSelector::_colorChanged() #endif _updating = TRUE; { - gdouble h = 0; - gdouble s = 0; - gdouble v = 0; - gtk_rgb_to_hsv( _color.v.c[0], _color.v.c[1], _color.v.c[2], &h, &s, &v ); - gtk_hsv_set_color( GTK_HSV(_wheel), h, s, v ); + float hsv[3] = {0,0,0}; + sp_color_rgb_to_hsv_floatv(hsv, _color.v.c[0], _color.v.c[1], _color.v.c[2]); + gimp_color_wheel_set_color( GIMP_COLOR_WHEEL(_wheel), hsv[0], hsv[1], hsv[2] ); } guint32 start = _color.toRGBA32( 0x00 ); @@ -336,21 +325,19 @@ void ColorWheelSelector::_sliderChanged( SPColorSlider *slider, SPColorWheelSele wheelSelector->_updateInternals( wheelSelector->_color, ColorScales::getScaled( wheelSelector->_adj ), wheelSelector->_dragging ); } -void ColorWheelSelector::_wheelChanged( GtkHSV *hsv, SPColorWheelSelector *cs ) +void ColorWheelSelector::_wheelChanged( GimpColorWheel *wheel, SPColorWheelSelector *cs ) { ColorWheelSelector* wheelSelector = static_cast<ColorWheelSelector*>(SP_COLOR_SELECTOR(cs)->base); gdouble h = 0; gdouble s = 0; gdouble v = 0; - gtk_hsv_get_color( hsv, &h, &s, &v ); + gimp_color_wheel_get_color( wheel, &h, &s, &v ); - gdouble r = 0; - gdouble g = 0; - gdouble b = 0; - gtk_hsv_to_rgb(h, s, v, &r, &g, &b); + float rgb[3] = {0,0,0}; + sp_color_hsv_to_rgb_floatv (rgb, h, s, v); - SPColor color(r, g, b); + SPColor color(rgb[0], rgb[1], rgb[2]); guint32 start = color.toRGBA32( 0x00 ); guint32 mid = color.toRGBA32( 0x7f ); @@ -359,7 +346,7 @@ void ColorWheelSelector::_wheelChanged( GtkHSV *hsv, SPColorWheelSelector *cs ) sp_color_slider_set_colors (SP_COLOR_SLIDER(wheelSelector->_slider), start, mid, end); preserve_icc(&color, cs); - wheelSelector->_updateInternals( color, wheelSelector->_alpha, gtk_hsv_is_adjusting( hsv ) ); + wheelSelector->_updateInternals( color, wheelSelector->_alpha, gimp_color_wheel_is_adjusting(wheel) ); } diff --git a/src/widgets/sp-color-wheel-selector.h b/src/widgets/sp-color-wheel-selector.h index 4d8f79976..bbd377422 100644 --- a/src/widgets/sp-color-wheel-selector.h +++ b/src/widgets/sp-color-wheel-selector.h @@ -4,13 +4,12 @@ #include <glib.h> #include <gtk/gtk.h> -#include "../color.h" #include "sp-color-slider.h" #include "sp-color-selector.h" -typedef struct _GtkHSV GtkHSV; +typedef struct _GimpColorWheel GimpColorWheel; struct SPColorWheelSelector; struct SPColorWheelSelectorClass; @@ -30,7 +29,7 @@ protected: static void _sliderGrabbed( SPColorSlider *slider, SPColorWheelSelector *cs ); static void _sliderReleased( SPColorSlider *slider, SPColorWheelSelector *cs ); static void _sliderChanged( SPColorSlider *slider, SPColorWheelSelector *cs ); - static void _wheelChanged( GtkHSV *hsv, SPColorWheelSelector *cs ); + static void _wheelChanged( GimpColorWheel *wheel, SPColorWheelSelector *cs ); static void _fooChanged( GtkWidget foo, SPColorWheelSelector *cs ); diff --git a/src/widgets/sp-widget.cpp b/src/widgets/sp-widget.cpp index c0ee44f83..0e2295e36 100644 --- a/src/widgets/sp-widget.cpp +++ b/src/widgets/sp-widget.cpp @@ -1,313 +1,360 @@ -#define __SP_WIDGET_C__ - /* * Abstract base class for dynamic control widgets * * Authors: * Lauris Kaplinski <lauris@kaplinski.com> * bulia byak <buliabyak@users.sf.net> + * Jon A. Cruz <jon@joncruz.org> * * Copyright (C) 1999-2002 Lauris Kaplinski * Copyright (C) 2000-2001 Ximian, Inc. + * Copyright (C) 2012 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ #include "macros.h" -#include "../document.h" +#include "document.h" #include "sp-widget.h" #include "helper/sp-marshal.h" +using Inkscape::SPWidgetImpl; + enum { - CONSTRUCT, - MODIFY_SELECTION, - CHANGE_SELECTION, - SET_SELECTION, - LAST_SIGNAL + CONSTRUCT, + MODIFY_SELECTION, + CHANGE_SELECTION, + SET_SELECTION, + LAST_SIGNAL }; -static void sp_widget_class_init (SPWidgetClass *klass); -static void sp_widget_init (SPWidget *widget); +namespace Inkscape { -static void sp_widget_destroy (GtkObject *object); +class SPWidgetImpl +{ +public: + SPWidgetImpl(SPWidget &target); + ~SPWidgetImpl(); -static void sp_widget_show (GtkWidget *widget); -static void sp_widget_hide (GtkWidget *widget); -static gint sp_widget_expose (GtkWidget *widget, GdkEventExpose *event); -static void sp_widget_size_request (GtkWidget *widget, GtkRequisition *requisition); + static void classInit(SPWidgetClass *klass); + static void init(SPWidget *widget); + static void dispose(GObject *object); + static void show(GtkWidget *widget); + static void hide(GtkWidget *widget); #if GTK_CHECK_VERSION(3,0,0) -static void sp_widget_get_preferred_width(GtkWidget *widget, - gint *minimal_width, - gint *natural_width); - -static void sp_widget_get_preferred_height(GtkWidget *widget, - gint *minimal_height, - gint *natural_height); + static void getPreferredWidth(GtkWidget *widget, + gint *minimal_width, + gint *natural_width); + + static void getPreferredHeight(GtkWidget *widget, + gint *minimal_height, + gint *natural_height); + static gboolean draw(GtkWidget *widget, cairo_t *cr); +#else + static void sizeRequest(GtkWidget *widget, GtkRequisition *requisition); + static gboolean expose(GtkWidget *widget, GdkEventExpose *event); #endif -static void sp_widget_size_allocate (GtkWidget *widget, GtkAllocation *allocation); + static void sizeAllocate(GtkWidget *widget, GtkAllocation *allocation); + static void modifySelectionCB(Application *inkscape, Selection *selection, guint flags, SPWidget *spw); + static void changeSelectionCB(Application *inkscape, Selection *selection, SPWidget *spw); + static void setSelectionCB(Application *inkscape, Selection *selection, SPWidget *spw); + + static GtkWidget *constructGlobal(SPWidget *spw, Inkscape::Application *inkscape); -static void sp_widget_modify_selection (Inkscape::Application *inkscape, Inkscape::Selection *selection, guint flags, SPWidget *spw); -static void sp_widget_change_selection (Inkscape::Application *inkscape, Inkscape::Selection *selection, SPWidget *spw); -static void sp_widget_set_selection (Inkscape::Application *inkscape, Inkscape::Selection *selection, SPWidget *spw); + void modifySelection(Application *inkscape, Selection *selection, guint flags); + void changeSelection(Application *inkscape, Selection *selection); + void setSelection(Application *inkscape, Selection *selection); -static GtkBinClass *parent_class; -static guint signals[LAST_SIGNAL] = {0}; +private: + static GtkBinClass *parentClass; + static guint signals[LAST_SIGNAL]; -GType -sp_widget_get_type (void) + SPWidget &_target; +}; + +GtkBinClass *SPWidgetImpl::parentClass = 0; +guint SPWidgetImpl::signals[LAST_SIGNAL] = {0}; + +} // namespace Inkscape + +GType SPWidget::getType() { - static GType type = 0; - if (!type) { - static const GTypeInfo info = { - sizeof (SPWidgetClass), - NULL, NULL, - (GClassInitFunc) sp_widget_class_init, - NULL, NULL, - sizeof (SPWidget), - 0, - (GInstanceInitFunc) sp_widget_init, - NULL - }; - type = g_type_register_static (GTK_TYPE_BIN, - "SPWidget", - &info, - (GTypeFlags)0); - } - return type; + static GType type = 0; + if (!type) { + static GTypeInfo const info = { + sizeof(SPWidgetClass), + NULL, NULL, + reinterpret_cast<GClassInitFunc>(SPWidgetImpl::classInit), + NULL, NULL, + sizeof(SPWidget), + 0, + reinterpret_cast<GInstanceInitFunc>(SPWidgetImpl::init), + NULL + }; + type = g_type_register_static(GTK_TYPE_BIN, + "SPWidget", + &info, + static_cast<GTypeFlags>(0)); + } + return type; } -static void -sp_widget_class_init (SPWidgetClass *klass) +namespace Inkscape { + +SPWidgetImpl::SPWidgetImpl(SPWidget &target) : + _target(target) { - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - object_class = (GtkObjectClass *) klass; - widget_class = (GtkWidgetClass *) klass; - - parent_class = (GtkBinClass*)g_type_class_peek_parent (klass); - - object_class->destroy = sp_widget_destroy; - - signals[CONSTRUCT] = g_signal_new ("construct", - G_TYPE_FROM_CLASS(object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (SPWidgetClass, construct), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[CHANGE_SELECTION] = g_signal_new ("change_selection", - G_TYPE_FROM_CLASS(object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (SPWidgetClass, change_selection), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); - signals[MODIFY_SELECTION] = g_signal_new ("modify_selection", - G_TYPE_FROM_CLASS(object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (SPWidgetClass, modify_selection), - NULL, NULL, - sp_marshal_VOID__POINTER_UINT, - G_TYPE_NONE, 2, - G_TYPE_POINTER, G_TYPE_UINT); - signals[SET_SELECTION] = g_signal_new ("set_selection", - G_TYPE_FROM_CLASS(object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (SPWidgetClass, set_selection), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); - - widget_class->show = sp_widget_show; - widget_class->hide = sp_widget_hide; - widget_class->expose_event = sp_widget_expose; -#if GTK_CHECK_VERSION(3,0,0) - widget_class->get_preferred_width = sp_widget_get_preferred_width; - widget_class->get_preferred_height = sp_widget_get_preferred_height; -#else - widget_class->size_request = sp_widget_size_request; -#endif - widget_class->size_allocate = sp_widget_size_allocate; } -static void -sp_widget_init (SPWidget *spw) +SPWidgetImpl::~SPWidgetImpl() { - spw->inkscape = NULL; } -static void -sp_widget_destroy (GtkObject *object) +void SPWidgetImpl::classInit(SPWidgetClass *klass) { - SPWidget *spw; - - spw = (SPWidget *) object; + GObjectClass *object_class = reinterpret_cast<GObjectClass *>(klass); + GtkWidgetClass *widget_class = reinterpret_cast<GtkWidgetClass *>(klass); + + parentClass = reinterpret_cast<GtkBinClass *>(g_type_class_peek_parent(klass)); + + object_class->dispose = SPWidgetImpl::dispose; + + signals[CONSTRUCT] = g_signal_new ("construct", + G_TYPE_FROM_CLASS(object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(SPWidgetClass, construct), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[CHANGE_SELECTION] = g_signal_new ("change_selection", + G_TYPE_FROM_CLASS(object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(SPWidgetClass, change_selection), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + + signals[MODIFY_SELECTION] = g_signal_new ("modify_selection", + G_TYPE_FROM_CLASS(object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(SPWidgetClass, modify_selection), + NULL, NULL, + sp_marshal_VOID__POINTER_UINT, + G_TYPE_NONE, 2, + G_TYPE_POINTER, G_TYPE_UINT); + + signals[SET_SELECTION] = g_signal_new ("set_selection", + G_TYPE_FROM_CLASS(object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET(SPWidgetClass, set_selection), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + + widget_class->show = SPWidgetImpl::show; + widget_class->hide = SPWidgetImpl::hide; +#if GTK_CHECK_VERSION(3,0,0) + widget_class->get_preferred_width = SPWidgetImpl::getPreferredWidth; + widget_class->get_preferred_height = SPWidgetImpl::getPreferredHeight; + widget_class->draw = SPWidgetImpl::draw; +#else + widget_class->size_request = SPWidgetImpl::sizeRequest; + widget_class->expose_event = SPWidgetImpl::expose; +#endif + widget_class->size_allocate = SPWidgetImpl::sizeAllocate; +} - if (spw->inkscape) { - /* Disconnect signals */ - // the checks are necessary because when destroy is caused by the the program shutting down, - // the inkscape object may already be (partly?) invalid --bb - if (G_IS_OBJECT(spw->inkscape) && G_OBJECT_GET_CLASS(G_OBJECT(spw->inkscape))) - sp_signal_disconnect_by_data (spw->inkscape, spw); - spw->inkscape = NULL; - } +void SPWidgetImpl::init(SPWidget *spw) +{ + spw->inkscape = NULL; - if (((GtkObjectClass *) parent_class)->destroy) - (* ((GtkObjectClass *) parent_class)->destroy) (object); + spw->_impl = new SPWidgetImpl(*spw); // ctor invoked after all other init } -static void -sp_widget_show (GtkWidget *widget) +void SPWidgetImpl::dispose(GObject *object) { - SPWidget *spw; + SPWidget *spw = reinterpret_cast<SPWidget *>(object); + + if (spw->inkscape) { + // Disconnect signals - spw = SP_WIDGET (widget); + // the checks are necessary because when destroy is caused by the program shutting down, + // the inkscape object may already be (partly?) invalid --bb + if (G_IS_OBJECT(spw->inkscape) && G_OBJECT_GET_CLASS(spw->inkscape)) { + sp_signal_disconnect_by_data(spw->inkscape, spw); + } + spw->inkscape = NULL; + } - if (spw->inkscape) { - /* Connect signals */ - g_signal_connect (G_OBJECT (spw->inkscape), "modify_selection", G_CALLBACK (sp_widget_modify_selection), spw); - g_signal_connect (G_OBJECT (spw->inkscape), "change_selection", G_CALLBACK (sp_widget_change_selection), spw); - g_signal_connect (G_OBJECT (spw->inkscape), "set_selection", G_CALLBACK (sp_widget_set_selection), spw); - } + delete spw->_impl; + spw->_impl = 0; - if (((GtkWidgetClass *) parent_class)->show) - (* ((GtkWidgetClass *) parent_class)->show) (widget); + if (reinterpret_cast<GObjectClass *>(parentClass)->dispose) { + (*reinterpret_cast<GObjectClass *>(parentClass)->dispose)(object); + } } -static void -sp_widget_hide (GtkWidget *widget) +void SPWidgetImpl::show(GtkWidget *widget) { - SPWidget *spw; + SPWidget *spw = SP_WIDGET(widget); + + if (spw->inkscape) { + // Connect signals + g_signal_connect(spw->inkscape, "modify_selection", G_CALLBACK(SPWidgetImpl::modifySelectionCB), spw); + g_signal_connect(spw->inkscape, "change_selection", G_CALLBACK(SPWidgetImpl::changeSelectionCB), spw); + g_signal_connect(spw->inkscape, "set_selection", G_CALLBACK(SPWidgetImpl::setSelectionCB), spw); + } + + if (reinterpret_cast<GtkWidgetClass *>(parentClass)->show) { + (*reinterpret_cast<GtkWidgetClass *>(parentClass)->show)(widget); + } +} - spw = SP_WIDGET (widget); +void SPWidgetImpl::hide(GtkWidget *widget) +{ + SPWidget *spw = SP_WIDGET (widget); - if (spw->inkscape) { - /* Disconnect signals */ - sp_signal_disconnect_by_data (spw->inkscape, spw); - } + if (spw->inkscape) { + // Disconnect signals + sp_signal_disconnect_by_data(spw->inkscape, spw); + } - if (((GtkWidgetClass *) parent_class)->hide) - (* ((GtkWidgetClass *) parent_class)->hide) (widget); + if (reinterpret_cast<GtkWidgetClass *>(parentClass)->hide) { + (*reinterpret_cast<GtkWidgetClass *>(parentClass)->hide)(widget); + } } -static gint -sp_widget_expose (GtkWidget *widget, GdkEventExpose *event) +#if GTK_CHECK_VERSION(3,0,0) +gboolean SPWidgetImpl::draw(GtkWidget *widget, cairo_t *cr) +#else +gboolean SPWidgetImpl::expose(GtkWidget *widget, GdkEventExpose *event) +#endif { - GtkBin *bin; - GtkWidget *child; + GtkBin *bin = GTK_BIN(widget); + GtkWidget *child = gtk_bin_get_child(bin); - bin = GTK_BIN (widget); - child = gtk_bin_get_child (bin); + if (child) { +#if GTK_CHECK_VERSION(3,0,0) + gtk_container_propagate_draw(GTK_CONTAINER(widget), child, cr); +#else + gtk_container_propagate_expose(GTK_CONTAINER(widget), child, event); +#endif + } - if (child) { - gtk_container_propagate_expose (GTK_CONTAINER(widget), child, event); - } - /* - if ((bin->child) && (!gtk_widget_get_has_window (bin->child))) { - GdkEventExpose ce; - ce = *event; - gtk_widget_event (bin->child, (GdkEvent *) &ce); - } - */ - - return FALSE; + return FALSE; } -static void -sp_widget_size_request (GtkWidget *widget, GtkRequisition *requisition) +#if GTK_CHECK_VERSION(3,0,0) +void SPWidgetImpl::getPreferredWidth(GtkWidget *widget, gint *minimal_width, gint *natural_width) { - GtkBin *bin = GTK_BIN (widget); - GtkWidget *child = gtk_bin_get_child (bin); + GtkBin *bin = GTK_BIN(widget); + GtkWidget *child = gtk_bin_get_child(bin); - if (child) - gtk_widget_size_request (child, requisition); + if(child) { + gtk_widget_get_preferred_width(child, minimal_width, natural_width); + } } -#if GTK_CHECK_VERSION(3,0,0) -static void sp_widget_get_preferred_width(GtkWidget *widget, gint *minimal_width, gint *natural_width) +void SPWidgetImpl::getPreferredHeight(GtkWidget *widget, gint *minimal_height, gint *natural_height) { - GtkRequisition requisition; - sp_widget_size_request(widget, &requisition); - *minimal_width = *natural_width = requisition.width; -} + GtkBin *bin = GTK_BIN(widget); + GtkWidget *child = gtk_bin_get_child(bin); -static void sp_widget_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height) + if(child) { + gtk_widget_get_preferred_height(child, minimal_height, natural_height); + } +} +#else +void SPWidgetImpl::sizeRequest(GtkWidget *widget, GtkRequisition *requisition) { - GtkRequisition requisition; - sp_widget_size_request(widget, &requisition); - *minimal_height = *natural_height = requisition.height; + GtkBin *bin = GTK_BIN(widget); + GtkWidget *child = gtk_bin_get_child(bin); + + if (child) { + gtk_widget_size_request(child, requisition); + } } #endif -static void -sp_widget_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +void SPWidgetImpl::sizeAllocate(GtkWidget *widget, GtkAllocation *allocation) { - GtkBin *bin = GTK_BIN (widget); - GtkWidget *child = gtk_bin_get_child (bin); + gtk_widget_set_allocation(widget, allocation); - gtk_widget_set_allocation (widget, allocation); + GtkBin *bin = GTK_BIN(widget); + GtkWidget *child = gtk_bin_get_child(bin); - if (child) - gtk_widget_size_allocate (child, allocation); + if (child) { + gtk_widget_size_allocate(child, allocation); + } } -/* Methods */ - -GtkWidget * -sp_widget_new_global (Inkscape::Application *inkscape) +GtkWidget *SPWidgetImpl::constructGlobal(SPWidget *spw, Inkscape::Application *inkscape) { - SPWidget *spw; + g_return_val_if_fail(!spw->inkscape, NULL); - spw = (SPWidget*)g_object_new (SP_TYPE_WIDGET, NULL); + spw->inkscape = inkscape; + if (gtk_widget_get_visible(GTK_WIDGET(spw))) { + g_signal_connect(inkscape, "modify_selection", G_CALLBACK(SPWidgetImpl::modifySelectionCB), spw); + g_signal_connect(inkscape, "change_selection", G_CALLBACK(SPWidgetImpl::changeSelectionCB), spw); + g_signal_connect(inkscape, "set_selection", G_CALLBACK(SPWidgetImpl::setSelectionCB), spw); + } - if (!sp_widget_construct_global (spw, inkscape)) { - g_object_unref (spw); - return NULL; - } + g_signal_emit(spw, signals[CONSTRUCT], 0); - return (GtkWidget *) spw; + return GTK_WIDGET(spw); } -GtkWidget * -sp_widget_construct_global (SPWidget *spw, Inkscape::Application *inkscape) +void SPWidgetImpl::modifySelectionCB(Application *inkscape, Selection *selection, guint flags, SPWidget *spw) { - g_return_val_if_fail (!spw->inkscape, NULL); + spw->_impl->modifySelection(inkscape, selection, flags); +} - spw->inkscape = inkscape; - if (gtk_widget_get_visible (GTK_WIDGET(spw))) { - g_signal_connect (G_OBJECT (inkscape), "modify_selection", G_CALLBACK (sp_widget_modify_selection), spw); - g_signal_connect (G_OBJECT (inkscape), "change_selection", G_CALLBACK (sp_widget_change_selection), spw); - g_signal_connect (G_OBJECT (inkscape), "set_selection", G_CALLBACK (sp_widget_set_selection), spw); - } +void SPWidgetImpl::changeSelectionCB(Application *inkscape, Selection *selection, SPWidget *spw) +{ + spw->_impl->changeSelection(inkscape, selection); +} - g_signal_emit (G_OBJECT (spw), signals[CONSTRUCT], 0); +void SPWidgetImpl::setSelectionCB(Application *inkscape, Selection *selection, SPWidget *spw) +{ + spw->_impl->setSelection(inkscape, selection); +} - return (GtkWidget *) spw; +void SPWidgetImpl::modifySelection(Application * /*inkscape*/, Selection *selection, guint flags) +{ + g_signal_emit(&_target, signals[MODIFY_SELECTION], 0, selection, flags); } -static void -sp_widget_modify_selection (Inkscape::Application */*inkscape*/, Inkscape::Selection *selection, guint flags, SPWidget *spw) +void SPWidgetImpl::changeSelection(Application * /*inkscape*/, Selection *selection) { - g_signal_emit (G_OBJECT (spw), signals[MODIFY_SELECTION], 0, selection, flags); + g_signal_emit(&_target, signals[CHANGE_SELECTION], 0, selection); } -static void -sp_widget_change_selection (Inkscape::Application */*inkscape*/, Inkscape::Selection *selection, SPWidget *spw) +void SPWidgetImpl::setSelection(Application * /*inkscape*/, Selection *selection) { - g_signal_emit (G_OBJECT (spw), signals[CHANGE_SELECTION], 0, selection); + // Emit "set_selection" signal + g_signal_emit(&_target, signals[SET_SELECTION], 0, selection); + // Inkscape will force "change_selection" anyways } -static void -sp_widget_set_selection (Inkscape::Application */*inkscape*/, Inkscape::Selection *selection, SPWidget *spw) +} // namespace Inkscape + +// Methods + +GtkWidget *sp_widget_new_global(Inkscape::Application *inkscape) { - /* Emit "set_selection" signal */ - g_signal_emit (G_OBJECT (spw), signals[SET_SELECTION], 0, selection); - /* Inkscape will force "change_selection" anyways */ + SPWidget *spw = reinterpret_cast<SPWidget*>(g_object_new(SP_TYPE_WIDGET, NULL)); + + if (!SPWidgetImpl::constructGlobal(spw, inkscape)) { + g_object_unref(spw); + spw = 0; + } + + return reinterpret_cast<GtkWidget *>(spw); } /* diff --git a/src/widgets/sp-widget.h b/src/widgets/sp-widget.h index 66320cd4d..3a23a92c5 100644 --- a/src/widgets/sp-widget.h +++ b/src/widgets/sp-widget.h @@ -1,52 +1,76 @@ -#ifndef __SP_WIDGET_H__ -#define __SP_WIDGET_H__ +#ifndef SEEN_SP_WIDGET_H +#define SEEN_SP_WIDGET_H /* * Abstract base class for dynamic control widgets * * Authors: * Lauris Kaplinski <lauris@kaplinski.com> + * Jon A. Cruz <jon@joncruz.org> * * Copyright (C) 1999-2002 Lauris Kaplinski * Copyright (C) 2000-2001 Ximian, Inc. + * Copyright (C) 2012 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ #include <glib.h> +#include <gtk/gtk.h> -#define SP_TYPE_WIDGET (sp_widget_get_type ()) +#define SP_TYPE_WIDGET (SPWidget::getType()) #define SP_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_WIDGET, SPWidget)) #define SP_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_WIDGET, SPWidgetClass)) #define SP_IS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_WIDGET)) #define SP_IS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_WIDGET)) -#include <gtk/gtk.h> namespace Inkscape { - class Application; - class Selection; + +struct Application; +class Selection; +class SPWidgetImpl; + } struct SPWidget { - GtkBin bin; - Inkscape::Application *inkscape; + friend class Inkscape::SPWidgetImpl; + + static GType getType(); + + // + + GtkBin bin; + Inkscape::Application *inkscape; + +private: + Inkscape::SPWidgetImpl *_impl; }; struct SPWidgetClass { - GtkBinClass bin_class; - void (* construct) (SPWidget *spw); - /* Selection change handlers */ - void (* modify_selection) (SPWidget *spw, Inkscape::Selection *selection, guint flags); - void (* change_selection) (SPWidget *spw, Inkscape::Selection *selection); - void (* set_selection) (SPWidget *spw, Inkscape::Selection *selection); -}; + GtkBinClass bin_class; + + void (* construct) (SPWidget *spw); -GType sp_widget_get_type (void); + // Selection change handlers + void (* modify_selection) (SPWidget *spw, Inkscape::Selection *selection, guint flags); + void (* change_selection) (SPWidget *spw, Inkscape::Selection *selection); + void (* set_selection) (SPWidget *spw, Inkscape::Selection *selection); +}; /* fixme: Think (Lauris) */ -/* Generic constructor for global widget */ -GtkWidget *sp_widget_new_global (Inkscape::Application *inkscape); -GtkWidget *sp_widget_construct_global (SPWidget *spw, Inkscape::Application *inkscape); -#endif +/** Generic constructor for global widget. */ +GtkWidget *sp_widget_new_global(Inkscape::Application *inkscape); + +#endif // SEEN_SP_WIDGET_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 : diff --git a/src/widgets/sp-xmlview-attr-list.cpp b/src/widgets/sp-xmlview-attr-list.cpp index 0b4dcce32..47b0ebb9d 100644 --- a/src/widgets/sp-xmlview-attr-list.cpp +++ b/src/widgets/sp-xmlview-attr-list.cpp @@ -22,7 +22,12 @@ static void sp_xmlview_attr_list_class_init (SPXMLViewAttrListClass * klass); static void sp_xmlview_attr_list_init (SPXMLViewAttrList * list); -static void sp_xmlview_attr_list_destroy (GtkObject * object); + +#if GTK_CHECK_VERSION(3,0,0) +static void sp_xmlview_attr_list_destroy(GtkWidget * object); +#else +static void sp_xmlview_attr_list_destroy(GtkObject * object); +#endif static void event_attr_changed (Inkscape::XML::Node * repr, const gchar * name, const gchar * old_value, const gchar * new_value, bool is_interactive, gpointer data); @@ -36,12 +41,9 @@ static Inkscape::XML::NodeEventVector repr_events = { NULL /* order_changed */ }; -GtkWidget * -sp_xmlview_attr_list_new (Inkscape::XML::Node * repr) +GtkWidget *sp_xmlview_attr_list_new (Inkscape::XML::Node * repr) { - SPXMLViewAttrList * attr_list; - - attr_list = (SPXMLViewAttrList*)g_object_new (SP_TYPE_XMLVIEW_ATTR_LIST, NULL); + SPXMLViewAttrList * attr_list = SP_XMLVIEW_ATTR_LIST(g_object_new(SP_TYPE_XMLVIEW_ATTR_LIST, NULL)); attr_list->store = gtk_list_store_new (ATTR_N_COLS, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING ); gtk_tree_view_set_model (GTK_TREE_VIEW(attr_list), GTK_TREE_MODEL(attr_list->store)); @@ -66,7 +68,7 @@ sp_xmlview_attr_list_new (Inkscape::XML::Node * repr) sp_xmlview_attr_list_set_repr (attr_list, repr); - return (GtkWidget *) attr_list; + return GTK_WIDGET(attr_list); } void @@ -109,24 +111,26 @@ GType sp_xmlview_attr_list_get_type(void) return type; } -void -sp_xmlview_attr_list_class_init (SPXMLViewAttrListClass * klass) +void sp_xmlview_attr_list_class_init (SPXMLViewAttrListClass * klass) { - GtkObjectClass * object_class; - - object_class = (GtkObjectClass *) klass; +#if GTK_CHECK_VERSION(3,0,0) + GtkWidgetClass * widget_class = GTK_WIDGET_CLASS(klass); + widget_class->destroy = sp_xmlview_attr_list_destroy; +#else + GtkObjectClass * object_class = GTK_OBJECT_CLASS(klass); object_class->destroy = sp_xmlview_attr_list_destroy; +#endif - parent_class = (GtkTreeViewClass*)g_type_class_peek_parent (klass); + parent_class = GTK_TREE_VIEW_CLASS(g_type_class_peek_parent (klass)); - g_signal_new ( "row-value-changed", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (SPXMLViewAttrListClass, row_changed), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); + g_signal_new("row-value-changed", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (SPXMLViewAttrListClass, row_changed), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); } void @@ -136,8 +140,11 @@ sp_xmlview_attr_list_init (SPXMLViewAttrList * list) list->repr = NULL; } -void -sp_xmlview_attr_list_destroy (GtkObject * object) +#if GTK_CHECK_VERSION(3,0,0) +void sp_xmlview_attr_list_destroy(GtkWidget * object) +#else +void sp_xmlview_attr_list_destroy(GtkObject * object) +#endif { SPXMLViewAttrList * list; @@ -146,7 +153,11 @@ sp_xmlview_attr_list_destroy (GtkObject * object) g_object_unref(list->store); sp_xmlview_attr_list_set_repr (list, NULL); - GTK_OBJECT_CLASS (parent_class)->destroy (object); +#if GTK_CHECK_VERSION(3,0,0) + GTK_WIDGET_CLASS(parent_class)->destroy (object); +#else + GTK_OBJECT_CLASS(parent_class)->destroy (object); +#endif } void sp_xmlview_attr_list_select_row_by_key(SPXMLViewAttrList * list, const gchar *name) diff --git a/src/widgets/sp-xmlview-attr-list.h b/src/widgets/sp-xmlview-attr-list.h index 8b1dae49b..367ef1a12 100644 --- a/src/widgets/sp-xmlview-attr-list.h +++ b/src/widgets/sp-xmlview-attr-list.h @@ -14,8 +14,6 @@ #include <stdio.h> #include <gtk/gtk.h> -#include "../xml/repr.h" - #define SP_TYPE_XMLVIEW_ATTR_LIST (sp_xmlview_attr_list_get_type ()) diff --git a/src/widgets/sp-xmlview-content.cpp b/src/widgets/sp-xmlview-content.cpp index d30f0bbe6..ac64dabdb 100644 --- a/src/widgets/sp-xmlview-content.cpp +++ b/src/widgets/sp-xmlview-content.cpp @@ -25,7 +25,12 @@ using Inkscape::DocumentUndo; static void sp_xmlview_content_class_init (SPXMLViewContentClass * klass); static void sp_xmlview_content_init (SPXMLViewContent * text); -static void sp_xmlview_content_destroy (GtkObject * object); + +#if GTK_CHECK_VERSION(3,0,0) +static void sp_xmlview_content_destroy(GtkWidget * object); +#else +static void sp_xmlview_content_destroy(GtkObject * object); +#endif void sp_xmlview_content_changed (GtkTextBuffer *tb, SPXMLViewContent *text); @@ -41,14 +46,10 @@ static Inkscape::XML::NodeEventVector repr_events = { NULL /* order_changed */ }; -GtkWidget * -sp_xmlview_content_new (Inkscape::XML::Node * repr) +GtkWidget *sp_xmlview_content_new(Inkscape::XML::Node * repr) { - GtkTextBuffer *tb; - SPXMLViewContent *text; - - tb = gtk_text_buffer_new (NULL); - text = (SPXMLViewContent*)g_object_new (SP_TYPE_XMLVIEW_CONTENT, NULL); + GtkTextBuffer *tb = gtk_text_buffer_new(NULL); + SPXMLViewContent *text = SP_XMLVIEW_CONTENT(g_object_new(SP_TYPE_XMLVIEW_CONTENT, NULL)); gtk_text_view_set_buffer (GTK_TEXT_VIEW (text), tb); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text), GTK_WRAP_CHAR); @@ -58,7 +59,7 @@ sp_xmlview_content_new (Inkscape::XML::Node * repr) sp_xmlview_content_set_repr (text, repr); - return (GtkWidget *) text; + return GTK_WIDGET(text); } void @@ -103,16 +104,17 @@ GType sp_xmlview_content_get_type(void) return type; } -void -sp_xmlview_content_class_init (SPXMLViewContentClass * klass) +void sp_xmlview_content_class_init(SPXMLViewContentClass * klass) { - GtkObjectClass * object_class; - - object_class = (GtkObjectClass *) klass; - - parent_class = (GtkTextViewClass*)g_type_class_peek_parent (klass); - +#if GTK_CHECK_VERSION(3,0,0) + GtkWidgetClass * widget_class = GTK_WIDGET_CLASS(klass); + widget_class->destroy = sp_xmlview_content_destroy; +#else + GtkObjectClass * object_class = GTK_OBJECT_CLASS(klass); object_class->destroy = sp_xmlview_content_destroy; +#endif + + parent_class = GTK_TEXT_VIEW_CLASS(g_type_class_peek_parent (klass)); } void @@ -122,16 +124,21 @@ sp_xmlview_content_init (SPXMLViewContent *text) text->blocked = FALSE; } -void -sp_xmlview_content_destroy (GtkObject * object) +#if GTK_CHECK_VERSION(3,0,0) +void sp_xmlview_content_destroy(GtkWidget * object) +#else +void sp_xmlview_content_destroy(GtkObject * object) +#endif { - SPXMLViewContent * text; - - text = SP_XMLVIEW_CONTENT (object); + SPXMLViewContent * text = SP_XMLVIEW_CONTENT (object); sp_xmlview_content_set_repr (text, NULL); +#if GTK_CHECK_VERSION(3,0,0) + GTK_WIDGET_CLASS (parent_class)->destroy (object); +#else GTK_OBJECT_CLASS (parent_class)->destroy (object); +#endif } void diff --git a/src/widgets/sp-xmlview-content.h b/src/widgets/sp-xmlview-content.h index 941ef0be1..8b1342c5e 100644 --- a/src/widgets/sp-xmlview-content.h +++ b/src/widgets/sp-xmlview-content.h @@ -13,16 +13,11 @@ */ #include <config.h> - #include <stdio.h> - #include <gtk/gtk.h> -#include "../xml/repr.h" - #include <glib.h> - #define SP_TYPE_XMLVIEW_CONTENT (sp_xmlview_content_get_type ()) #define SP_XMLVIEW_CONTENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_XMLVIEW_CONTENT, SPXMLViewContent)) #define SP_IS_XMLVIEW_CONTENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_XMLVIEW_CONTENT)) diff --git a/src/widgets/sp-xmlview-tree.cpp b/src/widgets/sp-xmlview-tree.cpp index aafd4ab79..43b7dc289 100644 --- a/src/widgets/sp-xmlview-tree.cpp +++ b/src/widgets/sp-xmlview-tree.cpp @@ -27,10 +27,14 @@ enum { STORE_TEXT_COL = 0, STORE_DATA_COL, STORE_REPR_COL, STORE_N_COLS }; static void sp_xmlview_tree_class_init (SPXMLViewTreeClass * klass); static void sp_xmlview_tree_init (SPXMLViewTree * tree); -static void sp_xmlview_tree_destroy (GtkObject * object); + +#if GTK_CHECK_VERSION(3,0,0) +static void sp_xmlview_tree_destroy(GtkWidget * object); +#else +static void sp_xmlview_tree_destroy(GtkObject * object); +#endif static NodeData * node_data_new (SPXMLViewTree * tree, GtkTreeIter * node, GtkTreeRowReference *rowref, Inkscape::XML::Node * repr); -static void node_data_free (gpointer data); static GtkTreeRowReference * add_node (SPXMLViewTree * tree, GtkTreeIter * parent, GtkTreeIter * before, Inkscape::XML::Node * repr); @@ -45,7 +49,6 @@ static void pi_content_changed (Inkscape::XML::Node * repr, const gchar * old_co static gboolean ref_to_sibling (NodeData *node, Inkscape::XML::Node * ref, GtkTreeIter *); static gboolean repr_to_child (NodeData *node, Inkscape::XML::Node * repr, GtkTreeIter *); -static Inkscape::XML::Node * sibling_to_ref (GtkTreeView * tree, GtkTreeIter * parent, GtkTreeIter * sibling); static gboolean tree_model_iter_compare(GtkTreeModel* store, GtkTreeIter * iter1, GtkTreeIter * iter2); GtkTreeRowReference *tree_iter_to_ref (SPXMLViewTree * tree, GtkTreeIter* iter); static gboolean tree_ref_to_iter (SPXMLViewTree * tree, GtkTreeIter* iter, GtkTreeRowReference *ref); @@ -91,15 +94,16 @@ static const Inkscape::XML::NodeEventVector pi_repr_events = { static GtkTreeViewClass * parent_class = NULL; -GtkWidget * -sp_xmlview_tree_new (Inkscape::XML::Node * repr, void * /*factory*/, void * /*data*/) +GtkWidget *sp_xmlview_tree_new(Inkscape::XML::Node * repr, void * /*factory*/, void * /*data*/) { - SPXMLViewTree * tree; + SPXMLViewTree *tree = SP_XMLVIEW_TREE(g_object_new (SP_TYPE_XMLVIEW_TREE, NULL)); + + tree->store = gtk_tree_store_new (STORE_N_COLS, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER); - tree = (SPXMLViewTree*)g_object_new (SP_TYPE_XMLVIEW_TREE, NULL); + // Detach the model from the view until all the data is loaded + g_object_ref(tree->store); + gtk_tree_view_set_model(GTK_TREE_VIEW(tree), NULL); - tree->store = gtk_tree_store_new (STORE_N_COLS, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER); - gtk_tree_view_set_model (GTK_TREE_VIEW(tree), GTK_TREE_MODEL(tree->store)); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(tree), FALSE); gtk_tree_view_set_reorderable (GTK_TREE_VIEW(tree), TRUE); gtk_tree_view_set_enable_search (GTK_TREE_VIEW(tree), TRUE); @@ -117,7 +121,7 @@ sp_xmlview_tree_new (Inkscape::XML::Node * repr, void * /*factory*/, void * /*da g_signal_connect(GTK_TREE_VIEW(tree), "drag_data_received", G_CALLBACK(on_drag_data_received), tree); g_signal_connect(GTK_TREE_VIEW(tree), "drag-motion", G_CALLBACK(do_drag_motion), tree); - return (GtkWidget *) tree; + return GTK_WIDGET(tree); } GType @@ -143,13 +147,17 @@ sp_xmlview_tree_get_type (void) return type; } -void -sp_xmlview_tree_class_init (SPXMLViewTreeClass * klass) +void sp_xmlview_tree_class_init(SPXMLViewTreeClass * klass) { - GtkObjectClass * object_class; - - object_class = (GtkObjectClass *) klass; - parent_class = (GtkTreeViewClass *) g_type_class_peek_parent (klass); +#if GTK_CHECK_VERSION(3,0,0) + GtkWidgetClass * widget_class = GTK_WIDGET_CLASS(klass); + widget_class->destroy = sp_xmlview_tree_destroy; +#else + GtkObjectClass * object_class = GTK_OBJECT_CLASS(klass); + object_class->destroy = sp_xmlview_tree_destroy; +#endif + + parent_class = GTK_TREE_VIEW_CLASS(g_type_class_peek_parent (klass)); // Signal for when a tree drag and drop has completed g_signal_new ( "tree_move", @@ -160,8 +168,6 @@ sp_xmlview_tree_class_init (SPXMLViewTreeClass * klass) g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); - - object_class->destroy = sp_xmlview_tree_destroy; } void @@ -172,16 +178,22 @@ sp_xmlview_tree_init (SPXMLViewTree * tree) tree->dndactive = FALSE; } -void -sp_xmlview_tree_destroy (GtkObject * object) -{ - SPXMLViewTree * tree; - tree = SP_XMLVIEW_TREE (object); +#if GTK_CHECK_VERSION(3,0,0) +void sp_xmlview_tree_destroy(GtkWidget * object) +#else +void sp_xmlview_tree_destroy(GtkObject * object) +#endif +{ + SPXMLViewTree * tree = SP_XMLVIEW_TREE (object); sp_xmlview_tree_set_repr (tree, NULL); - GTK_OBJECT_CLASS (parent_class)->destroy (object); +#if GTK_CHECK_VERSION(3,0,0) + GTK_WIDGET_CLASS(parent_class)->destroy (object); +#else + GTK_OBJECT_CLASS(parent_class)->destroy (object); +#endif } /* @@ -248,93 +260,71 @@ NodeData *node_data_new(SPXMLViewTree * tree, GtkTreeIter * /*node*/, GtkTreeRow return data; } -void -node_data_free (gpointer ptr) { - NodeData * data; - data = (NodeData *) ptr; - sp_repr_remove_listener_by_data (data->repr, data); - g_assert (data->repr != NULL); - Inkscape::GC::release(data->repr); - g_free (data); -} - -void -element_child_added (Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node * child, Inkscape::XML::Node * ref, gpointer ptr) +void element_child_added (Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node * child, Inkscape::XML::Node * ref, gpointer ptr) { - NodeData * data; - GtkTreeIter before; - - data = (NodeData *) ptr; + NodeData *data = static_cast<NodeData *>(ptr); + GtkTreeIter before; - if (data->tree->blocked) return; + if (data->tree->blocked) return; - if (!ref_to_sibling (data, ref, &before)) { - return; - } + if (!ref_to_sibling (data, ref, &before)) { + return; + } GtkTreeIter data_iter; tree_ref_to_iter(data->tree, &data_iter, data->rowref); - add_node (data->tree, &data_iter, &before, child); + add_node (data->tree, &data_iter, &before, child); } -void -element_attr_changed (Inkscape::XML::Node * repr, const gchar * key, const gchar * /*old_value*/, const gchar * new_value, bool /*is_interactive*/, gpointer ptr) +void element_attr_changed(Inkscape::XML::Node * repr, const gchar * key, const gchar * /*old_value*/, const gchar * new_value, bool /*is_interactive*/, gpointer ptr) { - NodeData * data; - gchar *label; - const gchar *layer; + NodeData *data = static_cast<NodeData *>(ptr); + gchar *label; - data = (NodeData *) ptr; + if (data->tree->blocked) return; - if (data->tree->blocked) return; - - if (0 != strcmp (key, "id") && 0 != strcmp (key, "inkscape:label")) - return; + if (0 != strcmp (key, "id") && 0 != strcmp (key, "inkscape:label")) + return; - new_value = repr->attribute("id"); - layer = repr->attribute("inkscape:label"); + new_value = repr->attribute("id"); + const gchar *layer = repr->attribute("inkscape:label"); - if (new_value && layer) { - label = g_strdup_printf ("<%s id=\"%s\" inkscape:label=\"%s\">", repr->name(), new_value, layer); - } else if (new_value) { - label = g_strdup_printf ("<%s id=\"%s\">", repr->name(), new_value); - } else { - label = g_strdup_printf ("<%s>", repr->name()); - } + if (new_value && layer) { + label = g_strdup_printf ("<%s id=\"%s\" inkscape:label=\"%s\">", repr->name(), new_value, layer); + } else if (new_value) { + label = g_strdup_printf ("<%s id=\"%s\">", repr->name(), new_value); + } else { + label = g_strdup_printf ("<%s>", repr->name()); + } - GtkTreeIter iter; - if (tree_ref_to_iter(data->tree, &iter, data->rowref)) { - gtk_tree_store_set (GTK_TREE_STORE(data->tree->store), &iter, STORE_TEXT_COL, label, -1); - } - g_free (label); + GtkTreeIter iter; + if (tree_ref_to_iter(data->tree, &iter, data->rowref)) { + gtk_tree_store_set (GTK_TREE_STORE(data->tree->store), &iter, STORE_TEXT_COL, label, -1); + } + g_free (label); } -void -element_child_removed (Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node * child, Inkscape::XML::Node * /*ref*/, gpointer ptr) +void element_child_removed(Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node * child, Inkscape::XML::Node * /*ref*/, gpointer ptr) { - NodeData * data; - data = (NodeData *) ptr; + NodeData *data = static_cast<NodeData *>(ptr); - if (data->tree->blocked) return; + if (data->tree->blocked) return; - GtkTreeIter iter; - if (repr_to_child (data, child, &iter)) { + GtkTreeIter iter; + if (repr_to_child (data, child, &iter)) { gtk_tree_store_remove (GTK_TREE_STORE(data->tree->store), &iter); } - } -void -element_order_changed (Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node * child, Inkscape::XML::Node * /*oldref*/, Inkscape::XML::Node * newref, gpointer ptr) +void element_order_changed(Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node * child, Inkscape::XML::Node * /*oldref*/, Inkscape::XML::Node * newref, gpointer ptr) { - NodeData * data; - GtkTreeIter before, node; - data = (NodeData *) ptr; + NodeData *data = static_cast<NodeData *>(ptr); + GtkTreeIter before, node; - if (data->tree->blocked) return; + if (data->tree->blocked) return; - ref_to_sibling (data, newref, &before); - repr_to_child (data, child, &node); + ref_to_sibling (data, newref, &before); + repr_to_child (data, child, &node); if (gtk_tree_store_iter_is_valid(data->tree->store, &before)) { gtk_tree_store_move_before (data->tree->store, &node, &before); @@ -344,59 +334,47 @@ element_order_changed (Inkscape::XML::Node * /*repr*/, Inkscape::XML::Node * chi } } -void -text_content_changed (Inkscape::XML::Node * /*repr*/, const gchar * /*old_content*/, const gchar * new_content, gpointer ptr) +void text_content_changed(Inkscape::XML::Node * /*repr*/, const gchar * /*old_content*/, const gchar * new_content, gpointer ptr) { - NodeData *data; - gchar *label; - - data = (NodeData *) ptr; + NodeData *data = static_cast<NodeData *>(ptr); - if (data->tree->blocked) return; + if (data->tree->blocked) return; - label = g_strdup_printf ("\"%s\"", new_content); + gchar *label = g_strdup_printf ("\"%s\"", new_content); GtkTreeIter iter; if (tree_ref_to_iter(data->tree, &iter, data->rowref)) { gtk_tree_store_set (GTK_TREE_STORE(data->tree->store), &iter, STORE_TEXT_COL, label, -1); } - g_free (label); + g_free (label); } -void -comment_content_changed (Inkscape::XML::Node */*repr*/, const gchar * /*old_content*/, const gchar *new_content, gpointer ptr) +void comment_content_changed(Inkscape::XML::Node * /*repr*/, const gchar * /*old_content*/, const gchar *new_content, gpointer ptr) { - NodeData *data; - gchar *label; - - data = (NodeData *) ptr; + NodeData *data = static_cast<NodeData*>(ptr); - if (data->tree->blocked) return; + if (data->tree->blocked) return; - label = g_strdup_printf ("<!--%s-->", new_content); + gchar *label = g_strdup_printf ("<!--%s-->", new_content); GtkTreeIter iter; if (tree_ref_to_iter(data->tree, &iter, data->rowref)) { gtk_tree_store_set (GTK_TREE_STORE(data->tree->store), &iter, STORE_TEXT_COL, label, -1); } - g_free (label); + g_free (label); } -void -pi_content_changed(Inkscape::XML::Node *repr, const gchar * /*old_content*/, const gchar *new_content, gpointer ptr) +void pi_content_changed(Inkscape::XML::Node *repr, const gchar * /*old_content*/, const gchar *new_content, gpointer ptr) { - NodeData *data; - gchar *label; - - data = (NodeData *) ptr; + NodeData *data = static_cast<NodeData *>(ptr); - if (data->tree->blocked) return; + if (data->tree->blocked) return; - label = g_strdup_printf ("<?%s %s?>", repr->name(), new_content); + gchar *label = g_strdup_printf ("<?%s %s?>", repr->name(), new_content); GtkTreeIter iter; if (tree_ref_to_iter(data->tree, &iter, data->rowref)) { gtk_tree_store_set (GTK_TREE_STORE(data->tree->store), &iter, STORE_TEXT_COL, label, -1); } - g_free (label); + g_free (label); } /* @@ -438,14 +416,14 @@ void on_drag_data_received(GtkWidget * /*wgt*/, GdkDragContext * /*context*/, in */ void on_row_changed(GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { - SPXMLViewTree *tree = (SPXMLViewTree *)user_data; + SPXMLViewTree *tree = SP_XMLVIEW_TREE(user_data); if (!tree->dndactive) { return; } tree->dndactive = FALSE; - Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(GTK_TREE_VIEW(tree), iter); + Inkscape::XML::Node *repr = sp_xmlview_tree_node_get_repr(tree_model, iter); GtkTreeIter new_parent; if (!gtk_tree_model_iter_parent(tree_model, &new_parent, iter)) { //No parent of drop location @@ -453,7 +431,7 @@ void on_row_changed(GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *it return; } - GtkTreeRowReference *old_parent_ref = (GtkTreeRowReference *)g_object_get_data (G_OBJECT (tree), "drag-src-path"); + GtkTreeRowReference *old_parent_ref = static_cast<GtkTreeRowReference *>(g_object_get_data (G_OBJECT (tree), "drag-src-path")); if (!old_parent_ref) { //No drag source location g_signal_emit_by_name(G_OBJECT (tree), "tree_move", GUINT_TO_POINTER(0) ); @@ -489,10 +467,10 @@ void on_row_changed(GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *it SP_XMLVIEW_TREE (tree)->blocked++; if (!tree_model_iter_compare (tree_model, &new_parent, &old_parent)) { - sp_xmlview_tree_node_get_repr (GTK_TREE_VIEW(tree), &old_parent)->changeOrder(repr, before_repr); + sp_xmlview_tree_node_get_repr (tree_model, &old_parent)->changeOrder(repr, before_repr); } else { - sp_xmlview_tree_node_get_repr (GTK_TREE_VIEW(tree), &old_parent)->removeChild(repr); - sp_xmlview_tree_node_get_repr (GTK_TREE_VIEW(tree), &new_parent)->addChild(repr, before_repr); + sp_xmlview_tree_node_get_repr (tree_model, &old_parent)->removeChild(repr); + sp_xmlview_tree_node_get_repr (tree_model, &new_parent)->addChild(repr, before_repr); } SP_XMLVIEW_TREE (tree)->blocked--; @@ -533,14 +511,28 @@ gboolean repr_to_child (NodeData *data, Inkscape::XML::Node * repr, GtkTreeIter { GtkTreeIter data_iter; tree_ref_to_iter(data->tree, &data_iter, data->rowref); + GtkTreeModel *model = GTK_TREE_MODEL(data->tree->store); + gboolean valid = false; - if (!gtk_tree_store_iter_is_valid(GTK_TREE_STORE(data->tree->store), &data_iter)) { + if (!gtk_tree_store_iter_is_valid(data->tree->store, &data_iter)) { return false; } - gboolean valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(data->tree->store), iter, &data_iter); - while (valid && sp_xmlview_tree_node_get_repr (GTK_TREE_VIEW(data->tree), iter) != repr) { - valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(data->tree->store), iter); + /* + * The node we are looking for is likely to be the last one, so check it first. + */ + gint n_children = gtk_tree_model_iter_n_children (model, &data_iter); + if (n_children > 1) { + valid = gtk_tree_model_iter_nth_child (model, iter, &data_iter, n_children-1); + if (valid && sp_xmlview_tree_node_get_repr (model, iter) == repr) { + //g_message("repr_to_child hit %d", n_children); + return valid; + } + } + + valid = gtk_tree_model_iter_children(model, iter, &data_iter); + while (valid && sp_xmlview_tree_node_get_repr (model, iter) != repr) { + valid = gtk_tree_model_iter_next(model, iter); } return valid; @@ -589,31 +581,6 @@ gboolean tree_model_iter_compare(GtkTreeModel* store, GtkTreeIter * iter1, GtkTr } -/* - * Return the node of parent iter's child sibling or NULL if sibling is the first child - */ -Inkscape::XML::Node * -sibling_to_ref (GtkTreeView * tree, GtkTreeIter * parent, GtkTreeIter * sibling) -{ - GtkTreeIter child; - GtkTreeModel* store = gtk_tree_view_get_model(tree); - - gboolean valid = gtk_tree_model_iter_children(store, &child, parent); - - if (! tree_model_iter_compare(store, &child, sibling)) { - return NULL; - } - - while (valid && tree_model_iter_compare(store, &child, sibling)) { - valid = gtk_tree_model_iter_next(store, &child); - } - - if (!gtk_tree_store_iter_is_valid(GTK_TREE_STORE(store), &child)) { - return NULL; - } - - return sp_xmlview_tree_node_get_repr (tree, &child); -} /* * Disable drag and drop target on : root node and non-element nodes @@ -629,10 +596,10 @@ gboolean do_drag_motion(GtkWidget *widget, GdkDragContext *context, gint x, gint if (path) { action = GDK_ACTION_MOVE; - SPXMLViewTree *tree = (SPXMLViewTree *)user_data; + SPXMLViewTree *tree = SP_XMLVIEW_TREE(user_data); GtkTreeIter iter; gtk_tree_model_get_iter(GTK_TREE_MODEL(tree->store), &iter, path); - if (sp_xmlview_tree_node_get_repr (GTK_TREE_VIEW(widget), &iter)->type() != Inkscape::XML::ELEMENT_NODE) { + if (sp_xmlview_tree_node_get_repr (GTK_TREE_MODEL(tree->store), &iter)->type() != Inkscape::XML::ELEMENT_NODE) { action = 0; } @@ -661,7 +628,17 @@ sp_xmlview_tree_set_repr (SPXMLViewTree * tree, Inkscape::XML::Node * repr) { if ( tree->repr == repr ) return; if (tree->repr) { - gtk_tree_store_clear(tree->store); + /* + * Would like to simple call gtk_tree_store_clear here, + * but it is extremely slow on large data sets. + * Instead just unref the old and create a new store. + */ + //gtk_tree_store_clear(tree->store); + gtk_tree_view_set_model(GTK_TREE_VIEW(tree), NULL); + g_object_unref(tree->store); + tree->store = gtk_tree_store_new (STORE_N_COLS, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER); + gtk_tree_view_set_model (GTK_TREE_VIEW(tree), GTK_TREE_MODEL(tree->store)); + Inkscape::GC::release(tree->repr); } tree->repr = repr; @@ -669,6 +646,11 @@ sp_xmlview_tree_set_repr (SPXMLViewTree * tree, Inkscape::XML::Node * repr) GtkTreeRowReference * rowref; Inkscape::GC::anchor(repr); rowref = add_node (tree, NULL, NULL, repr); + + // Set the tree model here, after all data is inserted + gtk_tree_view_set_model (GTK_TREE_VIEW(tree), GTK_TREE_MODEL(tree->store)); + g_object_unref(tree->store); + GtkTreePath *path = gtk_tree_row_reference_get_path(rowref); gtk_tree_view_expand_to_path (GTK_TREE_VIEW(tree), path); gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW(tree), path, NULL, true, 0.5, 0.0); @@ -680,10 +662,9 @@ sp_xmlview_tree_set_repr (SPXMLViewTree * tree, Inkscape::XML::Node * repr) * Return the repr at a given GtkTreeIter position */ Inkscape::XML::Node * -sp_xmlview_tree_node_get_repr (GtkTreeView *tree, GtkTreeIter * iter) +sp_xmlview_tree_node_get_repr (GtkTreeModel *model, GtkTreeIter * iter) { Inkscape::XML::Node *repr; - GtkTreeModel *model = gtk_tree_view_get_model(tree); gtk_tree_model_get (model, iter, STORE_REPR_COL, &repr, -1); return repr; @@ -743,3 +724,14 @@ gboolean search_equal_func(GtkTreeModel *model, gint /*column*/, const gchar *ke return !match; } + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/sp-xmlview-tree.h b/src/widgets/sp-xmlview-tree.h index 36b76f5d9..69228fa88 100644 --- a/src/widgets/sp-xmlview-tree.h +++ b/src/widgets/sp-xmlview-tree.h @@ -13,12 +13,9 @@ */ #include <gtk/gtk.h> -#include "../xml/repr.h" - #include <glib.h> - #define SP_TYPE_XMLVIEW_TREE (sp_xmlview_tree_get_type ()) #define SP_XMLVIEW_TREE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_XMLVIEW_TREE, SPXMLViewTree)) #define SP_IS_XMLVIEW_TREE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_XMLVIEW_TREE)) @@ -48,8 +45,19 @@ GtkWidget * sp_xmlview_tree_new (Inkscape::XML::Node * repr, void * factory, voi void sp_xmlview_tree_set_repr (SPXMLViewTree * tree, Inkscape::XML::Node * repr); -Inkscape::XML::Node * sp_xmlview_tree_node_get_repr (GtkTreeView * tree, GtkTreeIter * node); +Inkscape::XML::Node * sp_xmlview_tree_node_get_repr (GtkTreeModel *model, GtkTreeIter * node); gboolean sp_xmlview_tree_get_repr_node (SPXMLViewTree * tree, Inkscape::XML::Node * repr, GtkTreeIter *node); #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:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/spinbutton-events.cpp b/src/widgets/spinbutton-events.cpp index 565c89ece..0280694f6 100644 --- a/src/widgets/spinbutton-events.cpp +++ b/src/widgets/spinbutton-events.cpp @@ -3,7 +3,9 @@ * * Authors: * bulia byak <bulia@users.sourceforge.net> + * Jon A. Cruz <jon@joncruz.org> * + * Copyright (C) 2013 authors * Copyright (C) 2003 authors * * Released under GNU GPL, read the file 'COPYING' for more information @@ -16,122 +18,151 @@ #include <gtk/gtk.h> #include <gdk/gdkkeysyms.h> -#include "../event-context.h" +#include "ui/tools/tool-base.h" #include "sp-widget.h" #include "widget-sizes.h" +#include "spinbutton-events.h" - -gboolean -spinbutton_focus_in (GtkWidget *w, GdkEventKey */*event*/, gpointer /*data*/) +gboolean spinbutton_focus_in(GtkWidget *w, GdkEventKey * /*event*/, gpointer /*data*/) { - gdouble *ini; - - ini = (gdouble *) g_object_get_data(G_OBJECT (w), "ini"); - if (ini) g_free (ini); // free the old value if any + gdouble *ini = static_cast<gdouble *>(g_object_get_data(G_OBJECT(w), "ini")); + if (ini) { + g_free(ini); // free the old value if any + } - // retrieve the value - ini = g_new (gdouble, 1); - *ini = gtk_spin_button_get_value (GTK_SPIN_BUTTON(w)); + // retrieve the value + ini = g_new(gdouble, 1); + *ini = gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); - // remember it - g_object_set_data (G_OBJECT (w), "ini", ini); + // remember it + g_object_set_data(G_OBJECT(w), "ini", ini); - return FALSE; // I didn't consume the event + return FALSE; // I didn't consume the event } -void -spinbutton_undo (GtkWidget *w) +void spinbutton_undo(GtkWidget *w) { - gdouble *ini = (gdouble *) g_object_get_data(G_OBJECT (w), "ini"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), *ini); + gdouble *ini = static_cast<gdouble *>(g_object_get_data(G_OBJECT(w), "ini")); + if (ini) { + gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), *ini); + } } -void -spinbutton_defocus (GtkWidget *container) +void spinbutton_defocus(GtkWidget *container) { - // defocus spinbuttons by moving focus to the canvas, unless "stay" is on - gboolean stay = GPOINTER_TO_INT(g_object_get_data(G_OBJECT (container), "stay")); - if (stay) { - g_object_set_data (G_OBJECT (container), "stay", GINT_TO_POINTER (FALSE)); - } else { - GtkWidget *canvas = (GtkWidget *) g_object_get_data(G_OBJECT (container), "dtw"); - if (canvas) { - gtk_widget_grab_focus (GTK_WIDGET(canvas)); - } - } + // defocus spinbuttons by moving focus to the canvas, unless "stay" is on + gboolean stay = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(container), "stay")); + if (stay) { + g_object_set_data(G_OBJECT(container), "stay", GINT_TO_POINTER(FALSE)); + } else { + GtkWidget *canvas = GTK_WIDGET(g_object_get_data(G_OBJECT(container), "dtw")); + if (canvas) { + gtk_widget_grab_focus(GTK_WIDGET(canvas)); + } + } } -gboolean -spinbutton_keypress (GtkWidget *w, GdkEventKey *event, gpointer data) +gboolean spinbutton_keypress(GtkWidget *w, GdkEventKey *event, gpointer /*data*/) { - SPWidget *spw = (SPWidget *) data; - gdouble v; - - switch (get_group0_keyval (event)) { - case GDK_Escape: // defocus - spinbutton_undo (w); - spinbutton_defocus(GTK_WIDGET(spw)); - return TRUE; // I consumed the event - break; - case GDK_Return: // defocus - case GDK_KP_Enter: - spinbutton_defocus (GTK_WIDGET(spw)); - return TRUE; // I consumed the event - break; - case GDK_Tab: - case GDK_ISO_Left_Tab: - // set the flag meaning "do not leave toolbar when changing value" - g_object_set_data (G_OBJECT (spw), "stay", GINT_TO_POINTER(TRUE)); - return FALSE; // I didn't consume the event - break; - - // The following keys are processed manually because GTK implements them in strange ways - // (increments start with double step value and seem to grow as you press the key continuously) - - case GDK_Up: - case GDK_KP_Up: - g_object_set_data (G_OBJECT (spw), "stay", GINT_TO_POINTER(TRUE)); - v = gtk_spin_button_get_value(GTK_SPIN_BUTTON (w)); - v += SPIN_STEP; - gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), v); - return TRUE; // I consumed the event - break; - case GDK_Down: - case GDK_KP_Down: - g_object_set_data (G_OBJECT (spw), "stay", GINT_TO_POINTER(TRUE)); - v = gtk_spin_button_get_value(GTK_SPIN_BUTTON (w)); - v -= SPIN_STEP; - gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), v); - return TRUE; // I consumed the event - break; - case GDK_Page_Up: - case GDK_KP_Page_Up: - g_object_set_data (G_OBJECT (spw), "stay", GINT_TO_POINTER(TRUE)); - v = gtk_spin_button_get_value(GTK_SPIN_BUTTON (w)); - v += SPIN_PAGE_STEP; - gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), v); - return TRUE; // I consumed the event - break; - case GDK_Page_Down: - case GDK_KP_Page_Down: - g_object_set_data (G_OBJECT (spw), "stay", GINT_TO_POINTER(TRUE)); - v = gtk_spin_button_get_value(GTK_SPIN_BUTTON (w)); - v -= SPIN_PAGE_STEP; - gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), v); - return TRUE; // I consumed the event - break; - case GDK_z: - case GDK_Z: - g_object_set_data (G_OBJECT (spw), "stay", GINT_TO_POINTER(TRUE)); - if (event->state & GDK_CONTROL_MASK) { - spinbutton_undo (w); - return TRUE; // I consumed the event - } - break; + gboolean result = FALSE; // I didn't consume the event + + switch (Inkscape::UI::Tools::get_group0_keyval(event)) { + case GDK_KEY_Escape: // defocus + spinbutton_undo(w); + spinbutton_defocus(w); + result = TRUE; // I consumed the event + break; + case GDK_KEY_Return: // defocus + case GDK_KEY_KP_Enter: + spinbutton_defocus(w); + result = TRUE; // I consumed the event + break; + case GDK_KEY_Tab: + case GDK_KEY_ISO_Left_Tab: + // set the flag meaning "do not leave toolbar when changing value" + g_object_set_data(G_OBJECT(w), "stay", GINT_TO_POINTER(TRUE)); + result = FALSE; // I didn't consume the event + break; + + // The following keys are processed manually because GTK implements them in strange ways + // (increments start with double step value and seem to grow as you press the key continuously) + + case GDK_KEY_Up: + case GDK_KEY_KP_Up: + { + g_object_set_data(G_OBJECT(w), "stay", GINT_TO_POINTER(TRUE)); + gdouble v = gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); + gdouble step = 0; + gdouble page = 0; + gtk_spin_button_get_increments(GTK_SPIN_BUTTON(w), &step, &page); + v += step; + gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), v); + result = TRUE; // I consumed the event + break; + } + case GDK_KEY_Down: + case GDK_KEY_KP_Down: + { + g_object_set_data(G_OBJECT(w), "stay", GINT_TO_POINTER(TRUE)); + gdouble v = gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); + gdouble step = 0; + gdouble page = 0; + gtk_spin_button_get_increments(GTK_SPIN_BUTTON(w), &step, &page); + v -= step; + gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), v); + result = TRUE; // I consumed the event + break; + } + case GDK_KEY_Page_Up: + case GDK_KEY_KP_Page_Up: + { + g_object_set_data(G_OBJECT(w), "stay", GINT_TO_POINTER(TRUE)); + gdouble v = gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); + gdouble step = 0; + gdouble page = 0; + gtk_spin_button_get_increments(GTK_SPIN_BUTTON(w), &step, &page); + v += page; + gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), v); + result = TRUE; // I consumed the event + break; + } + case GDK_KEY_Page_Down: + case GDK_KEY_KP_Page_Down: + { + g_object_set_data(G_OBJECT(w), "stay", GINT_TO_POINTER(TRUE)); + gdouble v = gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); + gdouble step = 0; + gdouble page = 0; + gtk_spin_button_get_increments(GTK_SPIN_BUTTON(w), &step, &page); + v -= page; + gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), v); + result = TRUE; // I consumed the event + break; + } + case GDK_KEY_z: + case GDK_KEY_Z: + g_object_set_data(G_OBJECT(w), "stay", GINT_TO_POINTER(TRUE)); + if (event->state & GDK_CONTROL_MASK) { + spinbutton_undo(w); + result = TRUE; // I consumed the event + } + break; default: - return FALSE; - break; - } - return FALSE; // I didn't consume the event + result = FALSE; + break; + } + + return result; } + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/spiral-toolbar.cpp b/src/widgets/spiral-toolbar.cpp new file mode 100644 index 000000000..710be9440 --- /dev/null +++ b/src/widgets/spiral-toolbar.cpp @@ -0,0 +1,315 @@ +/** + * @file + * Spiral aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glibmm/i18n.h> + +#include "spiral-toolbar.h" +#include "desktop-handles.h" +#include "desktop.h" +#include "document-undo.h" +#include "ege-adjustment-action.h" +#include "ege-output-action.h" +#include "ink-action.h" +#include "preferences.h" +#include "selection.h" +#include "sp-spiral.h" +#include "toolbox.h" +#include "ui/icon-names.h" +#include "ui/uxmanager.h" +#include "verbs.h" +#include "widgets/spinbutton-events.h" +#include "xml/node-event-vector.h" +#include "xml/node.h" +#include "xml/repr.h" + +using Inkscape::UI::UXManager; +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; + +//######################## +//## Spiral ## +//######################## + +static void sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, Glib::ustring const &value_name) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + + if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/tools/shapes/spiral/" + value_name, + gtk_adjustment_get_value(adj)); + } + + // quit if run by the attr_changed listener + if (g_object_get_data( tbl, "freeze" )) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + gchar* namespaced_name = g_strconcat("sodipodi:", value_name.data(), NULL); + + bool modmade = false; + for (GSList const *items = sp_desktop_selection(desktop)->itemList(); + items != NULL; + items = items->next) + { + SPItem *item = reinterpret_cast<SPItem*>(items->data); + if (SP_IS_SPIRAL(item)) { + Inkscape::XML::Node *repr = item->getRepr(); + sp_repr_set_svg_double( repr, namespaced_name, + gtk_adjustment_get_value(adj) ); + item->updateRepr(); + modmade = true; + } + } + + g_free(namespaced_name); + + if (modmade) { + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL, + _("Change spiral")); + } + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + sp_spl_tb_value_changed(adj, tbl, "revolution"); +} + +static void sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + sp_spl_tb_value_changed(adj, tbl, "expansion"); +} + +static void sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + sp_spl_tb_value_changed(adj, tbl, "t0"); +} + +static void sp_spl_tb_defaults(GtkWidget * /*widget*/, GObject *obj) +{ + GtkWidget *tbl = GTK_WIDGET(obj); + + GtkAdjustment *adj; + + // fixme: make settable + gdouble rev = 3; + gdouble exp = 1.0; + gdouble t0 = 0.0; + + adj = GTK_ADJUSTMENT(g_object_get_data(obj, "revolution")); + gtk_adjustment_set_value(adj, rev); + gtk_adjustment_value_changed(adj); + + adj = GTK_ADJUSTMENT(g_object_get_data(obj, "expansion")); + gtk_adjustment_set_value(adj, exp); + gtk_adjustment_value_changed(adj); + + adj = GTK_ADJUSTMENT(g_object_get_data(obj, "t0")); + gtk_adjustment_set_value(adj, t0); + gtk_adjustment_value_changed(adj); + + spinbutton_defocus(tbl); +} + + +static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, + gchar const * /*name*/, + gchar const * /*old_value*/, + gchar const * /*new_value*/, + bool /*is_interactive*/, + gpointer data) +{ + GtkWidget *tbl = GTK_WIDGET(data); + + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + + // in turn, prevent callbacks from responding + g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE)); + + GtkAdjustment *adj; + adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "revolution")); + double revolution = 3.0; + sp_repr_get_double(repr, "sodipodi:revolution", &revolution); + gtk_adjustment_set_value(adj, revolution); + + adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "expansion")); + double expansion = 1.0; + sp_repr_get_double(repr, "sodipodi:expansion", &expansion); + gtk_adjustment_set_value(adj, expansion); + + adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "t0")); + double t0 = 0.0; + sp_repr_get_double(repr, "sodipodi:t0", &t0); + gtk_adjustment_set_value(adj, t0); + + g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE)); +} + + +static Inkscape::XML::NodeEventVector spiral_tb_repr_events = { + NULL, /* child_added */ + NULL, /* child_removed */ + spiral_tb_event_attr_changed, + NULL, /* content_changed */ + NULL /* order_changed */ +}; + +static void sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) +{ + int n_selected = 0; + Inkscape::XML::Node *repr = NULL; + + purge_repr_listener( tbl, tbl ); + + for (GSList const *items = selection->itemList(); + items != NULL; + items = items->next) + { + SPItem *item = reinterpret_cast<SPItem*>(items->data); + if (SP_IS_SPIRAL(item)) { + n_selected++; + repr = item->getRepr(); + } + } + + EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) ); + + if (n_selected == 0) { + g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL ); + } else if (n_selected == 1) { + g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); + + if (repr) { + g_object_set_data( tbl, "repr", repr ); + Inkscape::GC::anchor(repr); + sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl); + sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl); + } + } else { + // FIXME: implement averaging of all parameters for multiple selected + //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>")); + g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); + } +} + + +void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + EgeAdjustmentAction* eact = 0; + Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); + + { + EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 ); + ege_output_action_set_use_markup( act, TRUE ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_object_set_data( holder, "mode_action", act ); + } + + /* Revolution */ + { + gchar const* labels[] = {_("just a curve"), 0, _("one full revolution"), 0, 0, 0, 0, 0, 0}; + gdouble values[] = {0.01, 0.5, 1, 2, 3, 5, 10, 20, 50, 100}; + eact = create_adjustment_action( "SpiralRevolutionAction", + _("Number of turns"), _("Turns:"), _("Number of revolutions"), + "/tools/shapes/spiral/revolution", 3.0, + GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-spiral", + 0.01, 1024.0, 0.1, 1.0, + labels, values, G_N_ELEMENTS(labels), + sp_spl_tb_revolution_value_changed, NULL /*unit tracker*/, 1, 2); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + /* Expansion */ + { + gchar const* labels[] = {_("circle"), _("edge is much denser"), _("edge is denser"), _("even"), _("center is denser"), _("center is much denser"), 0}; + gdouble values[] = {0, 0.1, 0.5, 1, 1.5, 5, 20}; + eact = create_adjustment_action( "SpiralExpansionAction", + _("Divergence"), _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"), + "/tools/shapes/spiral/expansion", 1.0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0.0, 1000.0, 0.01, 1.0, + labels, values, G_N_ELEMENTS(labels), + sp_spl_tb_expansion_value_changed); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + /* T0 */ + { + gchar const* labels[] = {_("starts from center"), _("starts mid-way"), _("starts near edge")}; + gdouble values[] = {0, 0.5, 0.9}; + eact = create_adjustment_action( "SpiralT0Action", + _("Inner radius"), _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"), + "/tools/shapes/spiral/t0", 0.0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0.0, 0.999, 0.01, 1.0, + labels, values, G_N_ELEMENTS(labels), + sp_spl_tb_t0_value_changed); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + /* Reset */ + { + InkAction* inky = ink_action_new( "SpiralResetAction", + _("Defaults"), + _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), + INKSCAPE_ICON("edit-clear"), + secondarySize ); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + } + + + sigc::connection *connection = new sigc::connection( + sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), holder)) + ); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection ); + g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/spiral-toolbar.h b/src/widgets/spiral-toolbar.h new file mode 100644 index 000000000..3372ea224 --- /dev/null +++ b/src/widgets/spiral-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_SPIRAL_TOOLBAR_H +#define SEEN_SPIRAL_TOOLBAR_H + +/** + * @file + * Spiral aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_SPIRAL_TOOLBAR_H */ diff --git a/src/widgets/spray-toolbar.cpp b/src/widgets/spray-toolbar.cpp new file mode 100644 index 000000000..788ce6475 --- /dev/null +++ b/src/widgets/spray-toolbar.cpp @@ -0,0 +1,285 @@ +/** + * @file + * Spray aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glibmm/i18n.h> + +#include "spray-toolbar.h" +#include "desktop.h" +#include "document-undo.h" +#include "ege-adjustment-action.h" +#include "ege-select-one-action.h" +#include "ink-action.h" +#include "preferences.h" +#include "toolbox.h" +#include "ui/icon-names.h" + +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; + +// Disabled in 0.91 because of Bug #1274831 (crash, spraying an object +// with the mode: spray object in single path) +// Please enable again when working on 1.0 +#define ENABLE_SPRAY_MODE_SINGLE_PATH + +//######################## +//## Spray ## +//######################## + +static void sp_spray_width_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/spray/width", + gtk_adjustment_get_value(adj)); +} + +static void sp_spray_mean_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/spray/mean", + gtk_adjustment_get_value(adj)); +} + +static void sp_spray_standard_deviation_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/spray/standard_deviation", + gtk_adjustment_get_value(adj)); +} + +static void sp_spray_mode_changed( EgeSelectOneAction *act, GObject * /*tbl*/ ) +{ + int mode = ege_select_one_action_get_active( act ); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt("/tools/spray/mode", mode); +} + +static void sp_spray_population_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/spray/population", + gtk_adjustment_get_value(adj)); +} + +static void sp_spray_rotation_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/spray/rotation_variation", + gtk_adjustment_get_value(adj)); +} + +static void sp_spray_scale_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/spray/scale_variation", + gtk_adjustment_get_value(adj)); +} + + +void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + { + /* Width */ + gchar const* labels[] = {_("(narrow spray)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad spray)")}; + gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "SprayWidthAction", + _("Width"), _("Width:"), _("The width of the spray area (relative to the visible canvas area)"), + "/tools/spray/width", 15, + GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-spray", + 1, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_spray_width_value_changed, NULL /*unit tracker*/, 1, 0 ); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + { + /* Mean */ + gchar const* labels[] = {_("(default)"), 0, 0, 0, 0, 0, 0, _("(maximum mean)")}; + gdouble values[] = {0, 5, 10, 20, 30, 50, 70, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "SprayMeanAction", + _("Focus"), _("Focus:"), _("0 to spray a spot; increase to enlarge the ring radius"), + "/tools/spray/mean", 0, + GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-mean", + 0, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_spray_mean_value_changed, NULL /*unit tracker*/, 1, 0 ); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + { + /* Standard_deviation */ + gchar const* labels[] = {_("(minimum scatter)"), 0, 0, 0, 0, 0, _("(default)"), _("(maximum scatter)")}; + gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "SprayStandard_deviationAction", + C_("Spray tool", "Scatter"), C_("Spray tool", "Scatter:"), _("Increase to scatter sprayed objects"), + "/tools/spray/standard_deviation", 70, + GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-standard_deviation", + 1, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_spray_standard_deviation_value_changed, NULL /*unit tracker*/, 1, 0 ); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + /* Mode */ + { + GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); + + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Spray with copies"), + 1, _("Spray copies of the initial selection"), + 2, INKSCAPE_ICON("spray-mode-copy"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Spray with clones"), + 1, _("Spray clones of the initial selection"), + 2, INKSCAPE_ICON("spray-mode-clone"), + -1 ); +#ifdef ENABLE_SPRAY_MODE_SINGLE_PATH + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Spray single path"), + 1, _("Spray objects in a single path"), + 2, INKSCAPE_ICON("spray-mode-union"), + -1 ); +#endif + EgeSelectOneAction* act = ege_select_one_action_new( "SprayModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) ); + g_object_set( act, "short_label", _("Mode:"), NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "mode_action", act ); + + ege_select_one_action_set_appearance( act, "full" ); + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); + ege_select_one_action_set_icon_column( act, 2 ); + ege_select_one_action_set_icon_size( act, secondarySize ); + ege_select_one_action_set_tooltip_column( act, 1 ); + + gint mode = prefs->getInt("/tools/spray/mode", 1); + ege_select_one_action_set_active( act, mode ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_spray_mode_changed), holder ); + + g_object_set_data( G_OBJECT(holder), "spray_tool_mode", act); + } + + { /* Population */ + gchar const* labels[] = {_("(low population)"), 0, 0, 0, _("(default)"), 0, _("(high population)")}; + gdouble values[] = {5, 20, 35, 50, 70, 85, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "SprayPopulationAction", + _("Amount"), _("Amount:"), + _("Adjusts the number of items sprayed per click"), + "/tools/spray/population", 70, + GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-population", + 1, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_spray_population_value_changed, NULL /*unit tracker*/, 1, 0 ); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + g_object_set_data( holder, "spray_population", eact ); + } + + /* Use Pressure button */ + { + InkToggleAction* act = ink_toggle_action_new( "SprayPressureAction", + _("Pressure"), + _("Use the pressure of the input device to alter the amount of sprayed objects"), + INKSCAPE_ICON("draw-use-pressure"), + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/spray/usepressure"); + g_signal_connect(holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + + } + + { /* Rotation */ + gchar const* labels[] = {_("(default)"), 0, 0, 0, 0, 0, 0, _("(high rotation variation)")}; + gdouble values[] = {0, 10, 25, 35, 50, 60, 80, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "SprayRotationAction", + _("Rotation"), _("Rotation:"), + // xgettext:no-c-format + _("Variation of the rotation of the sprayed objects; 0% for the same rotation than the original object"), + "/tools/spray/rotation_variation", 0, + GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-rotation", + 0, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_spray_rotation_value_changed, NULL /*unit tracker*/, 1, 0 ); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + g_object_set_data( holder, "spray_rotation", eact ); + } + + { /* Scale */ + gchar const* labels[] = {_("(default)"), 0, 0, 0, 0, 0, 0, _("(high scale variation)")}; + gdouble values[] = {0, 10, 25, 35, 50, 60, 80, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "SprayScaleAction", + C_("Spray tool", "Scale"), C_("Spray tool", "Scale:"), + // xgettext:no-c-format + _("Variation in the scale of the sprayed objects; 0% for the same scale than the original object"), + "/tools/spray/scale_variation", 0, + GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-scale", + 0, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_spray_scale_value_changed, NULL /*unit tracker*/, 1, 0 ); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + g_object_set_data( holder, "spray_scale", eact ); + } + + + +} + + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/spray-toolbar.h b/src/widgets/spray-toolbar.h new file mode 100644 index 000000000..d1d5c7b4c --- /dev/null +++ b/src/widgets/spray-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_SPRAY_TOOLBAR_H +#define SEEN_SPRAY_TOOLBAR_H + +/** + * @file + * Spray aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_SELECT_TOOLBAR_H */ diff --git a/src/widgets/spw-utilities.cpp b/src/widgets/spw-utilities.cpp index f9c94dc47..9c0c8d7c6 100644 --- a/src/widgets/spw-utilities.cpp +++ b/src/widgets/spw-utilities.cpp @@ -2,7 +2,7 @@ * Inkscape Widget Utilities * * Authors: - * Bryce W. Harrington <brycehar@bryceharrington.com> + * Bryce W. Harrington <brycehar@bryceharrington.org> * bulia byak <buliabyak@users.sf.net> * * Copyright (C) 2003 Bryce W. Harrington @@ -17,13 +17,22 @@ #include <cstring> #include <string> +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + #include <gtkmm/box.h> #include <gtkmm/label.h> + +#if GTK_CHECK_VERSION(3,0,0) +#include <gtkmm/grid.h> +#else #include <gtkmm/table.h> +#endif #include "selection.h" -#include "helper/unit-menu.h" +#include "spw-utilities.h" #include <gtk/gtk.h> @@ -31,8 +40,11 @@ * Creates a label widget with the given text, at the given col, row * position in the table. */ -Gtk::Label * -spw_label(Gtk::Table *table, const gchar *label_text, int col, int row, Gtk::Widget* target) +#if GTK_CHECK_VERSION(3,0,0) +Gtk::Label * spw_label(Gtk::Grid *table, const gchar *label_text, int col, int row, Gtk::Widget* target) +#else +Gtk::Label * spw_label(Gtk::Table *table, const gchar *label_text, int col, int row, Gtk::Widget* target) +#endif { Gtk::Label *label_widget = new Gtk::Label(); g_assert(label_widget != NULL); @@ -47,7 +59,18 @@ spw_label(Gtk::Table *table, const gchar *label_text, int col, int row, Gtk::Wid } label_widget->set_alignment(1.0, 0.5); label_widget->show(); + +#if GTK_CHECK_VERSION(3,0,0) + label_widget->set_hexpand(); + label_widget->set_halign(Gtk::ALIGN_FILL); + label_widget->set_valign(Gtk::ALIGN_CENTER); + label_widget->set_margin_left(4); + label_widget->set_margin_right(4); + table->attach(*label_widget, col, row, 1, 1); +#else table->attach(*label_widget, col, col+1, row, row+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 4, 0); +#endif + return label_widget; } @@ -60,8 +83,19 @@ spw_label_old(GtkWidget *table, const gchar *label_text, int col, int row) g_assert(label_widget != NULL); gtk_misc_set_alignment (GTK_MISC (label_widget), 1.0, 0.5); gtk_widget_show (label_widget); - gtk_table_attach (GTK_TABLE (table), label_widget, col, col+1, row, row+1, + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(label_widget, 4); + gtk_widget_set_margin_right(label_widget, 4); + gtk_widget_set_hexpand(label_widget, TRUE); + gtk_widget_set_halign(label_widget, GTK_ALIGN_FILL); + gtk_widget_set_valign(label_widget, GTK_ALIGN_CENTER); + gtk_grid_attach(GTK_GRID(table), label_widget, col, row, 1, 1); +#else + gtk_table_attach(GTK_TABLE (table), label_widget, col, col+1, row, row+1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 4, 0); +#endif + return label_widget; } @@ -69,14 +103,26 @@ spw_label_old(GtkWidget *table, const gchar *label_text, int col, int row) * Creates a horizontal layout manager with 4-pixel spacing between children * and space for 'width' columns. */ -Gtk::HBox * -spw_hbox(Gtk::Table * table, int width, int col, int row) +#if GTK_CHECK_VERSION(3,0,0) +Gtk::HBox * spw_hbox(Gtk::Grid * table, int width, int col, int row) +#else +Gtk::HBox * spw_hbox(Gtk::Table * table, int width, int col, int row) +#endif { /* Create a new hbox with a 4-pixel spacing between children */ Gtk::HBox *hb = new Gtk::HBox(false, 4); g_assert(hb != NULL); hb->show(); + +#if GTK_CHECK_VERSION(3,0,0) + hb->set_hexpand(); + hb->set_halign(Gtk::ALIGN_FILL); + hb->set_valign(Gtk::ALIGN_CENTER); + table->attach(*hb, col, row, width, 1); +#else table->attach(*hb, col, col+width, row, row+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); +#endif + return hb; } @@ -116,16 +162,33 @@ spw_checkbutton(GtkWidget * dialog, GtkWidget * table, g_assert(dialog != NULL); g_assert(table != NULL); - GtkWidget *l = gtk_label_new (label); - gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5); - gtk_widget_show (l); + GtkWidget *l = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5); + gtk_widget_show (l); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_halign(l, GTK_ALIGN_FILL); + gtk_widget_set_hexpand(l, TRUE); + gtk_widget_set_valign(l, GTK_ALIGN_CENTER); + gtk_grid_attach(GTK_GRID(table), l, 0, row, 1, 1); +#else gtk_table_attach (GTK_TABLE (table), l, 0, 1, row, row+1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 0, 0); +#endif b = gtk_check_button_new (); gtk_widget_show (b); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_halign(b, GTK_ALIGN_FILL); + gtk_widget_set_hexpand(b, TRUE); + gtk_widget_set_valign(b, GTK_ALIGN_CENTER); + gtk_grid_attach(GTK_GRID(table), b, 1, row, 1, 1); +#else gtk_table_attach (GTK_TABLE (table), b, 1, 2, row, row+1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 0, 0); +#endif + g_object_set_data (G_OBJECT (b), "key", key); g_object_set_data (G_OBJECT (dialog), key, b); g_signal_connect (G_OBJECT (b), "toggled", cb, dialog); @@ -152,47 +215,22 @@ spw_dropdown(GtkWidget * dialog, GtkWidget * table, spw_label_old(table, label_text, 0, row); gtk_widget_show (selector); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_halign(selector, GTK_ALIGN_FILL); + gtk_widget_set_hexpand(selector, TRUE); + gtk_widget_set_valign(selector, GTK_ALIGN_CENTER); + gtk_grid_attach(GTK_GRID(table), selector, 1, row, 1, 1); +#else gtk_table_attach (GTK_TABLE (table), selector, 1, 2, row, row+1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 0, 0); +#endif + g_object_set_data (G_OBJECT (dialog), key, selector); return selector; } -/** - * Creates a unit selector widget, used for selecting whether one wishes - * to measure screen elements in millimeters, points, etc. This is a - * compound unit that includes a label as well as the dropdown selector. - */ -GtkWidget * -spw_unit_selector(GtkWidget * dialog, GtkWidget * table, - const gchar * label_text, gchar * key, int row, - GtkWidget * us, GCallback cb, bool can_be_negative) -{ - GtkWidget * sb; - GtkObject * a; - - g_assert(dialog != NULL); - g_assert(table != NULL); - g_assert(us != NULL); - - spw_label_old(table, label_text, 0, row); - - a = gtk_adjustment_new (0.0, can_be_negative?-1e6:0, 1e6, 1.0, 10.0, 10.0); - g_assert(a != NULL); - g_object_set_data (G_OBJECT (a), "key", key); - g_object_set_data (G_OBJECT (a), "unit_selector", us); - g_object_set_data (G_OBJECT (dialog), key, a); - sp_unit_selector_add_adjustment (SP_UNIT_SELECTOR (us), GTK_ADJUSTMENT (a)); - sb = gtk_spin_button_new (GTK_ADJUSTMENT (a), 1.0, 4); - g_assert(sb != NULL); - gtk_widget_show (sb); - gtk_table_attach (GTK_TABLE (table), sb, 1, 2, row, row+1, - (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)0, 0, 0); - g_signal_connect (G_OBJECT (a), "value_changed", cb, dialog); - return sb; -} - -void +static void sp_set_font_size_recursive (GtkWidget *w, gpointer font) { guint size = GPOINTER_TO_UINT (font); @@ -231,7 +269,7 @@ gpointer sp_search_by_data_recursive(GtkWidget *w, gpointer key) { gpointer r = NULL; - if (w && GTK_IS_OBJECT(w)) { + if (w && G_IS_OBJECT(w)) { r = g_object_get_data(G_OBJECT(w), (gchar *) key); } if (r) return r; @@ -253,9 +291,8 @@ gpointer sp_search_by_data_recursive(GtkWidget *w, gpointer key) GtkWidget *sp_search_by_value_recursive(GtkWidget *w, gchar *key, gchar *value) { gchar *r = NULL; - GtkWidget *child; - if (w && GTK_IS_OBJECT(w)) { + if (w && G_IS_OBJECT(w)) { r = (gchar *) g_object_get_data(G_OBJECT(w), key); } if (r && !strcmp (r, value)) return w; @@ -263,7 +300,7 @@ GtkWidget *sp_search_by_value_recursive(GtkWidget *w, gchar *key, gchar *value) if (GTK_IS_CONTAINER(w)) { GList *ch = gtk_container_get_children (GTK_CONTAINER(w)); for (GList *i = ch; i != NULL; i = i->next) { - child = sp_search_by_value_recursive(GTK_WIDGET(i->data), key, value); + GtkWidget *child = sp_search_by_value_recursive(GTK_WIDGET(i->data), key, value); if (child) return child; } } diff --git a/src/widgets/spw-utilities.h b/src/widgets/spw-utilities.h index 263abbcaf..31f29e026 100644 --- a/src/widgets/spw-utilities.h +++ b/src/widgets/spw-utilities.h @@ -5,7 +5,7 @@ * Inkscape Widget Utilities * * Author: - * Bryce W. Harrington <brycehar@bryceharrington.com> + * Bryce W. Harrington <brycehar@bryceharrington.org> * * Copyright (C) 2003 Bryce Harrington * @@ -20,18 +20,26 @@ namespace Gtk { class Label; + +#if GTK_CHECK_VERSION(3,0,0) + class Grid; +#else class Table; +#endif + class HBox; class Widget; } -Gtk::Label * -spw_label(Gtk::Table *table, gchar const *label_text, int col, int row, Gtk::Widget *target); -GtkWidget * -spw_label_old(GtkWidget *table, gchar const *label_text, int col, int row); +#if GTK_CHECK_VERSION(3,0,0) +Gtk::Label * spw_label(Gtk::Grid *table, gchar const *label_text, int col, int row, Gtk::Widget *target); +Gtk::HBox * spw_hbox(Gtk::Grid *table, int width, int col, int row); +#else +Gtk::Label * spw_label(Gtk::Table *table, gchar const *label_text, int col, int row, Gtk::Widget *target); +Gtk::HBox * spw_hbox(Gtk::Table *table, int width, int col, int row); +#endif -Gtk::HBox * -spw_hbox(Gtk::Table *table, int width, int col, int row); +GtkWidget * spw_label_old(GtkWidget *table, gchar const *label_text, int col, int row); GtkWidget * spw_vbox_checkbutton(GtkWidget *dialog, GtkWidget *table, @@ -48,11 +56,6 @@ spw_dropdown(GtkWidget *dialog, GtkWidget *table, GtkWidget *selector ); -GtkWidget * -spw_unit_selector(GtkWidget *dialog, GtkWidget *table, - gchar const *label, gchar *key, int row, - GtkWidget *us, GCallback cb, bool can_be_negative = false); - void sp_set_font_size (GtkWidget *w, guint font); void sp_set_font_size_smaller (GtkWidget *w); diff --git a/src/widgets/star-toolbar.cpp b/src/widgets/star-toolbar.cpp new file mode 100644 index 000000000..7a7d0dc71 --- /dev/null +++ b/src/widgets/star-toolbar.cpp @@ -0,0 +1,593 @@ +/** + * @file + * Star aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glibmm/i18n.h> + +#include "star-toolbar.h" +#include "desktop-handles.h" +#include "desktop.h" +#include "document-undo.h" +#include "ege-adjustment-action.h" +#include "ege-output-action.h" +#include "ege-select-one-action.h" +#include "ink-action.h" +#include "selection.h" +#include "sp-star.h" +#include "toolbox.h" +#include "ui/icon-names.h" +#include "ui/uxmanager.h" +#include "verbs.h" +#include "widgets/../preferences.h" +#include "xml/node-event-vector.h" +#include "xml/node.h" +#include "xml/repr.h" + +using Inkscape::UI::UXManager; +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; + + +//######################## +//## Star ## +//######################## + +static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge ) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( dataKludge, "desktop" )); + + if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { + // do not remember prefs if this call is initiated by an undo change, because undoing object + // creation sets bogus values to its attributes before it is deleted + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt("/tools/shapes/star/magnitude", + (gint)gtk_adjustment_get_value(adj)); + } + + // quit if run by the attr_changed listener + if (g_object_get_data( dataKludge, "freeze" )) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) ); + + bool modmade = false; + + Inkscape::Selection *selection = sp_desktop_selection(desktop); + GSList const *items = selection->itemList(); + for (; items != NULL; items = items->next) { + SPItem *item = reinterpret_cast<SPItem*>(items->data); + if (SP_IS_STAR(item)) { + Inkscape::XML::Node *repr = item->getRepr(); + sp_repr_set_int(repr,"sodipodi:sides", + (gint)gtk_adjustment_get_value(adj)); + double arg1 = 0.5; + sp_repr_get_double(repr, "sodipodi:arg1", &arg1); + sp_repr_set_svg_double(repr, "sodipodi:arg2", + (arg1 + M_PI / (gint)gtk_adjustment_get_value(adj))); + item->updateRepr(); + modmade = true; + } + } + if (modmade) { + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, + _("Star: Change number of corners")); + } + + g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge ) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( dataKludge, "desktop" )); + + if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { + if (!IS_NAN(gtk_adjustment_get_value(adj))) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/tools/shapes/star/proportion", + gtk_adjustment_get_value(adj)); + } + } + + // quit if run by the attr_changed listener + if (g_object_get_data( dataKludge, "freeze" )) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) ); + + bool modmade = false; + Inkscape::Selection *selection = sp_desktop_selection(desktop); + GSList const *items = selection->itemList(); + for (; items != NULL; items = items->next) { + SPItem *item = reinterpret_cast<SPItem *>(items->data); + if (SP_IS_STAR(item)) { + Inkscape::XML::Node *repr = item->getRepr(); + + gdouble r1 = 1.0; + gdouble r2 = 1.0; + sp_repr_get_double(repr, "sodipodi:r1", &r1); + sp_repr_get_double(repr, "sodipodi:r2", &r2); + if (r2 < r1) { + sp_repr_set_svg_double(repr, "sodipodi:r2", + r1*gtk_adjustment_get_value(adj)); + } else { + sp_repr_set_svg_double(repr, "sodipodi:r1", + r2*gtk_adjustment_get_value(adj)); + } + + item->updateRepr(); + modmade = true; + } + } + + if (modmade) { + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, + _("Star: Change spoke ratio")); + } + + g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge ) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( dataKludge, "desktop" )); + bool flat = ege_select_one_action_get_active( act ) == 0; + + if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool( "/tools/shapes/star/isflatsided", flat); + } + + // quit if run by the attr_changed listener + if (g_object_get_data( dataKludge, "freeze" )) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) ); + + Inkscape::Selection *selection = sp_desktop_selection(desktop); + GSList const *items = selection->itemList(); + GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) ); + bool modmade = false; + + if ( prop_action ) { + gtk_action_set_sensitive( prop_action, !flat ); + } + + for (; items != NULL; items = items->next) { + SPItem *item = reinterpret_cast<SPItem *>(items->data); + if (SP_IS_STAR(item)) { + Inkscape::XML::Node *repr = item->getRepr(); + repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" ); + item->updateRepr(); + modmade = true; + } + } + + if (modmade) { + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, + flat ? _("Make polygon") : _("Make star")); + } + + g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge ) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( dataKludge, "desktop" )); + + if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/tools/shapes/star/rounded", (gdouble) gtk_adjustment_get_value(adj)); + } + + // quit if run by the attr_changed listener + if (g_object_get_data( dataKludge, "freeze" )) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) ); + + bool modmade = false; + + Inkscape::Selection *selection = sp_desktop_selection(desktop); + GSList const *items = selection->itemList(); + for (; items != NULL; items = items->next) { + SPItem *item = reinterpret_cast<SPItem*>(items->data); + if (SP_IS_STAR(item)) { + Inkscape::XML::Node *repr = item->getRepr(); + sp_repr_set_svg_double(repr, "inkscape:rounded", + (gdouble) gtk_adjustment_get_value(adj)); + item->updateRepr(); + modmade = true; + } + } + if (modmade) { + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, + _("Star: Change rounding")); + } + + g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge ) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( dataKludge, "desktop" )); + + if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble("/tools/shapes/star/randomized", + (gdouble) gtk_adjustment_get_value(adj)); + } + + // quit if run by the attr_changed listener + if (g_object_get_data( dataKludge, "freeze" )) { + return; + } + + // in turn, prevent listener from responding + g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) ); + + bool modmade = false; + + Inkscape::Selection *selection = sp_desktop_selection(desktop); + GSList const *items = selection->itemList(); + for (; items != NULL; items = items->next) { + SPItem *item = reinterpret_cast<SPItem *>(items->data); + if (SP_IS_STAR(item)) { + Inkscape::XML::Node *repr = item->getRepr(); + sp_repr_set_svg_double(repr, "inkscape:randomized", + (gdouble) gtk_adjustment_get_value(adj)); + item->updateRepr(); + modmade = true; + } + } + if (modmade) { + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, + _("Star: Change randomization")); + } + + g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); +} + + +static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name, + gchar const * /*old_value*/, gchar const * /*new_value*/, + bool /*is_interactive*/, gpointer data) +{ + GtkWidget *tbl = GTK_WIDGET(data); + + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + + // in turn, prevent callbacks from responding + g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE)); + + GtkAdjustment *adj = 0; + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool isFlatSided = prefs->getBool("/tools/shapes/star/isflatsided", true); + + if (!strcmp(name, "inkscape:randomized")) { + adj = GTK_ADJUSTMENT( g_object_get_data(G_OBJECT(tbl), "randomized") ); + double randomized = 0.0; + sp_repr_get_double(repr, "inkscape:randomized", &randomized); + gtk_adjustment_set_value(adj, randomized); + } else if (!strcmp(name, "inkscape:rounded")) { + adj = GTK_ADJUSTMENT( g_object_get_data(G_OBJECT(tbl), "rounded") ); + double rounded = 0.0; + sp_repr_get_double(repr, "inkscape:rounded", &rounded); + gtk_adjustment_set_value(adj, rounded); + } else if (!strcmp(name, "inkscape:flatsided")) { + GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") ); + char const *flatsides = repr->attribute("inkscape:flatsided"); + EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) ); + if ( flatsides && !strcmp(flatsides,"false") ) { + ege_select_one_action_set_active( flat_action, 1 ); + gtk_action_set_sensitive( prop_action, TRUE ); + } else { + ege_select_one_action_set_active( flat_action, 0 ); + gtk_action_set_sensitive( prop_action, FALSE ); + } + } else if ((!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) && (!isFlatSided) ) { + adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "proportion")); + gdouble r1 = 1.0; + gdouble r2 = 1.0; + sp_repr_get_double(repr, "sodipodi:r1", &r1); + sp_repr_get_double(repr, "sodipodi:r2", &r2); + if (r2 < r1) { + gtk_adjustment_set_value(adj, r2/r1); + } else { + gtk_adjustment_set_value(adj, r1/r2); + } + } else if (!strcmp(name, "sodipodi:sides")) { + adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "magnitude")); + int sides = 0; + sp_repr_get_int(repr, "sodipodi:sides", &sides); + gtk_adjustment_set_value(adj, sides); + } + + g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE)); +} + + +static Inkscape::XML::NodeEventVector star_tb_repr_events = +{ + NULL, /* child_added */ + NULL, /* child_removed */ + star_tb_event_attr_changed, + NULL, /* content_changed */ + NULL /* order_changed */ +}; + + +/** + * \param selection Should not be NULL. + */ +static void +sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) +{ + int n_selected = 0; + Inkscape::XML::Node *repr = NULL; + + purge_repr_listener( tbl, tbl ); + + for (GSList const *items = selection->itemList(); + items != NULL; + items = items->next) + { + SPItem* item = reinterpret_cast<SPItem *>(items->data); + if (SP_IS_STAR(item)) { + n_selected++; + repr = item->getRepr(); + } + } + + EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) ); + + if (n_selected == 0) { + g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL ); + } else if (n_selected == 1) { + g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); + + if (repr) { + g_object_set_data( tbl, "repr", repr ); + Inkscape::GC::anchor(repr); + sp_repr_add_listener(repr, &star_tb_repr_events, tbl); + sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl); + } + } else { + // FIXME: implement averaging of all parameters for multiple selected stars + //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>")); + //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>")); + } +} + + +static void sp_stb_defaults( GtkWidget * /*widget*/, GObject *dataKludge ) +{ + // FIXME: in this and all other _default functions, set some flag telling the value_changed + // callbacks to lump all the changes for all selected objects in one undo step + + GtkAdjustment *adj = 0; + + // fixme: make settable in prefs! + gint mag = 5; + gdouble prop = 0.5; + gboolean flat = FALSE; + gdouble randomized = 0; + gdouble rounded = 0; + + EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) ); + ege_select_one_action_set_active( flat_action, flat ? 0 : 1 ); + + GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) ); + gtk_action_set_sensitive( sb2, !flat ); + + adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) ); + gtk_adjustment_set_value(adj, mag); + gtk_adjustment_value_changed(adj); + + adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) ); + gtk_adjustment_set_value(adj, prop); + gtk_adjustment_value_changed(adj); + + adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) ); + gtk_adjustment_set_value(adj, rounded); + gtk_adjustment_value_changed(adj); + + adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) ); + gtk_adjustment_set_value(adj, randomized); + gtk_adjustment_value_changed(adj); +} + + +void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); + + { + EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 ); + ege_output_action_set_use_markup( act, TRUE ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_object_set_data( holder, "mode_action", act ); + } + + { + EgeAdjustmentAction* eact = 0; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool isFlatSided = prefs->getBool("/tools/shapes/star/isflatsided", true); + + /* Flatsided checkbox */ + { + GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); + + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Polygon"), + 1, _("Regular polygon (with one handle) instead of a star"), + 2, INKSCAPE_ICON("draw-polygon"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Star"), + 1, _("Star instead of a regular polygon (with one handle)"), + 2, INKSCAPE_ICON("draw-star"), + -1 ); + + EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", (""), (""), NULL, GTK_TREE_MODEL(model) ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "flat_action", act ); + + ege_select_one_action_set_appearance( act, "full" ); + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); + ege_select_one_action_set_icon_column( act, 2 ); + ege_select_one_action_set_icon_size( act, secondarySize ); + ege_select_one_action_set_tooltip_column( act, 1 ); + + ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder); + } + + /* Magnitude */ + { + gchar const* labels[] = {_("triangle/tri-star"), _("square/quad-star"), _("pentagon/five-pointed star"), _("hexagon/six-pointed star"), 0, 0, 0, 0, 0}; + gdouble values[] = {3, 4, 5, 6, 7, 8, 10, 12, 20}; + eact = create_adjustment_action( "MagnitudeAction", + _("Corners"), _("Corners:"), _("Number of corners of a polygon or star"), + "/tools/shapes/star/magnitude", 3, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 3, 1024, 1, 5, + labels, values, G_N_ELEMENTS(labels), + sp_stb_magnitude_value_changed, NULL /*unit tracker*/, + 1.0, 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + /* Spoke ratio */ + { + gchar const* labels[] = {_("thin-ray star"), 0, _("pentagram"), _("hexagram"), _("heptagram"), _("octagram"), _("regular polygon")}; + gdouble values[] = {0.01, 0.2, 0.382, 0.577, 0.692, 0.765, 1}; + eact = create_adjustment_action( "SpokeAction", + _("Spoke ratio"), _("Spoke ratio:"), + // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle. + // Base radius is the same for the closest handle. + _("Base radius to tip radius ratio"), + "/tools/shapes/star/proportion", 0.5, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0.01, 1.0, 0.01, 0.1, + labels, values, G_N_ELEMENTS(labels), + sp_stb_proportion_value_changed ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + g_object_set_data( holder, "prop_action", eact ); + } + + if ( !isFlatSided ) { + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } else { + gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); + } + + /* Roundedness */ + { + gchar const* labels[] = {_("stretched"), _("twisted"), _("slightly pinched"), _("NOT rounded"), _("slightly rounded"), _("visibly rounded"), _("well rounded"), _("amply rounded"), 0, _("stretched"), _("blown up")}; + gdouble values[] = {-1, -0.2, -0.03, 0, 0.05, 0.1, 0.2, 0.3, 0.5, 1, 10}; + eact = create_adjustment_action( "RoundednessAction", + _("Rounded"), _("Rounded:"), _("How much rounded are the corners (0 for sharp)"), + "/tools/shapes/star/rounded", 0.0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + -10.0, 10.0, 0.01, 0.1, + labels, values, G_N_ELEMENTS(labels), + sp_stb_rounded_value_changed ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + /* Randomization */ + { + gchar const* labels[] = {_("NOT randomized"), _("slightly irregular"), _("visibly randomized"), _("strongly randomized"), _("blown up")}; + gdouble values[] = {0, 0.01, 0.1, 0.5, 10}; + eact = create_adjustment_action( "RandomizationAction", + _("Randomized"), _("Randomized:"), _("Scatter randomly the corners and angles"), + "/tools/shapes/star/randomized", 0.0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + -10.0, 10.0, 0.001, 0.01, + labels, values, G_N_ELEMENTS(labels), + sp_stb_randomized_value_changed, NULL /*unit tracker*/, 0.1, 3 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + } + + { + /* Reset */ + { + InkAction* inky = ink_action_new( "StarResetAction", + _("Defaults"), + _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), + INKSCAPE_ICON("edit-clear"), + Inkscape::ICON_SIZE_SMALL_TOOLBAR); + g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_stb_defaults), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); + gtk_action_set_sensitive( GTK_ACTION(inky), TRUE ); + } + } + + sigc::connection *connection = new sigc::connection( + sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), holder)) + ); + g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection ); + g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); +} + + + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/star-toolbar.h b/src/widgets/star-toolbar.h new file mode 100644 index 000000000..aa0db785c --- /dev/null +++ b/src/widgets/star-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_STAR_TOOLBAR_H +#define SEEN_STAR_TOOLBAR_H + +/** + * @file + * Star aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_SELECT_TOOLBAR_H */ diff --git a/src/widgets/stroke-marker-selector.cpp b/src/widgets/stroke-marker-selector.cpp index 9b2c3bb42..00b6b5c91 100644 --- a/src/widgets/stroke-marker-selector.cpp +++ b/src/widgets/stroke-marker-selector.cpp @@ -36,35 +36,39 @@ #include "sp-root.h" #include "ui/cache/svg_preview_cache.h" #include "helper/stock-items.h" +#include "gradient-vector.h" +#include <gtkmm/icontheme.h> #include <gtkmm/adjustment.h> #include "ui/widget/spinbutton.h" +#include "stroke-style.h" +#include "gradient-chemistry.h" static Inkscape::UI::Cache::SvgPreview svg_preview_cache; -MarkerComboBox::MarkerComboBox(gchar const *id) : +MarkerComboBox::MarkerComboBox(gchar const *id, int l) : Gtk::ComboBox(), combo_id(id), + loc(l), updating(false), - is_history(false) + markerCount(0) { marker_store = Gtk::ListStore::create(marker_columns); set_model(marker_store); pack_start(image_renderer, false); - pack_end(label_renderer, true); - label_renderer.set_padding(5, 0); - image_renderer.set_padding(5, 0); - set_cell_data_func(label_renderer, sigc::mem_fun(*this, &MarkerComboBox::prepareLabelRenderer)); set_cell_data_func(image_renderer, sigc::mem_fun(*this, &MarkerComboBox::prepareImageRenderer)); gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(gobj()), MarkerComboBox::separator_cb, NULL, NULL); - empty_image = new Gtk::Image(); + empty_image = new Gtk::Image( Glib::wrap( + sp_pixbuf_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("no-marker") ) ) ); sandbox = ink_markers_preview_doc (); desktop = inkscape_active_desktop(); doc = sp_desktop_document(desktop); + modified_connection = doc->getDefs()->connectModified( sigc::hide(sigc::hide(sigc::bind(sigc::ptr_fun(&MarkerComboBox::handleDefsModified), this))) ); + init_combo(); show(); @@ -73,6 +77,62 @@ MarkerComboBox::MarkerComboBox(gchar const *id) : MarkerComboBox::~MarkerComboBox() { delete combo_id; delete sandbox; + + if (doc) { + modified_connection.disconnect(); + } +} + +void MarkerComboBox::setDesktop(SPDesktop *desktop) +{ + if (this->desktop != desktop) { + + if (doc) { + modified_connection.disconnect(); + } + + this->desktop = desktop; + doc = sp_desktop_document(desktop); + + if (doc) { + modified_connection = doc->getDefs()->connectModified( sigc::hide(sigc::hide(sigc::bind(sigc::ptr_fun(&MarkerComboBox::handleDefsModified), this))) ); + } + + refreshHistory(); + } +} + +void +MarkerComboBox::handleDefsModified(MarkerComboBox *self) +{ + self->refreshHistory(); +} + +void +MarkerComboBox::refreshHistory() +{ + if (updating) + return; + + updating = true; + + GSList *ml = get_marker_list(doc); + + /* + * Seems to be no way to get notified of changes just to markers, + * so listen to changes in all defs and check if the number of markers has changed here + * to avoid unnecessary refreshes when things like gradients change + */ + if (markerCount != g_slist_length(ml)) { + const char *active = get_active()->get_value(marker_columns.marker); + sp_marker_list_from_doc(doc, true); + set_selected(active); + markerCount = g_slist_length(ml); + } + + g_slist_free (ml); + + updating = false; } /** @@ -81,12 +141,22 @@ MarkerComboBox::~MarkerComboBox() { void MarkerComboBox::init_combo() { - updating = false; + if (updating) + return; + + const gchar *active = NULL; + if (get_active()) { + active = get_active()->get_value(marker_columns.marker); + } if (!doc) { Gtk::TreeModel::Row row = *(marker_store->append()); row[marker_columns.label] = _("No document selected"); + row[marker_columns.marker] = g_strdup("None"); row[marker_columns.image] = NULL; + row[marker_columns.stock] = false; + row[marker_columns.history] = false; + row[marker_columns.separator] = false; set_sensitive(false); set_current(NULL); return; @@ -94,11 +164,17 @@ MarkerComboBox::init_combo() static SPDocument *markers_doc = NULL; - // add "None" - Gtk::TreeModel::Row row = *(marker_store->append()); - row[marker_columns.label] = _("None"); - row[marker_columns.marker] = g_strdup("none"); - row[marker_columns.image] = NULL; + // add separator + Gtk::TreeModel::Row row_sep = *(marker_store->append()); + row_sep[marker_columns.label] = "Separator"; + row_sep[marker_columns.marker] = g_strdup("None"); + row_sep[marker_columns.image] = NULL; + row_sep[marker_columns.stock] = false; + row_sep[marker_columns.history] = false; + row_sep[marker_columns.separator] = true; + + // load markers from the current doc + sp_marker_list_from_doc(doc, true); // find and load markers.svg if (markers_doc == NULL) { @@ -109,27 +185,17 @@ MarkerComboBox::init_combo() g_free(markers_source); } - // suck in from current doc - is_history = true; - sp_marker_list_from_doc(doc); - is_history = false; - - // add separator - Gtk::TreeModel::Row row_sep = *(marker_store->append()); - row_sep[marker_columns.label] = "Separator"; - row_sep[marker_columns.isseparator] = true; - row_sep[marker_columns.image] = NULL; - - // suck in from markers.svg + // load markers from markers.svg if (markers_doc) { doc->ensureUpToDate(); - sp_marker_list_from_doc(markers_doc); + sp_marker_list_from_doc(markers_doc, false); } set_sensitive(true); /* Set history */ - set_current(NULL); + set_selected(active); + } /** @@ -140,20 +206,8 @@ void MarkerComboBox::set_current(SPObject *marker) updating = true; if (marker != NULL) { - bool mark_is_stock = false; - if (marker->getRepr()->attribute("inkscape:stockid")) { - mark_is_stock = true; - } - - gchar *markname = 0; - if (mark_is_stock) { - markname = g_strdup(marker->getRepr()->attribute("inkscape:stockid")); - } else { - markname = g_strdup(marker->getRepr()->attribute("id")); - } - + gchar *markname = g_strdup(marker->getRepr()->attribute("id")); set_selected(markname); - g_free (markname); } else { @@ -177,7 +231,7 @@ const gchar * MarkerComboBox::get_active_marker_uri() gchar const *marker = ""; if (strcmp(markid, "none")) { - bool stockid = get_active()->get_value(marker_columns.isstock); + bool stockid = get_active()->get_value(marker_columns.stock); gchar *markurn; if (stockid) @@ -188,7 +242,7 @@ const gchar * MarkerComboBox::get_active_marker_uri() { markurn = g_strdup(markid); } - SPObject *mark = get_stock_item(markurn); + SPObject *mark = get_stock_item(markurn, stockid); g_free(markurn); if (mark) { Inkscape::XML::Node *repr = mark->getRepr(); @@ -201,13 +255,21 @@ const gchar * MarkerComboBox::get_active_marker_uri() return marker; } - void MarkerComboBox::set_active_history() { - set_selected(get_active()->get_value(marker_columns.marker)); + + const gchar *markid = get_active()->get_value(marker_columns.marker); + + // If forked from a stockid, add the stockid + SPObject const *marker = doc->getObjectById(markid); + if (marker && marker->getRepr()->attribute("inkscape:stockid")) { + markid = marker->getRepr()->attribute("inkscape:stockid"); + } + + set_selected(markid); } -void MarkerComboBox::set_selected(const gchar *name) { +void MarkerComboBox::set_selected(const gchar *name, gboolean retry/*=true*/) { if (!name) { set_active(0); @@ -220,42 +282,23 @@ void MarkerComboBox::set_selected(const gchar *name) { if (row[marker_columns.marker] && !strcmp(row[marker_columns.marker], name)) { set_active(iter); - if (strcmp(name, "none")) - set_history(row); return; } } -} -void MarkerComboBox::set_history(Gtk::TreeModel::Row match_row) { - - if (!match_row) { - return; - } - - for(Gtk::TreeIter iter = marker_store->children().begin(); - iter != marker_store->children().end(); ++iter) { - Gtk::TreeModel::Row row = (*iter); - if (row[marker_columns.history] && - !strcmp(row[marker_columns.marker], match_row[marker_columns.marker])) { - return; - } + // Didn't find it in the list, try refreshing from the doc + if (retry) { + sp_marker_list_from_doc(doc, true); + set_selected(name, false); } - - // Add a new row to the history - Gtk::TreeModel::Row row = *(marker_store->insert_after(marker_store->children().begin())); - row[marker_columns.marker] = g_strdup(match_row.get_value(marker_columns.marker)); - row[marker_columns.label] = match_row.get_value(marker_columns.label); - row[marker_columns.isstock] = match_row.get_value(marker_columns.isstock); - row[marker_columns.image] = match_row.get_value(marker_columns.image); - row[marker_columns.history] = true; } + /** * Pick up all markers from source, except those that are in * current_doc (if non-NULL), and add items to the combo. */ -void MarkerComboBox::sp_marker_list_from_doc(SPDocument *source) +void MarkerComboBox::sp_marker_list_from_doc(SPDocument *source, gboolean history) { GSList *ml = get_marker_list(source); GSList *clean_ml = NULL; @@ -267,10 +310,14 @@ void MarkerComboBox::sp_marker_list_from_doc(SPDocument *source) // Add to the list of markers we really do wish to show clean_ml = g_slist_prepend (clean_ml, ml->data); } - add_markers(clean_ml, source); + + remove_markers(history); // Seem to need to remove 2x + remove_markers(history); + add_markers(clean_ml, source, history); g_slist_free (ml); g_slist_free (clean_ml); + } /** @@ -284,6 +331,10 @@ GSList *MarkerComboBox::get_marker_list (SPDocument *source) GSList *ml = NULL; SPDefs *defs = source->getDefs(); + if (!defs) { + return NULL; + } + for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) { if (SP_IS_MARKER(child)) { @@ -294,37 +345,115 @@ GSList *MarkerComboBox::get_marker_list (SPDocument *source) } /** - * Adds previews of markers in marker_list to the combo + * Remove history or non-history markers from the combo + */ +void MarkerComboBox::remove_markers (gboolean history) +{ + // Having the model set causes assertions when erasing rows, temporarily disconnect + unset_model(); + for(Gtk::TreeIter iter = marker_store->children().begin(); + iter != marker_store->children().end(); ++iter) { + Gtk::TreeModel::Row row = (*iter); + if (row[marker_columns.history] == history && row[marker_columns.separator] == false) { + marker_store->erase(iter); + iter = marker_store->children().begin(); + } + } + + set_model(marker_store); +} + +/** + * Adds markers in marker_list to the combo */ -void MarkerComboBox::add_markers (GSList *marker_list, SPDocument *source) +void MarkerComboBox::add_markers (GSList *marker_list, SPDocument *source, gboolean history) { // Do this here, outside of loop, to speed up preview generation: Inkscape::Drawing drawing; unsigned const visionkey = SPItem::display_key_new(1); drawing.setRoot(sandbox->getRoot()->invoke_show(drawing, visionkey, SP_ITEM_SHOW_DISPLAY)); + // Find the separator, + Gtk::TreeIter sep_iter; + for(Gtk::TreeIter iter = marker_store->children().begin(); + iter != marker_store->children().end(); ++iter) { + Gtk::TreeModel::Row row = (*iter); + if (row[marker_columns.separator]) { + sep_iter = iter; + } + } + + if (history) { + // add "None" + Gtk::TreeModel::Row row = *(marker_store->prepend()); + row[marker_columns.label] = _("None"); + row[marker_columns.stock] = false; + row[marker_columns.marker] = g_strdup("None"); + row[marker_columns.image] = NULL; + row[marker_columns.history] = true; + row[marker_columns.separator] = false; + } for (; marker_list != NULL; marker_list = marker_list->next) { Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(marker_list->data)->getRepr(); - bool isstock = (repr->attribute("inkscape:stockid")); - gchar const *markid = repr->attribute("id"); + gchar const *markid = repr->attribute("inkscape:stockid") ? repr->attribute("inkscape:stockid") : repr->attribute("id"); // generate preview - Gtk::Image *prv = create_marker_image (22, markid, source, drawing, visionkey); + Gtk::Image *prv = create_marker_image (22, repr->attribute("id"), source, drawing, visionkey); prv->show(); - Gtk::TreeModel::Row row = *(marker_store->append()); - row[marker_columns.label] = g_strdup(markid); - row[marker_columns.marker] = g_strdup(markid); - row[marker_columns.isstock] = isstock; + // Add history before separator, others after + Gtk::TreeModel::Row row; + if (history) + row = *(marker_store->insert(sep_iter)); + else + row = *(marker_store->append()); + + row[marker_columns.label] = gr_ellipsize_text(markid, 20); + // Non "stock" markers can also have "inkscape:stockid" (when using extension ColorMarkers), + // So use !is_history instead to determine is it is "stock" (ie in the markers.svg file) + row[marker_columns.stock] = !history; + row[marker_columns.marker] = repr->attribute("id"); row[marker_columns.image] = prv; - row[marker_columns.history] = is_history; + row[marker_columns.history] = history; + row[marker_columns.separator] = false; } sandbox->getRoot()->invoke_hide(visionkey); } +/* + * Remove from the cache and recreate a marker image + */ +void +MarkerComboBox::update_marker_image(gchar const *mname) +{ + gchar *cache_name = g_strconcat(combo_id, mname, NULL); + Glib::ustring key = svg_preview_cache.cache_key(doc->getURI(), cache_name, 22); + g_free (cache_name); + svg_preview_cache.remove_preview_from_cache(key); + + Inkscape::Drawing drawing; + unsigned const visionkey = SPItem::display_key_new(1); + drawing.setRoot(sandbox->getRoot()->invoke_show(drawing, visionkey, SP_ITEM_SHOW_DISPLAY)); + Gtk::Image *prv = create_marker_image(22, mname, doc, drawing, visionkey); + if (prv) { + prv->show(); + } + sandbox->getRoot()->invoke_hide(visionkey); + + for(Gtk::TreeIter iter = marker_store->children().begin(); + iter != marker_store->children().end(); ++iter) { + Gtk::TreeModel::Row row = (*iter); + if (row[marker_columns.marker] && row[marker_columns.history] && + !strcmp(row[marker_columns.marker], mname)) { + row[marker_columns.image] = prv; + return; + } + } + +} /** * Creates a copy of the marker named mname, determines its visible and renderable * area in the bounding box, and then renders it. This allows us to fill in @@ -357,6 +486,38 @@ MarkerComboBox::create_marker_image(unsigned psize, gchar const *mname, Inkscape::GC::release(mrepr); + // If the marker color is a url link to a pattern or gradient copy that too + SPObject *mk = source->getObjectById(mname); + SPCSSAttr *css_marker = sp_css_attr_from_object(mk->firstChild(), SP_STYLE_FLAG_ALWAYS); + //const char *mfill = sp_repr_css_property(css_marker, "fill", "none"); + const char *mstroke = sp_repr_css_property(css_marker, "fill", "none"); + + if (!strncmp (mstroke, "url(", 4)) { + SPObject *linkObj = getMarkerObj(mstroke, source); + if (linkObj) { + Inkscape::XML::Node *grepr = linkObj->getRepr()->duplicate(xml_doc); + SPObject *oldmarker = sandbox->getObjectById(linkObj->getId()); + if (oldmarker) { + oldmarker->deleteObject(false); + } + defsrepr->appendChild(grepr); + Inkscape::GC::release(grepr); + + if (SP_IS_GRADIENT(linkObj)) { + SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (SP_GRADIENT(linkObj), false); + if (vector) { + Inkscape::XML::Node *grepr = vector->getRepr()->duplicate(xml_doc); + SPObject *oldmarker = sandbox->getObjectById(vector->getId()); + if (oldmarker) { + oldmarker->deleteObject(false); + } + defsrepr->appendChild(grepr); + Inkscape::GC::release(grepr); + } + } + } + } + // Uncomment this to get the sandbox documents saved (useful for debugging) //FILE *fp = fopen (g_strconcat(combo_id, mname, ".svg", NULL), "w"); //sp_repr_save_stream(sandbox->getReprDoc(), fp); @@ -383,24 +544,19 @@ MarkerComboBox::create_marker_image(unsigned psize, gchar const *mname, gchar *cache_name = g_strconcat(combo_id, mname, NULL); Glib::ustring key = svg_preview_cache.cache_key(source->getURI(), cache_name, psize); g_free (cache_name); - Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(svg_preview_cache.get_preview_from_cache(key)); + GdkPixbuf *pixbuf = svg_preview_cache.get_preview_from_cache(key); // no ref created if (!pixbuf) { - pixbuf = Glib::wrap(render_pixbuf(drawing, 0.8, *dbox, psize)); - svg_preview_cache.set_preview_in_cache(key, pixbuf->gobj()); + pixbuf = render_pixbuf(drawing, 0.8, *dbox, psize); + svg_preview_cache.set_preview_in_cache(key, pixbuf); + g_object_unref(pixbuf); // reference is held by svg_preview_cache } // Create widget - Gtk::Image *pb = new Gtk::Image(pixbuf); - + Gtk::Image *pb = Glib::wrap(GTK_IMAGE(gtk_image_new_from_pixbuf(pixbuf))); return pb; } -void MarkerComboBox::prepareLabelRenderer( Gtk::TreeModel::const_iterator const &row ) { - Glib::ustring name=(*row)[marker_columns.label]; - label_renderer.property_markup() = name.c_str(); -} - void MarkerComboBox::prepareImageRenderer( Gtk::TreeModel::const_iterator const &row ) { Gtk::Image *image = (*row)[marker_columns.image]; @@ -413,7 +569,7 @@ void MarkerComboBox::prepareImageRenderer( Gtk::TreeModel::const_iterator const gboolean MarkerComboBox::separator_cb (GtkTreeModel *model, GtkTreeIter *iter, gpointer /*data*/) { gboolean sep = FALSE; - gtk_tree_model_get(model, iter, 5, &sep, -1); + gtk_tree_model_get(model, iter, 4, &sep, -1); return sep; } diff --git a/src/widgets/stroke-marker-selector.h b/src/widgets/stroke-marker-selector.h index 4365b7e2a..27ac76d6f 100644 --- a/src/widgets/stroke-marker-selector.h +++ b/src/widgets/stroke-marker-selector.h @@ -10,12 +10,21 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + #include <gtkmm/box.h> #include <gtkmm/combobox.h> #include <gtkmm/liststore.h> #include <sigc++/signal.h> +#include "desktop.h" #include "document.h" #include "inkscape.h" #include "display/drawing.h" @@ -31,51 +40,57 @@ class Adjustment; class MarkerComboBox : public Gtk::ComboBox { public: - MarkerComboBox(gchar const *id); + MarkerComboBox(gchar const *id, int loc); ~MarkerComboBox(); + void setDesktop(SPDesktop *desktop); + sigc::signal<void> changed_signal; void set_current(SPObject *marker); void set_active_history(); - void set_selected(const gchar *name); + void set_selected(const gchar *name, gboolean retry=true); const gchar *get_active_marker_uri(); bool update() { return updating; }; gchar const *get_id() { return combo_id; }; + void update_marker_image(gchar const *mname); + int get_loc() { return loc; }; private: + Glib::RefPtr<Gtk::ListStore> marker_store; gchar const *combo_id; + int loc; bool updating; - bool is_history; + guint markerCount; SPDesktop *desktop; SPDocument *doc; SPDocument *sandbox; Gtk::Image *empty_image; - Gtk::CellRendererText label_renderer; Gtk::CellRendererPixbuf image_renderer; class MarkerColumns : public Gtk::TreeModel::ColumnRecord { public: Gtk::TreeModelColumn<Glib::ustring> label; Gtk::TreeModelColumn<const gchar *> marker; // ustring doesnt work here on windows due to unicode - Gtk::TreeModelColumn<bool> isstock; + Gtk::TreeModelColumn<gboolean> stock; Gtk::TreeModelColumn<Gtk::Image *> image; - Gtk::TreeModelColumn<bool> history; - Gtk::TreeModelColumn<bool> isseparator; + Gtk::TreeModelColumn<gboolean> history; + Gtk::TreeModelColumn<gboolean> separator; MarkerColumns() { - add(label); add(marker); add(isstock); add(image); add(history); add(isseparator); + add(label); add(stock); add(marker); add(history); add(separator); add(image); } }; MarkerColumns marker_columns; void init_combo(); void set_history(Gtk::TreeModel::Row match_row); - void sp_marker_list_from_doc(SPDocument *source); + void sp_marker_list_from_doc(SPDocument *source, gboolean history); GSList *get_marker_list (SPDocument *source); - void add_markers (GSList *marker_list, SPDocument *source); + void add_markers (GSList *marker_list, SPDocument *source, gboolean history); + void remove_markers (gboolean history); SPDocument *ink_markers_preview_doc (); Gtk::Image * create_marker_image(unsigned psize, gchar const *mname, SPDocument *source, Inkscape::Drawing &drawing, unsigned /*visionkey*/); @@ -83,11 +98,14 @@ private: /* * Callbacks for drawing the combo box */ - void prepareLabelRenderer( Gtk::TreeModel::const_iterator const &row ); void prepareImageRenderer( Gtk::TreeModel::const_iterator const &row ); static gboolean separator_cb (GtkTreeModel *model, GtkTreeIter *iter, gpointer data); + static void handleDefsModified(MarkerComboBox *self); + + void refreshHistory(); + sigc::connection modified_connection; }; #endif // SEEN_SP_MARKER_SELECTOR_NEW_H diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index 90bd62847..9567f81ba 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -17,308 +17,163 @@ #define noSP_SS_VERBOSE -#include "widgets/dash-selector.h" -#include <gtkmm/radiobutton.h> -#include <gtkmm/table.h> -#include <glibmm/i18n.h> - -#include "desktop-handles.h" -#include "desktop-style.h" -#include "dialogs/dialog-events.h" -#include "display/canvas-bpath.h" // for SP_STROKE_LINEJOIN_* -#include "display/drawing.h" -#include "document-private.h" -#include "document-undo.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/icon.h" -#include "widgets/paint-selector.h" -#include "widgets/sp-widget.h" -#include "widgets/spw-utilities.h" -#include "ui/widget/spinbutton.h" -#include "xml/repr.h" - #include "stroke-style.h" -#include "stroke-marker-selector.h" -#include "fill-style.h" // to get sp_fill_style_widget_set_desktop -#include "fill-n-stroke-factory.h" - -#include "verbs.h" +#include "../gradient-chemistry.h" +#include "sp-gradient.h" +#include "sp-stop.h" +#include "svg/svg-color.h" +#include "util/units.h" +#include "ui/widget/unit-menu.h" +#include "desktop-widget.h" using Inkscape::DocumentUndo; +using Inkscape::Util::unit_table; - -static MarkerComboBox *start_marker_combobox = NULL; -static MarkerComboBox *mid_marker_combobox = NULL; -static MarkerComboBox *end_marker_combobox = NULL; - -sigc::connection start_marker_connection; -sigc::connection mid_marker_connection; -sigc::connection end_marker_connection; - -static SPObject *ink_extract_marker_name(gchar const *n, SPDocument *doc); -static void ink_markers_combo_update(Gtk::Container* spw, SPMarkerLoc const which); - +/** + * Creates a new widget for the line stroke paint. + */ Gtk::Widget *sp_stroke_style_paint_widget_new(void) { return Inkscape::Widgets::createStyleWidget( STROKE ); } -void sp_stroke_style_widget_set_desktop(Gtk::Widget *widget, SPDesktop *desktop) -{ - sp_fill_style_widget_set_desktop(widget, desktop); -} - -/* Line */ - -static void sp_stroke_style_line_selection_modified(SPWidget *spw, Inkscape::Selection *selection, guint flags, gpointer data); -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_combo(Gtk::Container *spw, GSList const *objects); - - /** - * Helper function for creating radio buttons. This should probably be re-thought out - * when reimplementing this with Gtkmm. + * Creates a new widget for the line stroke style. */ -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) +Gtk::Widget *sp_stroke_style_line_widget_new(void) { - g_assert(icon != NULL); - g_assert(hb != NULL); - g_assert(spw != NULL); + return Inkscape::Widgets::createStrokeStyleWidget(); +} - if (tb == NULL) { - tb = new Gtk::RadioButton(); - } else { - Gtk::RadioButtonGroup grp = tb->get_group(); - tb = new Gtk::RadioButton(grp); +void sp_stroke_style_widget_set_desktop(Gtk::Widget *widget, SPDesktop *desktop) +{ + Inkscape::StrokeStyle *ss = dynamic_cast<Inkscape::StrokeStyle*>(widget); + if (ss) { + ss->setDesktop(desktop); } - - 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; - } + /** - * Handles when user selects one of the markers from the marker combobox. - * Gets the marker uri string and applies it to all selected - * items in the current desktop. + * 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 void -sp_marker_select(MarkerComboBox *marker_combo, Gtk::Container *spw, SPMarkerLoc const which) +SPObject* getMarkerObj(gchar const *n, SPDocument *doc) { - if (spw->get_data("update")) { - return; + gchar const *p = n; + while (*p != '\0' && *p != '#') { + p++; } - SPDesktop *desktop = inkscape_active_desktop(); - SPDocument *document = sp_desktop_document(desktop); - if (!document) { - return; + if (*p == '\0' || p[1] == '\0') { + return NULL; } - /* Get Marker */ - gchar const *marker = marker_combo->get_active_marker_uri(); - - - SPCSSAttr *css = sp_repr_css_attr_new(); - gchar const *combo_id = marker_combo->get_id(); - sp_repr_css_set_property(css, combo_id, marker); - - // Also update the marker combobox, so the document's markers - // show up at the top of the combobox -// sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL); - ink_markers_combo_update(spw, which); - - Inkscape::Selection *selection = sp_desktop_selection(desktop); - GSList const *items = selection->itemList(); - for (; items != NULL; items = items->next) { - SPItem *item = reinterpret_cast<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 = item->getRepr(); - if (selrepr) { - sp_repr_css_change_recursive(selrepr, css, "style"); - } - item->requestModified(SP_OBJECT_MODIFIED_FLAG); - item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + p++; + int c = 0; + while (p[c] != '\0' && p[c] != ')') { + c++; } - sp_repr_css_attr_unref(css); - css = 0; + if (p[c] == '\0') { + return NULL; + } - DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE, - _("Set markers")); + 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); -static void -ink_markers_combo_update(Gtk::Container* /*spw*/, SPMarkerLoc const which) { + g_free(b); + return marker; +} - switch (which) { - case SP_MARKER_LOC_START: - start_marker_connection.block(); - start_marker_combobox->set_active_history(); - start_marker_connection.unblock(); - break; +namespace Inkscape { - case SP_MARKER_LOC_MID: - mid_marker_connection.block(); - mid_marker_combobox->set_active_history(); - mid_marker_connection.unblock(); - break; - case SP_MARKER_LOC_END: - end_marker_connection.block(); - end_marker_combobox->set_active_history(); - end_marker_connection.unblock(); - break; - default: - g_assert_not_reached(); - } +/** + * Construct a stroke-style radio button with a given icon + * + * \param[in] grp The Gtk::RadioButtonGroup to which to add the new button + * \param[in] icon The icon to use for the button + * \param[in] button_type The type of stroke-style radio button (join/cap) + * \param[in] stroke_style The style attribute to associate with the button + */ +StrokeStyle::StrokeStyleButton::StrokeStyleButton(Gtk::RadioButtonGroup &grp, + char const *icon, + StrokeStyleButtonType button_type, + gchar const *stroke_style) + : + Gtk::RadioButton(grp), + button_type(button_type), + stroke_style(stroke_style) +{ + show(); + set_mode(false); + + Gtk::Widget *px = manage(Glib::wrap(sp_icon_new(Inkscape::ICON_SIZE_LARGE_TOOLBAR, icon))); + g_assert(px != NULL); + px->show(); + add(*px); } /** - * Sets the stroke width units for all selected items. - * Also handles absolute and dimensionless units. + * Create the fill or stroke style widget, and hook up all the signals. */ -static gboolean stroke_width_set_unit(SPUnitSelector *, - SPUnit const *old, - SPUnit const *new_units, - Gtk::Container *spw) +Gtk::Widget *Inkscape::Widgets::createStrokeStyleWidget( ) { - if (spw->get_data("update")) { - return FALSE; - } - - 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); + StrokeStyle *strokeStyle = new StrokeStyle(); - if (average == Geom::infinity() || 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; + return strokeStyle; } - -/** - * Creates a new widget for the line stroke style. - */ -Gtk::Container *sp_stroke_style_line_widget_new(void) +StrokeStyle::StrokeStyle() : + Gtk::VBox(), + miterLimitSpin(), + widthSpin(), + unitSelector(), + joinMiter(), + joinRound(), + joinBevel(), + capButt(), + capRound(), + capSquare(), + dashSelector(), + update(false), + desktop(0), + selectChangedConn(), + selectModifiedConn(), + startMarkerConn(), + midMarkerConn(), + endMarkerConn(), + _old_unit(NULL) { - Gtk::Widget *us; - SPDashSelector *ds; - GtkWidget *us_old, *spw_old; - Gtk::Container *spw; - Gtk::Table *t; - Inkscape::UI::Widget::SpinButton *sb; - Gtk::RadioButton *tb; - Gtk::HBox *f, *hb; - - spw_old = sp_widget_new_global(INKSCAPE); - spw = dynamic_cast<Gtk::Container *>(manage(Glib::wrap(spw_old))); - - f = new Gtk::HBox(false, 0); + Gtk::HBox *hb; + Gtk::HBox *f = new Gtk::HBox(false, 0); f->show(); - spw->add(*f); + 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); +#if WITH_GTKMM_3_0 + table = new Gtk::Grid(); + table->set_border_width(4); + table->set_row_spacing(4); +#else + table = new Gtk::Table(3, 6, false); + table->set_border_width(4); + table->set_row_spacings(4); +#endif + + table->show(); + f->add(*table); gint i = 0; //spw_label(t, C_("Stroke width", "_Width:"), 0, i); - hb = spw_hbox(t, 3, 1, i); + hb = spw_hbox(table, 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 @@ -328,73 +183,76 @@ Gtk::Container *sp_stroke_style_line_widget_new(void) // function in desktop-style. #if WITH_GTKMM_3_0 - Glib::RefPtr<Gtk::Adjustment> a = Gtk::Adjustment::create(1.0, 0.0, 1000.0, 0.1, 10.0, 0.0); - spw->set_data("width", &a); - sb = new Inkscape::UI::Widget::SpinButton(a, 0.1, 3); + widthAdj = new Glib::RefPtr<Gtk::Adjustment>(Gtk::Adjustment::create(1.0, 0.0, 1000.0, 0.1, 10.0, 0.0)); #else - Gtk::Adjustment *a = new Gtk::Adjustment(1.0, 0.0, 1000.0, 0.1, 10.0, 0.0); - spw->set_data("width", a); - sb = new Inkscape::UI::Widget::SpinButton(*a, 0.1, 3); + widthAdj = new Gtk::Adjustment(1.0, 0.0, 1000.0, 0.1, 10.0, 0.0); #endif - sb->set_tooltip_text(_("Stroke width")); - sb->show(); - spw_label(t, C_("Stroke width", "_Width:"), 0, i, sb); - sp_dialog_defocus_on_enter_cpp(sb); + widthSpin = new Inkscape::UI::Widget::SpinButton(*widthAdj, 0.1, 3); + widthSpin->set_tooltip_text(_("Stroke width")); + widthSpin->show(); + spw_label(table, C_("Stroke width", "_Width:"), 0, i, widthSpin); + + sp_dialog_defocus_on_enter_cpp(widthSpin); - 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)); + hb->pack_start(*widthSpin, false, false, 0); + unitSelector = new Inkscape::UI::Widget::UnitMenu(); + unitSelector->setUnitType(Inkscape::Util::UNIT_TYPE_LINEAR); + Gtk::Widget *us = manage(unitSelector); 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 ); + + unitSelector->addUnit(*unit_table.getUnit("%")); + _old_unit = unitSelector->getUnit(); + if (desktop) { + unitSelector->setUnit(sp_desktop_namedview(desktop)->doc_units->abbr); + _old_unit = sp_desktop_namedview(desktop)->doc_units; + } + widthSpin->setUnitMenu(unitSelector); + unitChangedConn = unitSelector->signal_changed().connect(sigc::mem_fun(*this, &StrokeStyle::unitChangedCB)); + 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)); +#if WITH_GTKMM_3_0 + (*widthAdj)->signal_value_changed().connect(sigc::mem_fun(*this, &StrokeStyle::widthChangedCB)); +#else + widthAdj->signal_value_changed().connect(sigc::mem_fun(*this, &StrokeStyle::widthChangedCB)); +#endif 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, NULL); + spw_label(table, _("Join:"), 0, i, NULL); - hb = spw_hbox(t, 3, 1, i); + hb = spw_hbox(table, 3, 1, i); - tb = NULL; + Gtk::RadioButtonGroup joinGrp; - tb = sp_stroke_radio_button(tb, INKSCAPE_ICON("stroke-join-miter"), - hb, spw, "join", "miter"); + joinMiter = makeRadioButton(joinGrp, INKSCAPE_ICON("stroke-join-miter"), + hb, STROKE_STYLE_BUTTON_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). - tb->set_tooltip_text(_("Miter join")); - spw->set_data("miter join", tb); - - tb = sp_stroke_radio_button(tb, INKSCAPE_ICON("stroke-join-round"), - hb, spw, "join", "round"); + joinMiter->set_tooltip_text(_("Miter join")); + joinRound = makeRadioButton(joinGrp, INKSCAPE_ICON("stroke-join-round"), + hb, STROKE_STYLE_BUTTON_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). - tb->set_tooltip_text(_("Round join")); - spw->set_data("round join", tb); - - tb = sp_stroke_radio_button(tb, INKSCAPE_ICON("stroke-join-bevel"), - hb, spw, "join", "bevel"); + joinRound->set_tooltip_text(_("Round join")); + joinBevel = makeRadioButton(joinGrp, INKSCAPE_ICON("stroke-join-bevel"), + hb, STROKE_STYLE_BUTTON_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). - tb->set_tooltip_text(_("Bevel join")); - spw->set_data("bevel join", tb); + joinBevel->set_tooltip_text(_("Bevel join")); i++; @@ -407,178 +265,480 @@ Gtk::Container *sp_stroke_style_line_widget_new(void) // when they become too long. //spw_label(t, _("Miter _limit:"), 0, i); - hb = spw_hbox(t, 3, 1, i); + hb = spw_hbox(table, 3, 1, i); #if WITH_GTKMM_3_0 - a = Gtk::Adjustment::create(4.0, 0.0, 100.0, 0.1, 10.0, 0.0); - spw->set_data("miterlimit", &a); - sb = new Inkscape::UI::Widget::SpinButton(a, 0.1, 2); + miterLimitAdj = new Glib::RefPtr<Gtk::Adjustment>(Gtk::Adjustment::create(4.0, 0.0, 100.0, 0.1, 10.0, 0.0)); + miterLimitSpin = new Inkscape::UI::Widget::SpinButton(*miterLimitAdj, 0.1, 2); #else - a = new Gtk::Adjustment(4.0, 0.0, 100.0, 0.1, 10.0, 0.0); - spw->set_data("miterlimit", a); - sb = new Inkscape::UI::Widget::SpinButton(*a, 0.1, 2); + miterLimitAdj = new Gtk::Adjustment(4.0, 0.0, 100.0, 0.1, 10.0, 0.0); + miterLimitSpin = new Inkscape::UI::Widget::SpinButton(*miterLimitAdj, 0.1, 2); #endif - sb->set_tooltip_text(_("Maximum length of the miter (in units of stroke width)")); - sb->show(); - spw_label(t, _("Miter _limit:"), 0, i, sb); - spw->set_data("miterlimit_sb", sb); - sp_dialog_defocus_on_enter_cpp(sb); + miterLimitSpin->set_tooltip_text(_("Maximum length of the miter (in units of stroke width)")); + miterLimitSpin->show(); + spw_label(table, _("Miter _limit:"), 0, i, miterLimitSpin); + sp_dialog_defocus_on_enter_cpp(miterLimitSpin); + + hb->pack_start(*miterLimitSpin, false, false, 0); - hb->pack_start(*sb, false, false, 0); +#if WITH_GTKMM_3_0 + (*miterLimitAdj)->signal_value_changed().connect(sigc::mem_fun(*this, &StrokeStyle::miterLimitChangedCB)); - a->signal_value_changed().connect(sigc::bind(sigc::ptr_fun(&sp_stroke_style_miterlimit_changed), spw)); +#else + miterLimitAdj->signal_value_changed().connect(sigc::mem_fun(*this, &StrokeStyle::miterLimitChangedCB)); +#endif i++; /* Cap type */ // TRANSLATORS: cap type specifies the shape for the ends of lines //spw_label(t, _("_Cap:"), 0, i); - spw_label(t, _("Cap:"), 0, i, NULL); + spw_label(table, _("Cap:"), 0, i, NULL); - hb = spw_hbox(t, 3, 1, i); + hb = spw_hbox(table, 3, 1, i); - tb = NULL; + Gtk::RadioButtonGroup capGrp; - tb = sp_stroke_radio_button(tb, INKSCAPE_ICON("stroke-cap-butt"), - hb, spw, "cap", "butt"); - spw->set_data("cap butt", tb); + capButt = makeRadioButton(capGrp, INKSCAPE_ICON("stroke-cap-butt"), + hb, STROKE_STYLE_BUTTON_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 - tb->set_tooltip_text(_("Butt cap")); + capButt->set_tooltip_text(_("Butt cap")); - tb = sp_stroke_radio_button(tb, INKSCAPE_ICON("stroke-cap-round"), - hb, spw, "cap", "round"); - spw->set_data("cap round", tb); + capRound = makeRadioButton(capGrp, INKSCAPE_ICON("stroke-cap-round"), + hb, STROKE_STYLE_BUTTON_CAP, "round"); // TRANSLATORS: Round cap: the line shape extends beyond the end point of the // line; the ends of the line are rounded - tb->set_tooltip_text(_("Round cap")); + capRound->set_tooltip_text(_("Round cap")); - tb = sp_stroke_radio_button(tb, INKSCAPE_ICON("stroke-cap-square"), - hb, spw, "cap", "square"); - spw->set_data("cap square", tb); + capSquare = makeRadioButton(capGrp, INKSCAPE_ICON("stroke-cap-square"), + hb, STROKE_STYLE_BUTTON_CAP, "square"); // TRANSLATORS: Square cap: the line shape extends beyond the end point of the // line; the ends of the line are square - tb->set_tooltip_text(_("Square cap")); + capSquare->set_tooltip_text(_("Square cap")); i++; - /* Dash */ - spw_label(t, _("Dashes:"), 0, i, NULL); //no mnemonic for now + spw_label(table, _("Dashes:"), 0, i, NULL); //no mnemonic for now //decide what to do: // implement a set_mnemonic_source function in the // SPDashSelector class, so that we do not have to // expose any of the underlying widgets? - ds = manage(new SPDashSelector); + dashSelector = manage(new SPDashSelector); + + dashSelector->show(); + +#if WITH_GTKMM_3_0 + dashSelector->set_hexpand(); + dashSelector->set_halign(Gtk::ALIGN_FILL); + dashSelector->set_valign(Gtk::ALIGN_CENTER); + table->attach(*dashSelector, 1, i, 3, 1); +#else + table->attach(*dashSelector, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); +#endif + + dashSelector->changed_signal.connect(sigc::mem_fun(*this, &StrokeStyle::lineDashChangedCB)); - 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*/ // 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. - start_marker_combobox = manage(new MarkerComboBox("marker-start")); - spw_label(t, _("_Start Markers:"), 0, i, start_marker_combobox); - start_marker_combobox->set_tooltip_text(_("Start Markers are drawn on the first node of a path or shape")); - start_marker_connection = start_marker_combobox->signal_changed().connect( - sigc::bind<MarkerComboBox *, Gtk::Container *, SPMarkerLoc>( - sigc::ptr_fun(&sp_marker_select), start_marker_combobox, spw, SP_MARKER_LOC_START)); - start_marker_combobox->show(); - t->attach(*start_marker_combobox, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); - spw->set_data("start_marker_combobox", start_marker_combobox); - i++; + spw_label(table, _("Markers:"), 0, i, NULL); - mid_marker_combobox = manage(new MarkerComboBox("marker-mid")); - spw_label(t, _("_Mid Markers:"), 0, i, mid_marker_combobox); - mid_marker_combobox->set_tooltip_text(_("Mid Markers are drawn on every node of a path or shape except the first and last nodes")); - mid_marker_connection = mid_marker_combobox->signal_changed().connect( - sigc::bind<MarkerComboBox *, Gtk::Container *, SPMarkerLoc>( - sigc::ptr_fun(&sp_marker_select), mid_marker_combobox, spw, SP_MARKER_LOC_MID)); - mid_marker_combobox->show(); - t->attach(*mid_marker_combobox, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); - spw->set_data("mid_marker_combobox", mid_marker_combobox); + hb = spw_hbox(table, 1, 1, i); i++; - end_marker_combobox = manage(new MarkerComboBox("marker-end")); - spw_label(t, _("_End Markers:"), 0, i, end_marker_combobox); - end_marker_combobox->set_tooltip_text(_("End Markers are drawn on the last node of a path or shape")); - end_marker_connection = end_marker_combobox->signal_changed().connect( - sigc::bind<MarkerComboBox *, Gtk::Container *, SPMarkerLoc>( - sigc::ptr_fun(&sp_marker_select), end_marker_combobox, spw, SP_MARKER_LOC_END)); - end_marker_combobox->show(); - t->attach(*end_marker_combobox, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0); - spw->set_data("end_marker_combobox", end_marker_combobox); - i++; + startMarkerCombo = manage(new MarkerComboBox("marker-start", SP_MARKER_LOC_START)); + startMarkerCombo->set_tooltip_text(_("Start Markers are drawn on the first node of a path or shape")); + startMarkerConn = startMarkerCombo->signal_changed().connect( + sigc::bind<MarkerComboBox *, StrokeStyle *, SPMarkerLoc>( + sigc::ptr_fun(&StrokeStyle::markerSelectCB), startMarkerCombo, this, SP_MARKER_LOC_START)); + startMarkerCombo->show(); + + hb->pack_start(*startMarkerCombo, true, true, 0); + + midMarkerCombo = manage(new MarkerComboBox("marker-mid", SP_MARKER_LOC_MID)); + midMarkerCombo->set_tooltip_text(_("Mid Markers are drawn on every node of a path or shape except the first and last nodes")); + midMarkerConn = midMarkerCombo->signal_changed().connect( + sigc::bind<MarkerComboBox *, StrokeStyle *, SPMarkerLoc>( + sigc::ptr_fun(&StrokeStyle::markerSelectCB), midMarkerCombo, this, SP_MARKER_LOC_MID)); + midMarkerCombo->show(); + + hb->pack_start(*midMarkerCombo, true, true, 0); + + endMarkerCombo = manage(new MarkerComboBox("marker-end", SP_MARKER_LOC_END)); + endMarkerCombo->set_tooltip_text(_("End Markers are drawn on the last node of a path or shape")); + endMarkerConn = endMarkerCombo->signal_changed().connect( + sigc::bind<MarkerComboBox *, StrokeStyle *, SPMarkerLoc>( + sigc::ptr_fun(&StrokeStyle::markerSelectCB), endMarkerCombo, this, SP_MARKER_LOC_END)); + endMarkerCombo->show(); + + hb->pack_start(*endMarkerCombo, true, true, 0); + + setDesktop(desktop); + updateLine(); + +} + +StrokeStyle::~StrokeStyle() +{ + selectModifiedConn.disconnect(); + selectChangedConn.disconnect(); +} + +void StrokeStyle::setDesktop(SPDesktop *desktop) +{ + if (this->desktop != desktop) { + + if (this->desktop) { + selectModifiedConn.disconnect(); + selectChangedConn.disconnect(); + } + this->desktop = desktop; + if (desktop && desktop->selection) { + selectChangedConn = desktop->selection->connectChanged(sigc::hide(sigc::mem_fun(*this, &StrokeStyle::selectionChangedCB))); + selectModifiedConn = desktop->selection->connectModified(sigc::hide<0>(sigc::mem_fun(*this, &StrokeStyle::selectionModifiedCB))); + } + updateLine(); + } +} + + +/** + * Helper function for creating stroke-style radio buttons. + * + * \param[in] grp The Gtk::RadioButtonGroup in which to add the button + * \param[in] icon The icon for the button + * \param[in] hb The Gtk::Box container in which to add the button + * \param[in] button_type The type (join/cap) for the button + * \param[in] stroke_style The style attribute to associate with the button + * + * \details After instantiating the button, it is added to a container box and + * a handler for the toggle event is connected. + */ +StrokeStyle::StrokeStyleButton * +StrokeStyle::makeRadioButton(Gtk::RadioButtonGroup &grp, + char const *icon, + Gtk::HBox *hb, + StrokeStyleButtonType button_type, + gchar const *stroke_style) +{ + g_assert(icon != NULL); + g_assert(hb != NULL); + + StrokeStyleButton *tb = new StrokeStyleButton(grp, icon, button_type, stroke_style); + + hb->pack_start(*tb, false, false, 0); + set_data(icon, tb); + + tb->signal_toggled().connect(sigc::bind<StrokeStyleButton *, StrokeStyle *>( + sigc::ptr_fun(&StrokeStyle::buttonToggledCB), tb, this)); + + return tb; +} - // FIXME: we cheat and still use gtk+ signals +/** + * Handles when user selects one of the markers from the marker combobox. + * Gets the marker uri string and applies it to all selected + * items in the current desktop. + */ +void StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, SPMarkerLoc const /*which*/) +{ + if (spw->update) { + return; + } - g_signal_connect(G_OBJECT(spw_old), "modify_selection", - G_CALLBACK(sp_stroke_style_line_selection_modified), - spw); - g_signal_connect(G_OBJECT(spw_old), "change_selection", - G_CALLBACK(sp_stroke_style_line_selection_changed), - spw); + spw->update = true; - sp_stroke_style_line_update(spw, desktop ? sp_desktop_selection(desktop) : NULL); + SPDocument *document = sp_desktop_document(spw->desktop); + if (!document) { + return; + } - return spw; + /* Get Marker */ + gchar const *marker = marker_combo->get_active_marker_uri(); + + + SPCSSAttr *css = sp_repr_css_attr_new(); + gchar const *combo_id = marker_combo->get_id(); + sp_repr_css_set_property(css, combo_id, marker); + + // Also update the marker combobox, so the document's markers + // show up at the top of the combobox +// sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL); + //spw->updateMarkerHist(which); + + Inkscape::Selection *selection = sp_desktop_selection(spw->desktop); + GSList const *items = selection->itemList(); + for (; items != NULL; items = items->next) { + SPItem *item = reinterpret_cast<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 = item->getRepr(); + if (selrepr) { + sp_repr_css_change_recursive(selrepr, css, "style"); + SPObject *markerObj = getMarkerObj(marker, document); + spw->setMarkerColor(markerObj, marker_combo->get_loc(), item); + } + + item->requestModified(SP_OBJECT_MODIFIED_FLAG); + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + + DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE, _("Set markers")); + } + + sp_repr_css_attr_unref(css); + css = 0; + + spw->update = false; +}; + +void StrokeStyle::updateMarkerHist(SPMarkerLoc const which) +{ + switch (which) { + case SP_MARKER_LOC_START: + startMarkerConn.block(); + startMarkerCombo->set_active_history(); + startMarkerConn.unblock(); + break; + + case SP_MARKER_LOC_MID: + midMarkerConn.block(); + midMarkerCombo->set_active_history(); + midMarkerConn.unblock(); + break; + + case SP_MARKER_LOC_END: + endMarkerConn.block(); + endMarkerCombo->set_active_history(); + endMarkerConn.unblock(); + break; + default: + g_assert_not_reached(); + } +} + +/** + * Callback for when UnitMenu widget is modified. + * Triggers update action. + */ +void StrokeStyle::unitChangedCB() +{ + Inkscape::Util::Unit const *new_unit = unitSelector->getUnit(); + if (new_unit->type == Inkscape::Util::UNIT_TYPE_DIMENSIONLESS) { + widthSpin->set_value(100); + } + widthSpin->set_value(Inkscape::Util::Quantity::convert(widthSpin->get_value(), _old_unit, new_unit)); + _old_unit = new_unit; } /** * 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) +void +StrokeStyle::selectionModifiedCB(guint flags) { - 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); + updateLine(); } - } /** * 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) +void +StrokeStyle::selectionChangedCB() +{ + updateLine(); +} + +/* + * Fork marker if necessary and set the referencing items url to the new marker + * Return the new marker + */ +SPObject * +StrokeStyle::forkMarker(SPObject *marker, int loc, SPItem *item) +{ + if (!item || !marker) { + return NULL; + } + + gchar const *marker_id = SPMarkerNames[loc].key; + + /* + * Optimization when all the references to this marker are from this item + * then we can reuse it and dont need to fork + */ + Glib::ustring urlId = Glib::ustring::format("url(#", marker->getRepr()->attribute("id"), ")"); + unsigned int refs = 0; + for (int i = SP_MARKER_LOC_START; i < SP_MARKER_LOC_QTY; i++) { + if (item->style->marker[i].set && !strcmp(urlId.c_str(), item->style->marker[i].value)) { + refs++; + } + } + if (marker->hrefcount <= refs) { + return marker; + } + + marker = sp_marker_fork_if_necessary(marker); + + // Update the items url to new marker + Inkscape::XML::Node *mark_repr = marker->getRepr(); + SPCSSAttr *css_item = sp_repr_css_attr_new(); + sp_repr_css_set_property(css_item, marker_id, g_strconcat("url(#", mark_repr->attribute("id"), ")", NULL)); + sp_repr_css_change_recursive(item->getRepr(), css_item, "style"); + + sp_repr_css_attr_unref(css_item); + css_item = 0; + + return marker; +} + +/** + * Change the color of the marker to match the color of the item. + * Marker stroke color is set to item stroke color. + * Fill color : + * 1. If the item has fill, use that for the marker fill, + * 2. If the marker has same fill and stroke assume its solid, use item stroke for both fill and stroke the line stroke + * 3. If the marker has fill color, use the marker fill color + * + */ +void +StrokeStyle::setMarkerColor(SPObject *marker, int loc, SPItem *item) { - Gtk::Container *spw = static_cast<Gtk::Container *>(data); - sp_stroke_style_line_update(spw, selection); + + if (!item || !marker) { + return; + } + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean colorStock = prefs->getBool("/options/markers/colorStockMarkers", true); + gboolean colorCustom = prefs->getBool("/options/markers/colorCustomMarkers", false); + const gchar *stock = marker->getRepr()->attribute("inkscape:isstock"); + gboolean isStock = (stock && !strcmp(stock,"true")); + + if (isStock ? !colorStock : !colorCustom) { + return; + } + + // Check if we need to fork this marker + marker = forkMarker(marker, loc, item); + + Inkscape::XML::Node *repr = marker->getRepr()->firstChild(); + if (!repr) { + return; + }; + + // Current line style + SPCSSAttr *css_item = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS); + const char *lstroke = getItemColorForMarker(item, FOR_STROKE, loc); + const char *lstroke_opacity = sp_repr_css_property(css_item, "stroke-opacity", "1"); + const char *lfill = getItemColorForMarker(item, FOR_FILL, loc); + const char *lfill_opacity = sp_repr_css_property(css_item, "fill-opacity", "1"); + + // Current marker style + SPCSSAttr *css_marker = sp_css_attr_from_object(marker->firstChild(), SP_STYLE_FLAG_ALWAYS); + const char *mfill = sp_repr_css_property(css_marker, "fill", "none"); + const char *mstroke = sp_repr_css_property(css_marker, "fill", "none"); + + // Create new marker style with the lines stroke + SPCSSAttr *css = sp_repr_css_attr_new(); + + sp_repr_css_set_property(css, "stroke", lstroke); + sp_repr_css_set_property(css, "stroke-opacity", lstroke_opacity); + + if (strcmp(lfill, "none") ) { + // 1. If the line has fill, use that for the marker fill + sp_repr_css_set_property(css, "fill", lfill); + sp_repr_css_set_property(css, "fill-opacity", lfill_opacity); + } + else if (mfill && mstroke && !strcmp(mfill, mstroke) && mfill[0] == '#' && strcmp(mfill, "#ffffff")) { + // 2. If the marker has same fill and stroke assume its solid. use line stroke for both fill and stroke the line stroke + sp_repr_css_set_property(css, "fill", lstroke); + sp_repr_css_set_property(css, "fill-opacity", lstroke_opacity); + } + else if (mfill && mfill[0] == '#' && strcmp(mfill, "#000000")) { + // 3. If the marker has fill color, use the marker fill color + sp_repr_css_set_property(css, "fill", mfill); + //sp_repr_css_set_property(css, "fill-opacity", mfill_opacity); + } + + sp_repr_css_change_recursive(marker->firstChild()->getRepr(), css, "style"); + + // Tell the combos to update its image cache of this marker + gchar const *mid = marker->getRepr()->attribute("id"); + startMarkerCombo->update_marker_image(mid); + midMarkerCombo->update_marker_image(mid); + endMarkerCombo->update_marker_image(mid); + + sp_repr_css_attr_unref(css); + css = 0; + + } +/* + * Get the fill or stroke color of the item + * If its a gradient, then return first or last stop color + */ +const char * +StrokeStyle::getItemColorForMarker(SPItem *item, Inkscape::PaintTarget fill_or_stroke, int loc) +{ + SPCSSAttr *css_item = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS); + const char *color; + if (fill_or_stroke == FOR_FILL) + color = sp_repr_css_property(css_item, "fill", "none"); + else + color = sp_repr_css_property(css_item, "stroke", "none"); + + if (!strncmp (color, "url(", 4)) { + // If the item has a gradient use the first stop color for the marker + + SPGradient *grad = getGradient(item, fill_or_stroke); + if (grad) { + SPGradient *vector = grad->getVector(FALSE); + SPStop *stop = vector->getFirstStop(); + if (loc == SP_MARKER_LOC_END) { + stop = sp_last_stop(vector); + } + if (stop) { + guint32 const c1 = stop->get_rgba32(); + gchar c[64]; + sp_svg_write_color(c, sizeof(c), c1); + color = g_strdup(c); + //lstroke_opacity = Glib::ustring::format(stop->opacity).c_str(); + } + } + } + return color; +} /** * Sets selector widgets' dash style from an SPStyle object. */ -static void -sp_dash_selector_set_from_style(SPDashSelector *dsel, SPStyle *style) +void +StrokeStyle::setDashSelectorFromStyle(SPDashSelector *dsel, SPStyle *style) { - if (style->stroke_dash.n_dash > 0) { + if (!style->stroke_dasharray.values.empty()) { double d[64]; - int len = MIN(style->stroke_dash.n_dash, 64); - for (int i = 0; i < len; i++) { + size_t len = MIN(style->stroke_dasharray.values.size(), 64); + for (unsigned i = 0; i < len; i++) { if (style->stroke_width.computed != 0) - d[i] = style->stroke_dash.dash[i] / style->stroke_width.computed; + d[i] = style->stroke_dasharray.values[i] / style->stroke_width.computed; else - d[i] = style->stroke_dash.dash[i]; // is there a better thing to do for stroke_width==0? + d[i] = style->stroke_dasharray.values[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); + style->stroke_dashoffset.value / style->stroke_width.computed : + style->stroke_dashoffset.value); } else { dsel->set_dash(0, NULL, 0.0); } @@ -587,69 +747,65 @@ sp_dash_selector_set_from_style(SPDashSelector *dsel, SPStyle *style) /** * 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) +void +StrokeStyle::setJoinType (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"))); + tb = joinMiter; break; case SP_STROKE_LINEJOIN_ROUND: - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON("stroke-join-round"))); + tb = joinRound; break; case SP_STROKE_LINEJOIN_BEVEL: - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON("stroke-join-bevel"))); + tb = joinBevel; break; default: break; } - sp_stroke_style_set_join_buttons(spw, tb); + setJoinButtons(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) +void +StrokeStyle::setCapType (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"))); + tb = capButt; break; case SP_STROKE_LINECAP_ROUND: - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON("stroke-cap-round"))); + tb = capRound; break; case SP_STROKE_LINECAP_SQUARE: - tb = static_cast<Gtk::RadioButton *>(spw->get_data(INKSCAPE_ICON("stroke-cap-square"))); + tb = capSquare; break; default: break; } - sp_stroke_style_set_cap_buttons(spw, tb); + setCapButtons(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) +void +StrokeStyle::updateLine() { - if (spw->get_data("update")) { + if (update) { return; } - spw->set_data("update", GINT_TO_POINTER(TRUE)); + update = true; - FillOrStroke kind = GPOINTER_TO_INT(spw->get_data("kind")) ? FILL : STROKE; + Inkscape::Selection *sel = desktop ? sp_desktop_selection(desktop) : NULL; - 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")); + FillOrStroke kind = GPOINTER_TO_INT(get_data("kind")) ? FILL : STROKE; // create temporary style SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); @@ -662,73 +818,75 @@ sp_stroke_style_line_update(Gtk::Container *spw, Inkscape::Selection *sel) if (!sel || sel->isEmpty()) { // Nothing selected, grey-out all controls in the stroke-style dialog - sset->set_sensitive(false); + table->set_sensitive(false); - spw->set_data("update", GINT_TO_POINTER(FALSE)); + update = false; return; } else { - sset->set_sensitive(true); - - SPUnit const *unit = sp_unit_selector_get_unit(us); + table->set_sensitive(true); if (result_sw == QUERY_STYLE_MULTIPLE_AVERAGED) { - sp_unit_selector_set_unit(us, &sp_unit_get_by_id(SP_UNIT_PERCENT)); + unitSelector->setUnit("%"); } 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); + Inkscape::Util::Unit const *tempunit = unitSelector->getUnit(); + if (tempunit->type != Inkscape::Util::UNIT_TYPE_LINEAR) { + unitSelector->setUnit(sp_desktop_namedview(SP_ACTIVE_DESKTOP)->doc_units->abbr); } } - unit = sp_unit_selector_get_unit(us); + Inkscape::Util::Unit const *unit = unitSelector->getUnit(); - 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); + if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) { + double avgwidth = Inkscape::Util::Quantity::convert(query->stroke_width.computed, "px", unit); +#if WITH_GTKMM_3_0 + (*widthAdj)->set_value(avgwidth); +#else + widthAdj->set_value(avgwidth); +#endif } else { - width->set_value(100); +#if WITH_GTKMM_3_0 + (*widthAdj)->set_value(100); +#else + widthAdj->set_value(100); +#endif } // if none of the selected objects has a stroke, than quite some controls should be disabled // The markers might still be shown though, so these will not be disabled bool enabled = (result_sw != QUERY_STYLE_NOTHING) && !targPaint.isNoneSet(); /* No objects stroked, set insensitive */ - Gtk::RadioButton *tb = NULL; - tb = static_cast<Gtk::RadioButton *>(spw->get_data("miter join")); - tb->set_sensitive(enabled); - tb = static_cast<Gtk::RadioButton *>(spw->get_data("round join")); - tb->set_sensitive(enabled); - tb = static_cast<Gtk::RadioButton *>(spw->get_data("bevel join")); - tb->set_sensitive(enabled); - - Inkscape::UI::Widget::SpinButton* sb = NULL; - sb = static_cast<Inkscape::UI::Widget::SpinButton *>(spw->get_data("miterlimit_sb")); - sb->set_sensitive(enabled); - - tb = static_cast<Gtk::RadioButton *>(spw->get_data("cap butt")); - tb->set_sensitive(enabled); - tb = static_cast<Gtk::RadioButton *>(spw->get_data("cap round")); - tb->set_sensitive(enabled); - tb = static_cast<Gtk::RadioButton *>(spw->get_data("cap square")); - tb->set_sensitive(enabled); - - dsel->set_sensitive(enabled); + joinMiter->set_sensitive(enabled); + joinRound->set_sensitive(enabled); + joinBevel->set_sensitive(enabled); + + miterLimitSpin->set_sensitive(enabled); + + capButt->set_sensitive(enabled); + capRound->set_sensitive(enabled); + capSquare->set_sensitive(enabled); + + dashSelector->set_sensitive(enabled); } if (result_ml != QUERY_STYLE_NOTHING) - ml->set_value(query->stroke_miterlimit.value); // TODO: reflect averagedness? +#if WITH_GTKMM_3_0 + (*miterLimitAdj)->set_value(query->stroke_miterlimit.value); // TODO: reflect averagedness? +#else + miterLimitAdj->set_value(query->stroke_miterlimit.value); // TODO: reflect averagedness? +#endif if (result_join != QUERY_STYLE_MULTIPLE_DIFFERENT) { - sp_jointype_set(spw, query->stroke_linejoin.value); + setJoinType(query->stroke_linejoin.value); } else { - sp_stroke_style_set_join_buttons(spw, NULL); + setJoinButtons(NULL); } if (result_cap != QUERY_STYLE_MULTIPLE_DIFFERENT) { - sp_captype_set (spw, query->stroke_linecap.value); + setCapType (query->stroke_linecap.value); } else { - sp_stroke_style_set_cap_buttons(spw, NULL); + setCapButtons(NULL); } sp_style_unref(query); @@ -741,21 +899,21 @@ sp_stroke_style_line_update(Gtk::Container *spw, Inkscape::Selection *sel) SPStyle * const style = object->style; /* Markers */ - sp_stroke_style_update_marker_combo(spw, objects); // FIXME: make this desktop query too + updateAllMarkers(objects); // FIXME: make this desktop query too /* Dash */ - sp_dash_selector_set_from_style(dsel, style); // FIXME: make this desktop query too + setDashSelectorFromStyle(dashSelector, style); // FIXME: make this desktop query too - sset->set_sensitive(true); + table->set_sensitive(true); - spw->set_data("update", GINT_TO_POINTER(FALSE)); + update = false; } /** * Sets a line's dash properties in a CSS style object. */ -static void -sp_stroke_style_set_scaled_dash(SPCSSAttr *css, +void +StrokeStyle::setScaledDash(SPCSSAttr *css, int ndash, double *dash, double offset, double scale) { @@ -781,21 +939,15 @@ sp_stroke_style_set_scaled_dash(SPCSSAttr *css, /** * Sets line properties like width, dashes, markers, etc. on all currently selected items. */ -static void -sp_stroke_style_scale_line(Gtk::Container *spw) +void +StrokeStyle::scaleLine() { - if (spw->get_data("update")) { + if (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; + update = true; + SPDocument *document = sp_desktop_document (desktop); Inkscape::Selection *selection = sp_desktop_selection (desktop); @@ -805,21 +957,25 @@ sp_stroke_style_scale_line(Gtk::Container *spw) SPCSSAttr *css = sp_repr_css_attr_new(); if (items) { +#if WITH_GTKMM_3_0 + double width_typed = (*widthAdj)->get_value(); + double const miterlimit = (*miterLimitAdj)->get_value(); +#else + double width_typed = widthAdj->get_value(); + double const miterlimit = miterLimitAdj->get_value(); +#endif - 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)); + Inkscape::Util::Unit const *const unit = unitSelector->getUnit(); double *dash, offset; int ndash; - dsel->get_dash(&ndash, &dash, &offset); + dashSelector->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); + if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) { + width = Inkscape::Util::Quantity::convert(width_typed, unit, "px"); } else { // percentage gdouble old_w = SP_OBJECT(i->data)->style->stroke_width.computed; width = old_w * width_typed / 100; @@ -838,16 +994,20 @@ sp_stroke_style_scale_line(Gtk::Container *spw) } /* Set dash */ - sp_stroke_style_set_scaled_dash(css, ndash, dash, offset, width); + setScaledDash(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) { + if (unit->type != Inkscape::Util::UNIT_TYPE_LINEAR) { // reset to 100 percent - wadj->set_value(100.0); +#if WITH_GTKMM_3_0 + (*widthAdj)->set_value(100.0); +#else + widthAdj->set_value(100.0); +#endif } } @@ -862,35 +1022,35 @@ sp_stroke_style_scale_line(Gtk::Container *spw) DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE, _("Set stroke style")); - spw->set_data("update", GINT_TO_POINTER(FALSE)); + update = 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) +void +StrokeStyle::widthChangedCB() { - if (spw->get_data("update")) { + if (update) { return; } - sp_stroke_style_scale_line(spw); + scaleLine(); } /** * 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) +void +StrokeStyle::miterLimitChangedCB() { - if (spw->get_data("update")) { + if (update) { return; } - sp_stroke_style_scale_line(spw); + scaleLine(); } /** @@ -898,14 +1058,14 @@ sp_stroke_style_miterlimit_changed(Gtk::Container *spw) * Causes all line styles to be applied to all selected items. */ -static void -sp_stroke_style_line_dash_changed(Gtk::Container *spw) +void +StrokeStyle::lineDashChangedCB() { - if (spw->get_data("update")) { + if (update) { return; } - sp_stroke_style_scale_line(spw); + scaleLine(); } /** @@ -915,48 +1075,36 @@ sp_stroke_style_line_dash_changed(Gtk::Container *spw) * calls the respective routines to update css properties, etc. * */ -static void sp_stroke_style_any_toggled(Gtk::ToggleButton *tb, Gtk::Container *spw) +void StrokeStyle::buttonToggledCB(StrokeStyleButton *tb, StrokeStyle *spw) { - if (spw->get_data("update")) { + if (spw->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")); + if (tb->get_button_type() == STROKE_STYLE_BUTTON_JOIN) { + spw->miterLimitSpin->set_sensitive(!strcmp(tb->get_stroke_style(), "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); + switch (tb->get_button_type()) { + case STROKE_STYLE_BUTTON_JOIN: + sp_repr_css_set_property(css, "stroke-linejoin", tb->get_stroke_style()); + sp_desktop_set_style (spw->desktop, css); + spw->setJoinButtons(tb); + break; + case STROKE_STYLE_BUTTON_CAP: + sp_repr_css_set_property(css, "stroke-linecap", tb->get_stroke_style()); + sp_desktop_set_style (spw->desktop, css); + spw->setCapButtons(tb); } sp_repr_css_attr_unref(css); css = 0; - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_DIALOG_FILL_STROKE, + DocumentUndo::done(sp_desktop_document(spw->desktop), SP_VERB_DIALOG_FILL_STROKE, _("Set stroke style")); } } @@ -964,38 +1112,24 @@ static void sp_stroke_style_any_toggled(Gtk::ToggleButton *tb, Gtk::Container *s /** * Updates the join style toggle buttons */ -static void -sp_stroke_style_set_join_buttons(Gtk::Container *spw, Gtk::ToggleButton *active) +void +StrokeStyle::setJoinButtons(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); + joinMiter->set_active(active == joinMiter); + miterLimitSpin->set_sensitive(active == joinMiter); + joinRound->set_active(active == joinRound); + joinBevel->set_active(active == joinBevel); } /** * Updates the cap style toggle buttons */ -static void -sp_stroke_style_set_cap_buttons(Gtk::Container *spw, Gtk::ToggleButton *active) +void +StrokeStyle::setCapButtons(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); + capButt->set_active(active == capButt); + capRound->set_active(active == capRound); + capSquare->set_active(active == capSquare); } @@ -1003,13 +1137,13 @@ sp_stroke_style_set_cap_buttons(Gtk::Container *spw, Gtk::ToggleButton *active) * Updates the marker combobox to highlight the appropriate marker and scroll to * that marker. */ -static void -sp_stroke_style_update_marker_combo(Gtk::Container *spw, GSList const *objects) +void +StrokeStyle::updateAllMarkers(GSList const *objects) { - struct { char const *key; int loc; } const keyloc[] = { - { "start_marker_combobox", SP_MARKER_LOC_START }, - { "mid_marker_combobox", SP_MARKER_LOC_MID }, - { "end_marker_combobox", SP_MARKER_LOC_END } + struct { MarkerComboBox *key; int loc; } const keyloc[] = { + { startMarkerCombo, SP_MARKER_LOC_START }, + { midMarkerCombo, SP_MARKER_LOC_MID }, + { endMarkerCombo, SP_MARKER_LOC_END } }; bool all_texts = true; @@ -1020,7 +1154,7 @@ sp_stroke_style_update_marker_combo(Gtk::Container *spw, GSList const *objects) } for (unsigned i = 0; i < G_N_ELEMENTS(keyloc); ++i) { - MarkerComboBox *combo = static_cast<MarkerComboBox *>(spw->get_data(keyloc[i].key)); + MarkerComboBox *combo = static_cast<MarkerComboBox *>(keyloc[i].key); // Per SVG spec, text objects cannot have markers; disable combobox if only texts are selected combo->set_sensitive(!all_texts); } @@ -1033,21 +1167,35 @@ sp_stroke_style_update_marker_combo(Gtk::Container *spw, GSList const *objects) // For all three marker types, // find the corresponding combobox item - MarkerComboBox *combo = static_cast<MarkerComboBox *>(spw->get_data(keyloc[i].key)); + MarkerComboBox *combo = static_cast<MarkerComboBox *>(keyloc[i].key); // Quit if we're in update state if (combo->update()) { return; } + combo->setDesktop(desktop); + 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, object->document); + SPObject *marker = getMarkerObj(object->style->marker[keyloc[i].loc].value, object->document); // Scroll the combobox to that marker combo->set_current(marker); + // Set the marker color + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean update = prefs->getBool("/options/markers/colorUpdateMarkers", true); + + if (update) { + setMarkerColor(marker, combo->get_loc(), SP_ITEM(object)); + + SPDocument *document = sp_desktop_document(desktop); + DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE, + _("Set marker color")); + } + } else { combo->set_current(NULL); } @@ -1056,41 +1204,9 @@ sp_stroke_style_update_marker_combo(Gtk::Container *spw, GSList const *objects) } -/** - * 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'; +} // namespace Inkscape - // FIXME: get the document from the object and let the caller pass it in - SPObject *marker = doc->getObjectById(b); - return marker; -} /* Local Variables: diff --git a/src/widgets/stroke-style.h b/src/widgets/stroke-style.h index 882901f45..6f0fe583b 100644 --- a/src/widgets/stroke-style.h +++ b/src/widgets/stroke-style.h @@ -15,11 +15,86 @@ #ifndef SEEN_DIALOGS_STROKE_STYLE_H #define SEEN_DIALOGS_STROKE_STYLE_H +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "widgets/dash-selector.h" +#include <gtkmm/radiobutton.h> + +#if WITH_GTKMM_3_0 +#include <gtkmm/grid.h> +#else +#include <gtkmm/table.h> +#endif + +#include <glibmm/i18n.h> + +#include "desktop.h" +#include "desktop-handles.h" +#include "desktop-style.h" +#include "dialogs/dialog-events.h" +#include "display/canvas-bpath.h" // for SP_STROKE_LINEJOIN_* +#include "display/drawing.h" +#include "document-private.h" +#include "document-undo.h" +#include "gradient-chemistry.h" +#include "helper/stock-items.h" +#include "inkscape.h" +#include "io/sys.h" +#include "marker.h" +#include "preferences.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/icon.h" +#include "widgets/paint-selector.h" +#include "widgets/sp-widget.h" +#include "widgets/spw-utilities.h" +#include "ui/widget/spinbutton.h" +#include "xml/repr.h" + +#include "stroke-style.h" +#include "stroke-marker-selector.h" +#include "fill-style.h" // to get sp_fill_style_widget_set_desktop +#include "fill-n-stroke-factory.h" + +#include "verbs.h" + namespace Gtk { class Widget; class Container; } +namespace Inkscape { + namespace Util { + class Unit; + } + namespace UI { + namespace Widget { + class UnitMenu; + } + } +} + +struct { gchar const *key; gint value; } const SPMarkerNames[] = { + {"marker-all", SP_MARKER_LOC}, + {"marker-start", SP_MARKER_LOC_START}, + {"marker-mid", SP_MARKER_LOC_MID}, + {"marker-end", SP_MARKER_LOC_END}, + {"", SP_MARKER_LOC_QTY}, + {NULL, -1} +}; + /** * Creates an instance of a paint style widget. */ @@ -28,13 +103,122 @@ Gtk::Widget *sp_stroke_style_paint_widget_new(void); /** * Creates an instance of a line style widget. */ -Gtk::Container *sp_stroke_style_line_widget_new(void); +Gtk::Widget *sp_stroke_style_line_widget_new(void); /** * Switches a line or paint style widget to track the given desktop. */ void sp_stroke_style_widget_set_desktop(Gtk::Widget *widget, SPDesktop *desktop); +SPObject *getMarkerObj(gchar const *n, SPDocument *doc); + +namespace Inkscape { +class StrokeStyleButton; + +class StrokeStyle : public Gtk::VBox +{ +public: + StrokeStyle(); + ~StrokeStyle(); + void setDesktop(SPDesktop *desktop); + +private: + /** List of valid types for the stroke-style radio-button widget */ + enum StrokeStyleButtonType { + STROKE_STYLE_BUTTON_JOIN, ///< A button to set the line-join style + STROKE_STYLE_BUTTON_CAP ///< A button to set the line-cap style + }; + + /** + * A custom radio-button for setting the stroke style. It can be configured + * to set either the join or cap style by setting the button_type field. + */ + class StrokeStyleButton : public Gtk::RadioButton { + public: + StrokeStyleButton(Gtk::RadioButtonGroup &grp, + char const *icon, + StrokeStyleButtonType button_type, + gchar const *stroke_style); + + /** Get the type (line/cap) of the stroke-style button */ + inline StrokeStyleButtonType get_button_type() {return button_type;} + + /** Get the stroke style attribute associated with the button */ + inline gchar const * get_stroke_style() {return stroke_style;} + + private: + StrokeStyleButtonType button_type; ///< The type (line/cap) of the button + gchar const *stroke_style; ///< The stroke style associated with the button + }; + + void updateLine(); + void updateAllMarkers(GSList const *objects); + void updateMarkerHist(SPMarkerLoc const which); + void setDashSelectorFromStyle(SPDashSelector *dsel, SPStyle *style); + void setJoinType (unsigned const jointype); + void setCapType (unsigned const captype); + void setJoinButtons(Gtk::ToggleButton *active); + void setCapButtons(Gtk::ToggleButton *active); + void scaleLine(); + void setScaledDash(SPCSSAttr *css, int ndash, double *dash, double offset, double scale); + void setMarkerColor(SPObject *marker, int loc, SPItem *item); + SPObject *forkMarker(SPObject *marker, int loc, SPItem *item); + const char *getItemColorForMarker(SPItem *item, Inkscape::PaintTarget fill_or_stroke, int loc); + + StrokeStyleButton * makeRadioButton(Gtk::RadioButtonGroup &grp, + char const *icon, + Gtk::HBox *hb, + StrokeStyleButtonType button_type, + gchar const *stroke_style); + + // Callback functions + void selectionModifiedCB(guint flags); + void selectionChangedCB(); + void widthChangedCB(); + void miterLimitChangedCB(); + void lineDashChangedCB(); + void unitChangedCB(); + static void markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, SPMarkerLoc const which); + static void buttonToggledCB(StrokeStyleButton *tb, StrokeStyle *spw); + + + MarkerComboBox *startMarkerCombo; + MarkerComboBox *midMarkerCombo; + MarkerComboBox *endMarkerCombo; +#if WITH_GTKMM_3_0 + Gtk::Grid *table; + Glib::RefPtr<Gtk::Adjustment> *widthAdj; + Glib::RefPtr<Gtk::Adjustment> *miterLimitAdj; +#else + Gtk::Table *table; + Gtk::Adjustment *widthAdj; + Gtk::Adjustment *miterLimitAdj; +#endif + Inkscape::UI::Widget::SpinButton *miterLimitSpin; + Inkscape::UI::Widget::SpinButton *widthSpin; + Inkscape::UI::Widget::UnitMenu *unitSelector; + StrokeStyleButton *joinMiter; + StrokeStyleButton *joinRound; + StrokeStyleButton *joinBevel; + StrokeStyleButton *capButt; + StrokeStyleButton *capRound; + StrokeStyleButton *capSquare; + SPDashSelector *dashSelector; + + gboolean update; + SPDesktop *desktop; + sigc::connection selectChangedConn; + sigc::connection selectModifiedConn; + sigc::connection startMarkerConn; + sigc::connection midMarkerConn; + sigc::connection endMarkerConn; + sigc::connection unitChangedConn; + + Inkscape::Util::Unit const *_old_unit; +}; + +} // namespace Inkscape + #endif // SEEN_DIALOGS_STROKE_STYLE_H /* diff --git a/src/widgets/swatch-selector.cpp b/src/widgets/swatch-selector.cpp index 5de71c95e..7178ad072 100644 --- a/src/widgets/swatch-selector.cpp +++ b/src/widgets/swatch-selector.cpp @@ -1,8 +1,5 @@ - - -#include <glibmm/i18n.h> - #include "swatch-selector.h" +#include <glibmm/i18n.h> #include "document.h" #include "document-undo.h" @@ -175,14 +172,14 @@ void SwatchSelector::setVector(SPDocument */*doc*/, SPGradient *vector) if ( vector && vector->isSolid() ) { SPStop* stop = vector->getFirstStop(); - guint32 const colorVal = sp_stop_get_rgba32(stop); + guint32 const colorVal = stop->get_rgba32(); _csel->base->setAlpha(SP_RGBA32_A_F(colorVal)); SPColor color( SP_RGBA32_R_F(colorVal), SP_RGBA32_G_F(colorVal), SP_RGBA32_B_F(colorVal) ); // set its color, from the stored array _csel->base->setColor( color ); gtk_widget_show_all( GTK_WIDGET(_csel) ); } else { - gtk_widget_hide( GTK_WIDGET(_csel) ); + //gtk_widget_hide( GTK_WIDGET(_csel) ); } /* diff --git a/src/widgets/swatch-selector.h b/src/widgets/swatch-selector.h index b97aac4f1..c8c9983a6 100644 --- a/src/widgets/swatch-selector.h +++ b/src/widgets/swatch-selector.h @@ -1,14 +1,20 @@ #ifndef SEEN_SP_SWATCH_SELECTOR_H #define SEEN_SP_SWATCH_SELECTOR_H +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif #include <gtkmm/box.h> class SPDocument; class SPGradient; -class SPColorSelector; -class SPGradientSelector; +struct SPColorSelector; +struct SPGradientSelector; namespace Inkscape { diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp new file mode 100644 index 000000000..349fefa12 --- /dev/null +++ b/src/widgets/text-toolbar.cpp @@ -0,0 +1,1652 @@ +/** + * @file + * Text aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 2001-2002 Ximian, Inc. + * Copyright (C) 1999-2013 authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "libnrtype/font-lister.h" +#include <glibmm/i18n.h> +#include "text-toolbar.h" +#include "connection-pool.h" +#include "desktop-handles.h" +#include "desktop-style.h" +#include "desktop.h" +#include "document-undo.h" +#include "document.h" +#include "ege-adjustment-action.h" +#include "ege-select-one-action.h" +#include "ink-action.h" +#include "ink-comboboxentry-action.h" +#include "inkscape.h" +#include "preferences.h" +#include "selection-chemistry.h" +#include "selection.h" +#include "sp-flowtext.h" +#include "sp-root.h" +#include "sp-text.h" +#include "style.h" +#include "svg/css-ostringstream.h" +#include "text-editing.h" +#include "toolbox.h" +#include "ui/icon-names.h" +#include "ui/tools/text-tool.h" +#include "verbs.h" +#include "xml/repr.h" + +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; + +//#define DEBUG_TEXT + +//######################## +//## Text Toolbox ## +//######################## + +// Functions for debugging: +#ifdef DEBUG_TEXT + +static void sp_print_font( SPStyle *query ) { + + bool family_set = query->text->font_family.set; + bool style_set = query->font_style.set; + bool fontspec_set = query->text->font_specification.set; + + std::cout << " Family set? " << family_set + << " Style set? " << style_set + << " FontSpec set? " << fontspec_set + << std::endl; + std::cout << " Family: " + << (query->text->font_family.value ? query->text->font_family.value : "No value") + << " Style: " << query->font_style.computed + << " Weight: " << query->font_weight.computed + << " FontSpec: " + << (query->text->font_specification.value ? query->text->font_specification.value : "No value") + << std::endl; + std::cout << " LineHeight: " << query->line_height.computed + << " WordSpacing: " << query->word_spacing.computed + << " LetterSpacing: " << query->letter_spacing.computed + << std::endl; +} + +static void sp_print_fontweight( SPStyle *query ) { + const gchar* names[] = {"100", "200", "300", "400", "500", "600", "700", "800", "900", + "NORMAL", "BOLD", "LIGHTER", "BOLDER", "Out of range"}; + // Missing book = 380 + int index = query->font_weight.computed; + if( index < 0 || index > 13 ) index = 13; + std::cout << " Weight: " << names[ index ] + << " (" << query->font_weight.computed << ")" << std::endl; + +} + +static void sp_print_fontstyle( SPStyle *query ) { + + const gchar* names[] = {"NORMAL", "ITALIC", "OBLIQUE", "Out of range"}; + int index = query->font_style.computed; + if( index < 0 || index > 3 ) index = 3; + std::cout << " Style: " << names[ index ] << std::endl; + +} +#endif + +// Font family +static void sp_text_fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, GObject *tbl ) +{ +#ifdef DEBUG_TEXT + std::cout << std::endl; + std::cout << "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" << std::endl; + std::cout << "sp_text_fontfamily_value_changed: " << std::endl; +#endif + + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { +#ifdef DEBUG_TEXT + std::cout << "sp_text_fontfamily_value_changed: frozen... return" << std::endl; + std::cout << "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n" << std::endl; +#endif + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + Glib::ustring new_family = ink_comboboxentry_action_get_active_text( act ); + + // TODO: Think about how to handle handle multiple selections. While + // the font-family may be the same for all, the styles might be different. + // See: TextEdit::onApply() for example of looping over selected items. + Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); +#ifdef DEBUG_TEXT + std::cout << " Old family: " << fontlister->get_font_family() << std::endl; + std::cout << " New family: " << new_family << std::endl; + std::cout << " Old active: " << fontlister->get_font_family_row() << std::endl; + std::cout << " New active: " << act->active << std::endl; +#endif + if( new_family.compare( fontlister->get_font_family() ) != 0 ) { + + std::pair<Glib::ustring,Glib::ustring> ui = fontlister->set_font_family( act->active ); + // active text set in sp_text_toolbox_selection_changed() + + SPCSSAttr *css = sp_repr_css_attr_new (); + fontlister->fill_css( css ); + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + sp_desktop_set_style (desktop, css, true, true); // Results in selection change called twice. + sp_repr_css_attr_unref (css); + + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, + _("Text: Change font family")); + } + + // unfreeze + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); + +#ifdef DEBUG_TEXT + std::cout << "sp_text_toolbox_fontfamily_changes: exit" << std::endl; + std::cout << "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" << std::endl; + std::cout << std::endl; +#endif +} + +// Font size +static void sp_text_fontsize_value_changed( Ink_ComboBoxEntry_Action *act, GObject *tbl ) +{ + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + gchar *text = ink_comboboxentry_action_get_active_text( act ); + gchar *endptr; + gdouble size = g_strtod( text, &endptr ); + if (endptr == text) { // Conversion failed, non-numeric input. + g_warning( "Conversion of size text to double failed, input: %s\n", text ); + g_free( text ); + return; + } + g_free( text ); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int max_size = prefs->getInt("/dialogs/textandfont/maxFontSize", 10000); // somewhat arbitrary, but text&font preview freezes with too huge fontsizes + + if (size > max_size) + size = max_size; + + // Set css font size. + SPCSSAttr *css = sp_repr_css_attr_new (); + Inkscape::CSSOStringStream osfs; + int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT); + if (prefs->getBool("/options/font/textOutputPx", true)) { + osfs << sp_style_css_size_units_to_px(size, unit) << sp_style_get_css_unit_string(SP_CSS_UNIT_PX); + } else { + osfs << size << sp_style_get_css_unit_string(unit); + } + sp_repr_css_set_property (css, "font-size", osfs.str().c_str()); + + // Apply font size to selected objects. + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + sp_desktop_set_style (desktop, css, true, true); + + // If no selected objects, set default. + SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); + int result_numbers = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); + if (result_numbers == QUERY_STYLE_NOTHING) + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->mergeStyle("/tools/text/style", css); + } else { + // Save for undo + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE, + _("Text: Change font size")); + } + + sp_style_unref(query); + + sp_repr_css_attr_unref (css); + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +/* + * Font style + */ +static void sp_text_fontstyle_value_changed( Ink_ComboBoxEntry_Action *act, GObject *tbl ) +{ + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + Glib::ustring new_style = ink_comboboxentry_action_get_active_text( act ); + + Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); + + if( new_style.compare( fontlister->get_font_style() ) != 0 ) { + + fontlister->set_font_style( new_style ); + // active text set in sp_text_toolbox_seletion_changed() + + SPCSSAttr *css = sp_repr_css_attr_new (); + fontlister->fill_css( css ); + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + sp_desktop_set_style (desktop, css, true, true); + sp_repr_css_attr_unref (css); + + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, + _("Text: Change font style")); + } + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +// Handles both Superscripts and Subscripts +static void sp_text_script_changed( InkToggleAction* act, GObject *tbl ) +{ + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + // Called by Superscript or Subscript button? + const gchar* name = gtk_action_get_name( GTK_ACTION( act ) ); + gint prop = (strcmp(name, "TextSuperscriptAction") == 0) ? 0 : 1; + +#ifdef DEBUG_TEXT + std::cout << "sp_text_script_changed: " << prop << std::endl; +#endif + + // Query baseline + SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); + int result_baseline = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BASELINES); + + bool setSuper = false; + bool setSub = false; + + if(result_baseline == QUERY_STYLE_NOTHING || result_baseline == QUERY_STYLE_MULTIPLE_DIFFERENT ) { + // If not set or mixed, turn on superscript or subscript + if( prop == 0 ) { + setSuper = true; + } else { + setSub = true; + } + } else { + // Superscript + gboolean superscriptSet = (query->baseline_shift.set && + query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL && + query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUPER ); + + // Subscript + gboolean subscriptSet = (query->baseline_shift.set && + query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL && + query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUB ); + + setSuper = !superscriptSet && prop == 0; + setSub = !subscriptSet && prop == 1; + } + + // Set css properties + SPCSSAttr *css = sp_repr_css_attr_new (); + if( setSuper || setSub ) { + // Openoffice 2.3 and Adobe use 58%, Microsoft Word 2002 uses 65%, LaTex about 70%. + // 58% looks too small to me, especially if a superscript is placed on a superscript. + // If you make a change here, consider making a change to baseline-shift amount + // in style.cpp. + sp_repr_css_set_property (css, "font-size", "65%"); + } else { + sp_repr_css_set_property (css, "font-size", ""); + } + if( setSuper ) { + sp_repr_css_set_property (css, "baseline-shift", "super"); + } else if( setSub ) { + sp_repr_css_set_property (css, "baseline-shift", "sub"); + } else { + sp_repr_css_set_property (css, "baseline-shift", "baseline"); + } + + // Apply css to selected objects. + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + sp_desktop_set_style (desktop, css, true, false); + + // Save for undo + if(result_baseline != QUERY_STYLE_NOTHING) { + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:script", SP_VERB_NONE, + _("Text: Change superscript or subscript")); + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl ) +{ + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + int mode = ege_select_one_action_get_active( act ); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt("/tools/text/align_mode", mode); + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + // move the x of all texts to preserve the same bbox + Inkscape::Selection *selection = sp_desktop_selection(desktop); + for (GSList const *items = selection->itemList(); items != NULL; items = items->next) { + if (SP_IS_TEXT(SP_ITEM(items->data))) { + SPItem *item = SP_ITEM(items->data); + + unsigned writing_mode = item->style->writing_mode.value; + // below, variable names suggest horizontal move, but we check the writing direction + // and move in the corresponding axis + Geom::Dim2 axis; + if (writing_mode == SP_CSS_WRITING_MODE_LR_TB || writing_mode == SP_CSS_WRITING_MODE_RL_TB) { + axis = Geom::X; + } else { + axis = Geom::Y; + } + + Geom::OptRect bbox = item->geometricBounds(); + if (!bbox) + continue; + double width = bbox->dimensions()[axis]; + // If you want to align within some frame, other than the text's own bbox, calculate + // the left and right (or top and bottom for tb text) slacks of the text inside that + // frame (currently unused) + double left_slack = 0; + double right_slack = 0; + unsigned old_align = item->style->text_align.value; + double move = 0; + if (old_align == SP_CSS_TEXT_ALIGN_START || old_align == SP_CSS_TEXT_ALIGN_LEFT) { + switch (mode) { + case 0: + move = -left_slack; + break; + case 1: + move = width/2 + (right_slack - left_slack)/2; + break; + case 2: + move = width + right_slack; + break; + } + } else if (old_align == SP_CSS_TEXT_ALIGN_CENTER) { + switch (mode) { + case 0: + move = -width/2 - left_slack; + break; + case 1: + move = (right_slack - left_slack)/2; + break; + case 2: + move = width/2 + right_slack; + break; + } + } else if (old_align == SP_CSS_TEXT_ALIGN_END || old_align == SP_CSS_TEXT_ALIGN_RIGHT) { + switch (mode) { + case 0: + move = -width - left_slack; + break; + case 1: + move = -width/2 + (right_slack - left_slack)/2; + break; + case 2: + move = right_slack; + break; + } + } + Geom::Point XY = SP_TEXT(item)->attributes.firstXY(); + if (axis == Geom::X) { + XY = XY + Geom::Point (move, 0); + } else { + XY = XY + Geom::Point (0, move); + } + SP_TEXT(item)->attributes.setFirstXY(XY); + item->updateRepr(); + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + } + } + + SPCSSAttr *css = sp_repr_css_attr_new (); + switch (mode) + { + case 0: + { + sp_repr_css_set_property (css, "text-anchor", "start"); + sp_repr_css_set_property (css, "text-align", "start"); + break; + } + case 1: + { + sp_repr_css_set_property (css, "text-anchor", "middle"); + sp_repr_css_set_property (css, "text-align", "center"); + break; + } + + case 2: + { + sp_repr_css_set_property (css, "text-anchor", "end"); + sp_repr_css_set_property (css, "text-align", "end"); + break; + } + + case 3: + { + sp_repr_css_set_property (css, "text-anchor", "start"); + sp_repr_css_set_property (css, "text-align", "justify"); + break; + } + } + + SPStyle *query = + sp_style_new (SP_ACTIVE_DOCUMENT); + int result_numbers = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); + + // If querying returned nothing, update default style. + if (result_numbers == QUERY_STYLE_NOTHING) + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->mergeStyle("/tools/text/style", css); + } + + sp_style_unref(query); + + sp_desktop_set_style (desktop, css, true, true); + if (result_numbers != QUERY_STYLE_NOTHING) + { + DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, + _("Text: Change alignment")); + } + sp_repr_css_attr_unref (css); + + gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas)); + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl ) +{ + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + // At the moment this handles only numerical values (i.e. no percent). + // Set css line height. + SPCSSAttr *css = sp_repr_css_attr_new (); + Inkscape::CSSOStringStream osfs; + osfs << gtk_adjustment_get_value(adj)*100 << "%"; + sp_repr_css_set_property (css, "line-height", osfs.str().c_str()); + + // Apply line-height to selected objects. + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + sp_desktop_set_style (desktop, css, true, false); + + + // Until deprecated sodipodi:linespacing purged: + Inkscape::Selection *selection = sp_desktop_selection(desktop); + GSList const *items = selection->itemList(); + bool modmade = false; + for (; items != NULL; items = items->next) { + if (SP_IS_TEXT (items->data)) { + SP_OBJECT(items->data)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); + modmade = true; + } + } + + // Save for undo + if(modmade) { + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:line-height", SP_VERB_NONE, + _("Text: Change line-height")); + } + + // If no selected objects, set default. + SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); + int result_numbers = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); + if (result_numbers == QUERY_STYLE_NOTHING) + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->mergeStyle("/tools/text/style", css); + } + sp_style_unref(query); + + sp_repr_css_attr_unref (css); + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_text_wordspacing_value_changed( GtkAdjustment *adj, GObject *tbl ) +{ + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + // At the moment this handles only numerical values (i.e. no em unit). + // Set css word-spacing + SPCSSAttr *css = sp_repr_css_attr_new (); + Inkscape::CSSOStringStream osfs; + osfs << gtk_adjustment_get_value(adj) << "px"; // For now always use px + sp_repr_css_set_property (css, "word-spacing", osfs.str().c_str()); + + // Apply word-spacing to selected objects. + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + sp_desktop_set_style (desktop, css, true, false); + + // If no selected objects, set default. + SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); + int result_numbers = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); + if (result_numbers == QUERY_STYLE_NOTHING) + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->mergeStyle("/tools/text/style", css); + } else { + // Save for undo + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:word-spacing", SP_VERB_NONE, + _("Text: Change word-spacing")); + } + sp_style_unref(query); + + sp_repr_css_attr_unref (css); + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_text_letterspacing_value_changed( GtkAdjustment *adj, GObject *tbl ) +{ + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + // At the moment this handles only numerical values (i.e. no em unit). + // Set css letter-spacing + SPCSSAttr *css = sp_repr_css_attr_new (); + Inkscape::CSSOStringStream osfs; + osfs << gtk_adjustment_get_value(adj) << "px"; // For now always use px + sp_repr_css_set_property (css, "letter-spacing", osfs.str().c_str()); + + // Apply letter-spacing to selected objects. + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + sp_desktop_set_style (desktop, css, true, false); + + // If no selected objects, set default. + SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); + int result_numbers = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); + if (result_numbers == QUERY_STYLE_NOTHING) + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->mergeStyle("/tools/text/style", css); + } + else + { + // Save for undo + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:letter-spacing", SP_VERB_NONE, + _("Text: Change letter-spacing")); + } + + sp_style_unref(query); + + sp_repr_css_attr_unref (css); + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + + +static void sp_text_dx_value_changed( GtkAdjustment *adj, GObject *tbl ) +{ + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + gdouble new_dx = gtk_adjustment_get_value(adj); + bool modmade = false; + + if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) { + Inkscape::UI::Tools::TextTool *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context); + if( tc ) { + unsigned char_index = -1; + TextTagAttributes *attributes = + text_tag_attributes_at_position( tc->text, std::min(tc->text_sel_start, tc->text_sel_end), &char_index ); + if( attributes ) { + double old_dx = attributes->getDx( char_index ); + double delta_dx = new_dx - old_dx; + sp_te_adjust_dx( tc->text, tc->text_sel_start, tc->text_sel_end, SP_ACTIVE_DESKTOP, delta_dx ); + modmade = true; + } + } + } + + if(modmade) { + // Save for undo + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:dx", SP_VERB_NONE, + _("Text: Change dx (kern)")); + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_text_dy_value_changed( GtkAdjustment *adj, GObject *tbl ) +{ + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + gdouble new_dy = gtk_adjustment_get_value(adj); + bool modmade = false; + + if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) { + Inkscape::UI::Tools::TextTool *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context); + if( tc ) { + unsigned char_index = -1; + TextTagAttributes *attributes = + text_tag_attributes_at_position( tc->text, std::min(tc->text_sel_start, tc->text_sel_end), &char_index ); + if( attributes ) { + double old_dy = attributes->getDy( char_index ); + double delta_dy = new_dy - old_dy; + sp_te_adjust_dy( tc->text, tc->text_sel_start, tc->text_sel_end, SP_ACTIVE_DESKTOP, delta_dy ); + modmade = true; + } + } + } + + if(modmade) { + // Save for undo + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:dy", SP_VERB_NONE, + _("Text: Change dy")); + } + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_text_rotation_value_changed( GtkAdjustment *adj, GObject *tbl ) +{ + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + gdouble new_degrees = gtk_adjustment_get_value(adj); + + bool modmade = false; + if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) { + Inkscape::UI::Tools::TextTool *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context); + if( tc ) { + unsigned char_index = -1; + TextTagAttributes *attributes = + text_tag_attributes_at_position( tc->text, std::min(tc->text_sel_start, tc->text_sel_end), &char_index ); + if( attributes ) { + double old_degrees = attributes->getRotate( char_index ); + double delta_deg = new_degrees - old_degrees; + sp_te_adjust_rotation( tc->text, tc->text_sel_start, tc->text_sel_end, SP_ACTIVE_DESKTOP, delta_deg ); + modmade = true; + } + } + } + + // Save for undo + if(modmade) { + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:rotate", SP_VERB_NONE, + _("Text: Change rotate")); + } + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_text_orientation_mode_changed( EgeSelectOneAction *act, GObject *tbl ) +{ + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + int mode = ege_select_one_action_get_active( act ); + + SPCSSAttr *css = sp_repr_css_attr_new (); + switch (mode) + { + case 0: + { + sp_repr_css_set_property (css, "writing-mode", "lr"); + break; + } + + case 1: + { + sp_repr_css_set_property (css, "writing-mode", "tb"); + break; + } + } + + SPStyle *query = + sp_style_new (SP_ACTIVE_DOCUMENT); + int result_numbers = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); + + // If querying returned nothing, update default style. + if (result_numbers == QUERY_STYLE_NOTHING) + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->mergeStyle("/tools/text/style", css); + } + + sp_desktop_set_style (SP_ACTIVE_DESKTOP, css, true, true); + if(result_numbers != QUERY_STYLE_NOTHING) + { + DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, + _("Text: Change orientation")); + } + sp_repr_css_attr_unref (css); + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +/* + * Set the default list of font sizes, scaled to the users preferred unit + */ +static void sp_text_set_sizes(GtkListStore* model_size, int unit) +{ + gtk_list_store_clear(model_size); + + // List of font sizes for drop-down menu + int sizes[] = { + 4, 6, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 28, + 32, 36, 40, 48, 56, 64, 72, 144 + }; + + // Array must be same length as SPCSSUnit in style.h + float ratios[] = {1, 1, 1, 10, 4, 40, 100, 16, 8, 0.16}; + + for( unsigned int i = 0; i < G_N_ELEMENTS(sizes); ++i ) { + GtkTreeIter iter; + Glib::ustring size = Glib::ustring::format(sizes[i] / (float)ratios[unit]); + gtk_list_store_append( model_size, &iter ); + gtk_list_store_set( model_size, &iter, 0, size.c_str(), -1 ); + } +} + + +/* + * This function sets up the text-tool tool-controls, setting the entry boxes + * etc. to the values from the current selection or the default if no selection. + * It is called whenever a text selection is changed, including stepping cursor + * through text, or setting focus to text. + */ +static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/, GObject *tbl) +{ +#ifdef DEBUG_TEXT + static int count = 0; + ++count; + std::cout << std::endl; + std::cout << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << std::endl; + std::cout << "sp_text_toolbox_selection_changed: start " << count << std::endl; + + std::cout << " Selected items:" << std::endl; + for (GSList const *items = sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList(); + items != NULL; + items = items->next) + { + const gchar* id = reinterpret_cast<SPItem *>(items->data)->getId(); + std::cout << " " << id << std::endl; + } + Glib::ustring selected_text = sp_text_get_selected_text((SP_ACTIVE_DESKTOP)->event_context); + std::cout << " Selected text:" << std::endl; + std::cout << selected_text << std::endl; +#endif + + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { +#ifdef DEBUG_TEXT + std::cout << " Frozen, returning" << std::endl; + std::cout << "sp_text_toolbox_selection_changed: exit " << count << std::endl; + std::cout << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << std::endl; + std::cout << std::endl; +#endif + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + Ink_ComboBoxEntry_Action* fontFamilyAction = + INK_COMBOBOXENTRY_ACTION( g_object_get_data( tbl, "TextFontFamilyAction" ) ); + Ink_ComboBoxEntry_Action* fontStyleAction = + INK_COMBOBOXENTRY_ACTION( g_object_get_data( tbl, "TextFontStyleAction" ) ); + + Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); + fontlister->update_font_list( sp_desktop_document( SP_ACTIVE_DESKTOP )); + fontlister->selection_update(); + + // Update font list, but only if widget already created. + if( fontFamilyAction->combobox != NULL ) { + ink_comboboxentry_action_set_active_text( fontFamilyAction, fontlister->get_font_family().c_str(), fontlister->get_font_family_row() ); + ink_comboboxentry_action_set_active_text( fontStyleAction, fontlister->get_font_style().c_str() ); + } + + // Only flowed text can be justified, only normal text can be kerned... + // Find out if we have flowed text now so we can use it several places + gboolean isFlow = false; + for (GSList const *items = sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList(); + items != NULL; + items = items->next) { + // const gchar* id = reinterpret_cast<SPItem *>(items->data)->getId(); + // std::cout << " " << id << std::endl; + if( SP_IS_FLOWTEXT(SP_ITEM(items->data))) { + isFlow = true; + // std::cout << " Found flowed text" << std::endl; + break; + } + } + + /* + * Query from current selection: + * Font family (font-family) + * Style (font-weight, font-style, font-stretch, font-variant, font-align) + * Numbers (font-size, letter-spacing, word-spacing, line-height, text-anchor, writing-mode) + * Font specification (Inkscape private attribute) + */ + SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); + int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); + int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); + int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); + int result_baseline = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BASELINES); + + /* + * If no text in selection (querying returned nothing), read the style from + * the /tools/text preferencess (default style for new texts). Return if + * tool bar already set to these preferences. + */ + if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING) { + // There are no texts in selection, read from preferences. + sp_style_read_from_prefs(query, "/tools/text"); +#ifdef DEBUG_TEXT + std::cout << " read style from prefs:" << std::endl; + sp_print_font( query ); +#endif + if (g_object_get_data(tbl, "text_style_from_prefs")) { + // Do not reset the toolbar style from prefs if we already did it last time + sp_style_unref(query); + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +#ifdef DEBUG_TEXT + std::cout << " text_style_from_prefs: toolbar already set" << std:: endl; + std::cout << "sp_text_toolbox_selection_changed: exit " << count << std::endl; + std::cout << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << std::endl; + std::cout << std::endl; +#endif + return; + } + + // To ensure the value of the combobox is properly set on start-up, only mark + // the prefs set if the combobox has already been constructed. + if( fontFamilyAction->combobox != NULL ) { + g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(TRUE)); + } + } else { + g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(FALSE)); + } + + // If we have valid query data for text (font-family, font-specification) set toolbar accordingly. + if (query->text) + { + // Size (average of text selected) + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT); + double size = sp_style_css_size_px_to_units(query->font_size.computed, unit); + + //gchar size_text[G_ASCII_DTOSTR_BUF_SIZE]; + //g_ascii_dtostr (size_text, sizeof (size_text), size); + + Inkscape::CSSOStringStream os; + os << size; + + Ink_ComboBoxEntry_Action* fontSizeAction = + INK_COMBOBOXENTRY_ACTION( g_object_get_data( tbl, "TextFontSizeAction" ) ); + + // Freeze to ignore callbacks. + //g_object_freeze_notify( G_OBJECT( fontSizeAction->combobox ) ); + sp_text_set_sizes(GTK_LIST_STORE(ink_comboboxentry_action_get_model(fontSizeAction)), unit); + //g_object_thaw_notify( G_OBJECT( fontSizeAction->combobox ) ); + + ink_comboboxentry_action_set_active_text( fontSizeAction, os.str().c_str() ); + + Glib::ustring tooltip = Glib::ustring::format(_("Font size"), " (", sp_style_get_css_unit_string(unit), ")"); + ink_comboboxentry_action_set_tooltip ( fontSizeAction, tooltip.c_str()); + + // Superscript + gboolean superscriptSet = + ((result_baseline == QUERY_STYLE_SINGLE || result_baseline == QUERY_STYLE_MULTIPLE_SAME ) && + query->baseline_shift.set && + query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL && + query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUPER ); + + InkToggleAction* textSuperscriptAction = INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextSuperscriptAction" ) ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(textSuperscriptAction), superscriptSet ); + + + // Subscript + gboolean subscriptSet = + ((result_baseline == QUERY_STYLE_SINGLE || result_baseline == QUERY_STYLE_MULTIPLE_SAME ) && + query->baseline_shift.set && + query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL && + query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUB ); + + InkToggleAction* textSubscriptAction = INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextSubscriptAction" ) ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(textSubscriptAction), subscriptSet ); + + + // Alignment + EgeSelectOneAction* textAlignAction = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextAlignAction" ) ); + + // Note: SVG 1.1 doesn't include text-align, SVG 1.2 Tiny doesn't include text-align="justify" + // text-align="justify" was a draft SVG 1.2 item (along with flowed text). + // Only flowed text can be left and right justified at the same time. + // Disable button if we don't have flowed text. + + // The GtkTreeModel class doesn't have a set function so we can't + // simply add an ege_select_one_action_set_sensitive method! + // We must set values directly with the GtkListStore and then + // ask that the GtkAction update the sensitive parameters. + GtkListStore * model = GTK_LIST_STORE( ege_select_one_action_get_model( textAlignAction ) ); + GtkTreePath * path = gtk_tree_path_new_from_string("3"); // Justify entry + GtkTreeIter iter; + gtk_tree_model_get_iter( GTK_TREE_MODEL (model), &iter, path ); + gtk_list_store_set( model, &iter, /* column */ 3, isFlow, -1 ); + ege_select_one_action_update_sensitive( textAlignAction ); + // ege_select_one_action_set_sensitive( textAlignAction, 3, isFlow ); + + int activeButton = 0; + if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY) + { + activeButton = 3; + } else { + if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START) activeButton = 0; + if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE) activeButton = 1; + if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END) activeButton = 2; + } + ege_select_one_action_set_active( textAlignAction, activeButton ); + + + // Line height (spacing) + double height; + if (query->line_height.normal) { + height = Inkscape::Text::Layout::LINE_HEIGHT_NORMAL; + } else { + if (query->line_height.unit == SP_CSS_UNIT_PERCENT) { + height = query->line_height.value; + } else { + height = query->line_height.computed; + } + } + + GtkAction* lineHeightAction = GTK_ACTION( g_object_get_data( tbl, "TextLineHeightAction" ) ); + GtkAdjustment *lineHeightAdjustment = + ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( lineHeightAction )); + gtk_adjustment_set_value( lineHeightAdjustment, height ); + + + // Word spacing + double wordSpacing; + if (query->word_spacing.normal) wordSpacing = 0.0; + else wordSpacing = query->word_spacing.computed; // Assume no units (change in desktop-style.cpp) + + GtkAction* wordSpacingAction = GTK_ACTION( g_object_get_data( tbl, "TextWordSpacingAction" ) ); + GtkAdjustment *wordSpacingAdjustment = + ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( wordSpacingAction )); + gtk_adjustment_set_value( wordSpacingAdjustment, wordSpacing ); + + + // Letter spacing + double letterSpacing; + if (query->letter_spacing.normal) letterSpacing = 0.0; + else letterSpacing = query->letter_spacing.computed; // Assume no units (change in desktop-style.cpp) + + GtkAction* letterSpacingAction = GTK_ACTION( g_object_get_data( tbl, "TextLetterSpacingAction" ) ); + GtkAdjustment *letterSpacingAdjustment = + ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( letterSpacingAction )); + gtk_adjustment_set_value( letterSpacingAdjustment, letterSpacing ); + + + // Orientation + int activeButton2 = (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB ? 0 : 1); + + EgeSelectOneAction* textOrientationAction = + EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextOrientationAction" ) ); + ege_select_one_action_set_active( textOrientationAction, activeButton2 ); + + + } // if( query->text ) + +#ifdef DEBUG_TEXT + std::cout << " GUI: fontfamily.value: " + << (query->text->font_family.value ? query->text->font_family.value : "No value") + << std::endl; + std::cout << " GUI: font_size.computed: " << query->font_size.computed << std::endl; + std::cout << " GUI: font_weight.computed: " << query->font_weight.computed << std::endl; + std::cout << " GUI: font_style.computed: " << query->font_style.computed << std::endl; + std::cout << " GUI: text_anchor.computed: " << query->text_anchor.computed << std::endl; + std::cout << " GUI: text_align.computed: " << query->text_align.computed << std::endl; + std::cout << " GUI: line_height.computed: " << query->line_height.computed + << " line_height.value: " << query->line_height.value + << " line_height.unit: " << query->line_height.unit << std::endl; + std::cout << " GUI: word_spacing.computed: " << query->word_spacing.computed + << " word_spacing.value: " << query->word_spacing.value + << " word_spacing.unit: " << query->word_spacing.unit << std::endl; + std::cout << " GUI: letter_spacing.computed: " << query->letter_spacing.computed + << " letter_spacing.value: " << query->letter_spacing.value + << " letter_spacing.unit: " << query->letter_spacing.unit << std::endl; + std::cout << " GUI: writing_mode.computed: " << query->writing_mode.computed << std::endl; +#endif + + sp_style_unref(query); + + // Kerning (xshift), yshift, rotation. NB: These are not CSS attributes. + if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) { + Inkscape::UI::Tools::TextTool *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context); + if( tc ) { + unsigned char_index = -1; + TextTagAttributes *attributes = + text_tag_attributes_at_position( tc->text, std::min(tc->text_sel_start, tc->text_sel_end), &char_index ); + if( attributes ) { + + // Dx + double dx = attributes->getDx( char_index ); + GtkAction* dxAction = GTK_ACTION( g_object_get_data( tbl, "TextDxAction" )); + GtkAdjustment *dxAdjustment = + ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( dxAction )); + gtk_adjustment_set_value( dxAdjustment, dx ); + + // Dy + double dy = attributes->getDy( char_index ); + GtkAction* dyAction = GTK_ACTION( g_object_get_data( tbl, "TextDyAction" )); + GtkAdjustment *dyAdjustment = + ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( dyAction )); + gtk_adjustment_set_value( dyAdjustment, dy ); + + // Rotation + double rotation = attributes->getRotate( char_index ); + /* SVG value is between 0 and 360 but we're using -180 to 180 in widget */ + if( rotation > 180.0 ) rotation -= 360.0; + GtkAction* rotationAction = GTK_ACTION( g_object_get_data( tbl, "TextRotationAction" )); + GtkAdjustment *rotationAdjustment = + ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( rotationAction )); + gtk_adjustment_set_value( rotationAdjustment, rotation ); + +#ifdef DEBUG_TEXT + std::cout << " GUI: Dx: " << dx << std::endl; + std::cout << " GUI: Dy: " << dy << std::endl; + std::cout << " GUI: Rotation: " << rotation << std::endl; +#endif + } + } + } + + { + // Set these here as we don't always have kerning/rotating attributes + GtkAction* dxAction = GTK_ACTION( g_object_get_data( tbl, "TextDxAction" )); + gtk_action_set_sensitive( GTK_ACTION(dxAction), !isFlow ); + + GtkAction* dyAction = GTK_ACTION( g_object_get_data( tbl, "TextDyAction" )); + gtk_action_set_sensitive( GTK_ACTION(dyAction), !isFlow ); + + GtkAction* rotationAction = GTK_ACTION( g_object_get_data( tbl, "TextRotationAction" )); + gtk_action_set_sensitive( GTK_ACTION(rotationAction), !isFlow ); + } + +#ifdef DEBUG_TEXT + std::cout << "sp_text_toolbox_selection_changed: exit " << count << std::endl; + std::cout << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << std::endl; + std::cout << std::endl; +#endif + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); + +} + +static void sp_text_toolbox_selection_modified(Inkscape::Selection *selection, guint /*flags*/, GObject *tbl) +{ + sp_text_toolbox_selection_changed (selection, tbl); +} + +static void +sp_text_toolbox_subselection_changed (gpointer /*tc*/, GObject *tbl) +{ + sp_text_toolbox_selection_changed (NULL, tbl); +} + +// TODO: possibly share with font-selector by moving most code to font-lister (passing family name) +static void sp_text_toolbox_select_cb( GtkEntry* entry, GtkEntryIconPosition /*position*/, GdkEvent /*event*/, gpointer /*data*/ ) { + + Glib::ustring family = gtk_entry_get_text ( entry ); + //std::cout << "text_toolbox_missing_font_cb: selecting: " << family << std::endl; + + // Get all items with matching font-family set (not inherited!). + GSList *selectList = NULL; + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SPDocument *document = sp_desktop_document( desktop ); + GSList *allList = get_all_items(NULL, document->getRoot(), desktop, false, false, true, NULL); + for (GSList *i = allList; i != NULL; i = i->next) { + + SPItem *item = SP_ITEM(i->data); + SPStyle *style = item->style; + + if (style && style->text) { + + Glib::ustring family_style; + if (style->text->font_family.set) { + family_style = style->text->font_family.value; + //std::cout << " family style from font_family: " << family_style << std::endl; + } + else if (style->text->font_specification.set) { + family_style = style->text->font_specification.value; + //std::cout << " family style from font_spec: " << family_style << std::endl; + } + + if (family_style.compare( family ) == 0 ) { + //std::cout << " found: " << item->getId() << std::endl; + selectList = g_slist_prepend (selectList, item); + } + } + } + + // Update selection + Inkscape::Selection *selection = sp_desktop_selection (desktop ); + selection->clear(); + //std::cout << " list length: " << g_slist_length ( selectList ) << std::endl; + selection->setList(selectList); +} + + +// Define all the "widgets" in the toolbar. +void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); + + /* Font family */ + { + // Font list + Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); + fontlister->update_font_list( sp_desktop_document( SP_ACTIVE_DESKTOP )); + Glib::RefPtr<Gtk::ListStore> store = fontlister->get_font_list(); + GtkListStore* model = store->gobj(); + + Ink_ComboBoxEntry_Action* act = + ink_comboboxentry_action_new( "TextFontFamilyAction", + _("Font Family"), + _("Select Font Family (Alt-X to access)"), + NULL, + GTK_TREE_MODEL(model), + -1, // Entry width + 50, // Extra list width + (gpointer)font_lister_cell_data_func, // Cell layout + (gpointer)font_lister_separator_func, + GTK_WIDGET(desktop->canvas)); // Focus widget + ink_comboboxentry_action_popup_enable( act ); // Enable entry completion + + gchar *const info = _("Select all text with this font-family"); + ink_comboboxentry_action_set_info( act, info ); // Show selection icon + ink_comboboxentry_action_set_info_cb( act, (gpointer)sp_text_toolbox_select_cb ); + + gchar *const warning = _("Font not found on system"); + ink_comboboxentry_action_set_warning( act, warning ); // Show icon w/ tooltip if font missing + ink_comboboxentry_action_set_warning_cb( act, (gpointer)sp_text_toolbox_select_cb ); + + //ink_comboboxentry_action_set_warning_callback( act, sp_text_fontfamily_select_all ); + ink_comboboxentry_action_set_altx_name( act, "altx-text" ); // Set Alt-X keyboard shortcut + g_signal_connect( G_OBJECT(act), "changed", G_CALLBACK(sp_text_fontfamily_value_changed), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "TextFontFamilyAction", act ); + + // Change style of drop-down from menu to list + gtk_rc_parse_string ( + "style \"dropdown-as-list-style\"\n" + "{\n" + " GtkComboBox::appears-as-list = 1\n" + "}\n" + "widget \"*.TextFontFamilyAction_combobox\" style \"dropdown-as-list-style\"" + "style \"fontfamily-separator-style\"\n" + "{\n" + " GtkWidget::wide-separators = 1\n" + " GtkWidget::separator-height = 6\n" + "}\n" + "widget \"*gtk-combobox-popup-window.GtkScrolledWindow.GtkTreeView\" style \"fontfamily-separator-style\""); + } + + /* Font size */ + { + // List of font sizes for drop-down menu + GtkListStore* model_size = gtk_list_store_new( 1, G_TYPE_STRING ); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT); + + sp_text_set_sizes(model_size, unit); + + Glib::ustring tooltip = Glib::ustring::format(_("Font size"), " (", sp_style_get_css_unit_string(unit), ")"); + + Ink_ComboBoxEntry_Action* act = ink_comboboxentry_action_new( "TextFontSizeAction", + _("Font Size"), + _(tooltip.c_str()), + NULL, + GTK_TREE_MODEL(model_size), + 4, // Width in characters + 0, // Extra list width + NULL, // Cell layout + NULL, // Separator + GTK_WIDGET(desktop->canvas)); // Focus widget + + g_signal_connect( G_OBJECT(act), "changed", G_CALLBACK(sp_text_fontsize_value_changed), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "TextFontSizeAction", act ); + } + + /* Font styles */ + { + Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); + Glib::RefPtr<Gtk::ListStore> store = fontlister->get_style_list(); + GtkListStore* model_style = store->gobj(); + + Ink_ComboBoxEntry_Action* act = ink_comboboxentry_action_new( "TextFontStyleAction", + _("Font Style"), + _("Font style"), + NULL, + GTK_TREE_MODEL(model_style), + 12, // Width in characters + 0, // Extra list width + NULL, // Cell layout + NULL, // Separator + GTK_WIDGET(desktop->canvas)); // Focus widget + + g_signal_connect( G_OBJECT(act), "changed", G_CALLBACK(sp_text_fontstyle_value_changed), holder ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "TextFontStyleAction", act ); + } + + /* Style - Superscript */ + { + InkToggleAction* act = ink_toggle_action_new( "TextSuperscriptAction", // Name + _("Toggle Superscript"), // Label + _("Toggle superscript"), // Tooltip + "text_superscript", // Icon (inkId) + secondarySize ); // Icon size + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_script_changed), holder ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/super", false) ); + g_object_set_data( holder, "TextSuperscriptAction", act ); + } + + /* Style - Subscript */ + { + InkToggleAction* act = ink_toggle_action_new( "TextSubscriptAction", // Name + _("Toggle Subscript"), // Label + _("Toggle subscript"), // Tooltip + "text_subscript", // Icon (inkId) + secondarySize ); // Icon size + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_script_changed), holder ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/sub", false) ); + g_object_set_data( holder, "TextSubscriptAction", act ); + } + + /* Alignment */ + { + GtkListStore* model = gtk_list_store_new( 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN ); + + GtkTreeIter iter; + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Align left"), + 1, _("Align left"), + 2, INKSCAPE_ICON("format-justify-left"), + 3, true, + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Align center"), + 1, _("Align center"), + 2, INKSCAPE_ICON("format-justify-center"), + 3, true, + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Align right"), + 1, _("Align right"), + 2, INKSCAPE_ICON("format-justify-right"), + 3, true, + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Justify"), + 1, _("Justify (only flowed text)"), + 2, INKSCAPE_ICON("format-justify-fill"), + 3, false, + -1 ); + + EgeSelectOneAction* act = ege_select_one_action_new( "TextAlignAction", // Name + _("Alignment"), // Label + _("Text alignment"), // Tooltip + NULL, // Icon name + GTK_TREE_MODEL(model) ); // Model + g_object_set( act, "short_label", "NotUsed", NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "TextAlignAction", act ); + + ege_select_one_action_set_appearance( act, "full" ); + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); + ege_select_one_action_set_icon_column( act, 2 ); + ege_select_one_action_set_icon_size( act, secondarySize ); + ege_select_one_action_set_tooltip_column( act, 1 ); + ege_select_one_action_set_sensitive_column( act, 3 ); + gint mode = prefs->getInt("/tools/text/align_mode", 0); + ege_select_one_action_set_active( act, mode ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_align_mode_changed), holder ); + } + + /* Orientation (Left to Right, Top to Bottom */ + { + GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); + + GtkTreeIter iter; + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Horizontal"), + 1, _("Horizontal text"), + 2, INKSCAPE_ICON("format-text-direction-horizontal"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Vertical"), + 1, _("Vertical text"), + 2, INKSCAPE_ICON("format-text-direction-vertical"), + -1 ); + + EgeSelectOneAction* act = ege_select_one_action_new( "TextOrientationAction", // Name + _("Orientation"), // Label + _("Text orientation"), // Tooltip + NULL, // Icon name + GTK_TREE_MODEL(model) ); // Model + + g_object_set( act, "short_label", "NotUsed", NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "TextOrientationAction", act ); + + ege_select_one_action_set_appearance( act, "full" ); + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); + ege_select_one_action_set_icon_column( act, 2 ); + ege_select_one_action_set_icon_size( act, secondarySize ); + ege_select_one_action_set_tooltip_column( act, 1 ); + + gint mode = prefs->getInt("/tools/text/orientation", 0); + ege_select_one_action_set_active( act, mode ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_orientation_mode_changed), holder ); + } + + /* Line height */ + { + // Drop down menu + gchar const* labels[] = {_("Smaller spacing"), 0, 0, 0, 0, C_("Text tool", "Normal"), 0, 0, 0, 0, 0, _("Larger spacing")}; + gdouble values[] = { 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1,2, 1.3, 1.4, 1.5, 2.0}; + + EgeAdjustmentAction *eact = create_adjustment_action( + "TextLineHeightAction", /* name */ + _("Line Height"), /* label */ + _("Line:"), /* short label */ + _("Spacing between lines (times font size)"), /* tooltip */ + "/tools/text/lineheight", /* preferences path */ + 0.0, /* default */ + GTK_WIDGET(desktop->canvas), /* focusTarget */ + holder, /* dataKludge */ + FALSE, /* set alt-x keyboard shortcut? */ + NULL, /* altx_mark */ + 0.0, 10.0, 0.01, 0.10, /* lower, upper, step (arrow up/down), page up/down */ + labels, values, G_N_ELEMENTS(labels), /* drop down menu */ + sp_text_lineheight_value_changed, /* callback */ + NULL, /* unit tracker */ + 0.1, /* step (used?) */ + 2, /* digits to show */ + 1.0 /* factor (multiplies default) */ + ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + g_object_set_data( holder, "TextLineHeightAction", eact ); + g_object_set( G_OBJECT(eact), "iconId", "text_line_spacing", NULL ); + } + + /* Word spacing */ + { + // Drop down menu + gchar const* labels[] = {_("Negative spacing"), 0, 0, 0, C_("Text tool", "Normal"), 0, 0, 0, 0, 0, 0, 0, _("Positive spacing")}; + gdouble values[] = {-2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0}; + + EgeAdjustmentAction *eact = create_adjustment_action( + "TextWordSpacingAction", /* name */ + _("Word spacing"), /* label */ + _("Word:"), /* short label */ + _("Spacing between words (px)"), /* tooltip */ + "/tools/text/wordspacing", /* preferences path */ + 0.0, /* default */ + GTK_WIDGET(desktop->canvas), /* focusTarget */ + holder, /* dataKludge */ + FALSE, /* set alt-x keyboard shortcut? */ + NULL, /* altx_mark */ + -100.0, 100.0, 0.01, 0.10, /* lower, upper, step (arrow up/down), page up/down */ + labels, values, G_N_ELEMENTS(labels), /* drop down menu */ + sp_text_wordspacing_value_changed, /* callback */ + NULL, /* unit tracker */ + 0.1, /* step (used?) */ + 2, /* digits to show */ + 1.0 /* factor (multiplies default) */ + ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + g_object_set_data( holder, "TextWordSpacingAction", eact ); + g_object_set( G_OBJECT(eact), "iconId", "text_word_spacing", NULL ); + } + + /* Letter spacing */ + { + // Drop down menu + gchar const* labels[] = {_("Negative spacing"), 0, 0, 0, C_("Text tool", "Normal"), 0, 0, 0, 0, 0, 0, 0, _("Positive spacing")}; + gdouble values[] = {-2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0}; + + EgeAdjustmentAction *eact = create_adjustment_action( + "TextLetterSpacingAction", /* name */ + _("Letter spacing"), /* label */ + _("Letter:"), /* short label */ + _("Spacing between letters (px)"), /* tooltip */ + "/tools/text/letterspacing", /* preferences path */ + 0.0, /* default */ + GTK_WIDGET(desktop->canvas), /* focusTarget */ + holder, /* dataKludge */ + FALSE, /* set alt-x keyboard shortcut? */ + NULL, /* altx_mark */ + -100.0, 100.0, 0.01, 0.10, /* lower, upper, step (arrow up/down), page up/down */ + labels, values, G_N_ELEMENTS(labels), /* drop down menu */ + sp_text_letterspacing_value_changed, /* callback */ + NULL, /* unit tracker */ + 0.1, /* step (used?) */ + 2, /* digits to show */ + 1.0 /* factor (multiplies default) */ + ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + g_object_set_data( holder, "TextLetterSpacingAction", eact ); + g_object_set( G_OBJECT(eact), "iconId", "text_letter_spacing", NULL ); + } + + /* Character kerning (horizontal shift) */ + { + // Drop down menu + gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + gdouble values[] = { -2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5 }; + + EgeAdjustmentAction *eact = create_adjustment_action( + "TextDxAction", /* name */ + _("Kerning"), /* label */ + _("Kern:"), /* short label */ + _("Horizontal kerning (px)"), /* tooltip */ + "/tools/text/dx", /* preferences path */ + 0.0, /* default */ + GTK_WIDGET(desktop->canvas), /* focusTarget */ + holder, /* dataKludge */ + FALSE, /* set alt-x keyboard shortcut? */ + NULL, /* altx_mark */ + -100.0, 100.0, 0.01, 0.1, /* lower, upper, step (arrow up/down), page up/down */ + labels, values, G_N_ELEMENTS(labels), /* drop down menu */ + sp_text_dx_value_changed, /* callback */ + NULL, /* unit tracker */ + 0.1, /* step (used?) */ + 2, /* digits to show */ + 1.0 /* factor (multiplies default) */ + ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + g_object_set_data( holder, "TextDxAction", eact ); + g_object_set( G_OBJECT(eact), "iconId", "text_horz_kern", NULL ); + } + + /* Character vertical shift */ + { + // Drop down menu + gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + gdouble values[] = { -2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5 }; + + EgeAdjustmentAction *eact = create_adjustment_action( + "TextDyAction", /* name */ + _("Vertical Shift"), /* label */ + _("Vert:"), /* short label */ + _("Vertical shift (px)"), /* tooltip */ + "/tools/text/dy", /* preferences path */ + 0.0, /* default */ + GTK_WIDGET(desktop->canvas), /* focusTarget */ + holder, /* dataKludge */ + FALSE, /* set alt-x keyboard shortcut? */ + NULL, /* altx_mark */ + -100.0, 100.0, 0.01, 0.1, /* lower, upper, step (arrow up/down), page up/down */ + labels, values, G_N_ELEMENTS(labels), /* drop down menu */ + sp_text_dy_value_changed, /* callback */ + NULL, /* unit tracker */ + 0.1, /* step (used?) */ + 2, /* digits to show */ + 1.0 /* factor (multiplies default) */ + ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + g_object_set_data( holder, "TextDyAction", eact ); + g_object_set( G_OBJECT(eact), "iconId", "text_vert_kern", NULL ); + } + + /* Character rotation */ + { + // Drop down menu + gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + gdouble values[] = { -90, -45, -30, -15, 0, 15, 30, 45, 90, 180 }; + + EgeAdjustmentAction *eact = create_adjustment_action( + "TextRotationAction", /* name */ + _("Letter rotation"), /* label */ + _("Rot:"), /* short label */ + _("Character rotation (degrees)"),/* tooltip */ + "/tools/text/rotation", /* preferences path */ + 0.0, /* default */ + GTK_WIDGET(desktop->canvas), /* focusTarget */ + holder, /* dataKludge */ + FALSE, /* set alt-x keyboard shortcut? */ + NULL, /* altx_mark */ + -180.0, 180.0, 0.1, 1.0, /* lower, upper, step (arrow up/down), page up/down */ + labels, values, G_N_ELEMENTS(labels), /* drop down menu */ + sp_text_rotation_value_changed, /* callback */ + NULL, /* unit tracker */ + 0.1, /* step (used?) */ + 2, /* digits to show */ + 1.0 /* factor (multiplies default) */ + ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + g_object_set_data( holder, "TextRotationAction", eact ); + g_object_set( G_OBJECT(eact), "iconId", "text_rotation", NULL ); + } + + // Is this necessary to call? Shouldn't hurt. + sp_text_toolbox_selection_changed(sp_desktop_selection(desktop), holder); + + // Watch selection + Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolboxGTK"); + + sigc::connection *c_selection_changed = + new sigc::connection (sp_desktop_selection (desktop)->connectChanged + (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), holder))); + pool->add_connection ("selection-changed", c_selection_changed); + + sigc::connection *c_selection_modified = + new sigc::connection (sp_desktop_selection (desktop)->connectModified + (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), holder))); + pool->add_connection ("selection-modified", c_selection_modified); + + sigc::connection *c_subselection_changed = + new sigc::connection (desktop->connectToolSubselectionChanged + (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), holder))); + pool->add_connection ("tool-subselection-changed", c_subselection_changed); + + Inkscape::ConnectionPool::connect_destroy (G_OBJECT (holder), pool); + + g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); + +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/text-toolbar.h b/src/widgets/text-toolbar.h new file mode 100644 index 000000000..86a1cad21 --- /dev/null +++ b/src/widgets/text-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_TEXT_TOOLBAR_H +#define SEEN_TEXT_TOOLBAR_H + +/** + * @file + * Text aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_TEXT_TOOLBAR_H */ diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index f29ac581d..02da805bf 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -1,7 +1,7 @@ /** * @file - * Controls bars for some of Inkscape's tools (for some tools, - * they are in their own files). + * Inkscape toolbar definitions and general utility functions. + * Each tool should have its own xxx-toolbar implementation file */ /* Authors: * MenTaLguY <mental@rydia.net> @@ -29,75 +29,35 @@ # include "config.h" #endif -#include <cstring> -#include <string> -#include "live_effects/lpe-line_segment.h" +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include <glibmm/threads.h> +#endif + +#include <gtkmm/box.h> #include <gtkmm/action.h> #include <gtkmm/actiongroup.h> #include <gtkmm/toolitem.h> - -#include "../libnrtype/font-lister.h" -#include <iostream> -#include <sstream> #include <glibmm/i18n.h> -#include "../box3d-context.h" -#include "../box3d.h" -#include "../conn-avoid-ref.h" -#include "../connection-pool.h" -#include "../connector-context.h" #include "../desktop.h" #include "../desktop-handles.h" #include "../desktop-style.h" -#include "../dialogs/dialog-events.h" -#include "../document-private.h" +#include "document-undo.h" #include "../ege-adjustment-action.h" #include "../ege-output-action.h" #include "../ege-select-one-action.h" -#include "../flood-context.h" -#include "gradient-toolbar.h" #include "../graphlayout.h" -#include "../helper/unit-menu.h" -#include "../helper/units.h" -#include "../helper/unit-tracker.h" +#include "../helper/action.h" +#include "../helper/action-context.h" #include "icon.h" #include "../ink-action.h" #include "../ink-comboboxentry-action.h" #include "../inkscape.h" #include "../interface.h" -#include "../libnrtype/font-instance.h" -#include "../live_effects/effect.h" -#include "../live_effects/lpe-angle_bisector.h" -#include "../lpe-tool-context.h" -#include "../mod360.h" -#include "../pen-context.h" -#include "../preferences.h" -#include "../selection-chemistry.h" -#include "../selection.h" -#include "select-toolbar.h" -#include "../shape-editor.h" #include "../shortcuts.h" -#include "../sp-clippath.h" -#include "../sp-ellipse.h" -#include "../sp-flowtext.h" -#include "../sp-mask.h" #include "../sp-namedview.h" -#include "../sp-rect.h" -#include "../sp-spiral.h" -#include "../sp-star.h" -#include "../sp-text.h" -#include "../style.h" -#include "../svg/css-ostringstream.h" -#include "../text-context.h" -#include "../text-editing.h" #include "../tools-switch.h" -#include "../tweak-context.h" -#include "../spray-context.h" -#include "../ui/dialog/calligraphic-profile-rename.h" #include "../ui/icon-names.h" -#include "../ui/tool/control-point-selection.h" -#include "../ui/tool/node-tool.h" -#include "../ui/tool/multi-path-manipulator.h" #include "../ui/widget/style-swatch.h" #include "../verbs.h" #include "../widgets/button.h" @@ -110,21 +70,44 @@ #include "../xml/repr.h" #include "ui/uxmanager.h" + +#include "arc-toolbar.h" +#include "box3d-toolbar.h" +#include "calligraphy-toolbar.h" +#include "connector-toolbar.h" +#include "dropper-toolbar.h" +#include "eraser-toolbar.h" +#include "gradient-toolbar.h" +#include "lpe-toolbar.h" +#include "mesh-toolbar.h" +#include "measure-toolbar.h" +#include "node-toolbar.h" +#include "rect-toolbar.h" +#include "paintbucket-toolbar.h" +#include "pencil-toolbar.h" +#include "select-toolbar.h" +#include "spray-toolbar.h" +#include "spiral-toolbar.h" +#include "star-toolbar.h" +#include "tweak-toolbar.h" +#include "text-toolbar.h" +#include "zoom-toolbar.h" + #include "toolbox.h" #include <gtk/gtk.h> -#if !GTK_CHECK_VERSION(2,22,0) -#include "compat-key-syms.h" -#endif +#include "ui/tools/tool-base.h" //#define DEBUG_TEXT -using Inkscape::UnitTracker; using Inkscape::UI::UXManager; using Inkscape::DocumentUndo; +using Inkscape::UI::PrefPusher; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::Tools::ToolBase; typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop); -typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox); +typedef void (*UpdateFunction)(SPDesktop *desktop, ToolBase *eventcontext, GtkWidget *toolbox); enum BarId { BAR_TOOL = 0, @@ -136,28 +119,7 @@ enum BarId { #define BAR_ID_KEY "BarIdValue" #define HANDLE_POS_MARK "x-inkscape-pos" -static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_measure_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop); -static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); -static void sp_lpetool_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); - -using Inkscape::UI::ToolboxFactory; Inkscape::IconSize ToolboxFactory::prefToSize( Glib::ustring const &path, int base ) { @@ -177,28 +139,29 @@ static struct { sp_verb_t verb; sp_verb_t doubleclick_verb; } const tools[] = { - { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS}, - { "InkNodeTool", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS }, - { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS }, - { "SPSprayContext", "spray_tool", SP_VERB_CONTEXT_SPRAY, SP_VERB_CONTEXT_SPRAY_PREFS }, - { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS }, - { "SPMeasureContext", "measure_tool", SP_VERB_CONTEXT_MEASURE, SP_VERB_CONTEXT_MEASURE_PREFS }, - { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS }, - { "Box3DContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS }, - { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS }, - { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS }, - { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS }, - { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS }, - { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS }, - { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS }, - { "SPLPEToolContext", "lpetool_tool", SP_VERB_CONTEXT_LPETOOL, SP_VERB_CONTEXT_LPETOOL_PREFS }, - { "SPEraserContext", "eraser_tool", SP_VERB_CONTEXT_ERASER, SP_VERB_CONTEXT_ERASER_PREFS }, - { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS }, - { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS }, - { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS }, - { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS }, - { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS }, - { NULL, NULL, 0, 0 } + { "/tools/select", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS}, + { "/tools/nodes", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS }, + { "/tools/tweak", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS }, + { "/tools/spray", "spray_tool", SP_VERB_CONTEXT_SPRAY, SP_VERB_CONTEXT_SPRAY_PREFS }, + { "/tools/zoom", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS }, + { "/tools/measure", "measure_tool", SP_VERB_CONTEXT_MEASURE, SP_VERB_CONTEXT_MEASURE_PREFS }, + { "/tools/shapes/rect", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS }, + { "/tools/shapes/3dbox", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS }, + { "/tools/shapes/arc", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS }, + { "/tools/shapes/star", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS }, + { "/tools/shapes/spiral", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS }, + { "/tools/freehand/pencil", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS }, + { "/tools/freehand/pen", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS }, + { "/tools/calligraphic", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS }, + { "/tools/lpetool", "lpetool_tool", SP_VERB_CONTEXT_LPETOOL, SP_VERB_CONTEXT_LPETOOL_PREFS }, + { "/tools/eraser", "eraser_tool", SP_VERB_CONTEXT_ERASER, SP_VERB_CONTEXT_ERASER_PREFS }, + { "/tools/paintbucket", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS }, + { "/tools/text", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS }, + { "/tools/connector","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS }, + { "/tools/gradient", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS }, + { "/tools/mesh", "mesh_tool", SP_VERB_CONTEXT_MESH, SP_VERB_CONTEXT_MESH_PREFS }, + { "/tools/dropper", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS }, + { NULL, NULL, 0, 0 } }; static struct { @@ -211,53 +174,53 @@ static struct { gchar const *swatch_tool; gchar const *swatch_tip; } const aux_toolboxes[] = { - { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar", + { "/tools/select", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar", SP_VERB_INVALID, 0, 0}, - { "InkNodeTool", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar", + { "/tools/nodes", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar", SP_VERB_INVALID, 0, 0}, - { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar", + { "/tools/tweak", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar", SP_VERB_CONTEXT_TWEAK_PREFS, "/tools/tweak", N_("Color/opacity used for color tweaking")}, - { "SPSprayContext", "spray_toolbox", 0, sp_spray_toolbox_prep, "SprayToolbar", + { "/tools/spray", "spray_toolbox", 0, sp_spray_toolbox_prep, "SprayToolbar", SP_VERB_INVALID, 0, 0}, - { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar", + { "/tools/zoom", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar", SP_VERB_INVALID, 0, 0}, - { "SPMeasureContext", "measure_toolbox", 0, sp_measure_toolbox_prep, "MeasureToolbar", + { "/tools/measure", "measure_toolbox", 0, sp_measure_toolbox_prep, "MeasureToolbar", SP_VERB_INVALID, 0, 0}, - { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar", + { "/tools/shapes/star", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar", SP_VERB_CONTEXT_STAR_PREFS, "/tools/shapes/star", N_("Style of new stars")}, - { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar", + { "/tools/shapes/rect", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar", SP_VERB_CONTEXT_RECT_PREFS, "/tools/shapes/rect", N_("Style of new rectangles")}, - { "Box3DContext", "3dbox_toolbox", 0, box3d_toolbox_prep, "3DBoxToolbar", + { "/tools/shapes/3dbox", "3dbox_toolbox", 0, box3d_toolbox_prep, "3DBoxToolbar", SP_VERB_CONTEXT_3DBOX_PREFS, "/tools/shapes/3dbox", N_("Style of new 3D boxes")}, - { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar", + { "/tools/shapes/arc", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar", SP_VERB_CONTEXT_ARC_PREFS, "/tools/shapes/arc", N_("Style of new ellipses")}, - { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar", + { "/tools/shapes/spiral", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar", SP_VERB_CONTEXT_SPIRAL_PREFS, "/tools/shapes/spiral", N_("Style of new spirals")}, - { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar", + { "/tools/freehand/pencil", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar", SP_VERB_CONTEXT_PENCIL_PREFS, "/tools/freehand/pencil", N_("Style of new paths created by Pencil")}, - { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar", + { "/tools/freehand/pen", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar", SP_VERB_CONTEXT_PEN_PREFS, "/tools/freehand/pen", N_("Style of new paths created by Pen")}, - { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar", + { "/tools/calligraphic", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar", SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "/tools/calligraphic", N_("Style of new calligraphic strokes")}, - { "SPEraserContext", "eraser_toolbox", 0, sp_eraser_toolbox_prep,"EraserToolbar", + { "/tools/eraser", "eraser_toolbox", 0, sp_eraser_toolbox_prep,"EraserToolbar", SP_VERB_CONTEXT_ERASER_PREFS, "/tools/eraser", _("TBD")}, - { "SPLPEToolContext", "lpetool_toolbox", 0, sp_lpetool_toolbox_prep, "LPEToolToolbar", + { "/tools/lpetool", "lpetool_toolbox", 0, sp_lpetool_toolbox_prep, "LPEToolToolbar", SP_VERB_CONTEXT_LPETOOL_PREFS, "/tools/lpetool", _("TBD")}, - { "SPTextContext", "text_toolbox", 0, sp_text_toolbox_prep, "TextToolbar", + { "/tools/text", "text_toolbox", 0, sp_text_toolbox_prep, "TextToolbar", SP_VERB_INVALID, 0, 0}, - { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar", + { "/tools/dropper", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar", SP_VERB_INVALID, 0, 0}, - { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar", + { "/tools/connector", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar", SP_VERB_INVALID, 0, 0}, - { "SPGradientContext", "gradient_toolbox", 0, sp_gradient_toolbox_prep, "GradientToolbar", - SP_VERB_INVALID, 0, 0}, - { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar", + { "/tools/gradient", "gradient_toolbox", 0, sp_gradient_toolbox_prep, "GradientToolbar", + SP_VERB_INVALID, 0, 0}, + { "/tools/mesh", "mesh_toolbox", 0, sp_mesh_toolbox_prep, "MeshToolbar", + SP_VERB_INVALID, 0, 0}, + { "/tools/paintbucket", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar", SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "/tools/paintbucket", N_("Style of Paint Bucket fill objects")}, { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL } }; -#define TOOLBAR_SLIDER_HINT "full" - static gchar const * ui_descr = "<ui>" " <toolbar name='SelectToolbar'>" @@ -449,6 +412,7 @@ static gchar const * ui_descr = " <toolbar name='CalligraphyToolbar'>" " <separator />" " <toolitem action='SetProfileAction'/>" + " <toolitem action='ProfileEditAction'/>" " <separator />" " <toolitem action='CalligraphyWidthAction' />" " <toolitem action='PressureAction' />" @@ -501,8 +465,9 @@ static gchar const * ui_descr = " <toolbar name='TextToolbar'>" " <toolitem action='TextFontFamilyAction' />" " <toolitem action='TextFontSizeAction' />" - " <toolitem action='TextBoldAction' />" - " <toolitem action='TextItalicAction' />" + " <toolitem action='TextFontStyleAction' />" +// " <toolitem action='TextBoldAction' />" +// " <toolitem action='TextItalicAction' />" " <separator />" " <toolitem action='TextAlignAction' />" " <separator />" @@ -548,6 +513,18 @@ static gchar const * ui_descr = " <toolitem action='GradientEditDeleteAction' />" " </toolbar>" + " <toolbar name='MeshToolbar'>" + " <toolitem action='MeshNewTypeAction' />" + " <toolitem action='MeshNewFillStrokeAction' />" + " <toolitem action='MeshRowAction' />" + " <toolitem action='MeshColumnAction' />" + " <separator />" +// " <toolitem action='MeshEditFillAction' />" +// " <toolitem action='MeshEditStrokeAction' />" +// " <toolitem action='MeshShowHandlesAction' />" + " <separator />" + " </toolbar>" + " <toolbar name='DropperToolbar'>" " <toolitem action='DropperOpacityAction' />" " <toolitem action='DropperPickAlphaAction' />" @@ -555,7 +532,6 @@ static gchar const * ui_descr = " </toolbar>" " <toolbar name='ConnectorToolbar'>" -// " <toolitem action='ConnectorEditModeAction' />" " <toolitem action='ConnectorAvoidAction' />" " <toolitem action='ConnectorIgnoreAction' />" " <toolitem action='ConnectorOrthogonalAction' />" @@ -565,8 +541,6 @@ static gchar const * ui_descr = " <toolitem action='ConnectorLengthAction' />" " <toolitem action='ConnectorDirectedAction' />" " <toolitem action='ConnectorOverlapAction' />" -// " <toolitem action='ConnectorNewConnPointAction' />" -// " <toolitem action='ConnectorRemoveConnPointAction' />" " </toolbar>" "</ui>" @@ -577,13 +551,13 @@ static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* deskto static void setup_snap_toolbox(GtkWidget *toolbox, SPDesktop *desktop); static void setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop); -static void update_tool_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox); +static void update_tool_toolbox(SPDesktop *desktop, ToolBase *eventcontext, GtkWidget *toolbox); static void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop); -static void update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox); +static void update_aux_toolbox(SPDesktop *desktop, ToolBase *eventcontext, GtkWidget *toolbox); static void setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop); -static void update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox); +static void update_commands_toolbox(SPDesktop *desktop, ToolBase *eventcontext, GtkWidget *toolbox); static GtkToolItem * sp_toolbox_button_item_new_from_verb_with_doubleclick( GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb, @@ -618,9 +592,9 @@ private: Glib::RefPtr<VerbAction> VerbAction::create(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view) { Glib::RefPtr<VerbAction> result; - SPAction *action = verb->get_action(view); + SPAction *action = verb->get_action(Inkscape::ActionContext(view)); if ( action ) { - //SPAction* action2 = verb2 ? verb2->get_action(view) : 0; + //SPAction* action2 = verb2 ? verb2->get_action(Inkscape::ActionContext(view)) : 0; result = Glib::RefPtr<VerbAction>(new VerbAction(verb, verb2, view)); } @@ -628,7 +602,7 @@ Glib::RefPtr<VerbAction> VerbAction::create(Inkscape::Verb* verb, Inkscape::Verb } VerbAction::VerbAction(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view) : - Gtk::Action(Glib::ustring(verb->get_id()), Gtk::StockID(verb->get_image()), Glib::ustring(_(verb->get_name())), Glib::ustring(_(verb->get_tip()))), + Gtk::Action(Glib::ustring(verb->get_id()), Gtk::StockID(verb->get_image()), Glib::ustring(g_dpgettext2(NULL, "ContextVerb", verb->get_name())), Glib::ustring(_(verb->get_tip()))), verb(verb), verb2(verb2), view(view), @@ -707,7 +681,7 @@ void VerbAction::set_active(bool active) void VerbAction::on_activate() { if ( verb ) { - SPAction *action = verb->get_action(view); + SPAction *action = verb->get_action(Inkscape::ActionContext(view)); if ( action ) { sp_action_perform(action, 0); } @@ -719,13 +693,13 @@ void VerbAction::on_activate() *dropper_opacity_entry ; */ // should be made a private member once this is converted to class -static void delete_connection(GObject * /*obj*/, sigc::connection *connection) +void delete_connection(GObject * /*obj*/, sigc::connection *connection) { connection->disconnect(); delete connection; } -static void purge_repr_listener( GObject* /*obj*/, GObject* tbl ) +void purge_repr_listener( GObject* /*obj*/, GObject* tbl ) { Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) ); if (oldrepr) { // remove old listener @@ -736,56 +710,6 @@ static void purge_repr_listener( GObject* /*obj*/, GObject* tbl ) } } -// ------------------------------------------------------ - -/** - * A simple mediator class that keeps UI controls matched to the preference values they set. - */ -class PrefPusher : public Inkscape::Preferences::Observer -{ -public: - /** - * Constructor for a boolean value that syncs to the supplied path. - * Initializes the widget to the current preference stored state and registers callbacks - * for widget changes and preference changes. - * - * @param act the widget to synchronize preference with. - * @param path the path to the preference the widget is synchronized with. - * @param callback function to invoke when changes are pushed. - * @param cbData data to be passed on to the callback function. - */ - PrefPusher( GtkToggleAction *act, Glib::ustring const &path, void (*callback)(GObject*) = 0, GObject *cbData = 0 ); - - /** - * Destructor that unregisters the preference callback. - */ - virtual ~PrefPusher(); - - /** - * Callback method invoked when the preference setting changes. - */ - virtual void notify(Inkscape::Preferences::Entry const &new_val); - -private: - /** - * Callback hook invoked when the widget changes. - * - * @param act the toggle action widget that was changed. - * @param self the PrefPusher instance the callback was registered to. - */ - static void toggleCB( GtkToggleAction *act, PrefPusher *self ); - - /** - * Method to handle the widget change. - */ - void handleToggled(); - - GtkToggleAction *act; - void (*callback)(GObject*); - GObject *cbData; - bool freeze; -}; - PrefPusher::PrefPusher( GtkToggleAction *act, Glib::ustring const &path, void (*callback)(GObject*), GObject *cbData ) : Observer(path), act(act), @@ -835,7 +759,7 @@ void PrefPusher::notify(Inkscape::Preferences::Entry const &newVal) } } -static void delete_prefspusher(GObject * /*obj*/, PrefPusher *watcher ) +void delete_prefspusher(GObject * /*obj*/, PrefPusher *watcher ) { delete watcher; } @@ -847,14 +771,14 @@ GtkToolItem * sp_toolbox_button_item_new_from_verb_with_doubleclick(GtkWidget *t Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb, Inkscape::UI::View::View *view) { - SPAction *action = verb->get_action(view); + SPAction *action = verb->get_action(Inkscape::ActionContext(view)); if (!action) { return NULL; } SPAction *doubleclick_action; if (doubleclick_verb) { - doubleclick_action = doubleclick_verb->get_action(view); + doubleclick_action = doubleclick_verb->get_action(Inkscape::ActionContext(view)); } else { doubleclick_action = NULL; } @@ -899,7 +823,7 @@ static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::Vi { GtkAction* act = 0; - SPAction* targetAction = verb->get_action(view); + SPAction* targetAction = verb->get_action(Inkscape::ActionContext(view)); InkAction* inky = ink_action_new( verb->get_id(), _(verb->get_name()), verb->get_tip(), verb->get_image(), size ); act = GTK_ACTION(inky); gtk_action_set_sensitive( act, targetAction->sensitive ); @@ -1017,36 +941,13 @@ static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* deskto } -static void handlebox_detached(GtkHandleBox* /*handlebox*/, GtkWidget* widget, gpointer /*userData*/) -{ - GtkAllocation alloc; - gtk_widget_get_allocation(widget, &alloc); - gtk_widget_set_size_request( widget, - alloc.width, - alloc.height ); -} - -static void handlebox_attached(GtkHandleBox* /*handlebox*/, GtkWidget* widget, gpointer /*userData*/) -{ - gtk_widget_set_size_request( widget, -1, -1 ); -} - -static GtkWidget* toolboxNewCommon( GtkWidget* tb, BarId id, GtkPositionType handlePos ) +static GtkWidget* toolboxNewCommon( GtkWidget* tb, BarId id, GtkPositionType /*handlePos*/ ) { g_object_set_data(G_OBJECT(tb), "desktop", NULL); gtk_widget_set_sensitive(tb, FALSE); - GtkWidget *hb = 0; - gboolean forceFloatAllowed = Inkscape::Preferences::get()->getBool("/options/workarounds/floatallowed", false); - if ( UXManager::getInstance()->isFloatWindowProblem() && !forceFloatAllowed ) { - hb = gtk_event_box_new(); // A simple, neutral container. - } else { - hb = gtk_handle_box_new(); - gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), handlePos); - gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT); - gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT); - } + GtkWidget *hb = gtk_event_box_new(); // A simple, neutral container. gtk_container_add(GTK_CONTAINER(hb), tb); gtk_widget_show(GTK_WIDGET(tb)); @@ -1054,11 +955,6 @@ static GtkWidget* toolboxNewCommon( GtkWidget* tb, BarId id, GtkPositionType han sigc::connection* conn = new sigc::connection; g_object_set_data(G_OBJECT(hb), "event_context_connection", conn); - if ( GTK_IS_HANDLE_BOX(hb) ) { - g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(handlebox_detached), static_cast<gpointer>(0)); - g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(handlebox_attached), static_cast<gpointer>(0)); - } - gpointer val = GINT_TO_POINTER(id); g_object_set_data(G_OBJECT(hb), BAR_ID_KEY, val); @@ -1117,7 +1013,7 @@ GtkWidget *ToolboxFactory::createSnapToolbox() return toolboxNewCommon( tb, BAR_SNAP, GTK_POS_LEFT ); } -static GtkWidget* createCustomSlider( GtkAdjustment *adjustment, gdouble climbRate, guint digits ) +static GtkWidget* createCustomSlider( GtkAdjustment *adjustment, gdouble climbRate, guint digits, Inkscape::UI::Widget::UnitTracker *unit_tracker) { #if WITH_GTKMM_3_0 Glib::RefPtr<Gtk::Adjustment> adj = Glib::wrap(adjustment, true); @@ -1125,6 +1021,7 @@ static GtkWidget* createCustomSlider( GtkAdjustment *adjustment, gdouble climbRa #else Inkscape::UI::Widget::SpinButton *inkSpinner = new Inkscape::UI::Widget::SpinButton(*Glib::wrap(adjustment, true), climbRate, digits); #endif + inkSpinner->addUnitTracker(unit_tracker); inkSpinner = Gtk::manage( inkSpinner ); GtkWidget *widget = GTK_WIDGET( inkSpinner->gobj() ); return widget; @@ -1134,12 +1031,12 @@ EgeAdjustmentAction * create_adjustment_action( gchar const *name, gchar const *label, gchar const *shortLabel, gchar const *tooltip, Glib::ustring const &path, gdouble def, GtkWidget *focusTarget, - GtkWidget *us, GObject *dataKludge, gboolean altx, gchar const *altx_mark, gdouble lower, gdouble upper, gdouble step, gdouble page, gchar const** descrLabels, gdouble const* descrValues, guint descrCount, void (*callback)(GtkAdjustment *, GObject *), + Inkscape::UI::Widget::UnitTracker *unit_tracker, gdouble climb/* = 0.1*/, guint digits/* = 3*/, double factor/* = 1.0*/ ) { static bool init = false; @@ -1151,13 +1048,10 @@ EgeAdjustmentAction * create_adjustment_action( gchar const *name, Inkscape::Preferences *prefs = Inkscape::Preferences::get(); GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs->getDouble(path, def) * factor, lower, upper, step, page, 0 ) ); - if (us) { - sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj ); - } g_signal_connect( G_OBJECT(adj), "value-changed", G_CALLBACK(callback), dataKludge ); - EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits ); + EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits, unit_tracker ); if ( shortLabel ) { g_object_set( act, "short_label", shortLabel, NULL ); } @@ -1187,653 +1081,6 @@ EgeAdjustmentAction * create_adjustment_action( gchar const *name, } -//#################################### -//# node editing callbacks -//#################################### - -/** Temporary hack: Returns the node tool in the active desktop. - * Will go away during tool refactoring. */ -static InkNodeTool *get_node_tool() -{ - InkNodeTool *tool = 0; - if (SP_ACTIVE_DESKTOP ) { - SPEventContext *ec = SP_ACTIVE_DESKTOP->event_context; - if (INK_IS_NODE_TOOL(ec)) { - tool = static_cast<InkNodeTool*>(ec); - } - } - return tool; -} - -static void sp_node_path_edit_add(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->insertNodes(); - } -} - -static void sp_node_path_edit_add_min_x(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->insertNodesAtExtrema(Inkscape::UI::PointManipulator::EXTR_MIN_X); - } -} -static void sp_node_path_edit_add_max_x(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->insertNodesAtExtrema(Inkscape::UI::PointManipulator::EXTR_MAX_X); - } -} -static void sp_node_path_edit_add_min_y(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->insertNodesAtExtrema(Inkscape::UI::PointManipulator::EXTR_MIN_Y); - } -} -static void sp_node_path_edit_add_max_y(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->insertNodesAtExtrema(Inkscape::UI::PointManipulator::EXTR_MAX_Y); - } -} - -static void sp_node_path_edit_delete(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - nt->_multipath->deleteNodes(prefs->getBool("/tools/nodes/delete_preserves_shape", true)); - } -} - -static void sp_node_path_edit_delete_segment(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->deleteSegments(); - } -} - -static void sp_node_path_edit_break(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->breakNodes(); - } -} - -static void sp_node_path_edit_join(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->joinNodes(); - } -} - -static void sp_node_path_edit_join_segment(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->joinSegments(); - } -} - -static void sp_node_path_edit_toline(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->setSegmentType(Inkscape::UI::SEGMENT_STRAIGHT); - } -} - -static void sp_node_path_edit_tocurve(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->setSegmentType(Inkscape::UI::SEGMENT_CUBIC_BEZIER); - } -} - -static void sp_node_path_edit_cusp(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->setNodeType(Inkscape::UI::NODE_CUSP); - } -} - -static void sp_node_path_edit_smooth(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->setNodeType(Inkscape::UI::NODE_SMOOTH); - } -} - -static void sp_node_path_edit_symmetrical(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->setNodeType(Inkscape::UI::NODE_SYMMETRIC); - } -} - -static void sp_node_path_edit_auto(void) -{ - InkNodeTool *nt = get_node_tool(); - if (nt) { - nt->_multipath->setNodeType(Inkscape::UI::NODE_AUTO); - } -} - -static void sp_node_path_edit_nextLPEparam(GtkAction * /*act*/, gpointer data) { - sp_selection_next_patheffect_param( reinterpret_cast<SPDesktop*>(data) ); -} - -/* is called when the node selection is modified */ -static void sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl) -{ - GtkAction* xact = GTK_ACTION( g_object_get_data( tbl, "nodes_x_action" ) ); - GtkAction* yact = GTK_ACTION( g_object_get_data( tbl, "nodes_y_action" ) ); - GtkAdjustment *xadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(xact)); - GtkAdjustment *yadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(yact)); - - // quit if run by the attr_changed listener - if (g_object_get_data( tbl, "freeze" )) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE)); - - UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) ); - if (!tracker) { - return; - } - SPUnit const *unit = tracker->getActiveUnit(); - - InkNodeTool *nt = get_node_tool(); - if (!nt || nt->_selected_nodes->empty()) { - // no path selected - gtk_action_set_sensitive(xact, FALSE); - gtk_action_set_sensitive(yact, FALSE); - } else { - gtk_action_set_sensitive(xact, TRUE); - gtk_action_set_sensitive(yact, TRUE); - Geom::Coord oldx = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit); - Geom::Coord oldy = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit); - Geom::Point mid = nt->_selected_nodes->pointwiseBounds()->midpoint(); - - if (oldx != mid[Geom::X]) { - gtk_adjustment_set_value(xadj, sp_pixels_get_units(mid[Geom::X], *unit)); - } - if (oldy != mid[Geom::Y]) { - gtk_adjustment_set_value(yadj, sp_pixels_get_units(mid[Geom::Y], *unit)); - } - } - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, Geom::Dim2 d) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" ); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" )); - if (!tracker) { - return; - } - SPUnit const *unit = tracker->getActiveUnit(); - - if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { - prefs->setDouble(Glib::ustring("/tools/nodes/") + (d == Geom::X ? "x" : "y"), - sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit)); - } - - // quit if run by the attr_changed listener - if (g_object_get_data( tbl, "freeze" )) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE)); - - InkNodeTool *nt = get_node_tool(); - if (nt && !nt->_selected_nodes->empty()) { - double val = sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit); - double oldval = nt->_selected_nodes->pointwiseBounds()->midpoint()[d]; - Geom::Point delta(0,0); - delta[d] = val - oldval; - nt->_multipath->move(delta); - } - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_node_path_x_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - sp_node_path_value_changed(adj, tbl, Geom::X); -} - -static void sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - sp_node_path_value_changed(adj, tbl, Geom::Y); -} - -static void sp_node_toolbox_sel_changed(Inkscape::Selection *selection, GObject *tbl) -{ - { - GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_lpeedit" ) ); - SPItem *item = selection->singleItem(); - if (item && SP_IS_LPE_ITEM(item)) { - if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(item))) { - gtk_action_set_sensitive(w, TRUE); - } else { - gtk_action_set_sensitive(w, FALSE); - } - } else { - gtk_action_set_sensitive(w, FALSE); - } - } -} - -static void sp_node_toolbox_sel_modified(Inkscape::Selection *selection, guint /*flags*/, GObject *tbl) -{ - sp_node_toolbox_sel_changed (selection, tbl); -} - - - -//################################ -//## Node Editing Toolbox ## -//################################ - -static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE ); - tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units ); - g_object_set_data( holder, "tracker", tracker ); - - Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); - - { - InkToolMenuAction* inky = ink_tool_menu_action_new( "NodeInsertAction", - _("Insert node"), - _("Insert new nodes into selected segments"), - INKSCAPE_ICON("node-add"), - secondarySize ); - g_object_set( INK_ACTION(inky), "short_label", _("Insert"), NULL ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - GtkToolItem *menu_tool_button = gtk_menu_tool_button_new (NULL, NULL); - gtk_activatable_set_related_action (GTK_ACTIVATABLE (menu_tool_button), GTK_ACTION(inky)); - // also create dummy menu action: - gtk_action_group_add_action( mainActions, gtk_action_new("NodeInsertActionMenu", NULL, NULL, NULL) ); - } - - { - InkAction* inky = ink_action_new( "NodeInsertActionMinX", - _("Insert node at min X"), - _("Insert new nodes at min X into selected segments"), - INKSCAPE_ICON("node_insert_min_x"), - secondarySize ); - g_object_set( inky, "short_label", _("Insert min X"), NULL ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add_min_x), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - { - InkAction* inky = ink_action_new( "NodeInsertActionMaxX", - _("Insert node at max X"), - _("Insert new nodes at max X into selected segments"), - INKSCAPE_ICON("node_insert_max_x"), - secondarySize ); - g_object_set( inky, "short_label", _("Insert max X"), NULL ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add_max_x), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - { - InkAction* inky = ink_action_new( "NodeInsertActionMinY", - _("Insert node at min Y"), - _("Insert new nodes at min Y into selected segments"), - INKSCAPE_ICON("node_insert_min_y"), - secondarySize ); - g_object_set( inky, "short_label", _("Insert min Y"), NULL ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add_min_y), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - { - InkAction* inky = ink_action_new( "NodeInsertActionMaxY", - _("Insert node at max Y"), - _("Insert new nodes at max Y into selected segments"), - INKSCAPE_ICON("node_insert_max_y"), - secondarySize ); - g_object_set( inky, "short_label", _("Insert max Y"), NULL ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add_max_y), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - { - InkAction* inky = ink_action_new( "NodeDeleteAction", - _("Delete node"), - _("Delete selected nodes"), - INKSCAPE_ICON("node-delete"), - secondarySize ); - g_object_set( inky, "short_label", _("Delete"), NULL ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - { - InkAction* inky = ink_action_new( "NodeJoinAction", - _("Join nodes"), - _("Join selected nodes"), - INKSCAPE_ICON("node-join"), - secondarySize ); - g_object_set( inky, "short_label", _("Join"), NULL ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - { - InkAction* inky = ink_action_new( "NodeBreakAction", - _("Break nodes"), - _("Break path at selected nodes"), - INKSCAPE_ICON("node-break"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - - { - InkAction* inky = ink_action_new( "NodeJoinSegmentAction", - _("Join with segment"), - _("Join selected endnodes with a new segment"), - INKSCAPE_ICON("node-join-segment"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - { - InkAction* inky = ink_action_new( "NodeDeleteSegmentAction", - _("Delete segment"), - _("Delete segment between two non-endpoint nodes"), - INKSCAPE_ICON("node-delete-segment"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - { - InkAction* inky = ink_action_new( "NodeCuspAction", - _("Node Cusp"), - _("Make selected nodes corner"), - INKSCAPE_ICON("node-type-cusp"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - { - InkAction* inky = ink_action_new( "NodeSmoothAction", - _("Node Smooth"), - _("Make selected nodes smooth"), - INKSCAPE_ICON("node-type-smooth"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - { - InkAction* inky = ink_action_new( "NodeSymmetricAction", - _("Node Symmetric"), - _("Make selected nodes symmetric"), - INKSCAPE_ICON("node-type-symmetric"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - { - InkAction* inky = ink_action_new( "NodeAutoAction", - _("Node Auto"), - _("Make selected nodes auto-smooth"), - INKSCAPE_ICON("node-type-auto-smooth"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_auto), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - { - InkAction* inky = ink_action_new( "NodeLineAction", - _("Node Line"), - _("Make selected segments lines"), - INKSCAPE_ICON("node-segment-line"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - { - InkAction* inky = ink_action_new( "NodeCurveAction", - _("Node Curve"), - _("Make selected segments curves"), - INKSCAPE_ICON("node-segment-curve"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - { - InkToggleAction* act = ink_toggle_action_new( "NodesShowTransformHandlesAction", - _("Show Transform Handles"), - _("Show transformation handles for selected nodes"), - "node-transform", - secondarySize ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/nodes/show_transform_handles"); - g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); - } - - { - InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction", - _("Show Handles"), - _("Show Bezier handles of selected nodes"), - INKSCAPE_ICON("show-node-handles"), - secondarySize ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/nodes/show_handles"); - g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); - } - - { - InkToggleAction* act = ink_toggle_action_new( "NodesShowHelperpath", - _("Show Outline"), - _("Show path outline (without path effects)"), - INKSCAPE_ICON("show-path-outline"), - secondarySize ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/nodes/show_outline"); - g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); - } - - { - Inkscape::Verb* verb = Inkscape::Verb::get(SP_VERB_EDIT_NEXT_PATHEFFECT_PARAMETER); - InkAction* inky = ink_action_new( verb->get_id(), - verb->get_name(), - verb->get_tip(), - INKSCAPE_ICON("path-effect-parameter-next"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_nextLPEparam), desktop ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - g_object_set_data( holder, "nodes_lpeedit", inky); - } - - { - InkToggleAction* inky = ink_toggle_action_new( "ObjectEditClipPathAction", - _("Edit clipping paths"), - _("Show clipping path(s) of selected object(s)"), - INKSCAPE_ICON("path-clip-edit"), - secondarySize ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(inky), "/tools/nodes/edit_clipping_paths"); - g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); - } - - { - InkToggleAction* inky = ink_toggle_action_new( "ObjectEditMaskPathAction", - _("Edit masks"), - _("Show mask(s) of selected object(s)"), - INKSCAPE_ICON("path-mask-edit"), - secondarySize ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(inky), "/tools/nodes/edit_masks"); - g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); - } - - /* X coord of selected node(s) */ - { - EgeAdjustmentAction* eact = 0; - gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500}; - eact = create_adjustment_action( "NodeXAction", - _("X coordinate:"), _("X:"), _("X coordinate of selected node(s)"), - "/tools/nodes/Xcoord", 0, - GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-nodes", - -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP, - labels, values, G_N_ELEMENTS(labels), - sp_node_path_x_value_changed ); - tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); - g_object_set_data( holder, "nodes_x_action", eact ); - gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - /* Y coord of selected node(s) */ - { - EgeAdjustmentAction* eact = 0; - gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500}; - eact = create_adjustment_action( "NodeYAction", - _("Y coordinate:"), _("Y:"), _("Y coordinate of selected node(s)"), - "/tools/nodes/Ycoord", 0, - GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL, - -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP, - labels, values, G_N_ELEMENTS(labels), - sp_node_path_y_value_changed ); - tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); - g_object_set_data( holder, "nodes_y_action", eact ); - gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - // add the units menu - { - GtkAction* act = tracker->createAction( "NodeUnitsAction", _("Units"), ("") ); - gtk_action_group_add_action( mainActions, act ); - } - - - sp_node_toolbox_sel_changed(sp_desktop_selection(desktop), holder); - - //watch selection - Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISNodeToolbox"); - - sigc::connection *c_selection_changed = - new sigc::connection (sp_desktop_selection (desktop)->connectChanged - (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_changed), (GObject*)holder))); - pool->add_connection ("selection-changed", c_selection_changed); - - sigc::connection *c_selection_modified = - new sigc::connection (sp_desktop_selection (desktop)->connectModified - (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_modified), (GObject*)holder))); - pool->add_connection ("selection-modified", c_selection_modified); - - sigc::connection *c_subselection_changed = - new sigc::connection (desktop->connectToolSubselectionChanged - (sigc::bind (sigc::ptr_fun (sp_node_toolbox_coord_changed), (GObject*)holder))); - pool->add_connection ("tool-subselection-changed", c_subselection_changed); - - Inkscape::ConnectionPool::connect_destroy (G_OBJECT (holder), pool); - - g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); -} // end of sp_node_toolbox_prep() - - -//######################## -//## Zoom Toolbox ## -//######################## - -static void sp_zoom_toolbox_prep(SPDesktop * /*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/) -{ - // no custom GtkAction setup needed -} // end of sp_zoom_toolbox_prep() - -static void -sp_measure_fontsize_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" ); - - if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt(Glib::ustring("/tools/measure/fontsize"), - gtk_adjustment_get_value(adj)); - } -} - -static void measure_unit_changed(GtkAction* /*act*/, GObject* tbl) -{ - UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker")); - SPUnit const *unit = tracker->getActiveUnit(); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt("/tools/measure/unitid", unit->unit_id); -} - -static void sp_measure_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObject* holder) -{ - UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE ); - tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units ); - g_object_set_data( holder, "tracker", tracker ); - - EgeAdjustmentAction *eact = 0; - - /* Font Size */ - { - eact = create_adjustment_action( "MeasureFontSizeAction", - _("Font Size"), _("Font Size:"), - _("The font size to be used in the measurement labels"), - "/tools/measure/fontsize", 0.0, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - 10, 36, 1.0, 4.0, - 0, 0, 0, - sp_measure_fontsize_value_changed); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - - // units label - { - EgeOutputAction* act = ege_output_action_new( "measure_units_label", _("Units:"), _("The units to be used for the measurements"), 0 ); - ege_output_action_set_use_markup( act, TRUE ); - g_object_set( act, "visible-overflown", FALSE, NULL ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - } - - // units menu - { - GtkAction* act = tracker->createAction( "MeasureUnitsAction", _("Units:"), _("The units to be used for the measurements") ); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(measure_unit_changed), (GObject*)holder ); - gtk_action_group_add_action( mainActions, act ); - } -} // end of sp_measure_toolbox_prep() - void ToolboxFactory::setToolboxDesktop(GtkWidget *toolbox, SPDesktop *desktop) { sigc::connection *conn = static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), @@ -1921,14 +1168,8 @@ static void setupToolboxCommon( GtkWidget *toolbox, Inkscape::IconSize toolboxSize = ToolboxFactory::prefToSize(sizePref); gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) ); - if (GTK_IS_HANDLE_BOX(toolbox)) { - // g_message("GRABBING ORIENTATION [%s]", toolbarName); - GtkPositionType pos = gtk_handle_box_get_handle_position(GTK_HANDLE_BOX(toolbox)); - orientation = ((pos == GTK_POS_LEFT) || (pos == GTK_POS_RIGHT)) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL; - } else { - GtkPositionType pos = static_cast<GtkPositionType>(GPOINTER_TO_INT(g_object_get_data( G_OBJECT(toolbox), HANDLE_POS_MARK ))); - orientation = ((pos == GTK_POS_LEFT) || (pos == GTK_POS_RIGHT)) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL; - } + GtkPositionType pos = static_cast<GtkPositionType>(GPOINTER_TO_INT(g_object_get_data( G_OBJECT(toolbox), HANDLE_POS_MARK ))); + orientation = ((pos == GTK_POS_LEFT) || (pos == GTK_POS_RIGHT)) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL; gtk_orientable_set_orientation (GTK_ORIENTABLE(toolBar), orientation); gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolBar), TRUE); @@ -1954,7 +1195,6 @@ void ToolboxFactory::setOrientation(GtkWidget* toolbox, GtkOrientation orientati #endif GtkPositionType pos = (orientation == GTK_ORIENTATION_HORIZONTAL) ? GTK_POS_LEFT : GTK_POS_TOP; - GtkHandleBox* handleBox = 0; if (GTK_IS_BIN(toolbox)) { #if DUMP_DETAILS @@ -2003,9 +1243,6 @@ void ToolboxFactory::setOrientation(GtkWidget* toolbox, GtkOrientation orientati if (GTK_IS_TOOLBAR(child2)) { GtkToolbar* childBar = GTK_TOOLBAR(child2); gtk_orientable_set_orientation(GTK_ORIENTABLE(childBar), orientation); - if (GTK_IS_HANDLE_BOX(toolbox)) { - handleBox = GTK_HANDLE_BOX(toolbox); - } } else { g_message("need to add dynamic switch"); } @@ -2013,25 +1250,14 @@ void ToolboxFactory::setOrientation(GtkWidget* toolbox, GtkOrientation orientati g_list_free(children); } else { // The call is being made before the toolbox proper has been setup. - if (GTK_IS_HANDLE_BOX(toolbox)) { - handleBox = GTK_HANDLE_BOX(toolbox); - } else { - g_object_set_data(G_OBJECT(toolbox), HANDLE_POS_MARK, GINT_TO_POINTER(pos)); - } + g_object_set_data(G_OBJECT(toolbox), HANDLE_POS_MARK, GINT_TO_POINTER(pos)); } } else if (GTK_IS_TOOLBAR(child)) { GtkToolbar* toolbar = GTK_TOOLBAR(child); gtk_orientable_set_orientation( GTK_ORIENTABLE(toolbar), orientation ); - if (GTK_IS_HANDLE_BOX(toolbox)) { - handleBox = GTK_HANDLE_BOX(toolbox); - } } } } - - if (handleBox) { - gtk_handle_box_set_handle_position(handleBox, pos); - } } void setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop) @@ -2069,6 +1295,9 @@ void setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop) " <!-- Fill -->" " <toolitem action='ToolPaintBucket' />" " <toolitem action='ToolGradient' />" +#ifdef WITH_MESH + " <toolitem action='ToolMesh' />" +#endif " <toolitem action='ToolDropper' />" " <toolitem action='ToolConnector' />" @@ -2082,10 +1311,10 @@ void setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop) "/toolbox/tools/small"); } -void update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget * /*toolbox*/ ) +void update_tool_toolbox( SPDesktop *desktop, ToolBase *eventcontext, GtkWidget * /*toolbox*/ ) { gchar const *const tname = ( eventcontext - ? g_type_name(G_OBJECT_TYPE(eventcontext)) + ? eventcontext->getPrefsPath().c_str() //g_type_name(G_OBJECT_TYPE(eventcontext)) : NULL ); Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop ); @@ -2146,8 +1375,13 @@ void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop) GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name]; +#if GTK_CHECK_VERSION(3,0,0) + GtkWidget* holder = gtk_grid_new(); + gtk_grid_attach( GTK_GRID(holder), kludge, 2, 0, 1, 1); +#else GtkWidget* holder = gtk_table_new( 1, 3, FALSE ); gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 ); +#endif gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name ); GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp ); @@ -2161,7 +1395,12 @@ void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop) Inkscape::IconSize toolboxSize = ToolboxFactory::prefToSize("/toolbox/small"); gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) ); +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_hexpand(toolBar, TRUE); + gtk_grid_attach( GTK_GRID(holder), toolBar, 0, 0, 1, 1); +#else gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 ); +#endif if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) { Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, _(aux_toolboxes[i].swatch_tip) ); @@ -2169,7 +1408,16 @@ void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop) swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id ); swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true ); GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() ); - gtk_table_attach( GTK_TABLE(holder), swatch_, 1, 2, 0, 1, (GtkAttachOptions)(GTK_SHRINK | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), AUX_BETWEEN_BUTTON_GROUPS, 0 ); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(swatch_, AUX_BETWEEN_BUTTON_GROUPS); + gtk_widget_set_margin_right(swatch_, AUX_BETWEEN_BUTTON_GROUPS); + gtk_widget_set_margin_top(swatch_, AUX_SPACING); + gtk_widget_set_margin_bottom(swatch_, AUX_SPACING); + gtk_grid_attach( GTK_GRID(holder), swatch_, 1, 0, 1, 1); +#else + gtk_table_attach( GTK_TABLE(holder), swatch_, 1, 2, 0, 1, (GtkAttachOptions)(GTK_SHRINK | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), AUX_BETWEEN_BUTTON_GROUPS, AUX_SPACING ); +#endif } gtk_widget_show_all( holder ); @@ -2185,10 +1433,10 @@ void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop) g_object_unref( G_OBJECT(grouper) ); } -void update_aux_toolbox(SPDesktop * /*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox) +void update_aux_toolbox(SPDesktop * /*desktop*/, ToolBase *eventcontext, GtkWidget *toolbox) { gchar const *tname = ( eventcontext - ? g_type_name(G_OBJECT_TYPE(eventcontext)) + ? eventcontext->getPrefsPath().c_str() //g_type_name(G_OBJECT_TYPE(eventcontext)) : NULL ); for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) { GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name)); @@ -2238,8 +1486,8 @@ void setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop) " <toolitem action='DialogXMLEditor' />" " <toolitem action='DialogAlignDistribute' />" " <separator />" - " <toolitem action='DialogPreferences' />" " <toolitem action='DialogDocumentProperties' />" + " <toolitem action='DialogPreferences' />" " </toolbar>" "</ui>"; @@ -2248,7 +1496,7 @@ void setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop) "/toolbox/small" ); } -void update_commands_toolbox(SPDesktop * /*desktop*/, SPEventContext * /*eventcontext*/, GtkWidget * /*toolbox*/) +void update_commands_toolbox(SPDesktop * /*desktop*/, ToolBase * /*eventcontext*/, GtkWidget * /*toolbox*/) { } @@ -2617,7 +1865,7 @@ Glib::ustring ToolboxFactory::getToolboxName(GtkWidget* toolbox) return name; } -void ToolboxFactory::updateSnapToolbox(SPDesktop *desktop, SPEventContext * /*eventcontext*/, GtkWidget *toolbox) +void ToolboxFactory::updateSnapToolbox(SPDesktop *desktop, ToolBase * /*eventcontext*/, GtkWidget *toolbox) { g_assert(desktop != NULL); g_assert(toolbox != NULL); @@ -2741,6054 +1989,6 @@ static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop) #define MODE_LABEL_WIDTH 70 -//######################## -//## Star ## -//######################## - -static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge ) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" ); - - if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { - // do not remember prefs if this call is initiated by an undo change, because undoing object - // creation sets bogus values to its attributes before it is deleted - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt("/tools/shapes/star/magnitude", - (gint)gtk_adjustment_get_value(adj)); - } - - // quit if run by the attr_changed listener - if (g_object_get_data( dataKludge, "freeze" )) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) ); - - bool modmade = false; - - Inkscape::Selection *selection = sp_desktop_selection(desktop); - GSList const *items = selection->itemList(); - for (; items != NULL; items = items->next) { - SPItem *item = reinterpret_cast<SPItem*>(items->data); - if (SP_IS_STAR(item)) { - Inkscape::XML::Node *repr = item->getRepr(); - sp_repr_set_int(repr,"sodipodi:sides", - (gint)gtk_adjustment_get_value(adj)); - double arg1 = 0.5; - sp_repr_get_double(repr, "sodipodi:arg1", &arg1); - sp_repr_set_svg_double(repr, "sodipodi:arg2", - (arg1 + M_PI / (gint)gtk_adjustment_get_value(adj))); - item->updateRepr(); - modmade = true; - } - } - if (modmade) { - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, - _("Star: Change number of corners")); - } - - g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge ) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" ); - - if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { - if (!IS_NAN(gtk_adjustment_get_value(adj))) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/tools/shapes/star/proportion", - gtk_adjustment_get_value(adj)); - } - } - - // quit if run by the attr_changed listener - if (g_object_get_data( dataKludge, "freeze" )) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) ); - - bool modmade = false; - Inkscape::Selection *selection = sp_desktop_selection(desktop); - GSList const *items = selection->itemList(); - for (; items != NULL; items = items->next) { - SPItem *item = reinterpret_cast<SPItem *>(items->data); - if (SP_IS_STAR(item)) { - Inkscape::XML::Node *repr = item->getRepr(); - - gdouble r1 = 1.0; - gdouble r2 = 1.0; - sp_repr_get_double(repr, "sodipodi:r1", &r1); - sp_repr_get_double(repr, "sodipodi:r2", &r2); - if (r2 < r1) { - sp_repr_set_svg_double(repr, "sodipodi:r2", - r1*gtk_adjustment_get_value(adj)); - } else { - sp_repr_set_svg_double(repr, "sodipodi:r1", - r2*gtk_adjustment_get_value(adj)); - } - - item->updateRepr(); - modmade = true; - } - } - - if (modmade) { - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, - _("Star: Change spoke ratio")); - } - - g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge ) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" ); - bool flat = ege_select_one_action_get_active( act ) == 0; - - if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool( "/tools/shapes/star/isflatsided", flat); - } - - // quit if run by the attr_changed listener - if (g_object_get_data( dataKludge, "freeze" )) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) ); - - Inkscape::Selection *selection = sp_desktop_selection(desktop); - GSList const *items = selection->itemList(); - GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) ); - bool modmade = false; - - if ( prop_action ) { - gtk_action_set_sensitive( prop_action, !flat ); - } - - for (; items != NULL; items = items->next) { - SPItem *item = reinterpret_cast<SPItem *>(items->data); - if (SP_IS_STAR(item)) { - Inkscape::XML::Node *repr = item->getRepr(); - repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" ); - item->updateRepr(); - modmade = true; - } - } - - if (modmade) { - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, - flat ? _("Make polygon") : _("Make star")); - } - - g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge ) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" ); - - if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/tools/shapes/star/rounded", (gdouble) gtk_adjustment_get_value(adj)); - } - - // quit if run by the attr_changed listener - if (g_object_get_data( dataKludge, "freeze" )) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) ); - - bool modmade = false; - - Inkscape::Selection *selection = sp_desktop_selection(desktop); - GSList const *items = selection->itemList(); - for (; items != NULL; items = items->next) { - SPItem *item = reinterpret_cast<SPItem*>(items->data); - if (SP_IS_STAR(item)) { - Inkscape::XML::Node *repr = item->getRepr(); - sp_repr_set_svg_double(repr, "inkscape:rounded", - (gdouble) gtk_adjustment_get_value(adj)); - item->updateRepr(); - modmade = true; - } - } - if (modmade) { - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, - _("Star: Change rounding")); - } - - g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge ) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" ); - - if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/tools/shapes/star/randomized", - (gdouble) gtk_adjustment_get_value(adj)); - } - - // quit if run by the attr_changed listener - if (g_object_get_data( dataKludge, "freeze" )) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) ); - - bool modmade = false; - - Inkscape::Selection *selection = sp_desktop_selection(desktop); - GSList const *items = selection->itemList(); - for (; items != NULL; items = items->next) { - SPItem *item = reinterpret_cast<SPItem *>(items->data); - if (SP_IS_STAR(item)) { - Inkscape::XML::Node *repr = item->getRepr(); - sp_repr_set_svg_double(repr, "inkscape:randomized", - (gdouble) gtk_adjustment_get_value(adj)); - item->updateRepr(); - modmade = true; - } - } - if (modmade) { - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, - _("Star: Change randomization")); - } - - g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); -} - - -static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name, - gchar const * /*old_value*/, gchar const * /*new_value*/, - bool /*is_interactive*/, gpointer data) -{ - GtkWidget *tbl = GTK_WIDGET(data); - - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - - // in turn, prevent callbacks from responding - g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE)); - - GtkAdjustment *adj = 0; - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool isFlatSided = prefs->getBool("/tools/shapes/star/isflatsided", true); - - if (!strcmp(name, "inkscape:randomized")) { - adj = GTK_ADJUSTMENT( g_object_get_data(G_OBJECT(tbl), "randomized") ); - double randomized = 0.0; - sp_repr_get_double(repr, "inkscape:randomized", &randomized); - gtk_adjustment_set_value(adj, randomized); - } else if (!strcmp(name, "inkscape:rounded")) { - adj = GTK_ADJUSTMENT( g_object_get_data(G_OBJECT(tbl), "rounded") ); - double rounded = 0.0; - sp_repr_get_double(repr, "inkscape:rounded", &rounded); - gtk_adjustment_set_value(adj, rounded); - } else if (!strcmp(name, "inkscape:flatsided")) { - GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") ); - char const *flatsides = repr->attribute("inkscape:flatsided"); - EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) ); - if ( flatsides && !strcmp(flatsides,"false") ) { - ege_select_one_action_set_active( flat_action, 1 ); - gtk_action_set_sensitive( prop_action, TRUE ); - } else { - ege_select_one_action_set_active( flat_action, 0 ); - gtk_action_set_sensitive( prop_action, FALSE ); - } - } else if ((!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) && (!isFlatSided) ) { - adj = (GtkAdjustment*)g_object_get_data(G_OBJECT(tbl), "proportion"); - gdouble r1 = 1.0; - gdouble r2 = 1.0; - sp_repr_get_double(repr, "sodipodi:r1", &r1); - sp_repr_get_double(repr, "sodipodi:r2", &r2); - if (r2 < r1) { - gtk_adjustment_set_value(adj, r2/r1); - } else { - gtk_adjustment_set_value(adj, r1/r2); - } - } else if (!strcmp(name, "sodipodi:sides")) { - adj = (GtkAdjustment*)g_object_get_data(G_OBJECT(tbl), "magnitude"); - int sides = 0; - sp_repr_get_int(repr, "sodipodi:sides", &sides); - gtk_adjustment_set_value(adj, sides); - } - - g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE)); -} - - -static Inkscape::XML::NodeEventVector star_tb_repr_events = -{ - NULL, /* child_added */ - NULL, /* child_removed */ - star_tb_event_attr_changed, - NULL, /* content_changed */ - NULL /* order_changed */ -}; - - -/** - * \param selection Should not be NULL. - */ -static void -sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) -{ - int n_selected = 0; - Inkscape::XML::Node *repr = NULL; - - purge_repr_listener( tbl, tbl ); - - for (GSList const *items = selection->itemList(); - items != NULL; - items = items->next) - { - SPItem* item = reinterpret_cast<SPItem *>(items->data); - if (SP_IS_STAR(item)) { - n_selected++; - repr = item->getRepr(); - } - } - - EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) ); - - if (n_selected == 0) { - g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL ); - } else if (n_selected == 1) { - g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); - - if (repr) { - g_object_set_data( tbl, "repr", repr ); - Inkscape::GC::anchor(repr); - sp_repr_add_listener(repr, &star_tb_repr_events, tbl); - sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl); - } - } else { - // FIXME: implement averaging of all parameters for multiple selected stars - //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>")); - //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>")); - } -} - - -static void sp_stb_defaults( GtkWidget * /*widget*/, GObject *dataKludge ) -{ - // FIXME: in this and all other _default functions, set some flag telling the value_changed - // callbacks to lump all the changes for all selected objects in one undo step - - GtkAdjustment *adj = 0; - - // fixme: make settable in prefs! - gint mag = 5; - gdouble prop = 0.5; - gboolean flat = FALSE; - gdouble randomized = 0; - gdouble rounded = 0; - - EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) ); - ege_select_one_action_set_active( flat_action, flat ? 0 : 1 ); - - GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) ); - gtk_action_set_sensitive( sb2, !flat ); - - adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) ); - gtk_adjustment_set_value(adj, mag); - gtk_adjustment_value_changed(adj); - - adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) ); - gtk_adjustment_set_value(adj, prop); - gtk_adjustment_value_changed(adj); - - adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) ); - gtk_adjustment_set_value(adj, rounded); - gtk_adjustment_value_changed(adj); - - adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) ); - gtk_adjustment_set_value(adj, randomized); - gtk_adjustment_value_changed(adj); -} - - -// public: -void sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide) -{ -#if GTK_CHECK_VERSION(3,0,0) - GtkWidget *boxl = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_set_homogeneous(GTK_BOX(boxl), FALSE); -#else - GtkWidget *boxl = gtk_hbox_new(FALSE, 0); -#endif - if (wide) { - gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1); - } - GtkWidget *l = gtk_label_new(NULL); - gtk_label_set_markup(GTK_LABEL(l), title); - gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0); - if ( GTK_IS_TOOLBAR(tbl) ) { - GtkToolItem *boxl_toolitem = gtk_tool_item_new(); - gtk_container_add(GTK_CONTAINER(boxl_toolitem), boxl); - gtk_toolbar_insert(GTK_TOOLBAR(tbl), boxl_toolitem, -1); - } else { - gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0); - } - g_object_set_data(G_OBJECT(tbl), "mode_label", l); -} - - -static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); - - { - EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 ); - ege_output_action_set_use_markup( act, TRUE ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_object_set_data( holder, "mode_action", act ); - } - - { - EgeAdjustmentAction* eact = 0; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool isFlatSided = prefs->getBool("/tools/shapes/star/isflatsided", true); - - /* Flatsided checkbox */ - { - GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); - - GtkTreeIter iter; - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Polygon"), - 1, _("Regular polygon (with one handle) instead of a star"), - 2, INKSCAPE_ICON("draw-polygon"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Star"), - 1, _("Star instead of a regular polygon (with one handle)"), - 2, INKSCAPE_ICON("draw-star"), - -1 ); - - EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", (""), (""), NULL, GTK_TREE_MODEL(model) ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - g_object_set_data( holder, "flat_action", act ); - - ege_select_one_action_set_appearance( act, "full" ); - ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); - g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); - ege_select_one_action_set_icon_column( act, 2 ); - ege_select_one_action_set_icon_size( act, secondarySize ); - ege_select_one_action_set_tooltip_column( act, 1 ); - - ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 ); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder); - } - - /* Magnitude */ - { - gchar const* labels[] = {_("triangle/tri-star"), _("square/quad-star"), _("pentagon/five-pointed star"), _("hexagon/six-pointed star"), 0, 0, 0, 0, 0}; - gdouble values[] = {3, 4, 5, 6, 7, 8, 10, 12, 20}; - eact = create_adjustment_action( "MagnitudeAction", - _("Corners"), _("Corners:"), _("Number of corners of a polygon or star"), - "/tools/shapes/star/magnitude", 3, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - 3, 1024, 1, 5, - labels, values, G_N_ELEMENTS(labels), - sp_stb_magnitude_value_changed, - 1.0, 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - /* Spoke ratio */ - { - gchar const* labels[] = {_("thin-ray star"), 0, _("pentagram"), _("hexagram"), _("heptagram"), _("octagram"), _("regular polygon")}; - gdouble values[] = {0.01, 0.2, 0.382, 0.577, 0.692, 0.765, 1}; - eact = create_adjustment_action( "SpokeAction", - _("Spoke ratio"), _("Spoke ratio:"), - // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle. - // Base radius is the same for the closest handle. - _("Base radius to tip radius ratio"), - "/tools/shapes/star/proportion", 0.5, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - 0.01, 1.0, 0.01, 0.1, - labels, values, G_N_ELEMENTS(labels), - sp_stb_proportion_value_changed ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - g_object_set_data( holder, "prop_action", eact ); - } - - if ( !isFlatSided ) { - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } else { - gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); - } - - /* Roundedness */ - { - gchar const* labels[] = {_("stretched"), _("twisted"), _("slightly pinched"), _("NOT rounded"), _("slightly rounded"), _("visibly rounded"), _("well rounded"), _("amply rounded"), 0, _("stretched"), _("blown up")}; - gdouble values[] = {-1, -0.2, -0.03, 0, 0.05, 0.1, 0.2, 0.3, 0.5, 1, 10}; - eact = create_adjustment_action( "RoundednessAction", - _("Rounded"), _("Rounded:"), _("How much rounded are the corners (0 for sharp)"), - "/tools/shapes/star/rounded", 0.0, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - -10.0, 10.0, 0.01, 0.1, - labels, values, G_N_ELEMENTS(labels), - sp_stb_rounded_value_changed ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - /* Randomization */ - { - gchar const* labels[] = {_("NOT randomized"), _("slightly irregular"), _("visibly randomized"), _("strongly randomized"), _("blown up")}; - gdouble values[] = {0, 0.01, 0.1, 0.5, 10}; - eact = create_adjustment_action( "RandomizationAction", - _("Randomized"), _("Randomized:"), _("Scatter randomly the corners and angles"), - "/tools/shapes/star/randomized", 0.0, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - -10.0, 10.0, 0.001, 0.01, - labels, values, G_N_ELEMENTS(labels), - sp_stb_randomized_value_changed, 0.1, 3 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - } - - { - /* Reset */ - { - GtkAction* act = gtk_action_new( "StarResetAction", - _("Defaults"), - _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), - GTK_STOCK_CLEAR ); - g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder ); - gtk_action_group_add_action( mainActions, act ); - gtk_action_set_sensitive( act, TRUE ); - } - } - - sigc::connection *connection = new sigc::connection( - sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder)) - ); - g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection ); - g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); -} - - -//######################## -//## Rect ## -//######################## - -static void sp_rtb_sensitivize( GObject *tbl ) -{ - GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") ); - GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") ); - GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") ); - - if (gtk_adjustment_get_value(adj1) == 0 && gtk_adjustment_get_value(adj2) == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now) - gtk_action_set_sensitive( not_rounded, FALSE ); - } else { - gtk_action_set_sensitive( not_rounded, TRUE ); - } -} - - -static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, - void (*setter)(SPRect *, gdouble)) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" ); - - UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" )); - SPUnit const *unit = tracker->getActiveUnit(); - - if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble(Glib::ustring("/tools/shapes/rect/") + value_name, - sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit)); - } - - // quit if run by the attr_changed listener - if (g_object_get_data( tbl, "freeze" )) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE)); - - bool modmade = false; - Inkscape::Selection *selection = sp_desktop_selection(desktop); - for (GSList const *items = selection->itemList(); items != NULL; items = items->next) { - if (SP_IS_RECT(items->data)) { - if (gtk_adjustment_get_value(adj) != 0) { - setter(SP_RECT(items->data), - sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit)); - } else { - SP_OBJECT(items->data)->getRepr()->setAttribute(value_name, NULL); - } - modmade = true; - } - } - - sp_rtb_sensitivize( tbl ); - - if (modmade) { - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT, - _("Change rectangle")); - } - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx); -} - -static void sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry); -} - -static void sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width); -} - -static void sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height); -} - - - -static void sp_rtb_defaults( GtkWidget * /*widget*/, GObject *obj) -{ - GtkAdjustment *adj = 0; - - adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") ); - gtk_adjustment_set_value(adj, 0.0); - // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects - gtk_adjustment_value_changed(adj); - - adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") ); - gtk_adjustment_set_value(adj, 0.0); - gtk_adjustment_value_changed(adj); - - sp_rtb_sensitivize( obj ); -} - -static void rect_tb_event_attr_changed(Inkscape::XML::Node * /*repr*/, gchar const * /*name*/, - gchar const * /*old_value*/, gchar const * /*new_value*/, - bool /*is_interactive*/, gpointer data) -{ - GObject *tbl = G_OBJECT(data); - - // quit if run by the _changed callbacks - if (g_object_get_data( tbl, "freeze" )) { - return; - } - - // in turn, prevent callbacks from responding - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) ); - SPUnit const *unit = tracker->getActiveUnit(); - - gpointer item = g_object_get_data( tbl, "item" ); - if (item && SP_IS_RECT(item)) { - { - GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) ); - gdouble rx = sp_rect_get_visible_rx(SP_RECT(item)); - gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit)); - } - - { - GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) ); - gdouble ry = sp_rect_get_visible_ry(SP_RECT(item)); - gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit)); - } - - { - GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) ); - gdouble width = sp_rect_get_visible_width (SP_RECT(item)); - gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit)); - } - - { - GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) ); - gdouble height = sp_rect_get_visible_height (SP_RECT(item)); - gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit)); - } - } - - sp_rtb_sensitivize( tbl ); - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - - -static Inkscape::XML::NodeEventVector rect_tb_repr_events = { - NULL, /* child_added */ - NULL, /* child_removed */ - rect_tb_event_attr_changed, - NULL, /* content_changed */ - NULL /* order_changed */ -}; - -/** - * \param selection should not be NULL. - */ -static void sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) -{ - int n_selected = 0; - Inkscape::XML::Node *repr = NULL; - SPItem *item = NULL; - - if ( g_object_get_data( tbl, "repr" ) ) { - g_object_set_data( tbl, "item", NULL ); - } - purge_repr_listener( tbl, tbl ); - - for (GSList const *items = selection->itemList(); - items != NULL; - items = items->next) { - if (SP_IS_RECT(reinterpret_cast<SPItem *>(items->data))) { - n_selected++; - item = reinterpret_cast<SPItem *>(items->data); - repr = item->getRepr(); - } - } - - EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) ); - - g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) ); - - if (n_selected == 0) { - g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL ); - - GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) ); - gtk_action_set_sensitive(w, FALSE); - GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) ); - gtk_action_set_sensitive(h, FALSE); - - } else if (n_selected == 1) { - g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); - g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) ); - - GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) ); - gtk_action_set_sensitive(w, TRUE); - GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) ); - gtk_action_set_sensitive(h, TRUE); - - if (repr) { - g_object_set_data( tbl, "repr", repr ); - g_object_set_data( tbl, "item", item ); - Inkscape::GC::anchor(repr); - sp_repr_add_listener(repr, &rect_tb_repr_events, tbl); - sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl); - } - } else { - // FIXME: implement averaging of all parameters for multiple selected - //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>")); - g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); - sp_rtb_sensitivize( tbl ); - } -} - - -static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - EgeAdjustmentAction* eact = 0; - Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); - - { - EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 ); - ege_output_action_set_use_markup( act, TRUE ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_object_set_data( holder, "mode_action", act ); - } - - // rx/ry units menu: create - UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE ); - //tracker->addUnit( SP_UNIT_PERCENT, 0 ); - // fixme: add % meaning per cent of the width/height - tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units ); - g_object_set_data( holder, "tracker", tracker ); - - /* W */ - { - gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500}; - eact = create_adjustment_action( "RectWidthAction", - _("Width"), _("W:"), _("Width of rectangle"), - "/tools/shapes/rect/width", 0, - GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect", - 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, - labels, values, G_N_ELEMENTS(labels), - sp_rtb_width_value_changed ); - tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); - g_object_set_data( holder, "width_action", eact ); - gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - /* H */ - { - gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500}; - eact = create_adjustment_action( "RectHeightAction", - _("Height"), _("H:"), _("Height of rectangle"), - "/tools/shapes/rect/height", 0, - GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL, - 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, - labels, values, G_N_ELEMENTS(labels), - sp_rtb_height_value_changed ); - tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); - g_object_set_data( holder, "height_action", eact ); - gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - /* rx */ - { - gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0}; - gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100}; - eact = create_adjustment_action( "RadiusXAction", - _("Horizontal radius"), _("Rx:"), _("Horizontal radius of rounded corners"), - "/tools/shapes/rect/rx", 0, - GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL, - 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, - labels, values, G_N_ELEMENTS(labels), - sp_rtb_rx_value_changed); - tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - /* ry */ - { - gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0}; - gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100}; - eact = create_adjustment_action( "RadiusYAction", - _("Vertical radius"), _("Ry:"), _("Vertical radius of rounded corners"), - "/tools/shapes/rect/ry", 0, - GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL, - 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, - labels, values, G_N_ELEMENTS(labels), - sp_rtb_ry_value_changed); - tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - // add the units menu - { - GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), ("") ); - gtk_action_group_add_action( mainActions, act ); - } - - /* Reset */ - { - InkAction* inky = ink_action_new( "RectResetAction", - _("Not rounded"), - _("Make corners sharp"), - INKSCAPE_ICON("rectangle-make-corners-sharp"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - gtk_action_set_sensitive( GTK_ACTION(inky), TRUE ); - g_object_set_data( holder, "not_rounded", inky ); - } - - g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) ); - sp_rtb_sensitivize( holder ); - - sigc::connection *connection = new sigc::connection( - sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder)) - ); - g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection ); - g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); -} - -//######################## -//## 3D Box ## -//######################## - -// normalize angle so that it lies in the interval [0,360] -static double box3d_normalize_angle (double a) { - double angle = a + ((int) (a/360.0))*360; - if (angle < 0) { - angle += 360.0; - } - return angle; -} - -static void box3d_set_button_and_adjustment(Persp3D *persp, - Proj::Axis axis, - GtkAdjustment *adj, - GtkAction *act, - GtkToggleAction *tact) -{ - // TODO: Take all selected perspectives into account but don't touch the state button if not all of them - // have the same state (otherwise a call to box3d_vp_z_state_changed() is triggered and the states - // are reset). - bool is_infinite = !persp3d_VP_is_finite(persp->perspective_impl, axis); - - if (is_infinite) { - gtk_toggle_action_set_active(tact, TRUE); - gtk_action_set_sensitive(act, TRUE); - - double angle = persp3d_get_infinite_angle(persp, axis); - if (angle != Geom::infinity()) { // FIXME: We should catch this error earlier (don't show the spinbutton at all) - gtk_adjustment_set_value(adj, box3d_normalize_angle(angle)); - } - } else { - gtk_toggle_action_set_active(tact, FALSE); - gtk_action_set_sensitive(act, FALSE); - } -} - -static void box3d_resync_toolbar(Inkscape::XML::Node *persp_repr, GObject *data) -{ - if (!persp_repr) { - g_print ("No perspective given to box3d_resync_toolbar().\n"); - return; - } - - GtkWidget *tbl = GTK_WIDGET(data); - GtkAdjustment *adj = 0; - GtkAction *act = 0; - GtkToggleAction *tact = 0; - Persp3D *persp = persp3d_get_from_repr(persp_repr); - if (!persp) { - // Hmm, is it an error if this happens? - return; - } - { - adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x")); - act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x_action")); - tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_x_state_action"))->action; - - box3d_set_button_and_adjustment(persp, Proj::X, adj, act, tact); - } - { - adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "box3d_angle_y")); - act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_y_action")); - tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_y_state_action"))->action; - - box3d_set_button_and_adjustment(persp, Proj::Y, adj, act, tact); - } - { - adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "box3d_angle_z")); - act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_z_action")); - tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_z_state_action"))->action; - - box3d_set_button_and_adjustment(persp, Proj::Z, adj, act, tact); - } -} - -static void box3d_persp_tb_event_attr_changed(Inkscape::XML::Node *repr, - gchar const * /*name*/, - gchar const * /*old_value*/, - gchar const * /*new_value*/, - bool /*is_interactive*/, - gpointer data) -{ - GtkWidget *tbl = GTK_WIDGET(data); - - // quit if run by the attr_changed or selection changed listener - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - - // set freeze so that it can be caught in box3d_angle_z_value_changed() (to avoid calling - // SPDocumentUndo::maybeDone() when the document is undo insensitive) - g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE)); - - // TODO: Only update the appropriate part of the toolbar -// if (!strcmp(name, "inkscape:vp_z")) { - box3d_resync_toolbar(repr, G_OBJECT(tbl)); -// } - - Persp3D *persp = persp3d_get_from_repr(repr); - persp3d_update_box_reprs(persp); - - g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE)); -} - -static Inkscape::XML::NodeEventVector box3d_persp_tb_repr_events = -{ - NULL, /* child_added */ - NULL, /* child_removed */ - box3d_persp_tb_event_attr_changed, - NULL, /* content_changed */ - NULL /* order_changed */ -}; - -/** - * \param selection Should not be NULL. - */ -// FIXME: This should rather be put into persp3d-reference.cpp or something similar so that it reacts upon each -// Change of the perspective, and not of the current selection (but how to refer to the toolbar then?) -static void box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) -{ - // Here the following should be done: If all selected boxes have finite VPs in a certain direction, - // disable the angle entry fields for this direction (otherwise entering a value in them should only - // update the perspectives with infinite VPs and leave the other ones untouched). - - Inkscape::XML::Node *persp_repr = NULL; - purge_repr_listener(tbl, tbl); - - SPItem *item = selection->singleItem(); - if (item && SP_IS_BOX3D(item)) { - // FIXME: Also deal with multiple selected boxes - SPBox3D *box = SP_BOX3D(item); - Persp3D *persp = box3d_get_perspective(box); - persp_repr = persp->getRepr(); - if (persp_repr) { - g_object_set_data(tbl, "repr", persp_repr); - Inkscape::GC::anchor(persp_repr); - sp_repr_add_listener(persp_repr, &box3d_persp_tb_repr_events, tbl); - sp_repr_synthesize_events(persp_repr, &box3d_persp_tb_repr_events, tbl); - } - - inkscape_active_document()->setCurrentPersp3D(persp3d_get_from_repr(persp_repr)); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setString("/tools/shapes/3dbox/persp", persp_repr->attribute("id")); - - g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE)); - box3d_resync_toolbar(persp_repr, tbl); - g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE)); - } -} - -static void box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis axis) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" ); - SPDocument *document = sp_desktop_document(desktop); - - // quit if run by the attr_changed or selection changed listener - if (g_object_get_data( dataKludge, "freeze" )) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data(dataKludge, "freeze", GINT_TO_POINTER(TRUE)); - - std::list<Persp3D *> sel_persps = sp_desktop_selection(desktop)->perspList(); - if (sel_persps.empty()) { - // this can happen when the document is created; we silently ignore it - return; - } - Persp3D *persp = sel_persps.front(); - - persp->perspective_impl->tmat.set_infinite_direction (axis, - gtk_adjustment_get_value(adj)); - persp->updateRepr(); - - // TODO: use the correct axis here, too - DocumentUndo::maybeDone(document, "perspangle", SP_VERB_CONTEXT_3DBOX, _("3D Box: Change perspective (angle of infinite axis)")); - - g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); -} - - -static void box3d_angle_x_value_changed(GtkAdjustment *adj, GObject *dataKludge) -{ - box3d_angle_value_changed(adj, dataKludge, Proj::X); -} - -static void box3d_angle_y_value_changed(GtkAdjustment *adj, GObject *dataKludge) -{ - box3d_angle_value_changed(adj, dataKludge, Proj::Y); -} - -static void box3d_angle_z_value_changed(GtkAdjustment *adj, GObject *dataKludge) -{ - box3d_angle_value_changed(adj, dataKludge, Proj::Z); -} - - -static void box3d_vp_state_changed( GtkToggleAction *act, GtkAction * /*box3d_angle*/, Proj::Axis axis ) -{ - // TODO: Take all selected perspectives into account - std::list<Persp3D *> sel_persps = sp_desktop_selection(inkscape_active_desktop())->perspList(); - if (sel_persps.empty()) { - // this can happen when the document is created; we silently ignore it - return; - } - Persp3D *persp = sel_persps.front(); - - bool set_infinite = gtk_toggle_action_get_active(act); - persp3d_set_VP_state (persp, axis, set_infinite ? Proj::VP_INFINITE : Proj::VP_FINITE); -} - -static void box3d_vp_x_state_changed( GtkToggleAction *act, GtkAction *box3d_angle ) -{ - box3d_vp_state_changed(act, box3d_angle, Proj::X); -} - -static void box3d_vp_y_state_changed( GtkToggleAction *act, GtkAction *box3d_angle ) -{ - box3d_vp_state_changed(act, box3d_angle, Proj::Y); -} - -static void box3d_vp_z_state_changed( GtkToggleAction *act, GtkAction *box3d_angle ) -{ - box3d_vp_state_changed(act, box3d_angle, Proj::Z); -} - -static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - EgeAdjustmentAction* eact = 0; - SPDocument *document = sp_desktop_document (desktop); - Persp3DImpl *persp_impl = document->getCurrentPersp3DImpl(); - - EgeAdjustmentAction* box3d_angle_x = 0; - EgeAdjustmentAction* box3d_angle_y = 0; - EgeAdjustmentAction* box3d_angle_z = 0; - - /* Angle X */ - { - gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 }; - gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; - eact = create_adjustment_action( "3DBoxAngleXAction", - _("Angle in X direction"), _("Angle X:"), - // Translators: PL is short for 'perspective line' - _("Angle of PLs in X direction"), - "/tools/shapes/3dbox/box3d_angle_x", 30, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-box3d", - -360.0, 360.0, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - box3d_angle_x_value_changed ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - g_object_set_data( holder, "box3d_angle_x_action", eact ); - box3d_angle_x = eact; - } - - if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::X)) { - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } else { - gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); - } - - - /* VP X state */ - { - InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXStateAction", - // Translators: VP is short for 'vanishing point' - _("State of VP in X direction"), - _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"), - INKSCAPE_ICON("perspective-parallel"), - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_object_set_data( holder, "box3d_vp_x_state_action", act ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_x_state_changed), box3d_angle_x ); - gtk_action_set_sensitive( GTK_ACTION(box3d_angle_x), !prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) ); - } - - /* Angle Y */ - { - gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 }; - gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; - eact = create_adjustment_action( "3DBoxAngleYAction", - _("Angle in Y direction"), _("Angle Y:"), - // Translators: PL is short for 'perspective line' - _("Angle of PLs in Y direction"), - "/tools/shapes/3dbox/box3d_angle_y", 30, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - -360.0, 360.0, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - box3d_angle_y_value_changed ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - g_object_set_data( holder, "box3d_angle_y_action", eact ); - box3d_angle_y = eact; - } - - if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::Y)) { - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } else { - gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); - } - - /* VP Y state */ - { - InkToggleAction* act = ink_toggle_action_new( "3DBoxVPYStateAction", - // Translators: VP is short for 'vanishing point' - _("State of VP in Y direction"), - _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"), - INKSCAPE_ICON("perspective-parallel"), - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_object_set_data( holder, "box3d_vp_y_state_action", act ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_y_state_changed), box3d_angle_y ); - gtk_action_set_sensitive( GTK_ACTION(box3d_angle_y), !prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) ); - } - - /* Angle Z */ - { - gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 }; - gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; - eact = create_adjustment_action( "3DBoxAngleZAction", - _("Angle in Z direction"), _("Angle Z:"), - // Translators: PL is short for 'perspective line' - _("Angle of PLs in Z direction"), - "/tools/shapes/3dbox/box3d_angle_z", 30, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - -360.0, 360.0, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - box3d_angle_z_value_changed ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - g_object_set_data( holder, "box3d_angle_z_action", eact ); - box3d_angle_z = eact; - } - - if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::Z)) { - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } else { - gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); - } - - /* VP Z state */ - { - InkToggleAction* act = ink_toggle_action_new( "3DBoxVPZStateAction", - // Translators: VP is short for 'vanishing point' - _("State of VP in Z direction"), - _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"), - INKSCAPE_ICON("perspective-parallel"), - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_object_set_data( holder, "box3d_vp_z_state_action", act ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_z_state_changed), box3d_angle_z ); - gtk_action_set_sensitive( GTK_ACTION(box3d_angle_z), !prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) ); - } - - sigc::connection *connection = new sigc::connection( - sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(box3d_toolbox_selection_changed), (GObject *)holder)) - ); - g_signal_connect(holder, "destroy", G_CALLBACK(delete_connection), connection); - g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder); -} - -//######################## -//## Spiral ## -//######################## - -static void sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, Glib::ustring const &value_name) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" ); - - if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/tools/shapes/spiral/" + value_name, - gtk_adjustment_get_value(adj)); - } - - // quit if run by the attr_changed listener - if (g_object_get_data( tbl, "freeze" )) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - gchar* namespaced_name = g_strconcat("sodipodi:", value_name.data(), NULL); - - bool modmade = false; - for (GSList const *items = sp_desktop_selection(desktop)->itemList(); - items != NULL; - items = items->next) - { - SPItem *item = reinterpret_cast<SPItem*>(items->data); - if (SP_IS_SPIRAL(item)) { - Inkscape::XML::Node *repr = item->getRepr(); - sp_repr_set_svg_double( repr, namespaced_name, - gtk_adjustment_get_value(adj) ); - item->updateRepr(); - modmade = true; - } - } - - g_free(namespaced_name); - - if (modmade) { - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL, - _("Change spiral")); - } - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - sp_spl_tb_value_changed(adj, tbl, "revolution"); -} - -static void sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - sp_spl_tb_value_changed(adj, tbl, "expansion"); -} - -static void sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - sp_spl_tb_value_changed(adj, tbl, "t0"); -} - -static void sp_spl_tb_defaults(GtkWidget * /*widget*/, GObject *obj) -{ - GtkWidget *tbl = GTK_WIDGET(obj); - - GtkAdjustment *adj; - - // fixme: make settable - gdouble rev = 5; - gdouble exp = 1.0; - gdouble t0 = 0.0; - - adj = (GtkAdjustment*)g_object_get_data(obj, "revolution"); - gtk_adjustment_set_value(adj, rev); - gtk_adjustment_value_changed(adj); - - adj = (GtkAdjustment*)g_object_get_data(obj, "expansion"); - gtk_adjustment_set_value(adj, exp); - gtk_adjustment_value_changed(adj); - - adj = (GtkAdjustment*)g_object_get_data(obj, "t0"); - gtk_adjustment_set_value(adj, t0); - gtk_adjustment_value_changed(adj); - - spinbutton_defocus(tbl); -} - - -static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, - gchar const * /*name*/, - gchar const * /*old_value*/, - gchar const * /*new_value*/, - bool /*is_interactive*/, - gpointer data) -{ - GtkWidget *tbl = GTK_WIDGET(data); - - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - - // in turn, prevent callbacks from responding - g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE)); - - GtkAdjustment *adj; - adj = (GtkAdjustment*)g_object_get_data(G_OBJECT(tbl), "revolution"); - double revolution = 3.0; - sp_repr_get_double(repr, "sodipodi:revolution", &revolution); - gtk_adjustment_set_value(adj, revolution); - - adj = (GtkAdjustment*)g_object_get_data(G_OBJECT(tbl), "expansion"); - double expansion = 1.0; - sp_repr_get_double(repr, "sodipodi:expansion", &expansion); - gtk_adjustment_set_value(adj, expansion); - - adj = (GtkAdjustment*)g_object_get_data(G_OBJECT(tbl), "t0"); - double t0 = 0.0; - sp_repr_get_double(repr, "sodipodi:t0", &t0); - gtk_adjustment_set_value(adj, t0); - - g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE)); -} - - -static Inkscape::XML::NodeEventVector spiral_tb_repr_events = { - NULL, /* child_added */ - NULL, /* child_removed */ - spiral_tb_event_attr_changed, - NULL, /* content_changed */ - NULL /* order_changed */ -}; - -static void sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) -{ - int n_selected = 0; - Inkscape::XML::Node *repr = NULL; - - purge_repr_listener( tbl, tbl ); - - for (GSList const *items = selection->itemList(); - items != NULL; - items = items->next) - { - SPItem *item = reinterpret_cast<SPItem*>(items->data); - if (SP_IS_SPIRAL(item)) { - n_selected++; - repr = item->getRepr(); - } - } - - EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) ); - - if (n_selected == 0) { - g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL ); - } else if (n_selected == 1) { - g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); - - if (repr) { - g_object_set_data( tbl, "repr", repr ); - Inkscape::GC::anchor(repr); - sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl); - sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl); - } - } else { - // FIXME: implement averaging of all parameters for multiple selected - //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>")); - g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); - } -} - - -static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - EgeAdjustmentAction* eact = 0; - Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); - - { - EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 ); - ege_output_action_set_use_markup( act, TRUE ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_object_set_data( holder, "mode_action", act ); - } - - /* Revolution */ - { - gchar const* labels[] = {_("just a curve"), 0, _("one full revolution"), 0, 0, 0, 0, 0, 0}; - gdouble values[] = {0.01, 0.5, 1, 2, 3, 5, 10, 20, 50, 100}; - eact = create_adjustment_action( "SpiralRevolutionAction", - _("Number of turns"), _("Turns:"), _("Number of revolutions"), - "/tools/shapes/spiral/revolution", 3.0, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral", - 0.01, 1024.0, 0.1, 1.0, - labels, values, G_N_ELEMENTS(labels), - sp_spl_tb_revolution_value_changed, 1, 2); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - /* Expansion */ - { - gchar const* labels[] = {_("circle"), _("edge is much denser"), _("edge is denser"), _("even"), _("center is denser"), _("center is much denser"), 0}; - gdouble values[] = {0, 0.1, 0.5, 1, 1.5, 5, 20}; - eact = create_adjustment_action( "SpiralExpansionAction", - _("Divergence"), _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"), - "/tools/shapes/spiral/expansion", 1.0, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - 0.0, 1000.0, 0.01, 1.0, - labels, values, G_N_ELEMENTS(labels), - sp_spl_tb_expansion_value_changed); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - /* T0 */ - { - gchar const* labels[] = {_("starts from center"), _("starts mid-way"), _("starts near edge")}; - gdouble values[] = {0, 0.5, 0.9}; - eact = create_adjustment_action( "SpiralT0Action", - _("Inner radius"), _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"), - "/tools/shapes/spiral/t0", 0.0, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - 0.0, 0.999, 0.01, 1.0, - labels, values, G_N_ELEMENTS(labels), - sp_spl_tb_t0_value_changed); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - /* Reset */ - { - InkAction* inky = ink_action_new( "SpiralResetAction", - _("Defaults"), - _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), - GTK_STOCK_CLEAR, - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - - sigc::connection *connection = new sigc::connection( - sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder)) - ); - g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection ); - g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); -} - -//######################## -//## Pen/Pencil ## -//######################## - -/* This is used in generic functions below to share large portions of code between pen and pencil tool */ -static Glib::ustring const freehand_tool_name(GObject *dataKludge) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data(dataKludge, "desktop"); - return ( tools_isactive(desktop, TOOLS_FREEHAND_PEN) - ? "/tools/freehand/pen" - : "/tools/freehand/pencil" ); -} - -static void freehand_mode_changed(EgeSelectOneAction* act, GObject* tbl) -{ - gint mode = ege_select_one_action_get_active(act); - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt(freehand_tool_name(tbl) + "/freehand-mode", mode); - - SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop"); - - // in pen tool we have more options than in pencil tool; if one of them was chosen, we do any - // preparatory work here - if (SP_IS_PEN_CONTEXT(desktop->event_context)) { - SPPenContext *pc = SP_PEN_CONTEXT(desktop->event_context); - sp_pen_context_set_polyline_mode(pc); - } -} - -static void sp_add_freehand_mode_toggle(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil) -{ - /* Freehand mode toggle buttons */ - { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - guint freehandMode = prefs->getInt(( tool_is_pencil ? "/tools/freehand/pencil/freehand-mode" : "/tools/freehand/pen/freehand-mode" ), 0); - Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); - - { - GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); - - GtkTreeIter iter; - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Bezier"), - 1, _("Create regular Bezier path"), - 2, INKSCAPE_ICON("path-mode-bezier"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Spiro"), - 1, _("Create Spiro path"), - 2, INKSCAPE_ICON("path-mode-spiro"), - -1 ); - - if (!tool_is_pencil) { - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Zigzag"), - 1, _("Create a sequence of straight line segments"), - 2, INKSCAPE_ICON("path-mode-polyline"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Paraxial"), - 1, _("Create a sequence of paraxial line segments"), - 2, INKSCAPE_ICON("path-mode-polyline-paraxial"), - -1 ); - } - - EgeSelectOneAction* act = ege_select_one_action_new(tool_is_pencil ? - "FreehandModeActionPencil" : - "FreehandModeActionPen", - (_("Mode:")), (_("Mode of new lines drawn by this tool")), NULL, GTK_TREE_MODEL(model) ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - - ege_select_one_action_set_appearance( act, "full" ); - ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); - g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); - ege_select_one_action_set_icon_column( act, 2 ); - ege_select_one_action_set_icon_size( act, secondarySize ); - ege_select_one_action_set_tooltip_column( act, 1 ); - - ege_select_one_action_set_active( act, freehandMode); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(freehand_mode_changed), holder); - } - } -} - -static void freehand_change_shape(EgeSelectOneAction* act, GObject *dataKludge) { - gint shape = ege_select_one_action_get_active( act ); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt(freehand_tool_name(dataKludge) + "/shape", shape); -} - -/** - * Generate the list of freehand advanced shape option entries. - */ -static GList * freehand_shape_dropdown_items_list() { - GList *glist = NULL; - - glist = g_list_append (glist, _("None")); - glist = g_list_append (glist, _("Triangle in")); - glist = g_list_append (glist, _("Triangle out")); - glist = g_list_append (glist, _("Ellipse")); - glist = g_list_append (glist, _("From clipboard")); - - return glist; -} - -static void freehand_add_advanced_shape_options(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil) -{ - /*advanced shape options */ - { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); - - GList* items = 0; - gint count = 0; - for ( items = freehand_shape_dropdown_items_list(); items ; items = g_list_next(items) ) - { - GtkTreeIter iter; - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 ); - count++; - } - g_list_free( items ); - items = 0; - EgeSelectOneAction* act1 = ege_select_one_action_new( - tool_is_pencil ? "SetPencilShapeAction" : "SetPenShapeAction", - _("Shape:"), (_("Shape of new paths drawn by this tool")), NULL, GTK_TREE_MODEL(model)); - g_object_set( act1, "short_label", _("Shape:"), NULL ); - ege_select_one_action_set_appearance( act1, "compact" ); - ege_select_one_action_set_active( act1, prefs->getInt(( tool_is_pencil ? "/tools/freehand/pencil/shape" : "/tools/freehand/pen/shape" ), 0) ); - g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(freehand_change_shape), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act1) ); - g_object_set_data( holder, "shape_action", act1 ); - } -} - -static void sp_pen_toolbox_prep(SPDesktop * /*desktop*/, GtkActionGroup* mainActions, GObject* holder) -{ - sp_add_freehand_mode_toggle(mainActions, holder, false); - freehand_add_advanced_shape_options(mainActions, holder, false); -} - - -static void sp_pencil_tb_defaults(GtkWidget * /*widget*/, GObject *obj) -{ - GtkWidget *tbl = GTK_WIDGET(obj); - - GtkAdjustment *adj; - - // fixme: make settable - gdouble tolerance = 4; - - adj = (GtkAdjustment*)g_object_get_data(obj, "tolerance"); - gtk_adjustment_set_value(adj, tolerance); - gtk_adjustment_value_changed(adj); - - spinbutton_defocus(tbl); -} - -static void sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - // quit if run by the attr_changed listener - if (g_object_get_data( tbl, "freeze" )) { - return; - } - // in turn, prevent listener from responding - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - prefs->setDouble("/tools/freehand/pencil/tolerance", - gtk_adjustment_get_value(adj)); - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -/* -class PencilToleranceObserver : public Inkscape::Preferences::Observer { -public: - PencilToleranceObserver(Glib::ustring const &path, GObject *x) : Observer(path), _obj(x) - { - g_object_set_data(_obj, "prefobserver", this); - } - virtual ~PencilToleranceObserver() { - if (g_object_get_data(_obj, "prefobserver") == this) { - g_object_set_data(_obj, "prefobserver", NULL); - } - } - virtual void notify(Inkscape::Preferences::Entry const &val) { - GObject* tbl = _obj; - if (g_object_get_data( tbl, "freeze" )) { - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - GtkAdjustment * adj = (GtkAdjustment*)g_object_get_data(tbl, "tolerance"); - - double v = val.getDouble(adj->value); - gtk_adjustment_set_value(adj, v); - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); - } -private: - GObject *_obj; -}; -*/ - -static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - sp_add_freehand_mode_toggle(mainActions, holder, true); - - EgeAdjustmentAction* eact = 0; - - /* Tolerance */ - { - gchar const* labels[] = {_("(many nodes, rough)"), _("(default)"), 0, 0, 0, 0, _("(few nodes, smooth)")}; - gdouble values[] = {1, 10, 20, 30, 50, 75, 100}; - eact = create_adjustment_action( "PencilToleranceAction", - _("Smoothing:"), _("Smoothing: "), - _("How much smoothing (simplifying) is applied to the line"), - "/tools/freehand/pencil/tolerance", - 3.0, - GTK_WIDGET(desktop->canvas), NULL, - holder, TRUE, "altx-pencil", - 1, 100.0, 0.5, 1.0, - labels, values, G_N_ELEMENTS(labels), - sp_pencil_tb_tolerance_value_changed, - 1, 2); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - /* advanced shape options */ - freehand_add_advanced_shape_options(mainActions, holder, true); - - /* Reset */ - { - InkAction* inky = ink_action_new( "PencilResetAction", - _("Defaults"), - _("Reset pencil parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), - GTK_STOCK_CLEAR, - Inkscape::ICON_SIZE_SMALL_TOOLBAR ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_pencil_tb_defaults), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); - -} - - -//######################## -//## Tweak ## -//######################## - -static void sp_tweak_width_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/tweak/width", - gtk_adjustment_get_value(adj) * 0.01 ); -} - -static void sp_tweak_force_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/tweak/force", - gtk_adjustment_get_value(adj) * 0.01 ); -} - -static void sp_tweak_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/tweak/usepressure", gtk_toggle_action_get_active(act)); -} - -static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl ) -{ - int mode = ege_select_one_action_get_active( act ); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt("/tools/tweak/mode", mode); - - static gchar const* names[] = {"tweak_doh", "tweak_dos", "tweak_dol", "tweak_doo", "tweak_channels_label"}; - bool flag = ((mode == TWEAK_MODE_COLORPAINT) || (mode == TWEAK_MODE_COLORJITTER)); - for (size_t i = 0; i < G_N_ELEMENTS(names); ++i) { - GtkAction *act = GTK_ACTION(g_object_get_data( tbl, names[i] )); - if (act) { - gtk_action_set_sensitive(act, flag); - } - } - GtkAction *fid = GTK_ACTION(g_object_get_data( tbl, "tweak_fidelity")); - if (fid) { - gtk_action_set_sensitive(fid, !flag); - } -} - -static void sp_tweak_fidelity_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/tweak/fidelity", - gtk_adjustment_get_value(adj) * 0.01 ); -} - -static void tweak_toggle_doh(GtkToggleAction *act, gpointer /*data*/) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/tweak/doh", gtk_toggle_action_get_active(act)); -} -static void tweak_toggle_dos(GtkToggleAction *act, gpointer /*data*/) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/tweak/dos", gtk_toggle_action_get_active(act)); -} -static void tweak_toggle_dol(GtkToggleAction *act, gpointer /*data*/) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/tweak/dol", gtk_toggle_action_get_active(act)); -} -static void tweak_toggle_doo(GtkToggleAction *act, gpointer /*data*/) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/tweak/doo", gtk_toggle_action_get_active(act)); -} - -static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - { - /* Width */ - gchar const* labels[] = {_("(pinch tweak)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad tweak)")}; - gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100}; - EgeAdjustmentAction *eact = create_adjustment_action( "TweakWidthAction", - _("Width"), _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"), - "/tools/tweak/width", 15, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-tweak", - 1, 100, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_tweak_width_value_changed, 0.01, 0, 100 ); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - - { - /* Force */ - gchar const* labels[] = {_("(minimum force)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum force)")}; - gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100}; - EgeAdjustmentAction *eact = create_adjustment_action( "TweakForceAction", - _("Force"), _("Force:"), _("The force of the tweak action"), - "/tools/tweak/force", 20, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-force", - 1, 100, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_tweak_force_value_changed, 0.01, 0, 100 ); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - /* Mode */ - { - GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); - - GtkTreeIter iter; - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Move mode"), - 1, _("Move objects in any direction"), - 2, INKSCAPE_ICON("object-tweak-push"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Move in/out mode"), - 1, _("Move objects towards cursor; with Shift from cursor"), - 2, INKSCAPE_ICON("object-tweak-attract"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Move jitter mode"), - 1, _("Move objects in random directions"), - 2, INKSCAPE_ICON("object-tweak-randomize"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Scale mode"), - 1, _("Shrink objects, with Shift enlarge"), - 2, INKSCAPE_ICON("object-tweak-shrink"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Rotate mode"), - 1, _("Rotate objects, with Shift counterclockwise"), - 2, INKSCAPE_ICON("object-tweak-rotate"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Duplicate/delete mode"), - 1, _("Duplicate objects, with Shift delete"), - 2, INKSCAPE_ICON("object-tweak-duplicate"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Push mode"), - 1, _("Push parts of paths in any direction"), - 2, INKSCAPE_ICON("path-tweak-push"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Shrink/grow mode"), - 1, _("Shrink (inset) parts of paths; with Shift grow (outset)"), - 2, INKSCAPE_ICON("path-tweak-shrink"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Attract/repel mode"), - 1, _("Attract parts of paths towards cursor; with Shift from cursor"), - 2, INKSCAPE_ICON("path-tweak-attract"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Roughen mode"), - 1, _("Roughen parts of paths"), - 2, INKSCAPE_ICON("path-tweak-roughen"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Color paint mode"), - 1, _("Paint the tool's color upon selected objects"), - 2, INKSCAPE_ICON("object-tweak-paint"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Color jitter mode"), - 1, _("Jitter the colors of selected objects"), - 2, INKSCAPE_ICON("object-tweak-jitter-color"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Blur mode"), - 1, _("Blur selected objects more; with Shift, blur less"), - 2, INKSCAPE_ICON("object-tweak-blur"), - -1 ); - - - EgeSelectOneAction* act = ege_select_one_action_new( "TweakModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) ); - g_object_set( act, "short_label", _("Mode:"), NULL ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - g_object_set_data( holder, "mode_action", act ); - - ege_select_one_action_set_appearance( act, "full" ); - ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); - g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); - ege_select_one_action_set_icon_column( act, 2 ); - ege_select_one_action_set_icon_size( act, secondarySize ); - ege_select_one_action_set_tooltip_column( act, 1 ); - - gint mode = prefs->getInt("/tools/tweak/mode", 0); - ege_select_one_action_set_active( act, mode ); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_tweak_mode_changed), holder ); - - g_object_set_data( G_OBJECT(holder), "tweak_tool_mode", act); - } - - guint mode = prefs->getInt("/tools/tweak/mode", 0); - - { - EgeOutputAction* act = ege_output_action_new( "TweakChannelsLabel", _("Channels:"), "", 0 ); - ege_output_action_set_use_markup( act, TRUE ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER) { - gtk_action_set_sensitive (GTK_ACTION(act), FALSE); - } - g_object_set_data( holder, "tweak_channels_label", act); - } - - { - InkToggleAction* act = ink_toggle_action_new( "TweakDoH", - _("Hue"), - _("In color mode, act on objects' hue"), - NULL, - Inkscape::ICON_SIZE_DECORATION ); - //TRANSLATORS: "H" here stands for hue - g_object_set( act, "short_label", _("H"), NULL ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doh", true) ); - if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER) { - gtk_action_set_sensitive (GTK_ACTION(act), FALSE); - } - g_object_set_data( holder, "tweak_doh", act); - } - { - InkToggleAction* act = ink_toggle_action_new( "TweakDoS", - _("Saturation"), - _("In color mode, act on objects' saturation"), - NULL, - Inkscape::ICON_SIZE_DECORATION ); - //TRANSLATORS: "S" here stands for Saturation - g_object_set( act, "short_label", _("S"), NULL ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dos", true) ); - if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER) { - gtk_action_set_sensitive (GTK_ACTION(act), FALSE); - } - g_object_set_data( holder, "tweak_dos", act ); - } - { - InkToggleAction* act = ink_toggle_action_new( "TweakDoL", - _("Lightness"), - _("In color mode, act on objects' lightness"), - NULL, - Inkscape::ICON_SIZE_DECORATION ); - //TRANSLATORS: "L" here stands for Lightness - g_object_set( act, "short_label", _("L"), NULL ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dol", true) ); - if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER) { - gtk_action_set_sensitive (GTK_ACTION(act), FALSE); - } - g_object_set_data( holder, "tweak_dol", act ); - } - { - InkToggleAction* act = ink_toggle_action_new( "TweakDoO", - _("Opacity"), - _("In color mode, act on objects' opacity"), - NULL, - Inkscape::ICON_SIZE_DECORATION ); - //TRANSLATORS: "O" here stands for Opacity - g_object_set( act, "short_label", _("O"), NULL ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doo", true) ); - if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER) { - gtk_action_set_sensitive (GTK_ACTION(act), FALSE); - } - g_object_set_data( holder, "tweak_doo", act ); - } - - { /* Fidelity */ - gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")}; - gdouble values[] = {10, 25, 35, 50, 60, 80, 100}; - EgeAdjustmentAction *eact = create_adjustment_action( "TweakFidelityAction", - _("Fidelity"), _("Fidelity:"), - _("Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"), - "/tools/tweak/fidelity", 50, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-fidelity", - 1, 100, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_tweak_fidelity_value_changed, 0.01, 0, 100 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER) { - gtk_action_set_sensitive (GTK_ACTION(eact), FALSE); - } - g_object_set_data( holder, "tweak_fidelity", eact ); - } - - - /* Use Pressure button */ - { - InkToggleAction* act = ink_toggle_action_new( "TweakPressureAction", - _("Pressure"), - _("Use the pressure of the input device to alter the force of tweak action"), - INKSCAPE_ICON("draw-use-pressure"), - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_tweak_pressure_state_changed), NULL); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/usepressure", true) ); - } - -} - - -//######################## -//## Spray ## -//######################## - -static void sp_spray_width_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/spray/width", - gtk_adjustment_get_value(adj)); -} - -static void sp_spray_mean_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/spray/mean", - gtk_adjustment_get_value(adj)); -} - -static void sp_spray_standard_deviation_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/spray/standard_deviation", - gtk_adjustment_get_value(adj)); -} - -static void sp_spray_mode_changed( EgeSelectOneAction *act, GObject * /*tbl*/ ) -{ - int mode = ege_select_one_action_get_active( act ); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt("/tools/spray/mode", mode); -} - -static void sp_spray_population_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/spray/population", - gtk_adjustment_get_value(adj)); -} - -static void sp_spray_rotation_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/spray/rotation_variation", - gtk_adjustment_get_value(adj)); -} - -static void sp_spray_scale_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/spray/scale_variation", - gtk_adjustment_get_value(adj)); -} - - -static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - { - /* Width */ - gchar const* labels[] = {_("(narrow spray)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad spray)")}; - gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100}; - EgeAdjustmentAction *eact = create_adjustment_action( "SprayWidthAction", - _("Width"), _("Width:"), _("The width of the spray area (relative to the visible canvas area)"), - "/tools/spray/width", 15, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spray", - 1, 100, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_spray_width_value_changed, 1, 0 ); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - { - /* Mean */ - gchar const* labels[] = {_("(default)"), 0, 0, 0, 0, 0, 0, _("(maximum mean)")}; - gdouble values[] = {0, 5, 10, 20, 30, 50, 70, 100}; - EgeAdjustmentAction *eact = create_adjustment_action( "SprayMeanAction", - _("Focus"), _("Focus:"), _("0 to spray a spot; increase to enlarge the ring radius"), - "/tools/spray/mean", 0, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-mean", - 0, 100, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_spray_mean_value_changed, 1, 0 ); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - { - /* Standard_deviation */ - gchar const* labels[] = {_("(minimum scatter)"), 0, 0, 0, 0, 0, _("(default)"), _("(maximum scatter)")}; - gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100}; - EgeAdjustmentAction *eact = create_adjustment_action( "SprayStandard_deviationAction", - C_("Spray tool", "Scatter"), C_("Spray tool", "Scatter:"), _("Increase to scatter sprayed objects"), - "/tools/spray/standard_deviation", 70, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-standard_deviation", - 1, 100, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_spray_standard_deviation_value_changed, 1, 0 ); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - /* Mode */ - { - GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); - - GtkTreeIter iter; - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Spray with copies"), - 1, _("Spray copies of the initial selection"), - 2, INKSCAPE_ICON("spray-mode-copy"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Spray with clones"), - 1, _("Spray clones of the initial selection"), - 2, INKSCAPE_ICON("spray-mode-clone"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Spray single path"), - 1, _("Spray objects in a single path"), - 2, INKSCAPE_ICON("spray-mode-union"), - -1 ); - - EgeSelectOneAction* act = ege_select_one_action_new( "SprayModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) ); - g_object_set( act, "short_label", _("Mode:"), NULL ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - g_object_set_data( holder, "mode_action", act ); - - ege_select_one_action_set_appearance( act, "full" ); - ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); - g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); - ege_select_one_action_set_icon_column( act, 2 ); - ege_select_one_action_set_icon_size( act, secondarySize ); - ege_select_one_action_set_tooltip_column( act, 1 ); - - gint mode = prefs->getInt("/tools/spray/mode", 1); - ege_select_one_action_set_active( act, mode ); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_spray_mode_changed), holder ); - - g_object_set_data( G_OBJECT(holder), "spray_tool_mode", act); - } - - { /* Population */ - gchar const* labels[] = {_("(low population)"), 0, 0, 0, _("(default)"), 0, _("(high population)")}; - gdouble values[] = {5, 20, 35, 50, 70, 85, 100}; - EgeAdjustmentAction *eact = create_adjustment_action( "SprayPopulationAction", - _("Amount"), _("Amount:"), - _("Adjusts the number of items sprayed per click"), - "/tools/spray/population", 70, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-population", - 1, 100, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_spray_population_value_changed, 1, 0 ); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - g_object_set_data( holder, "spray_population", eact ); - } - - /* Use Pressure button */ - { - InkToggleAction* act = ink_toggle_action_new( "SprayPressureAction", - _("Pressure"), - _("Use the pressure of the input device to alter the amount of sprayed objects"), - "use_pressure", - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/spray/usepressure"); - g_signal_connect(holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); - - } - - { /* Rotation */ - gchar const* labels[] = {_("(default)"), 0, 0, 0, 0, 0, 0, _("(high rotation variation)")}; - gdouble values[] = {0, 10, 25, 35, 50, 60, 80, 100}; - EgeAdjustmentAction *eact = create_adjustment_action( "SprayRotationAction", - _("Rotation"), _("Rotation:"), - // xgettext:no-c-format - _("Variation of the rotation of the sprayed objects; 0% for the same rotation than the original object"), - "/tools/spray/rotation_variation", 0, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-rotation", - 0, 100, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_spray_rotation_value_changed, 1, 0 ); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - g_object_set_data( holder, "spray_rotation", eact ); - } - - { /* Scale */ - gchar const* labels[] = {_("(default)"), 0, 0, 0, 0, 0, 0, _("(high scale variation)")}; - gdouble values[] = {0, 10, 25, 35, 50, 60, 80, 100}; - EgeAdjustmentAction *eact = create_adjustment_action( "SprayScaleAction", - C_("Spray tool", "Scale"), C_("Spray tool", "Scale:"), - // xgettext:no-c-format - _("Variation in the scale of the sprayed objects; 0% for the same scale than the original object"), - "/tools/spray/scale_variation", 0, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-scale", - 0, 100, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_spray_scale_value_changed, 1, 0 ); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - g_object_set_data( holder, "spray_scale", eact ); - } - - - -} - - -//######################## -//## Calligraphy ## -//######################## -static void update_presets_list(GObject *tbl) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (g_object_get_data(tbl, "presets_blocked")) { - return; - } - - EgeSelectOneAction *sel = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector")); - if (!sel) { - // WTF!? This will cause a segfault if ever reached - //ege_select_one_action_set_active(sel, 0); - return; - } - - std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset"); - - int ege_index = 1; - for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i, ++ege_index) { - bool match = true; - - std::vector<Inkscape::Preferences::Entry> preset = prefs->getAllEntries(*i); - for (std::vector<Inkscape::Preferences::Entry>::iterator j = preset.begin(); j != preset.end(); ++j) { - Glib::ustring entry_name = j->getEntryName(); - if (entry_name == "id" || entry_name == "name") { - continue; - } - - void *widget = g_object_get_data(tbl, entry_name.data()); - if (widget) { - if (GTK_IS_ADJUSTMENT(widget)) { - double v = j->getDouble(); - GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget); - //std::cout << "compared adj " << attr_name << gtk_adjustment_get_value(adj) << " to " << v << "\n"; - if (fabs(gtk_adjustment_get_value(adj) - v) > 1e-6) { - match = false; - break; - } - } else if (GTK_IS_TOGGLE_ACTION(widget)) { - bool v = j->getBool(); - GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget); - //std::cout << "compared toggle " << attr_name << gtk_toggle_action_get_active(toggle) << " to " << v << "\n"; - if ( static_cast<bool>(gtk_toggle_action_get_active(toggle)) != v ) { - match = false; - break; - } - } - } - } - - if (match) { - // newly added item is at the same index as the - // save command, so we need to change twice for it to take effect - ege_select_one_action_set_active(sel, 0); - ege_select_one_action_set_active(sel, ege_index); // one-based index - return; - } - } - - // no match found - ege_select_one_action_set_active(sel, 0); -} - -static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* tbl ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/calligraphic/mass", gtk_adjustment_get_value(adj) ); - update_presets_list(tbl); -} - -static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* tbl ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/calligraphic/wiggle", gtk_adjustment_get_value(adj) ); - update_presets_list(tbl); -} - -static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* tbl ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/calligraphic/angle", gtk_adjustment_get_value(adj) ); - update_presets_list(tbl); -} - -static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject *tbl ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/calligraphic/width", gtk_adjustment_get_value(adj) ); - update_presets_list(tbl); -} - -static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/tools/calligraphic/thinning", gtk_adjustment_get_value(adj) ); - update_presets_list(tbl); -} - -static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* tbl ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/calligraphic/flatness", gtk_adjustment_get_value(adj) ); - update_presets_list(tbl); -} - -static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/calligraphic/tremor", gtk_adjustment_get_value(adj) ); - update_presets_list(tbl); -} - -static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* tbl ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/calligraphic/cap_rounding", gtk_adjustment_get_value(adj) ); - update_presets_list(tbl); -} - -static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GObject* tbl ) -{ - // TODO merge into PrefPusher - GtkAction * calligraphy_angle = static_cast<GtkAction *> (g_object_get_data(tbl,"angle_action")); - if (calligraphy_angle ) { - gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) ); - } -} - - -static gchar const *const widget_names[] = { - "width", - "mass", - "wiggle", - "angle", - "thinning", - "tremor", - "flatness", - "cap_rounding", - "usepressure", - "tracebackground", - "usetilt" -}; - - -static void sp_dcc_build_presets_list(GObject *tbl) -{ - g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE)); - - EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector")); - GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector)); - gtk_list_store_clear (model); - - { - GtkTreeIter iter; - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("No preset"), 1, 0, -1 ); - } - - // iterate over all presets to populate the list - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset"); - int ii=1; - - for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i) { - GtkTreeIter iter; - Glib::ustring preset_name = prefs->getString(*i + "/name"); - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _(preset_name.data()), 1, ii++, -1 ); - } - - { - GtkTreeIter iter; - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("Save..."), 1, ii, -1 ); - g_object_set_data(tbl, "save_presets_index", GINT_TO_POINTER(ii)); - } - - g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE)); - - update_presets_list (tbl); -} - -static void sp_dcc_save_profile(GtkWidget * /*widget*/, GObject *tbl) -{ - using Inkscape::UI::Dialog::CalligraphicProfileRename; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop" ); - if (! desktop) { - return; - } - - if (g_object_get_data(tbl, "presets_blocked")) { - return; - } - - CalligraphicProfileRename::show(desktop); - if ( !CalligraphicProfileRename::applied()) { - // dialog cancelled - update_presets_list (tbl); - return; - } - Glib::ustring profile_name = CalligraphicProfileRename::getProfileName(); - - if (profile_name.empty()) { - // empty name entered - update_presets_list (tbl); - return; - } - - g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE)); - - // If there's a preset with the given name, find it and set save_path appropriately - std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset"); - int total_presets = presets.size(); - int new_index = -1; - Glib::ustring save_path; // profile pref path without a trailing slash - - int temp_index = 0; - for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i, ++temp_index) { - Glib::ustring name = prefs->getString(*i + "/name"); - if (!name.empty() && profile_name == name) { - new_index = temp_index; - save_path = *i; - break; - } - } - - if (new_index == -1) { - // no preset with this name, create - new_index = total_presets + 1; - gchar *profile_id = g_strdup_printf("/dcc%d", new_index); - save_path = Glib::ustring("/tools/calligraphic/preset") + profile_id; - g_free(profile_id); - } - - for (unsigned i = 0; i < G_N_ELEMENTS(widget_names); ++i) { - gchar const *const widget_name = widget_names[i]; - void *widget = g_object_get_data(tbl, widget_name); - if (widget) { - if (GTK_IS_ADJUSTMENT(widget)) { - GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget); - prefs->setDouble(save_path + "/" + widget_name, gtk_adjustment_get_value(adj)); - //std::cout << "wrote adj " << widget_name << ": " << v << "\n"; - } else if (GTK_IS_TOGGLE_ACTION(widget)) { - GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget); - prefs->setBool(save_path + "/" + widget_name, gtk_toggle_action_get_active(toggle)); - //std::cout << "wrote tog " << widget_name << ": " << v << "\n"; - } else { - g_warning("Unknown widget type for preset: %s\n", widget_name); - } - } else { - g_warning("Bad key when writing preset: %s\n", widget_name); - } - } - prefs->setString(save_path + "/name", profile_name); - - g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE)); - sp_dcc_build_presets_list (tbl); -} - - -static void sp_ddc_change_profile(EgeSelectOneAction* act, GObject* tbl) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - gint preset_index = ege_select_one_action_get_active( act ); - // This is necessary because EgeSelectOneAction spams us with GObject "changed" signal calls - // even when the preset is not changed. It would be good to replace it with something more - // modern. Index 0 means "No preset", so we don't do anything. - if (preset_index == 0) { - return; - } - - gint save_presets_index = GPOINTER_TO_INT(g_object_get_data(tbl, "save_presets_index")); - - if (preset_index == save_presets_index) { - // this is the Save command - sp_dcc_save_profile(NULL, tbl); - return; - } - - if (g_object_get_data(tbl, "presets_blocked")) { - return; - } - - // preset_index is one-based so we subtract 1 - std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset"); - Glib::ustring preset_path = presets.at(preset_index - 1); - - if (!preset_path.empty()) { - g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE)); //temporarily block the selector so no one will updadte it while we're reading it - - std::vector<Inkscape::Preferences::Entry> preset = prefs->getAllEntries(preset_path); - - // Shouldn't this be std::map? - for (std::vector<Inkscape::Preferences::Entry>::iterator i = preset.begin(); i != preset.end(); ++i) { - Glib::ustring entry_name = i->getEntryName(); - if (entry_name == "id" || entry_name == "name") { - continue; - } - void *widget = g_object_get_data(tbl, entry_name.data()); - if (widget) { - if (GTK_IS_ADJUSTMENT(widget)) { - GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget); - gtk_adjustment_set_value(adj, i->getDouble()); - //std::cout << "set adj " << attr_name << " to " << v << "\n"; - } else if (GTK_IS_TOGGLE_ACTION(widget)) { - GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget); - gtk_toggle_action_set_active(toggle, i->getBool()); - //std::cout << "set toggle " << attr_name << " to " << v << "\n"; - } else { - g_warning("Unknown widget type for preset: %s\n", entry_name.data()); - } - } else { - g_warning("Bad key found in a preset record: %s\n", entry_name.data()); - } - } - g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE)); - } -} - -static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - { - g_object_set_data(holder, "presets_blocked", GINT_TO_POINTER(TRUE)); - - EgeAdjustmentAction* calligraphy_angle = 0; - - { - /* Width */ - gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")}; - gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100}; - EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction", - _("Pen Width"), _("Width:"), - _("The width of the calligraphic pen (relative to the visible canvas area)"), - "/tools/calligraphic/width", 15, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy", - 1, 100, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_ddc_width_value_changed, 1, 0 ); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - { - /* Thinning */ - gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")}; - gdouble values[] = {-100, -40, -20, -10, 0, 10, 20, 40, 100}; - EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction", - _("Stroke Thinning"), _("Thinning:"), - _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"), - "/tools/calligraphic/thinning", 10, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - -100, 100, 1, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_ddc_velthin_value_changed, 1, 0); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - { - /* Angle */ - gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")}; - gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; - EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction", - _("Pen Angle"), _("Angle:"), - _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"), - "/tools/calligraphic/angle", 30, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle", - -90.0, 90.0, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_ddc_angle_value_changed, 1, 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - g_object_set_data( holder, "angle_action", eact ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - calligraphy_angle = eact; - } - - { - /* Fixation */ - gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")}; - gdouble values[] = {0, 20, 40, 60, 90, 100}; - EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction", - _("Fixation"), _("Fixation:"), - _("Angle behavior (0 = nib always perpendicular to stroke direction, 100 = fixed angle)"), - "/tools/calligraphic/flatness", 90, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - 0.0, 100, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_ddc_flatness_value_changed, 1, 0); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - { - /* Cap Rounding */ - gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")}; - gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0}; - // TRANSLATORS: "cap" means "end" (both start and finish) here - EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction", - _("Cap rounding"), _("Caps:"), - _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"), - "/tools/calligraphic/cap_rounding", 0.0, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - 0.0, 5.0, 0.01, 0.1, - labels, values, G_N_ELEMENTS(labels), - sp_ddc_cap_rounding_value_changed, 0.01, 2 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - { - /* Tremor */ - gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")}; - gdouble values[] = {0, 10, 20, 40, 60, 100}; - EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction", - _("Stroke Tremor"), _("Tremor:"), - _("Increase to make strokes rugged and trembling"), - "/tools/calligraphic/tremor", 0.0, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - 0.0, 100, 1, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_ddc_tremor_value_changed, 1, 0); - - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - { - /* Wiggle */ - gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")}; - gdouble values[] = {0, 20, 40, 60, 100}; - EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction", - _("Pen Wiggle"), _("Wiggle:"), - _("Increase to make the pen waver and wiggle"), - "/tools/calligraphic/wiggle", 0.0, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - 0.0, 100, 1, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_ddc_wiggle_value_changed, 1, 0); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - { - /* Mass */ - gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")}; - gdouble values[] = {0.0, 2, 10, 20, 50, 100}; - EgeAdjustmentAction* eact = create_adjustment_action( "MassAction", - _("Pen Mass"), _("Mass:"), - _("Increase to make the pen drag behind, as if slowed by inertia"), - "/tools/calligraphic/mass", 2.0, - GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL, - 0.0, 100, 1, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_ddc_mass_value_changed, 1, 0); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - - /* Trace Background button */ - { - InkToggleAction* act = ink_toggle_action_new( "TraceAction", - _("Trace Background"), - _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"), - INKSCAPE_ICON("draw-trace-background"), - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/calligraphic/tracebackground", update_presets_list, holder); - g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); - g_object_set_data( holder, "tracebackground", act ); - } - - /* Use Pressure button */ - { - InkToggleAction* act = ink_toggle_action_new( "PressureAction", - _("Pressure"), - _("Use the pressure of the input device to alter the width of the pen"), - INKSCAPE_ICON("draw-use-pressure"), - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/calligraphic/usepressure", update_presets_list, holder); - g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); - g_object_set_data( holder, "usepressure", act ); - } - - /* Use Tilt button */ - { - InkToggleAction* act = ink_toggle_action_new( "TiltAction", - _("Tilt"), - _("Use the tilt of the input device to alter the angle of the pen's nib"), - INKSCAPE_ICON("draw-use-tilt"), - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/calligraphic/usetilt", update_presets_list, holder); - g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), holder ); - gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs->getBool("/tools/calligraphic/usetilt", true) ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/calligraphic/usetilt", true) ); - g_object_set_data( holder, "usetilt", act ); - } - - /*calligraphic profile */ - { - GtkListStore* model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT); - EgeSelectOneAction* act1 = ege_select_one_action_new ("SetProfileAction", "" , (_("Choose a preset")), NULL, GTK_TREE_MODEL(model)); - ege_select_one_action_set_appearance (act1, "compact"); - g_object_set_data (holder, "profile_selector", act1 ); - - g_object_set_data(holder, "presets_blocked", GINT_TO_POINTER(FALSE)); - - sp_dcc_build_presets_list (holder); - - g_signal_connect(G_OBJECT(act1), "changed", G_CALLBACK(sp_ddc_change_profile), holder); - gtk_action_group_add_action(mainActions, GTK_ACTION(act1)); - } - } -} - - -//######################## -//## Circle / Arc ## -//######################## - -static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 ) -{ - GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) ); - GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) ); - - if (v1 == 0 && v2 == 0) { - if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now) - gtk_action_set_sensitive( ocb, FALSE ); - gtk_action_set_sensitive( make_whole, FALSE ); - } - } else { - gtk_action_set_sensitive( ocb, TRUE ); - gtk_action_set_sensitive( make_whole, TRUE ); - } -} - -static void -sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" ); - - if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble(Glib::ustring("/tools/shapes/arc/") + value_name, gtk_adjustment_get_value(adj)); - } - - // quit if run by the attr_changed listener - if (g_object_get_data( tbl, "freeze" )) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL); - - bool modmade = false; - for (GSList const *items = sp_desktop_selection(desktop)->itemList(); - items != NULL; - items = items->next) - { - SPItem *item = SP_ITEM(items->data); - - if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) { - - SPGenericEllipse *ge = SP_GENERICELLIPSE(item); - SPArc *arc = SP_ARC(item); - - if (!strcmp(value_name, "start")) { - ge->start = (gtk_adjustment_get_value(adj) * M_PI)/ 180; - } else { - ge->end = (gtk_adjustment_get_value(adj) * M_PI)/ 180; - } - - sp_genericellipse_normalize(ge); - ((SPObject *)arc)->updateRepr(); - ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); - - modmade = true; - } - } - - g_free(namespaced_name); - - GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) ); - - sp_arctb_sensitivize( tbl, gtk_adjustment_get_value(adj), gtk_adjustment_get_value(other) ); - - if (modmade) { - DocumentUndo::maybeDone(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC, - _("Arc: Change start/end")); - } - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - - -static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - sp_arctb_startend_value_changed(adj, tbl, "start", "end"); -} - -static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - sp_arctb_startend_value_changed(adj, tbl, "end", "start"); -} - - -static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl ) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" ); - if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/shapes/arc/open", ege_select_one_action_get_active(act) != 0); - } - - // quit if run by the attr_changed listener - if (g_object_get_data( tbl, "freeze" )) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - bool modmade = false; - - if ( ege_select_one_action_get_active(act) != 0 ) { - for (GSList const *items = sp_desktop_selection(desktop)->itemList(); - items != NULL; - items = items->next) - { - SPItem *item = reinterpret_cast<SPItem*>(items->data); - if (SP_IS_ARC(item)) { - Inkscape::XML::Node *repr = item->getRepr(); - repr->setAttribute("sodipodi:open", "true"); - item->updateRepr(); - modmade = true; - } - } - } else { - for (GSList const *items = sp_desktop_selection(desktop)->itemList(); - items != NULL; - items = items->next) - { - SPItem *item = reinterpret_cast<SPItem *>(items->data); - if (SP_IS_ARC(item)) { - Inkscape::XML::Node *repr = item->getRepr(); - repr->setAttribute("sodipodi:open", NULL); - item->updateRepr(); - modmade = true; - } - } - } - - if (modmade) { - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC, - _("Arc: Change open/closed")); - } - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_arctb_defaults(GtkWidget *, GObject *obj) -{ - GtkAdjustment *adj; - adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") ); - gtk_adjustment_set_value(adj, 0.0); - gtk_adjustment_value_changed(adj); - - adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") ); - gtk_adjustment_set_value(adj, 0.0); - gtk_adjustment_value_changed(adj); - - spinbutton_defocus(GTK_WIDGET(obj)); -} - -static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const * /*name*/, - gchar const * /*old_value*/, gchar const * /*new_value*/, - bool /*is_interactive*/, gpointer data) -{ - GObject *tbl = G_OBJECT(data); - - // quit if run by the _changed callbacks - if (g_object_get_data( tbl, "freeze" )) { - return; - } - - // in turn, prevent callbacks from responding - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - gdouble start = 0.; - gdouble end = 0.; - sp_repr_get_double(repr, "sodipodi:start", &start); - sp_repr_get_double(repr, "sodipodi:end", &end); - - GtkAdjustment *adj1,*adj2; - adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) ); - gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI)); - adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) ); - gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI)); - - sp_arctb_sensitivize( tbl, gtk_adjustment_get_value(adj1), gtk_adjustment_get_value(adj2) ); - - char const *openstr = NULL; - openstr = repr->attribute("sodipodi:open"); - EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) ); - - if (openstr) { - ege_select_one_action_set_active( ocb, 1 ); - } else { - ege_select_one_action_set_active( ocb, 0 ); - } - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static Inkscape::XML::NodeEventVector arc_tb_repr_events = { - NULL, /* child_added */ - NULL, /* child_removed */ - arc_tb_event_attr_changed, - NULL, /* content_changed */ - NULL /* order_changed */ -}; - - -static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) -{ - int n_selected = 0; - Inkscape::XML::Node *repr = NULL; - - purge_repr_listener( tbl, tbl ); - - for (GSList const *items = selection->itemList(); - items != NULL; - items = items->next) - { - SPItem *item = reinterpret_cast<SPItem *>(items->data); - if (SP_IS_ARC(item)) { - n_selected++; - repr = item->getRepr(); - } - } - - EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) ); - - g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) ); - if (n_selected == 0) { - g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL ); - } else if (n_selected == 1) { - g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) ); - g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); - - if (repr) { - g_object_set_data( tbl, "repr", repr ); - Inkscape::GC::anchor(repr); - sp_repr_add_listener(repr, &arc_tb_repr_events, tbl); - sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl); - } - } else { - // FIXME: implement averaging of all parameters for multiple selected - //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>")); - g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL ); - sp_arctb_sensitivize( tbl, 1, 0 ); - } -} - - -static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - EgeAdjustmentAction* eact = 0; - Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); - - - { - EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 ); - ege_output_action_set_use_markup( act, TRUE ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_object_set_data( holder, "mode_action", act ); - } - - /* Start */ - { - eact = create_adjustment_action( "ArcStartAction", - _("Start"), _("Start:"), - _("The angle (in degrees) from the horizontal to the arc's start point"), - "/tools/shapes/arc/start", 0.0, - GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc", - -360.0, 360.0, 1.0, 10.0, - 0, 0, 0, - sp_arctb_start_value_changed); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - /* End */ - { - eact = create_adjustment_action( "ArcEndAction", - _("End"), _("End:"), - _("The angle (in degrees) from the horizontal to the arc's end point"), - "/tools/shapes/arc/end", 0.0, - GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL, - -360.0, 360.0, 1.0, 10.0, - 0, 0, 0, - sp_arctb_end_value_changed); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - /* Segments / Pie checkbox */ - { - GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); - - GtkTreeIter iter; - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Closed arc"), - 1, _("Switch to segment (closed shape with two radii)"), - 2, INKSCAPE_ICON("draw-ellipse-segment"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Open Arc"), - 1, _("Switch to arc (unclosed shape)"), - 2, INKSCAPE_ICON("draw-ellipse-arc"), - -1 ); - - EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", (""), (""), NULL, GTK_TREE_MODEL(model) ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - g_object_set_data( holder, "open_action", act ); - - ege_select_one_action_set_appearance( act, "full" ); - ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); - g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); - ege_select_one_action_set_icon_column( act, 2 ); - ege_select_one_action_set_icon_size( act, secondarySize ); - ege_select_one_action_set_tooltip_column( act, 1 ); - - bool isClosed = !prefs->getBool("/tools/shapes/arc/open", false); - ege_select_one_action_set_active( act, isClosed ? 0 : 1 ); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder ); - } - - /* Make Whole */ - { - InkAction* inky = ink_action_new( "ArcResetAction", - _("Make whole"), - _("Make the shape a whole ellipse, not arc or segment"), - INKSCAPE_ICON("draw-ellipse-whole"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - gtk_action_set_sensitive( GTK_ACTION(inky), TRUE ); - g_object_set_data( holder, "make_whole", inky ); - } - - g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) ); - // sensitivize make whole and open checkbox - { - GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) ); - GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) ); - sp_arctb_sensitivize( holder, gtk_adjustment_get_value(adj1), gtk_adjustment_get_value(adj2) ); - } - - - sigc::connection *connection = new sigc::connection( - sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder)) - ); - g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection ); - g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); -} - - - - -// toggle button callbacks and updaters - -//######################## -//## Dropper ## -//######################## - -static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt( "/tools/dropper/pick", gtk_toggle_action_get_active( act ) ); - GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") ); - if ( set_action ) { - if ( gtk_toggle_action_get_active( act ) ) { - gtk_action_set_sensitive( set_action, TRUE ); - } else { - gtk_action_set_sensitive( set_action, FALSE ); - } - } - - spinbutton_defocus(GTK_WIDGET(tbl)); -} - -static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool( "/tools/dropper/setalpha", gtk_toggle_action_get_active( act ) ); - spinbutton_defocus(GTK_WIDGET(tbl)); -} - - -/** - * Dropper auxiliary toolbar construction and setup. - * - * TODO: Would like to add swatch of current color. - * TODO: Add queue of last 5 or so colors selected with new swatches so that - * can drag and drop places. Will provide a nice mixing palette. - */ -static void sp_dropper_toolbox_prep(SPDesktop * /*desktop*/, GtkActionGroup* mainActions, GObject* holder) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gint pickAlpha = prefs->getInt( "/tools/dropper/pick", 1 ); - - { - EgeOutputAction* act = ege_output_action_new( "DropperOpacityAction", _("Opacity:"), "", 0 ); - ege_output_action_set_use_markup( act, TRUE ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - } - - { - InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction", - _("Pick opacity"), - _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"), - NULL, - Inkscape::ICON_SIZE_DECORATION ); - g_object_set( act, "short_label", _("Pick"), NULL ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_object_set_data( holder, "pick_action", act ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder ); - } - - { - InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction", - _("Assign opacity"), - _("If alpha was picked, assign it to selection as fill or stroke transparency"), - NULL, - Inkscape::ICON_SIZE_DECORATION ); - g_object_set( act, "short_label", _("Assign"), NULL ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_object_set_data( holder, "set_action", act ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/dropper/setalpha", true) ); - // make sure it's disabled if we're not picking alpha - gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder ); - } -} - - -//######################## -//## LPETool ## -//######################## - -// the subtools from which the toolbar is built automatically are listed in lpe-tool-context.h - -// this is called when the mode is changed via the toolbar (i.e., one of the subtool buttons is pressed) -static void sp_lpetool_mode_changed(EgeSelectOneAction *act, GObject *tbl) -{ - using namespace Inkscape::LivePathEffect; - - SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop"); - SPEventContext *ec = desktop->event_context; - if (!SP_IS_LPETOOL_CONTEXT(ec)) { - return; - } - - // only take action if run by the attr_changed listener - if (!g_object_get_data(tbl, "freeze")) { - // in turn, prevent listener from responding - g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE)); - - gint mode = ege_select_one_action_get_active(act); - EffectType type = lpesubtools[mode].type; - - SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context); - bool success = lpetool_try_construction(lc, type); - if (success) { - // since the construction was already performed, we set the state back to inactive - ege_select_one_action_set_active(act, 0); - mode = 0; - } else { - // switch to the chosen subtool - SP_LPETOOL_CONTEXT(desktop->event_context)->mode = type; - } - - if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt( "/tools/lpetool/mode", mode ); - } - - g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE)); - } -} - -static void sp_lpetool_toolbox_sel_modified(Inkscape::Selection *selection, guint /*flags*/, GObject * /*tbl*/) -{ - SPEventContext *ec = selection->desktop()->event_context; - if (SP_IS_LPETOOL_CONTEXT(ec)) { - lpetool_update_measuring_items(SP_LPETOOL_CONTEXT(ec)); - } -} - -static void sp_lpetool_toolbox_sel_changed(Inkscape::Selection *selection, GObject *tbl) -{ - using namespace Inkscape::LivePathEffect; - SPEventContext *ec = selection->desktop()->event_context; - if (!SP_IS_LPETOOL_CONTEXT(ec)) { - return; - } - SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(ec); - - lpetool_delete_measuring_items(lc); - lpetool_create_measuring_items(lc, selection); - - // activate line segment combo box if a single item with LPELineSegment is selected - GtkAction* w = GTK_ACTION(g_object_get_data(tbl, "lpetool_line_segment_action")); - SPItem *item = selection->singleItem(); - if (item && SP_IS_LPE_ITEM(item) && lpetool_item_has_construction(lc, item)) { - SPLPEItem *lpeitem = SP_LPE_ITEM(item); - Effect* lpe = sp_lpe_item_get_current_lpe(lpeitem); - if (lpe && lpe->effectType() == LINE_SEGMENT) { - LPELineSegment *lpels = static_cast<LPELineSegment*>(lpe); - g_object_set_data(tbl, "currentlpe", lpe); - g_object_set_data(tbl, "currentlpeitem", lpeitem); - gtk_action_set_sensitive(w, TRUE); - ege_select_one_action_set_active(EGE_SELECT_ONE_ACTION(w), lpels->end_type.get_value()); - } else { - g_object_set_data(tbl, "currentlpe", NULL); - g_object_set_data(tbl, "currentlpeitem", NULL); - gtk_action_set_sensitive(w, FALSE); - } - } else { - g_object_set_data(tbl, "currentlpe", NULL); - g_object_set_data(tbl, "currentlpeitem", NULL); - gtk_action_set_sensitive(w, FALSE); - } -} - -static void lpetool_toggle_show_bbox(GtkToggleAction *act, gpointer data) { - SPDesktop *desktop = static_cast<SPDesktop *>(data); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - bool show = gtk_toggle_action_get_active( act ); - prefs->setBool("/tools/lpetool/show_bbox", show); - - if (tools_isactive(desktop, TOOLS_LPETOOL)) { - SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context); - lpetool_context_reset_limiting_bbox(lc); - } -} - -static void lpetool_toggle_show_measuring_info(GtkToggleAction *act, GObject *tbl) -{ - SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(tbl, "desktop")); - if (!tools_isactive(desktop, TOOLS_LPETOOL)) { - return; - } - - GtkAction *unitact = static_cast<GtkAction*>(g_object_get_data(tbl, "lpetool_units_action")); - SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context); - if (tools_isactive(desktop, TOOLS_LPETOOL)) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool show = gtk_toggle_action_get_active( act ); - prefs->setBool("/tools/lpetool/show_measuring_info", show); - lpetool_show_measuring_info(lc, show); - gtk_action_set_sensitive(GTK_ACTION(unitact), show); - } -} - -static void lpetool_unit_changed(GtkAction* /*act*/, GObject* tbl) -{ - UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker")); - SPUnit const *unit = tracker->getActiveUnit(); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt("/tools/lpetool/unitid", unit->unit_id); - - SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" ); - if (SP_IS_LPETOOL_CONTEXT(desktop->event_context)) { - SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context); - lpetool_delete_measuring_items(lc); - lpetool_create_measuring_items(lc); - } -} - -static void lpetool_toggle_set_bbox(GtkToggleAction *act, gpointer data) -{ - SPDesktop *desktop = static_cast<SPDesktop *>(data); - Inkscape::Selection *selection = desktop->selection; - - Geom::OptRect bbox = selection->visualBounds(); - - if (bbox) { - Geom::Point A(bbox->min()); - Geom::Point B(bbox->max()); - - A *= desktop->doc2dt(); - B *= desktop->doc2dt(); - - // TODO: should we provide a way to store points in prefs? - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/tools/lpetool/bbox_upperleftx", A[Geom::X]); - prefs->setDouble("/tools/lpetool/bbox_upperlefty", A[Geom::Y]); - prefs->setDouble("/tools/lpetool/bbox_lowerrightx", B[Geom::X]); - prefs->setDouble("/tools/lpetool/bbox_lowerrighty", B[Geom::Y]); - - lpetool_context_reset_limiting_bbox(SP_LPETOOL_CONTEXT(desktop->event_context)); - } - - gtk_toggle_action_set_active(act, false); -} - -static void sp_line_segment_build_list(GObject *tbl) -{ - g_object_set_data(tbl, "line_segment_list_blocked", GINT_TO_POINTER(TRUE)); - - EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "lpetool_line_segment_action")); - GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector)); - gtk_list_store_clear (model); - - // TODO: we add the entries of rht combo box manually; later this should be done automatically - { - GtkTreeIter iter; - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("Closed"), 1, 0, -1 ); - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("Open start"), 1, 1, -1 ); - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("Open end"), 1, 2, -1 ); - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, _("Open both"), 1, 3, -1 ); - } - - g_object_set_data(tbl, "line_segment_list_blocked", GINT_TO_POINTER(FALSE)); -} - -static void sp_lpetool_change_line_segment_type(EgeSelectOneAction* act, GObject* tbl) -{ - using namespace Inkscape::LivePathEffect; - - // quit if run by the attr_changed listener - if (g_object_get_data(tbl, "freeze")) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE)); - - LPELineSegment *lpe = static_cast<LPELineSegment *>(g_object_get_data(tbl, "currentlpe")); - SPLPEItem *lpeitem = static_cast<SPLPEItem *>(g_object_get_data(tbl, "currentlpeitem")); - if (lpeitem) { - SPLPEItem *lpeitem = static_cast<SPLPEItem *>(g_object_get_data(tbl, "currentlpeitem")); - lpe->end_type.param_set_value(static_cast<Inkscape::LivePathEffect::EndType>(ege_select_one_action_get_active(act))); - sp_lpe_item_update_patheffect(lpeitem, true, true); - } - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void lpetool_open_lpe_dialog(GtkToggleAction *act, gpointer data) -{ - SPDesktop *desktop = static_cast<SPDesktop *>(data); - - if (tools_isactive(desktop, TOOLS_LPETOOL)) { - sp_action_perform(Inkscape::Verb::get(SP_VERB_DIALOG_LIVE_PATH_EFFECT)->get_action(desktop), NULL); - } - gtk_toggle_action_set_active(act, false); -} - -static void sp_lpetool_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - UnitTracker* tracker = new UnitTracker(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE); - tracker->setActiveUnit(sp_desktop_namedview(desktop)->doc_units); - g_object_set_data(holder, "tracker", tracker); - SPUnit const *unit = tracker->getActiveUnit(); - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt("/tools/lpetool/unitid", unit->unit_id); - - /** Automatically create a list of LPEs that get added to the toolbar **/ - { - GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); - - GtkTreeIter iter; - - // the first toggle button represents the state that no subtool is active (remove this when - // this can be modeled by EgeSelectOneAction or some other action) - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("All inactive"), - 1, _("No geometric tool is active"), - 2, "draw-geometry-inactive", - -1 ); - - Inkscape::LivePathEffect::EffectType type; - for (int i = 1; i < num_subtools; ++i) { // we start with i = 1 because INVALID_LPE was already added - type = lpesubtools[i].type; - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str(), - 1, Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str(), - 2, lpesubtools[i].icon_name, - -1 ); - } - - EgeSelectOneAction* act = ege_select_one_action_new( "LPEToolModeAction", (""), (""), NULL, GTK_TREE_MODEL(model) ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - g_object_set_data( holder, "lpetool_mode_action", act ); - - ege_select_one_action_set_appearance( act, "full" ); - ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); - g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); - ege_select_one_action_set_icon_column( act, 2 ); - ege_select_one_action_set_tooltip_column( act, 1 ); - - gint lpeToolMode = prefs->getInt("/tools/lpetool/mode", 0); - ege_select_one_action_set_active( act, lpeToolMode ); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_lpetool_mode_changed), holder ); - } - - /* Show limiting bounding box */ - { - InkToggleAction* act = ink_toggle_action_new( "LPEShowBBoxAction", - _("Show limiting bounding box"), - _("Show bounding box (used to cut infinite lines)"), - "show-bounding-box", - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_show_bbox), desktop ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/lpetool/show_bbox", true ) ); - } - - /* Set limiting bounding box to bbox of current selection */ - { - InkToggleAction* act = ink_toggle_action_new( "LPEBBoxFromSelectionAction", - _("Get limiting bounding box from selection"), - _("Set limiting bounding box (used to cut infinite lines) to the bounding box of current selection"), - "draw-geometry-set-bounding-box", - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_set_bbox), desktop ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), FALSE ); - } - - - /* Combo box to choose line segment type */ - { - GtkListStore* model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT); - EgeSelectOneAction* act = ege_select_one_action_new ("LPELineSegmentAction", "" , (_("Choose a line segment type")), NULL, GTK_TREE_MODEL(model)); - ege_select_one_action_set_appearance (act, "compact"); - g_object_set_data (holder, "lpetool_line_segment_action", act ); - - g_object_set_data(holder, "line_segment_list_blocked", GINT_TO_POINTER(FALSE)); - - sp_line_segment_build_list (holder); - - g_signal_connect(G_OBJECT(act), "changed", G_CALLBACK(sp_lpetool_change_line_segment_type), holder); - gtk_action_set_sensitive( GTK_ACTION(act), FALSE ); - gtk_action_group_add_action(mainActions, GTK_ACTION(act)); - } - - /* Display measuring info for selected items */ - { - InkToggleAction* act = ink_toggle_action_new( "LPEMeasuringAction", - _("Display measuring info"), - _("Display measuring info for selected items"), - "draw-geometry-show-measuring-info", - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_show_measuring_info), holder ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/lpetool/show_measuring_info", true ) ); - } - - // add the units menu - { - GtkAction* act = tracker->createAction( "LPEToolUnitsAction", _("Units"), ("") ); - gtk_action_group_add_action( mainActions, act ); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(lpetool_unit_changed), (GObject*)holder ); - g_object_set_data(holder, "lpetool_units_action", act); - gtk_action_set_sensitive(act, prefs->getBool("/tools/lpetool/show_measuring_info", true)); - } - - /* Open LPE dialog (to adapt parameters numerically) */ - { - InkToggleAction* act = ink_toggle_action_new( "LPEOpenLPEDialogAction", - _("Open LPE dialog"), - _("Open LPE dialog (to adapt parameters numerically)"), - "dialog-geometry", - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_open_lpe_dialog), desktop ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), FALSE ); - } - - //watch selection - Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISNodeToolbox"); - - sigc::connection *c_selection_modified = - new sigc::connection (sp_desktop_selection (desktop)->connectModified - (sigc::bind (sigc::ptr_fun (sp_lpetool_toolbox_sel_modified), (GObject*)holder))); - pool->add_connection ("selection-modified", c_selection_modified); - - sigc::connection *c_selection_changed = - new sigc::connection (sp_desktop_selection (desktop)->connectChanged - (sigc::bind (sigc::ptr_fun(sp_lpetool_toolbox_sel_changed), (GObject*)holder))); - pool->add_connection ("selection-changed", c_selection_changed); -} - -//######################## -//## Eraser ## -//######################## - -static void sp_erc_width_value_changed( GtkAdjustment *adj, GObject *tbl ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble( "/tools/eraser/width", gtk_adjustment_get_value(adj) ); - update_presets_list(tbl); -} - -static void sp_erasertb_mode_changed( EgeSelectOneAction *act, GObject *tbl ) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" ); - bool eraserMode = ege_select_one_action_get_active( act ) != 0; - if (DocumentUndo::getUndoSensitive(sp_desktop_document(desktop))) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool( "/tools/eraser/mode", eraserMode ); - } - - // only take action if run by the attr_changed listener - if (!g_object_get_data( tbl, "freeze" )) { - // in turn, prevent listener from responding - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - if ( eraserMode != 0 ) { - } else { - } - // TODO finish implementation - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); - } -} - -static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - { - GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); - - GtkTreeIter iter; - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Delete"), - 1, _("Delete objects touched by the eraser"), - 2, INKSCAPE_ICON("draw-eraser-delete-objects"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Cut"), - 1, _("Cut out from objects"), - 2, INKSCAPE_ICON("path-difference"), - -1 ); - - EgeSelectOneAction* act = ege_select_one_action_new( "EraserModeAction", (""), (""), NULL, GTK_TREE_MODEL(model) ); - g_object_set( act, "short_label", _("Mode:"), NULL ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - g_object_set_data( holder, "eraser_mode_action", act ); - - ege_select_one_action_set_appearance( act, "full" ); - ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); - g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); - ege_select_one_action_set_icon_column( act, 2 ); - ege_select_one_action_set_tooltip_column( act, 1 ); - - /// @todo Convert to boolean? - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0; - ege_select_one_action_set_active( act, eraserMode ); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_erasertb_mode_changed), holder ); - } - - { - /* Width */ - gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")}; - gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100}; - EgeAdjustmentAction *eact = create_adjustment_action( "EraserWidthAction", - _("Pen Width"), _("Width:"), - _("The width of the eraser pen (relative to the visible canvas area)"), - "/tools/eraser/width", 15, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-eraser", - 1, 100, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_erc_width_value_changed, 1, 0); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - -} - -//######################## -//## Text Toolbox ## -//######################## - -// Functions for debugging: -#ifdef DEBUG_TEXT - -static void sp_print_font( SPStyle *query ) { - - bool family_set = query->text->font_family.set; - bool style_set = query->font_style.set; - bool fontspec_set = query->text->font_specification.set; - - std::cout << " Family set? " << family_set - << " Style set? " << style_set - << " FontSpec set? " << fontspec_set - << std::endl; - std::cout << " Family: " - << (query->text->font_family.value ? query->text->font_family.value : "No value") - << " Style: " << query->font_style.computed - << " Weight: " << query->font_weight.computed - << " FontSpec: " - << (query->text->font_specification.value ? query->text->font_specification.value : "No value") - << std::endl; -} - -static void sp_print_fontweight( SPStyle *query ) { - const gchar* names[] = {"100", "200", "300", "400", "500", "600", "700", "800", "900", - "NORMAL", "BOLD", "LIGHTER", "BOLDER", "Out of range"}; - // Missing book = 380 - int index = query->font_weight.computed; - if( index < 0 || index > 13 ) index = 13; - std::cout << " Weight: " << names[ index ] - << " (" << query->font_weight.computed << ")" << std::endl; - -} - -static void sp_print_fontstyle( SPStyle *query ) { - - const gchar* names[] = {"NORMAL", "ITALIC", "OBLIQUE", "Out of range"}; - int index = query->font_style.computed; - if( index < 0 || index > 3 ) index = 3; - std::cout << " Style: " << names[ index ] << std::endl; - -} -#endif - -// Format family drop-down menu. -static void cell_data_func(GtkCellLayout * /*cell_layout*/, - GtkCellRenderer *cell, - GtkTreeModel *tree_model, - GtkTreeIter *iter, - gpointer /*data*/) -{ - gchar *family; - gtk_tree_model_get(tree_model, iter, 0, &family, -1); - gchar *const family_escaped = g_markup_escape_text(family, -1); - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - int show_sample = prefs->getInt("/tools/text/show_sample_in_list", 1); - if (show_sample) { - - Glib::ustring sample = prefs->getString("/tools/text/font_sample"); - gchar *const sample_escaped = g_markup_escape_text(sample.data(), -1); - - std::stringstream markup; - markup << family_escaped << " <span foreground='gray' font_family='" - << family_escaped << "'>" << sample_escaped << "</span>"; - g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL); - - g_free(sample_escaped); - } else { - g_object_set (G_OBJECT (cell), "markup", family_escaped, NULL); - } - // This doesn't work for two reasons... it set both selected and not selected backgrounds - // to white.. which means that white foreground text is invisible. It also only effects - // the text region, leaving the padding untouched. - // g_object_set (G_OBJECT (cell), "cell-background", "white", "cell-background-set", true, NULL); - - g_free(family); - g_free(family_escaped); -} - -// Font family -// -// In most cases we should just be able to set the new family name -// but there may be cases where a font family doesn't follow the -// standard naming pattern. To handle those cases, we do a song and -// dance to use Pango to find the best match. To do that we start -// with the old "fontSpec" (which is the returned string from -// pango_font_description_to_string() with the size unset). This -// has the form "[family-list] [style-options]" where the -// family-list is a comma separated list of font-family names -// (optionally terminated by a comma). An example would be -// "DejaVu Sans, Sans Bold". Only a "fontSpec" containing a -// single font-family will work with Pango's best match routine. -// If we can't obtain a good "fontSpec", we then resort to blindly -// changing the font-family. -static void sp_text_fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, GObject *tbl ) -{ -#ifdef DEBUG_TEXT - std::cout << std::endl; - std::cout << "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" << std::endl; - std::cout << "sp_text_fontfamily_value_changed: " << std::endl; -#endif - - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - gchar *family = ink_comboboxentry_action_get_active_text( act ); -#ifdef DEBUG_TEXT - std::cout << " New family: " << family << std::endl; -#endif - - // First try to get the old font spec from the stored value - SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - int result_fontspec = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION); - - Glib::ustring fontSpec = query->text->font_specification.set ? query->text->font_specification.value : ""; -#ifdef DEBUG_TEXT - std::cout << " fontSpec from query :" << fontSpec << ":" << std::endl; -#endif - - // If that didn't work, try to get font spec from style - if (fontSpec.empty()) { - - // Must query all to fill font-family, font-style, font-weight, font-specification - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); - - // Construct a new font specification if it does not yet exist - font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query); - if( fontFromStyle ) { - fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle); - fontFromStyle->Unref(); - } - -#ifdef DEBUG_TEXT - std::cout << " fontSpec empty, try from style" << std::endl; - std::cout << " from style :" << fontSpec << ":" << std::endl; - sp_print_font( query ); -#endif - - } - - // And if that didn't work use default. DO WE REALLY WANT TO DO THIS? - if ( fontSpec.empty() ) { - - sp_style_read_from_prefs(query, "/tools/text"); - - // Construct a new font specification if it does not yet exist - font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query); - if ( fontFromStyle ) { - fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle); - fontFromStyle->Unref(); - } - -#ifdef DEBUG_TEXT - std::cout << " fontSpec empty, trying from prefs" << std::endl; - std::cout << " from prefs :" << fontSpec << ":" << std::endl; - sp_print_font( query ); -#endif - } - - // Now we have a font specification, replace family. - Glib::ustring newFontSpec = ""; - SPCSSAttr *css = sp_repr_css_attr_new (); - - if (!fontSpec.empty()) newFontSpec = font_factory::Default()->ReplaceFontSpecificationFamily(fontSpec, family); - -#ifdef DEBUG_TEXT - std::cout << " New FontSpec from ReplaceFontSpecificationFamily :" << newFontSpec << ":" << std::endl; -#endif - - if (!fontSpec.empty() && !newFontSpec.empty() ) { - - if (fontSpec != newFontSpec) { - - font_instance *font = font_factory::Default()->FaceFromFontSpecification(newFontSpec.c_str()); - - if (font) { - sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str()); - - // Set all the these just in case they were altered when finding the best - // match for the new family and old style... Unnecessary? - - gchar c[256]; - - font->Family(c, 256); - - sp_repr_css_set_property (css, "font-family", c); - - font->Attribute( "weight", c, 256); - sp_repr_css_set_property (css, "font-weight", c); - - font->Attribute("style", c, 256); - sp_repr_css_set_property (css, "font-style", c); - - font->Attribute("stretch", c, 256); - sp_repr_css_set_property (css, "font-stretch", c); - - font->Attribute("variant", c, 256); - sp_repr_css_set_property (css, "font-variant", c); - - font->Unref(); - } else { - g_warning(_("Failed to find font matching: %s\n"), newFontSpec.c_str()); - } - } - } else { - - // Either old font does not exist on system or ReplaceFontSpecificationFamily() failed. - // Blindly fall back to setting the family to text in the font-family chooser. - -#ifdef DEBUG_TEXT - std::cout << " Failed to find new font, blindly setting family: " << family << std::endl; -#endif - sp_repr_css_set_property (css, "-inkscape-font-specification", family); - sp_repr_css_set_property (css, "font-family", family); - } - - // If querying returned nothing, update default style. - if (result_fontspec == QUERY_STYLE_NOTHING) - { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->mergeStyle("/tools/text/style", css); - //sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace through a verb - } - else - { - sp_desktop_set_style (SP_ACTIVE_DESKTOP, css, true, true); - } - - sp_style_unref(query); - - g_free (family); - - // Save for undo - if (result_fontspec != QUERY_STYLE_NOTHING) { - DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, - _("Text: Change font family")); - } - sp_repr_css_attr_unref (css); - - // unfreeze - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); - - // focus to canvas - gtk_widget_grab_focus (GTK_WIDGET((SP_ACTIVE_DESKTOP)->canvas)); - -#ifdef DEBUG_TEXT - std::cout << "sp_text_toolbox_fontfamily_changes: exit" << std::endl; - std::cout << "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" << std::endl; - std::cout << std::endl; -#endif -} - -// Font size -static void sp_text_fontsize_value_changed( Ink_ComboBoxEntry_Action *act, GObject *tbl ) -{ - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - gchar *text = ink_comboboxentry_action_get_active_text( act ); - gchar *endptr; - gdouble size = g_strtod( text, &endptr ); - if (endptr == text) { // Conversion failed, non-numeric input. - g_warning( "Conversion of size text to double failed, input: %s\n", text ); - g_free( text ); - return; - } - g_free( text ); - - // Set css font size. - SPCSSAttr *css = sp_repr_css_attr_new (); - Inkscape::CSSOStringStream osfs; - osfs << size << "px"; // For now always use px - sp_repr_css_set_property (css, "font-size", osfs.str().c_str()); - - // Apply font size to selected objects. - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - sp_desktop_set_style (desktop, css, true, true); - - // If no selected objects, set default. - SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - int result_numbers = - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); - if (result_numbers == QUERY_STYLE_NOTHING) - { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->mergeStyle("/tools/text/style", css); - } else { - // Save for undo - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE, - _("Text: Change font size")); - } - - sp_style_unref(query); - - sp_repr_css_attr_unref (css); - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -// Handles both Bold and Italic/Oblique -static void sp_text_style_changed( InkToggleAction* act, GObject *tbl ) -{ - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - // Called by Bold or Italics button? - const gchar* name = gtk_action_get_name( GTK_ACTION( act ) ); - gint prop = (strcmp(name, "TextBoldAction") == 0) ? 0 : 1; - - // First query font-specification, this is the most complete font face description. - SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - int result_fontspec = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION); - - // font_specification will not be set unless defined explicitely on a tspan. - // This should be fixed! - Glib::ustring fontSpec = query->text->font_specification.set ? query->text->font_specification.value : ""; - - if (fontSpec.empty()) { - // Construct a new font specification if it does not yet exist - // Must query font-family, font-style, font-weight, to find correct font face. - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); - - font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query); - if ( fontFromStyle ) { - fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle); - fontFromStyle->Unref(); - } - } - - // Now that we have the old face, find the new face. - Glib::ustring newFontSpec = ""; - SPCSSAttr *css = sp_repr_css_attr_new (); - gboolean active = gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(act) ); - - switch (prop) - { - case 0: - { - // Bold - if (!fontSpec.empty()) newFontSpec = font_factory::Default()->FontSpecificationSetBold(fontSpec, active); - if ( !fontSpec.empty() && !newFontSpec.empty() ) { - - // Set weight using new font if found. - font_instance * font = font_factory::Default()->FaceFromFontSpecification(newFontSpec.c_str()); - if (font) { - gchar c[256]; - font->Attribute( "weight", c, 256); - sp_repr_css_set_property (css, "font-weight", c); - font->Unref(); - font = NULL; - } - } else { - - // Blindly set weight. - sp_repr_css_set_property (css, "font-weight", (active == 0 ? "normal" : "bold") ); - } - break; - } - - case 1: - { - // Italic/Oblique - if (!fontSpec.empty()) newFontSpec = font_factory::Default()->FontSpecificationSetItalic(fontSpec, active); - - if ( !fontSpec.empty() && !newFontSpec.empty() ) { - - // Don't even set the italic/oblique if the font didn't exist on the system - if ( active ) { - if ( newFontSpec.find( "Italic" ) != Glib::ustring::npos ) { - sp_repr_css_set_property (css, "font-style", "italic"); - } else { - sp_repr_css_set_property (css, "font-style", "oblique"); - } - } else { - sp_repr_css_set_property (css, "font-style", "normal"); - } - - } else { - - // Blindly set style. - sp_repr_css_set_property (css, "font-style", (active == 0 ? "normal" : "italic") ); - } - break; - } - } - - if (!newFontSpec.empty()) { - sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str()); - } - - // If querying returned nothing, update default style. - if (result_fontspec == QUERY_STYLE_NOTHING) - { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->mergeStyle("/tools/text/style", css); - } - - sp_style_unref(query); - - // Do we need to update other CSS values? - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - sp_desktop_set_style (desktop, css, true, true); - if (result_fontspec != QUERY_STYLE_NOTHING) { - DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, - _("Text: Change font style")); - } - sp_repr_css_attr_unref (css); - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -// Handles both Superscripts and Subscripts -static void sp_text_script_changed( InkToggleAction* act, GObject *tbl ) -{ - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - // Called by Superscript or Subscript button? - const gchar* name = gtk_action_get_name( GTK_ACTION( act ) ); - gint prop = (strcmp(name, "TextSuperscriptAction") == 0) ? 0 : 1; - -#ifdef DEBUG_TEXT - std::cout << "sp_text_script_changed: " << prop << std::endl; -#endif - - // Query baseline - SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - int result_baseline = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BASELINES); - - bool setSuper = false; - bool setSub = false; - - if(result_baseline == QUERY_STYLE_NOTHING || result_baseline == QUERY_STYLE_MULTIPLE_DIFFERENT ) { - // If not set or mixed, turn on superscript or subscript - if( prop == 0 ) { - setSuper = true; - } else { - setSub = true; - } - } else { - // Superscript - gboolean superscriptSet = (query->baseline_shift.set && - query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL && - query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUPER ); - - // Subscript - gboolean subscriptSet = (query->baseline_shift.set && - query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL && - query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUB ); - - setSuper = !superscriptSet && prop == 0; - setSub = !subscriptSet && prop == 1; - } - - // Set css properties - SPCSSAttr *css = sp_repr_css_attr_new (); - if( setSuper || setSub ) { - // Openoffice 2.3 and Adobe use 58%, Microsoft Word 2002 uses 65%, LaTex about 70%. - // 58% looks too small to me, especially if a superscript is placed on a superscript. - // If you make a change here, consider making a change to baseline-shift amount - // in style.cpp. - sp_repr_css_set_property (css, "font-size", "65%"); - } else { - sp_repr_css_set_property (css, "font-size", ""); - } - if( setSuper ) { - sp_repr_css_set_property (css, "baseline-shift", "super"); - } else if( setSub ) { - sp_repr_css_set_property (css, "baseline-shift", "sub"); - } else { - sp_repr_css_set_property (css, "baseline-shift", "baseline"); - } - - // Apply css to selected objects. - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - sp_desktop_set_style (desktop, css, true, false); - - // Save for undo - if(result_baseline != QUERY_STYLE_NOTHING) { - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:script", SP_VERB_NONE, - _("Text: Change superscript or subscript")); - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl ) -{ - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - int mode = ege_select_one_action_get_active( act ); - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt("/tools/text/align_mode", mode); - - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - - // move the x of all texts to preserve the same bbox - Inkscape::Selection *selection = sp_desktop_selection(desktop); - for (GSList const *items = selection->itemList(); items != NULL; items = items->next) { - if (SP_IS_TEXT((SPItem *) items->data)) { - SPItem *item = SP_ITEM(items->data); - - unsigned writing_mode = item->style->writing_mode.value; - // below, variable names suggest horizontal move, but we check the writing direction - // and move in the corresponding axis - Geom::Dim2 axis; - if (writing_mode == SP_CSS_WRITING_MODE_LR_TB || writing_mode == SP_CSS_WRITING_MODE_RL_TB) { - axis = Geom::X; - } else { - axis = Geom::Y; - } - - Geom::OptRect bbox = item->geometricBounds(); - if (!bbox) - continue; - double width = bbox->dimensions()[axis]; - // If you want to align within some frame, other than the text's own bbox, calculate - // the left and right (or top and bottom for tb text) slacks of the text inside that - // frame (currently unused) - double left_slack = 0; - double right_slack = 0; - unsigned old_align = item->style->text_align.value; - double move = 0; - if (old_align == SP_CSS_TEXT_ALIGN_START || old_align == SP_CSS_TEXT_ALIGN_LEFT) { - switch (mode) { - case 0: - move = -left_slack; - break; - case 1: - move = width/2 + (right_slack - left_slack)/2; - break; - case 2: - move = width + right_slack; - break; - } - } else if (old_align == SP_CSS_TEXT_ALIGN_CENTER) { - switch (mode) { - case 0: - move = -width/2 - left_slack; - break; - case 1: - move = (right_slack - left_slack)/2; - break; - case 2: - move = width/2 + right_slack; - break; - } - } else if (old_align == SP_CSS_TEXT_ALIGN_END || old_align == SP_CSS_TEXT_ALIGN_RIGHT) { - switch (mode) { - case 0: - move = -width - left_slack; - break; - case 1: - move = -width/2 + (right_slack - left_slack)/2; - break; - case 2: - move = right_slack; - break; - } - } - Geom::Point XY = SP_TEXT(item)->attributes.firstXY(); - if (axis == Geom::X) { - XY = XY + Geom::Point (move, 0); - } else { - XY = XY + Geom::Point (0, move); - } - SP_TEXT(item)->attributes.setFirstXY(XY); - item->updateRepr(); - item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); - } - } - - SPCSSAttr *css = sp_repr_css_attr_new (); - switch (mode) - { - case 0: - { - sp_repr_css_set_property (css, "text-anchor", "start"); - sp_repr_css_set_property (css, "text-align", "start"); - break; - } - case 1: - { - sp_repr_css_set_property (css, "text-anchor", "middle"); - sp_repr_css_set_property (css, "text-align", "center"); - break; - } - - case 2: - { - sp_repr_css_set_property (css, "text-anchor", "end"); - sp_repr_css_set_property (css, "text-align", "end"); - break; - } - - case 3: - { - sp_repr_css_set_property (css, "text-anchor", "start"); - sp_repr_css_set_property (css, "text-align", "justify"); - break; - } - } - - SPStyle *query = - sp_style_new (SP_ACTIVE_DOCUMENT); - int result_numbers = - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); - - // If querying returned nothing, update default style. - if (result_numbers == QUERY_STYLE_NOTHING) - { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->mergeStyle("/tools/text/style", css); - } - - sp_style_unref(query); - - sp_desktop_set_style (desktop, css, true, true); - if (result_numbers != QUERY_STYLE_NOTHING) - { - DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, - _("Text: Change alignment")); - } - sp_repr_css_attr_unref (css); - - gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas)); - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl ) -{ - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - // At the moment this handles only numerical values (i.e. no percent). - // Set css line height. - SPCSSAttr *css = sp_repr_css_attr_new (); - Inkscape::CSSOStringStream osfs; - osfs << gtk_adjustment_get_value(adj)*100 << "%"; - sp_repr_css_set_property (css, "line-height", osfs.str().c_str()); - - // Apply line-height to selected objects. - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - sp_desktop_set_style (desktop, css, true, false); - - - // Until deprecated sodipodi:linespacing purged: - Inkscape::Selection *selection = sp_desktop_selection(desktop); - GSList const *items = selection->itemList(); - bool modmade = false; - for (; items != NULL; items = items->next) { - if (SP_IS_TEXT (items->data)) { - SP_OBJECT(items->data)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); - modmade = true; - } - } - - // Save for undo - if(modmade) { - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:line-height", SP_VERB_NONE, - _("Text: Change line-height")); - } - - // If no selected objects, set default. - SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - int result_numbers = - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); - if (result_numbers == QUERY_STYLE_NOTHING) - { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->mergeStyle("/tools/text/style", css); - } - sp_style_unref(query); - - sp_repr_css_attr_unref (css); - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_text_wordspacing_value_changed( GtkAdjustment *adj, GObject *tbl ) -{ - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - // At the moment this handles only numerical values (i.e. no em unit). - // Set css word-spacing - SPCSSAttr *css = sp_repr_css_attr_new (); - Inkscape::CSSOStringStream osfs; - osfs << gtk_adjustment_get_value(adj) << "px"; // For now always use px - sp_repr_css_set_property (css, "word-spacing", osfs.str().c_str()); - - // Apply word-spacing to selected objects. - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - sp_desktop_set_style (desktop, css, true, false); - - // If no selected objects, set default. - SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - int result_numbers = - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); - if (result_numbers == QUERY_STYLE_NOTHING) - { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->mergeStyle("/tools/text/style", css); - } else { - // Save for undo - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:word-spacing", SP_VERB_NONE, - _("Text: Change word-spacing")); - } - sp_style_unref(query); - - sp_repr_css_attr_unref (css); - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_text_letterspacing_value_changed( GtkAdjustment *adj, GObject *tbl ) -{ - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - // At the moment this handles only numerical values (i.e. no em unit). - // Set css letter-spacing - SPCSSAttr *css = sp_repr_css_attr_new (); - Inkscape::CSSOStringStream osfs; - osfs << gtk_adjustment_get_value(adj) << "px"; // For now always use px - sp_repr_css_set_property (css, "letter-spacing", osfs.str().c_str()); - - // Apply letter-spacing to selected objects. - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - sp_desktop_set_style (desktop, css, true, false); - - - // If no selected objects, set default. - SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - int result_numbers = - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); - if (result_numbers == QUERY_STYLE_NOTHING) - { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->mergeStyle("/tools/text/style", css); - } - else - { - // Save for undo - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:letter-spacing", SP_VERB_NONE, - _("Text: Change letter-spacing")); - } - - sp_style_unref(query); - - - sp_repr_css_attr_unref (css); - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - - -static void sp_text_dx_value_changed( GtkAdjustment *adj, GObject *tbl ) -{ - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - gdouble new_dx = gtk_adjustment_get_value(adj); - bool modmade = false; - - if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) { - SPTextContext *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context); - if( tc ) { - unsigned char_index = -1; - TextTagAttributes *attributes = - text_tag_attributes_at_position( tc->text, std::min(tc->text_sel_start, tc->text_sel_end), &char_index ); - if( attributes ) { - double old_dx = attributes->getDx( char_index ); - double delta_dx = new_dx - old_dx; - sp_te_adjust_dx( tc->text, tc->text_sel_start, tc->text_sel_end, SP_ACTIVE_DESKTOP, delta_dx ); - modmade = true; - } - } - } - - if(modmade) { - // Save for undo - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:dx", SP_VERB_NONE, - _("Text: Change dx (kern)")); - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_text_dy_value_changed( GtkAdjustment *adj, GObject *tbl ) -{ - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - gdouble new_dy = gtk_adjustment_get_value(adj); - bool modmade = false; - - if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) { - SPTextContext *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context); - if( tc ) { - unsigned char_index = -1; - TextTagAttributes *attributes = - text_tag_attributes_at_position( tc->text, std::min(tc->text_sel_start, tc->text_sel_end), &char_index ); - if( attributes ) { - double old_dy = attributes->getDy( char_index ); - double delta_dy = new_dy - old_dy; - sp_te_adjust_dy( tc->text, tc->text_sel_start, tc->text_sel_end, SP_ACTIVE_DESKTOP, delta_dy ); - modmade = true; - } - } - } - - if(modmade) { - // Save for undo - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:dy", SP_VERB_NONE, - _("Text: Change dy")); - } - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_text_rotation_value_changed( GtkAdjustment *adj, GObject *tbl ) -{ - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - gdouble new_degrees = gtk_adjustment_get_value(adj); - - bool modmade = false; - if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) { - SPTextContext *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context); - if( tc ) { - unsigned char_index = -1; - TextTagAttributes *attributes = - text_tag_attributes_at_position( tc->text, std::min(tc->text_sel_start, tc->text_sel_end), &char_index ); - if( attributes ) { - double old_degrees = attributes->getRotate( char_index ); - double delta_deg = new_degrees - old_degrees; - sp_te_adjust_rotation( tc->text, tc->text_sel_start, tc->text_sel_end, SP_ACTIVE_DESKTOP, delta_deg ); - modmade = true; - } - } - } - - // Save for undo - if(modmade) { - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:rotate", SP_VERB_NONE, - _("Text: Change rotate")); - } - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_text_orientation_mode_changed( EgeSelectOneAction *act, GObject *tbl ) -{ - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - int mode = ege_select_one_action_get_active( act ); - - SPCSSAttr *css = sp_repr_css_attr_new (); - switch (mode) - { - case 0: - { - sp_repr_css_set_property (css, "writing-mode", "lr"); - break; - } - - case 1: - { - sp_repr_css_set_property (css, "writing-mode", "tb"); - break; - } - } - - SPStyle *query = - sp_style_new (SP_ACTIVE_DOCUMENT); - int result_numbers = - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); - - // If querying returned nothing, update default style. - if (result_numbers == QUERY_STYLE_NOTHING) - { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->mergeStyle("/tools/text/style", css); - } - - sp_desktop_set_style (SP_ACTIVE_DESKTOP, css, true, true); - if(result_numbers != QUERY_STYLE_NOTHING) - { - DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, - _("Text: Change orientation")); - } - sp_repr_css_attr_unref (css); - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -/* - * This function sets up the text-tool tool-controls, setting the entry boxes - * etc. to the values from the current selection or the default if no selection. - * It is called whenever a text selection is changed, including stepping cursor - * through text, or setting focus to text. - */ -static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/, GObject *tbl) -{ -#ifdef DEBUG_TEXT - static int count = 0; - ++count; - std::cout << std::endl; - std::cout << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << std::endl; - std::cout << "sp_text_toolbox_selection_changed: start " << count << std::endl; - - std::cout << " Selected items:" << std::endl; - for (GSList const *items = sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList(); - items != NULL; - items = items->next) - { - const gchar* id = reinterpret_cast<SPItem *>(items->data)->getId(); - std::cout << " " << id << std::endl; - } - Glib::ustring selected_text = sp_text_get_selected_text((SP_ACTIVE_DESKTOP)->event_context); - std::cout << " Selected text:" << std::endl; - std::cout << selected_text << std::endl; -#endif - - // quit if run by the _changed callbacks - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { -#ifdef DEBUG_TEXT - std::cout << " Frozen, returning" << std::endl; - std::cout << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << std::endl; - std::cout << std::endl; -#endif - return; - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - // Only flowed text can be justified, only normal text can be kerned... - // Find out if we have flowed text now so we can use it several places - gboolean isFlow = false; - for (GSList const *items = sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList(); - items != NULL; - items = items->next) { - // const gchar* id = reinterpret_cast<SPItem *>(items->data)->getId(); - // std::cout << " " << id << std::endl; - if( SP_IS_FLOWTEXT(( SPItem *) items->data )) { - isFlow = true; - // std::cout << " Found flowed text" << std::endl; - break; - } - } - - /* - * Query from current selection: - * Font family (font-family) - * Style (font-weight, font-style, font-stretch, font-variant, font-align) - * Numbers (font-size, letter-spacing, word-spacing, line-height, text-anchor, writing-mode) - * Font specification (Inkscape private attribute) - */ - SPStyle *query = - sp_style_new (SP_ACTIVE_DOCUMENT); - int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); - int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); - int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); - int result_baseline = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_BASELINES); - - // Used later: - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION); - - /* - * If no text in selection (querying returned nothing), read the style from - * the /tools/text preferencess (default style for new texts). Return if - * tool bar already set to these preferences. - */ - if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING) { - // There are no texts in selection, read from preferences. - sp_style_read_from_prefs(query, "/tools/text"); -#ifdef DEBUG_TEXT - std::cout << " read style from prefs:" << std::endl; - sp_print_font( query ); -#endif - if (g_object_get_data(tbl, "text_style_from_prefs")) { - // Do not reset the toolbar style from prefs if we already did it last time - sp_style_unref(query); - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -#ifdef DEBUG_TEXT - std::cout << " text_style_from_prefs: toolbar already set" << std:: endl; - std::cout << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << std::endl; - std::cout << std::endl; -#endif - return; - } - - g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(TRUE)); - } else { - g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(FALSE)); - } - - // If we have valid query data for text (font-family, font-specification) set toolbar accordingly. - if (query->text) - { - // Font family - if( query->text->font_family.value ) { - gchar *fontFamily = query->text->font_family.value; - - Ink_ComboBoxEntry_Action* fontFamilyAction = - INK_COMBOBOXENTRY_ACTION( g_object_get_data( tbl, "TextFontFamilyAction" ) ); - ink_comboboxentry_action_set_active_text( fontFamilyAction, fontFamily ); - } - - - // Size (average of text selected) - double size = query->font_size.computed; - gchar size_text[G_ASCII_DTOSTR_BUF_SIZE]; - g_ascii_dtostr (size_text, sizeof (size_text), size); - - Ink_ComboBoxEntry_Action* fontSizeAction = - INK_COMBOBOXENTRY_ACTION( g_object_get_data( tbl, "TextFontSizeAction" ) ); - ink_comboboxentry_action_set_active_text( fontSizeAction, size_text ); - - - // Weight (Bold) - // Note: in the enumeration, normal and lighter come at the end so we must explicitly test for them. - gboolean boldSet = ((query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700) && - (query->font_weight.computed != SP_CSS_FONT_WEIGHT_NORMAL) && - (query->font_weight.computed != SP_CSS_FONT_WEIGHT_LIGHTER)); - - InkToggleAction* textBoldAction = INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextBoldAction" ) ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(textBoldAction), boldSet ); - - - // Style (Italic/Oblique) - gboolean italicSet = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL); - - InkToggleAction* textItalicAction = INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextItalicAction" ) ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(textItalicAction), italicSet ); - - - // Superscript - gboolean superscriptSet = - ((result_baseline == QUERY_STYLE_SINGLE || result_baseline == QUERY_STYLE_MULTIPLE_SAME ) && - query->baseline_shift.set && - query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL && - query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUPER ); - - InkToggleAction* textSuperscriptAction = INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextSuperscriptAction" ) ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(textSuperscriptAction), superscriptSet ); - - - // Subscript - gboolean subscriptSet = - ((result_baseline == QUERY_STYLE_SINGLE || result_baseline == QUERY_STYLE_MULTIPLE_SAME ) && - query->baseline_shift.set && - query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL && - query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUB ); - - InkToggleAction* textSubscriptAction = INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextSubscriptAction" ) ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(textSubscriptAction), subscriptSet ); - - - // Alignment - EgeSelectOneAction* textAlignAction = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextAlignAction" ) ); - - // Note: SVG 1.1 doesn't include text-align, SVG 1.2 Tiny doesn't include text-align="justify" - // text-align="justify" was a draft SVG 1.2 item (along with flowed text). - // Only flowed text can be left and right justified at the same time. - // Disable button if we don't have flowed text. - - // The GtkTreeModel class doesn't have a set function so we can't - // simply add an ege_select_one_action_set_sensitive method! - // We must set values directly with the GtkListStore and then - // ask that the GtkAction update the sensitive parameters. - GtkListStore * model = GTK_LIST_STORE( ege_select_one_action_get_model( textAlignAction ) ); - GtkTreePath * path = gtk_tree_path_new_from_string("3"); // Justify entry - GtkTreeIter iter; - gtk_tree_model_get_iter( GTK_TREE_MODEL (model), &iter, path ); - gtk_list_store_set( model, &iter, /* column */ 3, isFlow, -1 ); - ege_select_one_action_update_sensitive( textAlignAction ); - // ege_select_one_action_set_sensitive( textAlignAction, 3, isFlow ); - - int activeButton = 0; - if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY) - { - activeButton = 3; - } else { - if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START) activeButton = 0; - if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE) activeButton = 1; - if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END) activeButton = 2; - } - ege_select_one_action_set_active( textAlignAction, activeButton ); - - - // Line height (spacing) - double height; - if (query->line_height.normal) { - height = Inkscape::Text::Layout::LINE_HEIGHT_NORMAL; - } else { - if (query->line_height.unit == SP_CSS_UNIT_PERCENT) { - height = query->line_height.value; - } else { - height = query->line_height.computed; - } - } - - GtkAction* lineHeightAction = GTK_ACTION( g_object_get_data( tbl, "TextLineHeightAction" ) ); - GtkAdjustment *lineHeightAdjustment = - ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( lineHeightAction )); - gtk_adjustment_set_value( lineHeightAdjustment, height ); - - - // Word spacing - double wordSpacing; - if (query->word_spacing.normal) wordSpacing = 0.0; - else wordSpacing = query->word_spacing.computed; // Assume no units (change in desktop-style.cpp) - - GtkAction* wordSpacingAction = GTK_ACTION( g_object_get_data( tbl, "TextWordSpacingAction" ) ); - GtkAdjustment *wordSpacingAdjustment = - ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( wordSpacingAction )); - gtk_adjustment_set_value( wordSpacingAdjustment, wordSpacing ); - - - // Letter spacing - double letterSpacing; - if (query->letter_spacing.normal) letterSpacing = 0.0; - else letterSpacing = query->letter_spacing.computed; // Assume no units (change in desktop-style.cpp) - - GtkAction* letterSpacingAction = GTK_ACTION( g_object_get_data( tbl, "TextLetterSpacingAction" ) ); - GtkAdjustment *letterSpacingAdjustment = - ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( letterSpacingAction )); - gtk_adjustment_set_value( letterSpacingAdjustment, letterSpacing ); - - - // Orientation - int activeButton2 = (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB ? 0 : 1); - - EgeSelectOneAction* textOrientationAction = - EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextOrientationAction" ) ); - ege_select_one_action_set_active( textOrientationAction, activeButton2 ); - - - } // if( query->text ) - -#ifdef DEBUG_TEXT - std::cout << " GUI: fontfamily.value: " - << (query->text->font_family.value ? query->text->font_family.value : "No value") - << std::endl; - std::cout << " GUI: font_size.computed: " << query->font_size.computed << std::endl; - std::cout << " GUI: font_weight.computed: " << query->font_weight.computed << std::endl; - std::cout << " GUI: font_style.computed: " << query->font_style.computed << std::endl; - std::cout << " GUI: text_anchor.computed: " << query->text_anchor.computed << std::endl; - std::cout << " GUI: text_align.computed: " << query->text_align.computed << std::endl; - std::cout << " GUI: line_height.computed: " << query->line_height.computed - << " line_height.value: " << query->line_height.value - << " line_height.unit: " << query->line_height.unit << std::endl; - std::cout << " GUI: word_spacing.computed: " << query->word_spacing.computed - << " word_spacing.value: " << query->word_spacing.value - << " word_spacing.unit: " << query->word_spacing.unit << std::endl; - std::cout << " GUI: letter_spacing.computed: " << query->letter_spacing.computed - << " letter_spacing.value: " << query->letter_spacing.value - << " letter_spacing.unit: " << query->letter_spacing.unit << std::endl; - std::cout << " GUI: writing_mode.computed: " << query->writing_mode.computed << std::endl; -#endif - - sp_style_unref(query); - - // Kerning (xshift), yshift, rotation. NB: These are not CSS attributes. - if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) { - SPTextContext *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context); - if( tc ) { - unsigned char_index = -1; - TextTagAttributes *attributes = - text_tag_attributes_at_position( tc->text, std::min(tc->text_sel_start, tc->text_sel_end), &char_index ); - if( attributes ) { - - // Dx - double dx = attributes->getDx( char_index ); - GtkAction* dxAction = GTK_ACTION( g_object_get_data( tbl, "TextDxAction" )); - GtkAdjustment *dxAdjustment = - ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( dxAction )); - gtk_adjustment_set_value( dxAdjustment, dx ); - - // Dy - double dy = attributes->getDy( char_index ); - GtkAction* dyAction = GTK_ACTION( g_object_get_data( tbl, "TextDyAction" )); - GtkAdjustment *dyAdjustment = - ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( dyAction )); - gtk_adjustment_set_value( dyAdjustment, dy ); - - // Rotation - double rotation = attributes->getRotate( char_index ); - /* SVG value is between 0 and 360 but we're using -180 to 180 in widget */ - if( rotation > 180.0 ) rotation -= 360.0; - GtkAction* rotationAction = GTK_ACTION( g_object_get_data( tbl, "TextRotationAction" )); - GtkAdjustment *rotationAdjustment = - ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( rotationAction )); - gtk_adjustment_set_value( rotationAdjustment, rotation ); - -#ifdef DEBUG_TEXT - std::cout << " GUI: Dx: " << dx << std::endl; - std::cout << " GUI: Dy: " << dy << std::endl; - std::cout << " GUI: Rotation: " << rotation << std::endl; -#endif - } - } - } - - { - // Set these here as we don't always have kerning/rotating attributes - GtkAction* dxAction = GTK_ACTION( g_object_get_data( tbl, "TextDxAction" )); - gtk_action_set_sensitive( GTK_ACTION(dxAction), !isFlow ); - - GtkAction* dyAction = GTK_ACTION( g_object_get_data( tbl, "TextDyAction" )); - gtk_action_set_sensitive( GTK_ACTION(dyAction), !isFlow ); - - GtkAction* rotationAction = GTK_ACTION( g_object_get_data( tbl, "TextRotationAction" )); - gtk_action_set_sensitive( GTK_ACTION(rotationAction), !isFlow ); - } - -#ifdef DEBUG_TEXT - std::cout << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << std::endl; - std::cout << std::endl; -#endif - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); - -} - -static void sp_text_toolbox_selection_modified(Inkscape::Selection *selection, guint /*flags*/, GObject *tbl) -{ - sp_text_toolbox_selection_changed (selection, tbl); -} - -void -sp_text_toolbox_subselection_changed (gpointer /*tc*/, GObject *tbl) -{ - sp_text_toolbox_selection_changed (NULL, tbl); -} - -// Define all the "widgets" in the toolbar. -static void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); - - // Is this used? - UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE ); - tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units ); - g_object_set_data( holder, "tracker", tracker ); - - /* Font family */ - { - // Font list - Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list(); - GtkListStore* model = store->gobj(); - - Ink_ComboBoxEntry_Action* act = ink_comboboxentry_action_new( "TextFontFamilyAction", - _("Font Family"), - _("Select Font Family (Alt-X to access)"), - NULL, - GTK_TREE_MODEL(model), - -1, // Entry width - 50, // Extra list width - (gpointer)cell_data_func ); // Cell layout - ink_comboboxentry_action_popup_enable( act ); // Enable entry completion - gchar *const warning = _("Font not found on system"); - ink_comboboxentry_action_set_warning( act, warning ); // Show icon with tooltip if missing font - ink_comboboxentry_action_set_altx_name( act, "altx-text" ); // Set Alt-X keyboard shortcut - g_signal_connect( G_OBJECT(act), "changed", G_CALLBACK(sp_text_fontfamily_value_changed), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - g_object_set_data( holder, "TextFontFamilyAction", act ); - - // Change style of drop-down from menu to list - gtk_rc_parse_string ( - "style \"dropdown-as-list-style\"\n" - "{\n" - " GtkComboBox::appears-as-list = 1\n" - "}\n" - "widget \"*.TextFontFamilyAction_combobox\" style \"dropdown-as-list-style\""); - } - - /* Font size */ - { - // List of font sizes for drop-down menu - GtkListStore* model_size = gtk_list_store_new( 1, G_TYPE_STRING ); - gchar const *const sizes[] = { - "4", "6", "8", "9", "10", "11", "12", "13", "14", "16", - "18", "20", "22", "24", "28", "32", "36", "40", "48", "56", - "64", "72", "144" - }; - for( unsigned int i = 0; i < G_N_ELEMENTS(sizes); ++i ) { - GtkTreeIter iter; - gtk_list_store_append( model_size, &iter ); - gtk_list_store_set( model_size, &iter, 0, sizes[i], -1 ); - } - - Ink_ComboBoxEntry_Action* act = ink_comboboxentry_action_new( "TextFontSizeAction", - _("Font Size"), - _("Font size (px)"), - NULL, - GTK_TREE_MODEL(model_size), - 4 ); // Width in characters - g_signal_connect( G_OBJECT(act), "changed", G_CALLBACK(sp_text_fontsize_value_changed), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - g_object_set_data( holder, "TextFontSizeAction", act ); - } - - /* Style - Bold */ - { - InkToggleAction* act = ink_toggle_action_new( "TextBoldAction", // Name - _("Toggle Bold"), // Label - _("Toggle bold or normal weight"), // Tooltip - GTK_STOCK_BOLD, // Icon (inkId) - secondarySize ); // Icon size - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_style_changed), holder ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/bold", false) ); - g_object_set_data( holder, "TextBoldAction", act ); - } - - /* Style - Italic/Oblique */ - { - InkToggleAction* act = ink_toggle_action_new( "TextItalicAction", // Name - _("Toggle Italic/Oblique"), // Label - _("Toggle italic/oblique style"),// Tooltip - GTK_STOCK_ITALIC, // Icon (inkId) - secondarySize ); // Icon size - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_style_changed), holder ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/italic", false) ); - g_object_set_data( holder, "TextItalicAction", act ); - } - - /* Style - Superscript */ - { - InkToggleAction* act = ink_toggle_action_new( "TextSuperscriptAction", // Name - _("Toggle Superscript"), // Label - _("Toggle superscript"), // Tooltip - "text_superscript", // Icon (inkId) - secondarySize ); // Icon size - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_script_changed), holder ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/super", false) ); - g_object_set_data( holder, "TextSuperscriptAction", act ); - } - - /* Style - Subscript */ - { - InkToggleAction* act = ink_toggle_action_new( "TextSubscriptAction", // Name - _("Toggle Subscript"), // Label - _("Toggle subscript"), // Tooltip - "text_subscript", // Icon (inkId) - secondarySize ); // Icon size - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_script_changed), holder ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/sub", false) ); - g_object_set_data( holder, "TextSubscriptAction", act ); - } - - /* Alignment */ - { - GtkListStore* model = gtk_list_store_new( 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN ); - - GtkTreeIter iter; - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Align left"), - 1, _("Align left"), - 2, GTK_STOCK_JUSTIFY_LEFT, - 3, true, - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Align center"), - 1, _("Align center"), - 2, GTK_STOCK_JUSTIFY_CENTER, - 3, true, - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Align right"), - 1, _("Align right"), - 2, GTK_STOCK_JUSTIFY_RIGHT, - 3, true, - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Justify"), - 1, _("Justify (only flowed text)"), - 2, GTK_STOCK_JUSTIFY_FILL, - 3, false, - -1 ); - - EgeSelectOneAction* act = ege_select_one_action_new( "TextAlignAction", // Name - _("Alignment"), // Label - _("Text alignment"), // Tooltip - NULL, // StockID - GTK_TREE_MODEL(model) ); // Model - g_object_set( act, "short_label", "NotUsed", NULL ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - g_object_set_data( holder, "TextAlignAction", act ); - - ege_select_one_action_set_appearance( act, "full" ); - ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); - g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); - ege_select_one_action_set_icon_column( act, 2 ); - ege_select_one_action_set_icon_size( act, secondarySize ); - ege_select_one_action_set_tooltip_column( act, 1 ); - ege_select_one_action_set_sensitive_column( act, 3 ); - gint mode = prefs->getInt("/tools/text/align_mode", 0); - ege_select_one_action_set_active( act, mode ); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_align_mode_changed), holder ); - } - - /* Orientation (Left to Right, Top to Bottom */ - { - GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); - - GtkTreeIter iter; - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Horizontal"), - 1, _("Horizontal text"), - 2, INKSCAPE_ICON("format-text-direction-horizontal"), - -1 ); - - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, - 0, _("Vertical"), - 1, _("Vertical text"), - 2, INKSCAPE_ICON("format-text-direction-vertical"), - -1 ); - - EgeSelectOneAction* act = ege_select_one_action_new( "TextOrientationAction", // Name - _("Orientation"), // Label - _("Text orientation"), // Tooltip - NULL, // StockID - GTK_TREE_MODEL(model) ); // Model - - g_object_set( act, "short_label", "NotUsed", NULL ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - g_object_set_data( holder, "TextOrientationAction", act ); - - ege_select_one_action_set_appearance( act, "full" ); - ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); - g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); - ege_select_one_action_set_icon_column( act, 2 ); - ege_select_one_action_set_icon_size( act, secondarySize ); - ege_select_one_action_set_tooltip_column( act, 1 ); - - gint mode = prefs->getInt("/tools/text/orientation", 0); - ege_select_one_action_set_active( act, mode ); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_orientation_mode_changed), holder ); - } - - /* Line height */ - { - // Drop down menu - gchar const* labels[] = {_("Smaller spacing"), 0, 0, 0, 0, C_("Text tool", "Normal"), 0, 0, 0, 0, 0, _("Larger spacing")}; - gdouble values[] = { 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1,2, 1.3, 1.4, 1.5, 2.0}; - - EgeAdjustmentAction *eact = create_adjustment_action( - "TextLineHeightAction", /* name */ - _("Line Height"), /* label */ - _("Line:"), /* short label */ - _("Spacing between lines (times font size)"), /* tooltip */ - "/tools/text/lineheight", /* preferences path */ - 0.0, /* default */ - GTK_WIDGET(desktop->canvas), /* focusTarget */ - NULL, /* unit selector */ - holder, /* dataKludge */ - FALSE, /* set alt-x keyboard shortcut? */ - NULL, /* altx_mark */ - 0.0, 10.0, 0.01, 0.10, /* lower, upper, step (arrow up/down), page up/down */ - labels, values, G_N_ELEMENTS(labels), /* drop down menu */ - sp_text_lineheight_value_changed, /* callback */ - 0.1, /* step (used?) */ - 2, /* digits to show */ - 1.0 /* factor (multiplies default) */ - ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - g_object_set_data( holder, "TextLineHeightAction", eact ); - g_object_set( G_OBJECT(eact), "iconId", "text_line_spacing", NULL ); - } - - /* Word spacing */ - { - // Drop down menu - gchar const* labels[] = {_("Negative spacing"), 0, 0, 0, C_("Text tool", "Normal"), 0, 0, 0, 0, 0, 0, 0, _("Positive spacing")}; - gdouble values[] = {-2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0}; - - EgeAdjustmentAction *eact = create_adjustment_action( - "TextWordSpacingAction", /* name */ - _("Word spacing"), /* label */ - _("Word:"), /* short label */ - _("Spacing between words (px)"), /* tooltip */ - "/tools/text/wordspacing", /* preferences path */ - 0.0, /* default */ - GTK_WIDGET(desktop->canvas), /* focusTarget */ - NULL, /* unit selector */ - holder, /* dataKludge */ - FALSE, /* set alt-x keyboard shortcut? */ - NULL, /* altx_mark */ - -100.0, 100.0, 0.01, 0.10, /* lower, upper, step (arrow up/down), page up/down */ - labels, values, G_N_ELEMENTS(labels), /* drop down menu */ - sp_text_wordspacing_value_changed, /* callback */ - 0.1, /* step (used?) */ - 2, /* digits to show */ - 1.0 /* factor (multiplies default) */ - ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - g_object_set_data( holder, "TextWordSpacingAction", eact ); - g_object_set( G_OBJECT(eact), "iconId", "text_word_spacing", NULL ); - } - - /* Letter spacing */ - { - // Drop down menu - gchar const* labels[] = {_("Negative spacing"), 0, 0, 0, C_("Text tool", "Normal"), 0, 0, 0, 0, 0, 0, 0, _("Positive spacing")}; - gdouble values[] = {-2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0}; - - EgeAdjustmentAction *eact = create_adjustment_action( - "TextLetterSpacingAction", /* name */ - _("Letter spacing"), /* label */ - _("Letter:"), /* short label */ - _("Spacing between letters (px)"), /* tooltip */ - "/tools/text/letterspacing", /* preferences path */ - 0.0, /* default */ - GTK_WIDGET(desktop->canvas), /* focusTarget */ - NULL, /* unit selector */ - holder, /* dataKludge */ - FALSE, /* set alt-x keyboard shortcut? */ - NULL, /* altx_mark */ - -100.0, 100.0, 0.01, 0.10, /* lower, upper, step (arrow up/down), page up/down */ - labels, values, G_N_ELEMENTS(labels), /* drop down menu */ - sp_text_letterspacing_value_changed, /* callback */ - 0.1, /* step (used?) */ - 2, /* digits to show */ - 1.0 /* factor (multiplies default) */ - ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - g_object_set_data( holder, "TextLetterSpacingAction", eact ); - g_object_set( G_OBJECT(eact), "iconId", "text_letter_spacing", NULL ); - } - - /* Character kerning (horizontal shift) */ - { - // Drop down menu - gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - gdouble values[] = { -2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5 }; - - EgeAdjustmentAction *eact = create_adjustment_action( - "TextDxAction", /* name */ - _("Kerning"), /* label */ - _("Kern:"), /* short label */ - _("Horizontal kerning (px)"), /* tooltip */ - "/tools/text/dx", /* preferences path */ - 0.0, /* default */ - GTK_WIDGET(desktop->canvas), /* focusTarget */ - NULL, /* unit selector */ - holder, /* dataKludge */ - FALSE, /* set alt-x keyboard shortcut? */ - NULL, /* altx_mark */ - -100.0, 100.0, 0.01, 0.1, /* lower, upper, step (arrow up/down), page up/down */ - labels, values, G_N_ELEMENTS(labels), /* drop down menu */ - sp_text_dx_value_changed, /* callback */ - 0.1, /* step (used?) */ - 2, /* digits to show */ - 1.0 /* factor (multiplies default) */ - ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - g_object_set_data( holder, "TextDxAction", eact ); - g_object_set( G_OBJECT(eact), "iconId", "text_horz_kern", NULL ); - } - - /* Character vertical shift */ - { - // Drop down menu - gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - gdouble values[] = { -2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5 }; - - EgeAdjustmentAction *eact = create_adjustment_action( - "TextDyAction", /* name */ - _("Vertical Shift"), /* label */ - _("Vert:"), /* short label */ - _("Vertical shift (px)"), /* tooltip */ - "/tools/text/dy", /* preferences path */ - 0.0, /* default */ - GTK_WIDGET(desktop->canvas), /* focusTarget */ - NULL, /* unit selector */ - holder, /* dataKludge */ - FALSE, /* set alt-x keyboard shortcut? */ - NULL, /* altx_mark */ - -100.0, 100.0, 0.01, 0.1, /* lower, upper, step (arrow up/down), page up/down */ - labels, values, G_N_ELEMENTS(labels), /* drop down menu */ - sp_text_dy_value_changed, /* callback */ - 0.1, /* step (used?) */ - 2, /* digits to show */ - 1.0 /* factor (multiplies default) */ - ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - g_object_set_data( holder, "TextDyAction", eact ); - g_object_set( G_OBJECT(eact), "iconId", "text_vert_kern", NULL ); - } - - /* Character rotation */ - { - // Drop down menu - gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - gdouble values[] = { -90, -45, -30, -15, 0, 15, 30, 45, 90, 180 }; - - EgeAdjustmentAction *eact = create_adjustment_action( - "TextRotationAction", /* name */ - _("Letter rotation"), /* label */ - _("Rot:"), /* short label */ - _("Character rotation (degrees)"),/* tooltip */ - "/tools/text/rotation", /* preferences path */ - 0.0, /* default */ - GTK_WIDGET(desktop->canvas), /* focusTarget */ - NULL, /* unit selector */ - holder, /* dataKludge */ - FALSE, /* set alt-x keyboard shortcut? */ - NULL, /* altx_mark */ - -180.0, 180.0, 0.1, 1.0, /* lower, upper, step (arrow up/down), page up/down */ - labels, values, G_N_ELEMENTS(labels), /* drop down menu */ - sp_text_rotation_value_changed, /* callback */ - 0.1, /* step (used?) */ - 2, /* digits to show */ - 1.0 /* factor (multiplies default) */ - ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - g_object_set_data( holder, "TextRotationAction", eact ); - g_object_set( G_OBJECT(eact), "iconId", "text_rotation", NULL ); - } - - // Is this necessary to call? Shouldn't hurt. - sp_text_toolbox_selection_changed(sp_desktop_selection(desktop), holder); - - // Watch selection - Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolboxGTK"); - - sigc::connection *c_selection_changed = - new sigc::connection (sp_desktop_selection (desktop)->connectChanged - (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)holder))); - pool->add_connection ("selection-changed", c_selection_changed); - - sigc::connection *c_selection_modified = - new sigc::connection (sp_desktop_selection (desktop)->connectModified - (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)holder))); - pool->add_connection ("selection-modified", c_selection_modified); - - sigc::connection *c_subselection_changed = - new sigc::connection (desktop->connectToolSubselectionChanged - (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)holder))); - pool->add_connection ("tool-subselection-changed", c_subselection_changed); - - Inkscape::ConnectionPool::connect_destroy (G_OBJECT (holder), pool); - - g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder ); - -} - - -//######################### -//## Connector ## -//######################### - -static void sp_connector_mode_toggled( GtkToggleAction* act, GObject * /*tbl*/ ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/connector/mode", - gtk_toggle_action_get_active( act )); -} - -static void sp_connector_path_set_avoid(void) -{ - cc_selection_set_avoid(true); -} - - -static void sp_connector_path_set_ignore(void) -{ - cc_selection_set_avoid(false); -} - -static void sp_connector_orthogonal_toggled( GtkToggleAction* act, GObject *tbl ) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" ); - Inkscape::Selection * selection = sp_desktop_selection(desktop); - SPDocument *doc = sp_desktop_document(desktop); - - if (!DocumentUndo::getUndoSensitive(doc)) { - return; - } - - - // quit if run by the _changed callbacks - if (g_object_get_data( tbl, "freeze" )) { - return; - } - - // in turn, prevent callbacks from responding - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - bool is_orthog = gtk_toggle_action_get_active( act ); - gchar orthog_str[] = "orthogonal"; - gchar polyline_str[] = "polyline"; - gchar *value = is_orthog ? orthog_str : polyline_str ; - - bool modmade = false; - GSList *l = (GSList *) selection->itemList(); - while (l) { - SPItem *item = (SPItem *) l->data; - - if (cc_item_is_connector(item)) { - item->setAttribute( "inkscape:connector-type", - value, NULL); - item->avoidRef->handleSettingChange(); - modmade = true; - } - l = l->next; - } - - if (!modmade) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/connector/orthogonal", is_orthog); - } else { - - DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, - is_orthog ? _("Set connector type: orthogonal"): _("Set connector type: polyline")); - } - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void connector_curvature_changed(GtkAdjustment *adj, GObject* tbl) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" ); - Inkscape::Selection * selection = sp_desktop_selection(desktop); - SPDocument *doc = sp_desktop_document(desktop); - - if (!DocumentUndo::getUndoSensitive(doc)) { - return; - } - - - // quit if run by the _changed callbacks - if (g_object_get_data( tbl, "freeze" )) { - return; - } - - // in turn, prevent callbacks from responding - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); - - gdouble newValue = gtk_adjustment_get_value(adj); - gchar value[G_ASCII_DTOSTR_BUF_SIZE]; - g_ascii_dtostr(value, G_ASCII_DTOSTR_BUF_SIZE, newValue); - - bool modmade = false; - GSList *l = (GSList *) selection->itemList(); - while (l) { - SPItem *item = (SPItem *) l->data; - - if (cc_item_is_connector(item)) { - item->setAttribute( "inkscape:connector-curvature", - value, NULL); - item->avoidRef->handleSettingChange(); - modmade = true; - } - l = l->next; - } - - if (!modmade) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble(Glib::ustring("/tools/connector/curvature"), newValue); - } - else { - DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, - _("Change connector curvature")); - } - - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - - -static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" ); - SPDocument *doc = sp_desktop_document(desktop); - - if (!DocumentUndo::getUndoSensitive(doc)) { - return; - } - - Inkscape::XML::Node *repr = desktop->namedview->getRepr(); - - if ( !repr->attribute("inkscape:connector-spacing") && - ( gtk_adjustment_get_value(adj) == defaultConnSpacing )) { - // Don't need to update the repr if the attribute doesn't - // exist and it is being set to the default value -- as will - // happen at startup. - return; - } - - // quit if run by the attr_changed listener - if (g_object_get_data( tbl, "freeze" )) { - return; - } - - // in turn, prevent listener from responding - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE)); - - sp_repr_set_css_double(repr, "inkscape:connector-spacing", gtk_adjustment_get_value(adj)); - desktop->namedview->updateRepr(); - bool modmade = false; - - GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop); - for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) { - SPItem *item = reinterpret_cast<SPItem *>(iter->data); - Geom::Affine m = Geom::identity(); - avoid_item_move(&m, item); - modmade = true; - } - - if (items) { - g_slist_free(items); - } - if(modmade) { - DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, - _("Change connector spacing")); - } - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); -} - -static void sp_connector_graph_layout(void) -{ - if (!SP_ACTIVE_DESKTOP) { - return; - } - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - // hack for clones, see comment in align-and-distribute.cpp - int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); - prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); - - graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList()); - - prefs->setInt("/options/clonecompensation/value", saved_compensation); - - DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network")); -} - -static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GObject * /*tbl*/ ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/connector/directedlayout", - gtk_toggle_action_get_active( act )); -} - -static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GObject * /*tbl*/ ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/connector/avoidoverlaplayout", - gtk_toggle_action_get_active( act )); -} - - -static void connector_length_changed(GtkAdjustment *adj, GObject* /*tbl*/) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setDouble("/tools/connector/length", gtk_adjustment_get_value(adj)); -} - -static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr, - gchar const *name, gchar const * /*old_value*/, gchar const * /*new_value*/, - bool /*is_interactive*/, gpointer data) -{ - GtkWidget *tbl = GTK_WIDGET(data); - - if ( !g_object_get_data(G_OBJECT(tbl), "freeze") - && (strcmp(name, "inkscape:connector-spacing") == 0) ) { - GtkAdjustment *adj = static_cast<GtkAdjustment*>(g_object_get_data(G_OBJECT(tbl), "spacing")); - gdouble spacing = defaultConnSpacing; - sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing); - - gtk_adjustment_set_value(adj, spacing); - gtk_adjustment_value_changed(adj); - - spinbutton_defocus(tbl); - } -} - -static void sp_connector_new_connection_point(GtkWidget *, GObject *tbl) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" ); - SPConnectorContext* cc = SP_CONNECTOR_CONTEXT(desktop->event_context); - - if (cc->mode == SP_CONNECTOR_CONTEXT_EDITING_MODE) { - cc_create_connection_point(cc); - } -} - -static void sp_connector_remove_connection_point(GtkWidget *, GObject *tbl) -{ - SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" ); - SPConnectorContext* cc = SP_CONNECTOR_CONTEXT(desktop->event_context); - - if (cc->mode == SP_CONNECTOR_CONTEXT_EDITING_MODE) { - cc_remove_connection_point(cc); - } -} - -static Inkscape::XML::NodeEventVector connector_tb_repr_events = { - NULL, /* child_added */ - NULL, /* child_removed */ - connector_tb_event_attr_changed, - NULL, /* content_changed */ - NULL /* order_changed */ -}; - -static void sp_connector_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) -{ - GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "curvature" ) ); - GtkToggleAction *act = GTK_TOGGLE_ACTION( g_object_get_data( tbl, "orthogonal" ) ); - SPItem *item = selection->singleItem(); - if (SP_IS_PATH(item)) - { - gdouble curvature = SP_PATH(item)->connEndPair.getCurvature(); - bool is_orthog = SP_PATH(item)->connEndPair.isOrthogonal(); - gtk_toggle_action_set_active(act, is_orthog); - gtk_adjustment_set_value(adj, curvature); - } - -} - -static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder ) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); - - // Editing mode toggle button - { - InkToggleAction* act = ink_toggle_action_new( "ConnectorEditModeAction", - _("EditMode"), - _("Switch between connection point editing and connector drawing mode"), - INKSCAPE_ICON("connector-edit"), - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - - bool tbuttonstate = prefs->getBool("/tools/connector/mode"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), ( tbuttonstate ? TRUE : FALSE )); - g_object_set_data( holder, "mode", act ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_connector_mode_toggled), holder ); - } - - - { - InkAction* inky = ink_action_new( "ConnectorAvoidAction", - _("Avoid"), - _("Make connectors avoid selected objects"), - INKSCAPE_ICON("connector-avoid"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - { - InkAction* inky = ink_action_new( "ConnectorIgnoreAction", - _("Ignore"), - _("Make connectors ignore selected objects"), - INKSCAPE_ICON("connector-ignore"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - // Orthogonal connectors toggle button - { - InkToggleAction* act = ink_toggle_action_new( "ConnectorOrthogonalAction", - _("Orthogonal"), - _("Make connector orthogonal or polyline"), - INKSCAPE_ICON("connector-orthogonal"), - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - - bool tbuttonstate = prefs->getBool("/tools/connector/orthogonal"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), ( tbuttonstate ? TRUE : FALSE )); - g_object_set_data( holder, "orthogonal", act ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_connector_orthogonal_toggled), holder ); - } - - EgeAdjustmentAction* eact = 0; - // Curvature spinbox - eact = create_adjustment_action( "ConnectorCurvatureAction", - _("Connector Curvature"), _("Curvature:"), - _("The amount of connectors curvature"), - "/tools/connector/curvature", defaultConnCurvature, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-curvature", - 0, 100, 1.0, 10.0, - 0, 0, 0, - connector_curvature_changed, 1, 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - - // Spacing spinbox - eact = create_adjustment_action( "ConnectorSpacingAction", - _("Connector Spacing"), _("Spacing:"), - _("The amount of space left around objects by auto-routing connectors"), - "/tools/connector/spacing", defaultConnSpacing, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing", - 0, 100, 1.0, 10.0, - 0, 0, 0, - connector_spacing_changed, 1, 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - - // Graph (connector network) layout - { - InkAction* inky = ink_action_new( "ConnectorGraphAction", - _("Graph"), - _("Nicely arrange selected connector network"), - INKSCAPE_ICON("distribute-graph"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - // Default connector length spinbox - eact = create_adjustment_action( "ConnectorLengthAction", - _("Connector Length"), _("Length:"), - _("Ideal length for connectors when layout is applied"), - "/tools/connector/length", 100, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length", - 10, 1000, 10.0, 100.0, - 0, 0, 0, - connector_length_changed, 1, 0 ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - - - // Directed edges toggle button - { - InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction", - _("Downwards"), - _("Make connectors with end-markers (arrows) point downwards"), - INKSCAPE_ICON("distribute-graph-directed"), - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - - bool tbuttonstate = prefs->getBool("/tools/connector/directedlayout"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), ( tbuttonstate ? TRUE : FALSE )); - - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder ); - sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_connector_toolbox_selection_changed), (GObject *)holder)); - } - - // Avoid overlaps toggle button - { - InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction", - _("Remove overlaps"), - _("Do not allow overlapping shapes"), - INKSCAPE_ICON("distribute-remove-overlaps"), - Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - - bool tbuttonstate = prefs->getBool("/tools/connector/avoidoverlaplayout"); - gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), (tbuttonstate ? TRUE : FALSE )); - - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder ); - } - - - // New connection point button - { - InkAction* inky = ink_action_new( "ConnectorNewConnPointAction", - _("New connection point"), - _("Add a new connection point to the currently selected item"), - INKSCAPE_ICON("connector-new-connpoint"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_new_connection_point), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - // Remove selected connection point button - - { - InkAction* inky = ink_action_new( "ConnectorRemoveConnPointAction", - _("Remove connection point"), - _("Remove the currently selected connection point"), - INKSCAPE_ICON("connector-remove-connpoint"), - secondarySize ); - g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_remove_connection_point), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(inky) ); - } - - - // Code to watch for changes to the connector-spacing attribute in - // the XML. - Inkscape::XML::Node *repr = desktop->namedview->getRepr(); - g_assert(repr != NULL); - - purge_repr_listener( holder, holder ); - - if (repr) { - g_object_set_data( holder, "repr", repr ); - Inkscape::GC::anchor(repr); - sp_repr_add_listener( repr, &connector_tb_repr_events, holder ); - sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder ); - } -} // end of sp_connector_toolbox_prep() - - -//######################### -//## Paintbucket ## -//######################### - -static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/) -{ - gint channels = ege_select_one_action_get_active( act ); - flood_channels_set_channels( channels ); -} - -static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject * /*tbl*/) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt("/tools/paintbucket/threshold", (gint)gtk_adjustment_get_value(adj)); -} - -static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject * /*tbl*/) -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/paintbucket/autogap", ege_select_one_action_get_active( act )); -} - -static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl) -{ - UnitTracker* tracker = static_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" )); - SPUnit const *unit = tracker->getActiveUnit(); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - // Don't adjust the offset value because we're saving the - // unit and it'll be correctly handled on load. - prefs->setDouble("/tools/paintbucket/offset", (gdouble)gtk_adjustment_get_value(adj)); - prefs->setString("/tools/paintbucket/offsetunits", sp_unit_get_abbreviation(unit)); -} - -static void paintbucket_defaults(GtkWidget *, GObject *tbl) -{ - // FIXME: make defaults settable via Inkscape Options - struct KeyValue { - char const *key; - double value; - } const key_values[] = { - {"threshold", 15}, - {"offset", 0.0} - }; - - for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) { - KeyValue const &kv = key_values[i]; - GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(tbl, kv.key)); - if ( adj ) { - gtk_adjustment_set_value(adj, kv.value); - } - } - - EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "channels_action" ) ); - ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB ); - EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "autogap_action" ) ); - ege_select_one_action_set_active( autogap_action, 0 ); -} - -static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) -{ - EgeAdjustmentAction* eact = 0; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - { - GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); - - GList* items = 0; - gint count = 0; - for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) ) - { - GtkTreeIter iter; - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 ); - count++; - } - g_list_free( items ); - items = 0; - EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) ); - g_object_set( act1, "short_label", _("Fill by:"), NULL ); - ege_select_one_action_set_appearance( act1, "compact" ); - ege_select_one_action_set_active( act1, prefs->getInt("/tools/paintbucket/channels", 0) ); - g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act1) ); - g_object_set_data( holder, "channels_action", act1 ); - } - - // Spacing spinbox - { - eact = create_adjustment_action( - "ThresholdAction", - _("Fill Threshold"), _("Threshold:"), - _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"), - "/tools/paintbucket/threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, - "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0, - 0, 0, 0, - paintbucket_threshold_changed, 1, 0 ); - - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - // Create the units menu. - UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE ); - Glib::ustring stored_unit = prefs->getString("/tools/paintbucket/offsetunits"); - if (!stored_unit.empty()) { - tracker->setActiveUnit(sp_unit_get_by_abbreviation(stored_unit.data())); - } - g_object_set_data( holder, "tracker", tracker ); - { - GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), ("") ); - gtk_action_group_add_action( mainActions, act ); - } - - // Offset spinbox - { - eact = create_adjustment_action( - "OffsetAction", - _("Grow/shrink by"), _("Grow/shrink by:"), - _("The amount to grow (positive) or shrink (negative) the created fill path"), - "/tools/paintbucket/offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, - "inkscape:paintbucket-offset", -1e4, 1e4, 0.1, 0.5, - 0, 0, 0, - paintbucket_offset_changed, 1, 2); - tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); - - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - } - - /* Auto Gap */ - { - GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); - - GList* items = 0; - gint count = 0; - for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) ) - { - GtkTreeIter iter; - gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 ); - count++; - } - g_list_free( items ); - items = 0; - EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) ); - g_object_set( act2, "short_label", _("Close gaps:"), NULL ); - ege_select_one_action_set_appearance( act2, "compact" ); - ege_select_one_action_set_active( act2, prefs->getBool("/tools/paintbucket/autogap") ); - g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder ); - gtk_action_group_add_action( mainActions, GTK_ACTION(act2) ); - g_object_set_data( holder, "autogap_action", act2 ); - } - - /* Reset */ - { - GtkAction* act = gtk_action_new( "PaintbucketResetAction", - _("Defaults"), - _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), - GTK_STOCK_CLEAR ); - g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder ); - gtk_action_group_add_action( mainActions, act ); - gtk_action_set_sensitive( act, TRUE ); - } - -} /* Local Variables: diff --git a/src/widgets/toolbox.h b/src/widgets/toolbox.h index bb2edf964..fb749bfb5 100644 --- a/src/widgets/toolbox.h +++ b/src/widgets/toolbox.h @@ -18,12 +18,28 @@ #include "icon-size.h" #include "../ege-adjustment-action.h" +#include "../preferences.h" + +#define TOOLBAR_SLIDER_HINT "full" class SPDesktop; -class SPEventContext; namespace Inkscape { namespace UI { +namespace Tools { + +class ToolBase; + +} +} +} + +namespace Inkscape { +namespace UI { + +namespace Widget { + class UnitTracker; +} /** * Main toolbox source. @@ -43,7 +59,7 @@ public: static Glib::ustring getToolboxName(GtkWidget* toolbox); - static void updateSnapToolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox); + static void updateSnapToolbox(SPDesktop *desktop, Inkscape::UI::Tools::ToolBase *eventcontext, GtkWidget *toolbox); static Inkscape::IconSize prefToSize(Glib::ustring const &path, int base = 0 ); @@ -51,25 +67,76 @@ private: ToolboxFactory(); }; +/** + * A simple mediator class that keeps UI controls matched to the preference values they set. + */ +class PrefPusher : public Inkscape::Preferences::Observer +{ +public: + /** + * Constructor for a boolean value that syncs to the supplied path. + * Initializes the widget to the current preference stored state and registers callbacks + * for widget changes and preference changes. + * + * @param act the widget to synchronize preference with. + * @param path the path to the preference the widget is synchronized with. + * @param callback function to invoke when changes are pushed. + * @param cbData data to be passed on to the callback function. + */ + PrefPusher( GtkToggleAction *act, Glib::ustring const &path, void (*callback)(GObject*) = 0, GObject *cbData = 0 ); + + /** + * Destructor that unregisters the preference callback. + */ + virtual ~PrefPusher(); + + /** + * Callback method invoked when the preference setting changes. + */ + virtual void notify(Inkscape::Preferences::Entry const &new_val); + + +private: + /** + * Callback hook invoked when the widget changes. + * + * @param act the toggle action widget that was changed. + * @param self the PrefPusher instance the callback was registered to. + */ + static void toggleCB( GtkToggleAction *act, PrefPusher *self ); + + /** + * Method to handle the widget change. + */ + void handleToggled(); + + GtkToggleAction *act; + void (*callback)(GObject*); + GObject *cbData; + bool freeze; +}; + + } // namespace UI } // namespace Inkscape // utility -// TODO remove this: -void sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide = true); +void delete_prefspusher(GObject * /*obj*/, Inkscape::UI::PrefPusher *watcher ); +void purge_repr_listener( GObject* /*obj*/, GObject* tbl ); +void delete_connection(GObject * /*obj*/, sigc::connection *connection); EgeAdjustmentAction * create_adjustment_action( gchar const *name, gchar const *label, gchar const *shortLabel, gchar const *tooltip, Glib::ustring const &path, gdouble def, GtkWidget *focusTarget, - GtkWidget *us, GObject *dataKludge, gboolean altx, gchar const *altx_mark, gdouble lower, gdouble upper, gdouble step, gdouble page, gchar const** descrLabels, gdouble const* descrValues, guint descrCount, void (*callback)(GtkAdjustment *, GObject *), + Inkscape::UI::Widget::UnitTracker *unit_tracker = NULL, gdouble climb = 0.1, guint digits = 3, double factor = 1.0 ); #endif /* !SEEN_TOOLBOX_H */ diff --git a/src/widgets/tweak-toolbar.cpp b/src/widgets/tweak-toolbar.cpp new file mode 100644 index 000000000..050d7fb5e --- /dev/null +++ b/src/widgets/tweak-toolbar.cpp @@ -0,0 +1,393 @@ +/** + * @file + * Tweak aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ui/widget/spinbutton.h" +#include <glibmm/i18n.h> +#include "tweak-toolbar.h" +#include "desktop.h" +#include "document-undo.h" +#include "ege-adjustment-action.h" +#include "ege-output-action.h" +#include "ege-select-one-action.h" +#include "ink-action.h" +#include "preferences.h" +#include "toolbox.h" +#include "ui/icon-names.h" +#include "ui/tools/tweak-tool.h" + +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::PrefPusher; + + +//######################## +//## Tweak ## +//######################## + +static void sp_tweak_width_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/tweak/width", + gtk_adjustment_get_value(adj) * 0.01 ); +} + +static void sp_tweak_force_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/tweak/force", + gtk_adjustment_get_value(adj) * 0.01 ); +} + +static void sp_tweak_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/tweak/usepressure", gtk_toggle_action_get_active(act)); +} + +static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl ) +{ + int mode = ege_select_one_action_get_active( act ); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt("/tools/tweak/mode", mode); + + static gchar const* names[] = {"tweak_doh", "tweak_dos", "tweak_dol", "tweak_doo", "tweak_channels_label"}; + bool flag = ((mode == Inkscape::UI::Tools::TWEAK_MODE_COLORPAINT) || (mode == Inkscape::UI::Tools::TWEAK_MODE_COLORJITTER)); + for (size_t i = 0; i < G_N_ELEMENTS(names); ++i) { + GtkAction *act = GTK_ACTION(g_object_get_data( tbl, names[i] )); + if (act) { + gtk_action_set_sensitive(act, flag); + } + } + GtkAction *fid = GTK_ACTION(g_object_get_data( tbl, "tweak_fidelity")); + if (fid) { + gtk_action_set_sensitive(fid, !flag); + } +} + +static void sp_tweak_fidelity_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/tweak/fidelity", + gtk_adjustment_get_value(adj) * 0.01 ); +} + +static void tweak_toggle_doh(GtkToggleAction *act, gpointer /*data*/) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/tweak/doh", gtk_toggle_action_get_active(act)); +} +static void tweak_toggle_dos(GtkToggleAction *act, gpointer /*data*/) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/tweak/dos", gtk_toggle_action_get_active(act)); +} +static void tweak_toggle_dol(GtkToggleAction *act, gpointer /*data*/) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/tweak/dol", gtk_toggle_action_get_active(act)); +} +static void tweak_toggle_doo(GtkToggleAction *act, gpointer /*data*/) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/tweak/doo", gtk_toggle_action_get_active(act)); +} + +void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + { + /* Width */ + gchar const* labels[] = {_("(pinch tweak)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad tweak)")}; + gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "TweakWidthAction", + _("Width"), _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"), + "/tools/tweak/width", 15, + GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-tweak", + 1, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_tweak_width_value_changed, NULL /*unit tracker*/, 0.01, 0, 100 ); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + + { + /* Force */ + gchar const* labels[] = {_("(minimum force)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum force)")}; + gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "TweakForceAction", + _("Force"), _("Force:"), _("The force of the tweak action"), + "/tools/tweak/force", 20, + GTK_WIDGET(desktop->canvas), holder, TRUE, "tweak-force", + 1, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_tweak_force_value_changed, NULL /*unit tracker*/, 0.01, 0, 100 ); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + /* Mode */ + { + GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); + + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Move mode"), + 1, _("Move objects in any direction"), + 2, INKSCAPE_ICON("object-tweak-push"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Move in/out mode"), + 1, _("Move objects towards cursor; with Shift from cursor"), + 2, INKSCAPE_ICON("object-tweak-attract"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Move jitter mode"), + 1, _("Move objects in random directions"), + 2, INKSCAPE_ICON("object-tweak-randomize"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Scale mode"), + 1, _("Shrink objects, with Shift enlarge"), + 2, INKSCAPE_ICON("object-tweak-shrink"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Rotate mode"), + 1, _("Rotate objects, with Shift counterclockwise"), + 2, INKSCAPE_ICON("object-tweak-rotate"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Duplicate/delete mode"), + 1, _("Duplicate objects, with Shift delete"), + 2, INKSCAPE_ICON("object-tweak-duplicate"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Push mode"), + 1, _("Push parts of paths in any direction"), + 2, INKSCAPE_ICON("path-tweak-push"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Shrink/grow mode"), + 1, _("Shrink (inset) parts of paths; with Shift grow (outset)"), + 2, INKSCAPE_ICON("path-tweak-shrink"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Attract/repel mode"), + 1, _("Attract parts of paths towards cursor; with Shift from cursor"), + 2, INKSCAPE_ICON("path-tweak-attract"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Roughen mode"), + 1, _("Roughen parts of paths"), + 2, INKSCAPE_ICON("path-tweak-roughen"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Color paint mode"), + 1, _("Paint the tool's color upon selected objects"), + 2, INKSCAPE_ICON("object-tweak-paint"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Color jitter mode"), + 1, _("Jitter the colors of selected objects"), + 2, INKSCAPE_ICON("object-tweak-jitter-color"), + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Blur mode"), + 1, _("Blur selected objects more; with Shift, blur less"), + 2, INKSCAPE_ICON("object-tweak-blur"), + -1 ); + + + EgeSelectOneAction* act = ege_select_one_action_new( "TweakModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) ); + g_object_set( act, "short_label", _("Mode:"), NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "mode_action", act ); + + ege_select_one_action_set_appearance( act, "full" ); + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); + ege_select_one_action_set_icon_column( act, 2 ); + ege_select_one_action_set_icon_size( act, secondarySize ); + ege_select_one_action_set_tooltip_column( act, 1 ); + + gint mode = prefs->getInt("/tools/tweak/mode", 0); + ege_select_one_action_set_active( act, mode ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_tweak_mode_changed), holder ); + + g_object_set_data( G_OBJECT(holder), "tweak_tool_mode", act); + } + + guint mode = prefs->getInt("/tools/tweak/mode", 0); + + { + EgeOutputAction* act = ege_output_action_new( "TweakChannelsLabel", _("Channels:"), "", 0 ); + ege_output_action_set_use_markup( act, TRUE ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + if (mode != Inkscape::UI::Tools::TWEAK_MODE_COLORPAINT && mode != Inkscape::UI::Tools::TWEAK_MODE_COLORJITTER) { + gtk_action_set_sensitive (GTK_ACTION(act), FALSE); + } + g_object_set_data( holder, "tweak_channels_label", act); + } + + { + InkToggleAction* act = ink_toggle_action_new( "TweakDoH", + _("Hue"), + _("In color mode, act on objects' hue"), + NULL, + Inkscape::ICON_SIZE_DECORATION ); + //TRANSLATORS: "H" here stands for hue + g_object_set( act, "short_label", _("H"), NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doh", true) ); + if (mode != Inkscape::UI::Tools::TWEAK_MODE_COLORPAINT && mode != Inkscape::UI::Tools::TWEAK_MODE_COLORJITTER) { + gtk_action_set_sensitive (GTK_ACTION(act), FALSE); + } + g_object_set_data( holder, "tweak_doh", act); + } + { + InkToggleAction* act = ink_toggle_action_new( "TweakDoS", + _("Saturation"), + _("In color mode, act on objects' saturation"), + NULL, + Inkscape::ICON_SIZE_DECORATION ); + //TRANSLATORS: "S" here stands for Saturation + g_object_set( act, "short_label", _("S"), NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dos", true) ); + if (mode != Inkscape::UI::Tools::TWEAK_MODE_COLORPAINT && mode != Inkscape::UI::Tools::TWEAK_MODE_COLORJITTER) { + gtk_action_set_sensitive (GTK_ACTION(act), FALSE); + } + g_object_set_data( holder, "tweak_dos", act ); + } + { + InkToggleAction* act = ink_toggle_action_new( "TweakDoL", + _("Lightness"), + _("In color mode, act on objects' lightness"), + NULL, + Inkscape::ICON_SIZE_DECORATION ); + //TRANSLATORS: "L" here stands for Lightness + g_object_set( act, "short_label", _("L"), NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dol", true) ); + if (mode != Inkscape::UI::Tools::TWEAK_MODE_COLORPAINT && mode != Inkscape::UI::Tools::TWEAK_MODE_COLORJITTER) { + gtk_action_set_sensitive (GTK_ACTION(act), FALSE); + } + g_object_set_data( holder, "tweak_dol", act ); + } + { + InkToggleAction* act = ink_toggle_action_new( "TweakDoO", + _("Opacity"), + _("In color mode, act on objects' opacity"), + NULL, + Inkscape::ICON_SIZE_DECORATION ); + //TRANSLATORS: "O" here stands for Opacity + g_object_set( act, "short_label", _("O"), NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doo", true) ); + if (mode != Inkscape::UI::Tools::TWEAK_MODE_COLORPAINT && mode != Inkscape::UI::Tools::TWEAK_MODE_COLORJITTER) { + gtk_action_set_sensitive (GTK_ACTION(act), FALSE); + } + g_object_set_data( holder, "tweak_doo", act ); + } + + { /* Fidelity */ + gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")}; + gdouble values[] = {10, 25, 35, 50, 60, 80, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "TweakFidelityAction", + _("Fidelity"), _("Fidelity:"), + _("Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"), + "/tools/tweak/fidelity", 50, + GTK_WIDGET(desktop->canvas), holder, TRUE, "tweak-fidelity", + 1, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_tweak_fidelity_value_changed, NULL /*unit tracker*/, 0.01, 0, 100 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + if (mode == Inkscape::UI::Tools::TWEAK_MODE_COLORPAINT || mode == Inkscape::UI::Tools::TWEAK_MODE_COLORJITTER) { + gtk_action_set_sensitive (GTK_ACTION(eact), FALSE); + } + g_object_set_data( holder, "tweak_fidelity", eact ); + } + + + /* Use Pressure button */ + { + InkToggleAction* act = ink_toggle_action_new( "TweakPressureAction", + _("Pressure"), + _("Use the pressure of the input device to alter the force of tweak action"), + INKSCAPE_ICON("draw-use-pressure"), + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_tweak_pressure_state_changed), NULL); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/usepressure", 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/tweak-toolbar.h b/src/widgets/tweak-toolbar.h new file mode 100644 index 000000000..1a65a0844 --- /dev/null +++ b/src/widgets/tweak-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_TWEAK_TOOLBAR_H +#define SEEN_TWEAK_TOOLBAR_H + +/** + * @file + * Tweak aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_SELECT_TOOLBAR_H */ diff --git a/src/widgets/widget-sizes.h b/src/widgets/widget-sizes.h index 644740637..87c7ca2e0 100644 --- a/src/widgets/widget-sizes.h +++ b/src/widgets/widget-sizes.h @@ -29,17 +29,12 @@ #define STATUS_ZOOM_WIDTH 57 -#define SELECTED_STYLE_SB_WIDTH 38 -#define SELECTED_STYLE_WIDTH 180 -#define STYLE_SWATCH_WIDTH 100 +#define SELECTED_STYLE_SB_WIDTH 48 +#define SELECTED_STYLE_WIDTH 190 +#define STYLE_SWATCH_WIDTH 135 #define STATUS_LAYER_FONT_SIZE 7700 -#define RULER_WIDTH 12 -#define RULER_HEIGHT 12 -#define RULER_FONT_SIZE 6500 -#define RULER_FONT_VERTICAL_SPACING 1.2 - /* Local Variables: mode:c++ diff --git a/src/widgets/zoom-toolbar.cpp b/src/widgets/zoom-toolbar.cpp new file mode 100644 index 000000000..79feef86d --- /dev/null +++ b/src/widgets/zoom-toolbar.cpp @@ -0,0 +1,51 @@ +/** + * @file + * Zoom aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "zoom-toolbar.h" + +//######################## +//## Zoom Toolbox ## +//######################## + +void sp_zoom_toolbox_prep(SPDesktop * /*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/) +{ + // no custom GtkAction setup needed +} // end of sp_zoom_toolbox_prep() + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/zoom-toolbar.h b/src/widgets/zoom-toolbar.h new file mode 100644 index 000000000..45d979066 --- /dev/null +++ b/src/widgets/zoom-toolbar.h @@ -0,0 +1,37 @@ +#ifndef SEEN_ZOOM_TOOLBAR_H +#define SEEN_ZOOM_TOOLBAR_H + +/** + * @file + * Zoom aux toolbar + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +class SPDesktop; + +typedef struct _GtkActionGroup GtkActionGroup; +typedef struct _GObject GObject; + +void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); + +#endif /* !SEEN_ZOOM_TOOLBAR_H */ |
