stroke-style.cpp revision fc2e20aa610641335a34aa9b6604c3c4ec0ae7c4
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Lauris Kaplinski <lauris@kaplinski.com>
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Bryce Harrington <brycehar@bryceharrington.org>
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * bulia byak <buliabyak@users.sf.net>
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Maximilian Albert <maximilian.albert@gmail.com>
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Josh Andler <scislac@users.sf.net>
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Jon A. Cruz <jon@joncruz.org>
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Abhishek Sharma
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Copyright (C) 2001-2005 authors
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Copyright (C) 2001 Ximian, Inc.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Copyright (C) 2004 John Cliff
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Copyright (C) 2008 Maximilian Albert (gtkmm-ification)
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Released under GNU GPL, read the file 'COPYING' for more information
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Creates a new widget for the line stroke paint.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding return Inkscape::Widgets::createStyleWidget( STROKE );
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Creates a new widget for the line stroke style.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding return Inkscape::Widgets::createStrokeStyleWidget();
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fieldingvoid sp_stroke_style_widget_set_desktop(Gtk::Widget *widget, SPDesktop *desktop)
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding Inkscape::StrokeStyle *ss = dynamic_cast<Inkscape::StrokeStyle*>(widget);
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Extract the actual name of the link
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * e.g. get mTriangle from url(#mTriangle).
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * \return Buffer containing the actual name, allocated from GLib;
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * the caller should free the buffer when they no longer need it.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb gchar const *p = n;
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb int c = 0;
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb if (p[c] == '\0') {
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb b[c] = '\0';
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // FIXME: get the document from the object and let the caller pass it in
48d7c43629323c8d5ee9f7bd0d194de0a376b391rbb * Construct a stroke-style radio button with a given icon
48d7c43629323c8d5ee9f7bd0d194de0a376b391rbb * \param[in] grp The Gtk::RadioButtonGroup to which to add the new button
f62217781f5eb75b0e52b9074fd21dc20a13b4a3trawick * \param[in] icon The icon to use for the button
f62217781f5eb75b0e52b9074fd21dc20a13b4a3trawick * \param[in] button_type The type of stroke-style radio button (join/cap)
f62217781f5eb75b0e52b9074fd21dc20a13b4a3trawick * \param[in] stroke_style The style attribute to associate with the button
f13986a3b239d6172a2774c436d8e46b1d5d38ectrawickStrokeStyle::StrokeStyleButton::StrokeStyleButton(Gtk::RadioButtonGroup &grp,
f13986a3b239d6172a2774c436d8e46b1d5d38ectrawick char const *icon,
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb Gtk::Widget *px = manage(Glib::wrap(sp_icon_new(Inkscape::ICON_SIZE_LARGE_TOOLBAR, icon)));
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * Create the fill or stroke style widget, and hook up all the signals.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbbGtk::Widget *Inkscape::Widgets::createStrokeStyleWidget( )
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb //spw_label(t, C_("Stroke width", "_Width:"), 0, i);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb// TODO: when this is gtkmmified, use an Inkscape::UI::Widget::ScalarUnit instead of the separate
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb// spinbutton and unit selector for stroke width. In sp_stroke_style_line_update, use
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb// setHundredPercent to remember the averaged width corresponding to 100%. Then the
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb// stroke_width_set_unit will be removed (because ScalarUnit takes care of conversions itself), and
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb// with it, the two remaining calls of stroke_average_width, allowing us to get rid of that
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb// function in desktop-style.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb widthAdj = new Glib::RefPtr<Gtk::Adjustment>(Gtk::Adjustment::create(1.0, 0.0, 1000.0, 0.1, 10.0, 0.0));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb widthAdj = new Gtk::Adjustment(1.0, 0.0, 1000.0, 0.1, 10.0, 0.0);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb widthSpin = new Inkscape::UI::Widget::SpinButton(*widthAdj, 0.1, 3);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb spw_label(table, C_("Stroke width", "_Width:"), 0, i, widthSpin);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb unitSelector->setUnitType(Inkscape::Util::UNIT_TYPE_LINEAR);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb unitSelector->setUnit(sp_desktop_namedview(desktop)->doc_units->abbr);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb _old_unit = new Inkscape::Util::Unit(*sp_desktop_namedview(desktop)->doc_units);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb _old_unit = new Inkscape::Util::Unit(unitSelector->getUnit());
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb unitChangedConn = unitSelector->signal_changed().connect(sigc::mem_fun(*this, &StrokeStyle::unitChangedCB));
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm (*widthAdj)->signal_value_changed().connect(sigc::mem_fun(*this, &StrokeStyle::widthChangedCB));
39813b8983b16dce75194e7b70184fd68743db90manoj widthAdj->signal_value_changed().connect(sigc::mem_fun(*this, &StrokeStyle::widthChangedCB));
39813b8983b16dce75194e7b70184fd68743db90manoj /* Join type */
39813b8983b16dce75194e7b70184fd68743db90manoj // TRANSLATORS: The line join style specifies the shape to be used at the
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // corners of paths. It can be "miter", "round" or "bevel".
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb joinMiter = makeRadioButton(joinGrp, INKSCAPE_ICON("stroke-join-miter"),
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // TRANSLATORS: Miter join: joining lines with a sharp (pointed) corner.
be0e6ea9b4676d85da9cde63fa9ae443d1560f54stoddard // For an example, draw a triangle with a large stroke width and modify the
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // "Join" option (in the Fill and Stroke dialog).
905a3d840ca9cc2e1adc62db6d6e3683cf89a94agstein joinRound = makeRadioButton(joinGrp, INKSCAPE_ICON("stroke-join-round"),
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm // TRANSLATORS: Round join: joining lines with a rounded corner.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // For an example, draw a triangle with a large stroke width and modify the
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // "Join" option (in the Fill and Stroke dialog).
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm joinBevel = makeRadioButton(joinGrp, INKSCAPE_ICON("stroke-join-bevel"),
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // TRANSLATORS: Bevel join: joining lines with a blunted (flattened) corner.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // For an example, draw a triangle with a large stroke width and modify the
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // "Join" option (in the Fill and Stroke dialog).
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb /* Miterlimit */
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // TRANSLATORS: Miter limit: only for "miter join", this limits the length
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // of the sharp "spike" when the lines connect at too sharp an angle.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // When two line segments meet at a sharp angle, a miter join results in a
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // spike that extends well beyond the connection point. The purpose of the
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm // miter limit is to cut off such spikes (i.e. convert them into bevels)
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // when they become too long.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb //spw_label(t, _("Miter _limit:"), 0, i);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb miterLimitAdj = new Glib::RefPtr<Gtk::Adjustment>(Gtk::Adjustment::create(4.0, 0.0, 100.0, 0.1, 10.0, 0.0));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb miterLimitSpin = new Inkscape::UI::Widget::SpinButton(*miterLimitAdj, 0.1, 2);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb miterLimitAdj = new Gtk::Adjustment(4.0, 0.0, 100.0, 0.1, 10.0, 0.0);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb miterLimitSpin = new Inkscape::UI::Widget::SpinButton(*miterLimitAdj, 0.1, 2);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb miterLimitSpin->set_tooltip_text(_("Maximum length of the miter (in units of stroke width)"));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb spw_label(table, _("Miter _limit:"), 0, i, miterLimitSpin);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb (*miterLimitAdj)->signal_value_changed().connect(sigc::mem_fun(*this, &StrokeStyle::miterLimitChangedCB));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb miterLimitAdj->signal_value_changed().connect(sigc::mem_fun(*this, &StrokeStyle::miterLimitChangedCB));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb /* Cap type */
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // TRANSLATORS: cap type specifies the shape for the ends of lines
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb //spw_label(t, _("_Cap:"), 0, i);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb capButt = makeRadioButton(capGrp, INKSCAPE_ICON("stroke-cap-butt"),
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // TRANSLATORS: Butt cap: the line shape does not extend beyond the end point
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // of the line; the ends of the line are square
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb capRound = makeRadioButton(capGrp, INKSCAPE_ICON("stroke-cap-round"),
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // TRANSLATORS: Round cap: the line shape extends beyond the end point of the
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // line; the ends of the line are rounded
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb capSquare = makeRadioButton(capGrp, INKSCAPE_ICON("stroke-cap-square"),
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // TRANSLATORS: Square cap: the line shape extends beyond the end point of the
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // line; the ends of the line are square
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb /* Dash */
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb spw_label(table, _("Dashes:"), 0, i, NULL); //no mnemonic for now
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb //decide what to do:
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // implement a set_mnemonic_source function in the
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // SPDashSelector class, so that we do not have to
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // expose any of the underlying widgets?
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb table->attach(*dashSelector, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb dashSelector->changed_signal.connect(sigc::mem_fun(*this, &StrokeStyle::lineDashChangedCB));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb /* Drop down marker selectors*/
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm // TRANSLATORS: Path markers are an SVG feature that allows you to attach arbitrary shapes
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // (arrowheads, bullets, faces, whatever) to the start, end, or middle nodes of a path.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb startMarkerCombo = manage(new MarkerComboBox("marker-start", SP_MARKER_LOC_START));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb startMarkerCombo->set_tooltip_text(_("Start Markers are drawn on the first node of a path or shape"));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb startMarkerConn = startMarkerCombo->signal_changed().connect(
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sigc::bind<MarkerComboBox *, StrokeStyle *, SPMarkerLoc>(
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sigc::ptr_fun(&StrokeStyle::markerSelectCB), startMarkerCombo, this, SP_MARKER_LOC_START));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb midMarkerCombo = manage(new MarkerComboBox("marker-mid", SP_MARKER_LOC_MID));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb midMarkerCombo->set_tooltip_text(_("Mid Markers are drawn on every node of a path or shape except the first and last nodes"));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb midMarkerConn = midMarkerCombo->signal_changed().connect(
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sigc::bind<MarkerComboBox *, StrokeStyle *, SPMarkerLoc>(
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sigc::ptr_fun(&StrokeStyle::markerSelectCB), midMarkerCombo, this, SP_MARKER_LOC_MID));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb endMarkerCombo = manage(new MarkerComboBox("marker-end", SP_MARKER_LOC_END));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb endMarkerCombo->set_tooltip_text(_("End Markers are drawn on the last node of a path or shape"));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb endMarkerConn = endMarkerCombo->signal_changed().connect(
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sigc::bind<MarkerComboBox *, StrokeStyle *, SPMarkerLoc>(
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sigc::ptr_fun(&StrokeStyle::markerSelectCB), endMarkerCombo, this, SP_MARKER_LOC_END));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb if (this->desktop) {
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb selectChangedConn = desktop->selection->connectChanged(sigc::hide(sigc::mem_fun(*this, &StrokeStyle::selectionChangedCB)));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb selectModifiedConn = desktop->selection->connectModified(sigc::hide<0>(sigc::mem_fun(*this, &StrokeStyle::selectionModifiedCB)));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * Helper function for creating stroke-style radio buttons.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * \param[in] grp The Gtk::RadioButtonGroup in which to add the button
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * \param[in] icon The icon for the button
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * \param[in] hb The Gtk::Box container in which to add the button
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * \param[in] button_type The type (join/cap) for the button
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * \param[in] stroke_style The style attribute to associate with the button
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * \details After instantiating the button, it is added to a container box and
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * a handler for the toggle event is connected.
c33e53e173268441b12fa3939a189bca3205f8c1trawickStrokeStyle::makeRadioButton(Gtk::RadioButtonGroup &grp,
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb char const *icon,
1f4b45b1cfdced41a18a6f3a2596e749c1c88fbftrawick StrokeStyleButton *tb = new StrokeStyleButton(grp, icon, button_type, stroke_style);
7e998f3c4d3c22956a1105906169f2c9fdb8e57dtrawick tb->signal_toggled().connect(sigc::bind<StrokeStyleButton *, StrokeStyle *>(
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sigc::ptr_fun(&StrokeStyle::buttonToggledCB), tb, this));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * Handles when user selects one of the markers from the marker combobox.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * Gets the marker uri string and applies it to all selected
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * items in the current desktop.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbbvoid StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, SPMarkerLoc const /*which*/)
7e998f3c4d3c22956a1105906169f2c9fdb8e57dtrawick SPDocument *document = sp_desktop_document(spw->desktop);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb /* Get Marker */
7e998f3c4d3c22956a1105906169f2c9fdb8e57dtrawick gchar const *marker = marker_combo->get_active_marker_uri();
d6e78e25e55d4eead29e200c9498479b747af3bdtrawick // Also update the marker combobox, so the document's markers
d6e78e25e55d4eead29e200c9498479b747af3bdtrawick // show up at the top of the combobox
d6e78e25e55d4eead29e200c9498479b747af3bdtrawick// sp_stroke_style_line_update( SP_WIDGET(spw), desktop ? sp_desktop_selection(desktop) : NULL);
d6e78e25e55d4eead29e200c9498479b747af3bdtrawick //spw->updateMarkerHist(which);
d6e78e25e55d4eead29e200c9498479b747af3bdtrawick Inkscape::Selection *selection = sp_desktop_selection(spw->desktop);
7e998f3c4d3c22956a1105906169f2c9fdb8e57dtrawick SPItem *item = reinterpret_cast<SPItem *>(items->data);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb if (!SP_IS_SHAPE(item) || SP_IS_RECT(item)) { // can't set marker to rect, until it's converted to using <path>
ec1807360643d980dcd3cb6b8df26ce50045c50dtrawick sp_repr_css_change_recursive(selrepr, css, "style");
ec1807360643d980dcd3cb6b8df26ce50045c50dtrawick SPObject *markerObj = getMarkerObj(marker, document);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb spw->setMarkerColor(markerObj, marker_combo->get_loc(), item);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE, _("Set markers"));
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmvoid StrokeStyle::updateMarkerHist(SPMarkerLoc const which)
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb switch (which) {
5827adc4c40ff4b10db9b09cea43f4307c8fc319trawick * Callback for when UnitMenu widget is modified.
5827adc4c40ff4b10db9b09cea43f4307c8fc319trawick * Triggers update action.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb Inkscape::Util::Unit new_unit = unitSelector->getUnit();
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb if (new_unit.type == Inkscape::Util::UNIT_TYPE_DIMENSIONLESS) {
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb widthSpin->set_value(Inkscape::Util::Quantity::convert(widthSpin->get_value(), *_old_unit, new_unit));
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * Callback for when stroke style widget is modified.
a437779c0ce405a99250e725d7f6ad7533bed96ctrawick * Triggers update action.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG)) {
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * Callback for when stroke style widget is changed.
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * Triggers update action.
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * Fork marker if necessary and set the referencing items url to the new marker
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * Return the new marker
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbbStrokeStyle::forkMarker(SPObject *marker, int loc, SPItem *item)
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * Optimization when all the references to this marker are from this item
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * then we can reuse it and dont need to fork
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb Glib::ustring urlId = Glib::ustring::format("url(#", marker->getRepr()->attribute("id"), ")");
ebe70c2684539a5fb2d899241d1601710dfa38a4trawick unsigned int refs = 0;
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb for (int i = SP_MARKER_LOC_START; i < SP_MARKER_LOC_QTY; i++) {
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb if (item->style->marker[i].set && !strcmp(urlId.c_str(), item->style->marker[i].value)) {
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // Update the items url to new marker
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sp_repr_css_set_property(css_item, marker_id, g_strconcat("url(#", mark_repr->attribute("id"), ")", NULL));
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sp_repr_css_change_recursive(item->getRepr(), css_item, "style");
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * Change the color of the marker to match the color of the item.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * Marker stroke color is set to item stroke color.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * Fill color :
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * 1. If the item has fill, use that for the marker fill,
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * 2. If the marker has same fill and stroke assume its solid, use item stroke for both fill and stroke the line stroke
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * 3. If the marker has fill color, use the marker fill color
ebe70c2684539a5fb2d899241d1601710dfa38a4trawickStrokeStyle::setMarkerColor(SPObject *marker, int loc, SPItem *item)
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb Inkscape::Preferences *prefs = Inkscape::Preferences::get();
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb gboolean colorStock = prefs->getBool("/options/markers/colorStockMarkers", true);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb gboolean colorCustom = prefs->getBool("/options/markers/colorCustomMarkers", false);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb const gchar *stock = marker->getRepr()->attribute("inkscape:isstock");
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // Check if we need to fork this marker
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb Inkscape::XML::Node *repr = marker->getRepr()->firstChild();
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // Current line style
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb SPCSSAttr *css_item = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb const char *lstroke = getItemColorForMarker(item, FOR_STROKE, loc);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb const char *lstroke_opacity = sp_repr_css_property(css_item, "stroke-opacity", "1");
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm const char *lfill = getItemColorForMarker(item, FOR_FILL, loc);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm const char *lfill_opacity = sp_repr_css_property(css_item, "fill-opacity", "1");
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // Current marker style
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm SPCSSAttr *css_marker = sp_css_attr_from_object(marker->firstChild(), SP_STYLE_FLAG_ALWAYS);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb const char *mfill = sp_repr_css_property(css_marker, "fill", "none");
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm const char *mstroke = sp_repr_css_property(css_marker, "fill", "none");
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm // Create new marker style with the lines stroke
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sp_repr_css_set_property(css, "stroke-opacity", lstroke_opacity);
10a4cdd68ef1ca0e54af296fe1d08ac00150c90bwrowe // 1. If the line has fill, use that for the marker fill
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sp_repr_css_set_property(css, "fill-opacity", lfill_opacity);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb else if (mfill && mstroke && !strcmp(mfill, mstroke) && mfill[0] == '#' && strcmp(mfill, "#ffffff")) {
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // 2. If the marker has same fill and stroke assume its solid. use line stroke for both fill and stroke the line stroke
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sp_repr_css_set_property(css, "fill-opacity", lstroke_opacity);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb else if (mfill && mfill[0] == '#' && strcmp(mfill, "#000000")) {
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // 3. If the marker has fill color, use the marker fill color
1f961f350a73525fcbac770383b8e6f0d18e8909trawick //sp_repr_css_set_property(css, "fill-opacity", mfill_opacity);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sp_repr_css_change_recursive(marker->firstChild()->getRepr(), css, "style");
f31dc3b5fa09e42f0f47656ac852da5eb805d436rbb // Tell the combos to update its image cache of this marker
1f961f350a73525fcbac770383b8e6f0d18e8909trawick gchar const *mid = marker->getRepr()->attribute("id");
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * Get the fill or stroke color of the item
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * If its a gradient, then return first or last stop color
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbbconst char *
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmStrokeStyle::getItemColorForMarker(SPItem *item, Inkscape::PaintTarget fill_or_stroke, int loc)
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb SPCSSAttr *css_item = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb const char *color;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm color = sp_repr_css_property(css_item, "stroke", "none");
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // If the item has a gradient use the first stop color for the marker
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm //lstroke_opacity = Glib::ustring::format(stop->opacity).c_str();
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * Sets selector widgets' dash style from an SPStyle object.
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmStrokeStyle::setDashSelectorFromStyle(SPDashSelector *dsel, SPStyle *style)
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb double d[64];
1f961f350a73525fcbac770383b8e6f0d18e8909trawick for (int i = 0; i < len; i++) {
1f961f350a73525fcbac770383b8e6f0d18e8909trawick d[i] = style->stroke_dash.dash[i] / style->stroke_width.computed;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm d[i] = style->stroke_dash.dash[i]; // is there a better thing to do for stroke_width==0?
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb dsel->set_dash(len, d, style->stroke_width.computed != 0 ?
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb style->stroke_dash.offset / style->stroke_width.computed :
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * Sets the join type for a line, and updates the stroke style widget's buttons
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * Sets the cap type for a line, and updates the stroke style widget's buttons
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * Callback for when stroke style widget is updated, including markers, cap type,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * join type, etc.
000b67449410515eac43e76ef6667915bfd4d2abgstein Inkscape::Selection *sel = desktop ? sp_desktop_selection(desktop) : NULL;
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb FillOrStroke kind = GPOINTER_TO_INT(get_data("kind")) ? FILL : STROKE;
000b67449410515eac43e76ef6667915bfd4d2abgstein // create temporary style
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // query into it
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb int result_sw = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEWIDTH);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb int result_ml = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEMITERLIMIT);
000b67449410515eac43e76ef6667915bfd4d2abgstein int result_cap = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKECAP);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb int result_join = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_STROKEJOIN);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb SPIPaint &targPaint = (kind == FILL) ? query->fill : query->stroke;
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // Nothing selected, grey-out all controls in the stroke-style dialog
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb Inkscape::Util::Unit const *unit = new Inkscape::Util::Unit(unitSelector->getUnit());
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // same width, or only one object; no sense to keep percent, switch to absolute
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb unitSelector->setUnit(sp_desktop_namedview(SP_ACTIVE_DESKTOP)->doc_units->abbr);
f31dc3b5fa09e42f0f47656ac852da5eb805d436rbb unit = new Inkscape::Util::Unit(unitSelector->getUnit());
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb double avgwidth = Inkscape::Util::Quantity::convert(query->stroke_width.computed, "px", *unit);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // if none of the selected objects has a stroke, than quite some controls should be disabled
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb // The markers might still be shown though, so these will not be disabled
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm bool enabled = (result_sw != QUERY_STYLE_NOTHING) && !targPaint.isNoneSet();
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb /* No objects stroked, set insensitive */
f31dc3b5fa09e42f0f47656ac852da5eb805d436rbb (*miterLimitAdj)->set_value(query->stroke_miterlimit.value); // TODO: reflect averagedness?
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb miterLimitAdj->set_value(query->stroke_miterlimit.value); // TODO: reflect averagedness?
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb /* Markers */
f31dc3b5fa09e42f0f47656ac852da5eb805d436rbb updateAllMarkers(objects); // FIXME: make this desktop query too
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb /* Dash */
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb setDashSelectorFromStyle(dashSelector, style); // FIXME: make this desktop query too
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb * Sets a line's dash properties in a CSS style object.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb if (ndash > 0) {
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb for (int i = 0; i < ndash; i++) {
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sp_repr_css_set_property(css, "stroke-dasharray", osarray.str().c_str());
f31dc3b5fa09e42f0f47656ac852da5eb805d436rbb sp_repr_css_set_property(css, "stroke-dashoffset", osoffset.str().c_str());
4b86db47932a21da10cd35317b3da737f2b073c4rbb sp_repr_css_set_property(css, "stroke-dasharray", "none");
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb sp_repr_css_set_property(css, "stroke-dashoffset", NULL);
f31dc3b5fa09e42f0f47656ac852da5eb805d436rbb * Sets line properties like width, dashes, markers, etc. on all currently selected items.
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb Inkscape::Selection *selection = sp_desktop_selection (desktop);
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb /* TODO: Create some standardized method */
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb double const miterlimit = (*miterLimitAdj)->get_value();
8877cd6a81e0d6b3c534609c4ebf06a96734dabcrbb Inkscape::Util::Unit const *const unit = new Inkscape::Util::Unit(unitSelector->getUnit());
double width;
#if WITH_GTKMM_3_0
css = 0;
update = false;
if (update) {
scaleLine();
if (update) {
scaleLine();
if (update) {
scaleLine();
case STROKE_STYLE_BUTTON_JOIN:
case STROKE_STYLE_BUTTON_CAP:
css = 0;
bool all_texts = true;
all_texts = false;
if (update) {