summaryrefslogtreecommitdiffstats
path: root/src/widgets/stroke-style.cpp
diff options
context:
space:
mode:
authorMartin Owens <doctormo@gmail.com>2014-03-27 01:33:44 +0000
committerMartin Owens <doctormo@gmail.com>2014-03-27 01:33:44 +0000
commit5a4fb2325f60d292b47330f540b26a3279341c90 (patch)
treed2aa7967be25450b83e625025366c618101ae49f /src/widgets/stroke-style.cpp
parentThe Polar Arrange Tab of the Arrange Dialog now hides the parametric (diff)
parentRemove Snap menu item and improve grid menu item text (diff)
downloadinkscape-5a4fb2325f60d292b47330f540b26a3279341c90.tar.gz
inkscape-5a4fb2325f60d292b47330f540b26a3279341c90.zip
Commit a merge to trunk, with probabal errors
(bzr r11073.1.36)
Diffstat (limited to 'src/widgets/stroke-style.cpp')
-rw-r--r--src/widgets/stroke-style.cpp1282
1 files changed, 699 insertions, 583 deletions
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: