stroke-style.cpp revision acd93b79c034f4bcc8ff02de8aa877f70f081881
/* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* Bryce Harrington <brycehar@bryceharrington.org>
* bulia byak <buliabyak@users.sf.net>
* Maximilian Albert <maximilian.albert@gmail.com>
* Josh Andler <scislac@users.sf.net>
* Jon A. Cruz <jon@joncruz.org>
* Abhishek Sharma
*
* Copyright (C) 2001-2005 authors
* Copyright (C) 2001 Ximian, Inc.
* Copyright (C) 2004 John Cliff
* Copyright (C) 2008 Maximilian Albert (gtkmm-ification)
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#define noSP_SS_VERBOSE
#include "stroke-style.h"
#include "gradient-chemistry.h"
#include "sp-gradient.h"
#include "sp-stop.h"
#include "svg/svg-color.h"
#include "ui/widget/unit-menu.h"
#include "desktop-widget.h"
using Inkscape::DocumentUndo;
/**
* Creates a new widget for the line stroke paint.
*/
{
}
/**
* Creates a new widget for the line stroke style.
*/
{
}
{
if (ss) {
}
}
/**
* 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.
*/
{
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;
}
b[c] = '\0';
// FIXME: get the document from the object and let the caller pass it in
g_free(b);
return marker;
}
namespace Inkscape {
/**
* 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] stroke_style The style attribute to associate with the button
*/
char const *icon,
gchar const *stroke_style)
:
{
show();
set_mode(false);
}
/**
* Create the fill or stroke style widget, and hook up all the signals.
*/
{
return strokeStyle;
}
StrokeStyle::StrokeStyle() :
widthSpin(),
unitSelector(),
joinMiter(),
joinRound(),
joinBevel(),
capButt(),
capRound(),
capSquare(),
dashSelector(),
update(false),
desktop(0),
{
f->show();
add(*f);
#if WITH_GTKMM_3_0
#else
#endif
gint i = 0;
//spw_label(t, C_("Stroke width", "_Width:"), 0, i);
// TODO: when this is gtkmmified, use an Inkscape::UI::Widget::ScalarUnit instead of the separate
// spinbutton and unit selector for stroke width. In sp_stroke_style_line_update, use
// setHundredPercent to remember the averaged width corresponding to 100%. Then the
// stroke_width_set_unit will be removed (because ScalarUnit takes care of conversions itself), and
// with it, the two remaining calls of stroke_average_width, allowing us to get rid of that
// function in desktop-style.
#if WITH_GTKMM_3_0
widthAdj = new Glib::RefPtr<Gtk::Adjustment>(Gtk::Adjustment::create(1.0, 0.0, 1000.0, 0.1, 10.0, 0.0));
#else
#endif
if (desktop) {
}
unitChangedConn = unitSelector->signal_changed().connect(sigc::mem_fun(*this, &StrokeStyle::unitChangedCB));
#if WITH_GTKMM_3_0
#else
#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".
// 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).
// 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).
// 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).
i++;
/* Miterlimit */
// TRANSLATORS: Miter limit: only for "miter join", this limits the length
// of the sharp "spike" when the lines connect at too sharp an angle.
// When two line segments meet at a sharp angle, a miter join results in a
// spike that extends well beyond the connection point. The purpose of the
// miter limit is to cut off such spikes (i.e. convert them into bevels)
// when they become too long.
//spw_label(t, _("Miter _limit:"), 0, i);
#if WITH_GTKMM_3_0
miterLimitAdj = new Glib::RefPtr<Gtk::Adjustment>(Gtk::Adjustment::create(4.0, 0.0, 100.0, 0.1, 10.0, 0.0));
#else
#endif
miterLimitSpin->show();
#if WITH_GTKMM_3_0
(*miterLimitAdj)->signal_value_changed().connect(sigc::mem_fun(*this, &StrokeStyle::miterLimitChangedCB));
#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);
// TRANSLATORS: Butt cap: the line shape does not extend beyond the end point
// of the line; the ends of the line are square
// TRANSLATORS: Round cap: the line shape extends beyond the end point of the
// line; the ends of the line are rounded
// TRANSLATORS: Square cap: the line shape extends beyond the end point of the
// line; the ends of the line are square
i++;
/* Dash */
//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?
dashSelector->show();
#if WITH_GTKMM_3_0
#else
table->attach(*dashSelector, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0);
#endif
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.
i++;
startMarkerCombo->set_tooltip_text(_("Start Markers are drawn on the first node of a path or shape"));
startMarkerCombo->show();
midMarkerCombo->set_tooltip_text(_("Mid Markers are drawn on every node of a path or shape except the first and last nodes"));
midMarkerCombo->show();
endMarkerCombo->show();
updateLine();
}
{
}
{
if (this->desktop) {
}
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] 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.
*/
char const *icon,
gchar const *stroke_style)
{
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.
*/
void StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, SPMarkerLoc const /*which*/)
{
return;
}
if (!document) {
return;
}
/* Get 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 ? desktop->getSelection() : NULL);
//spw->updateMarkerHist(which);
if (!SP_IS_SHAPE(item) || SP_IS_RECT(item)) { // can't set marker to rect, until it's converted to using <path>
continue;
}
if (selrepr) {
}
}
css = 0;
};
{
switch (which) {
case SP_MARKER_LOC_START:
break;
case SP_MARKER_LOC_MID:
break;
case SP_MARKER_LOC_END:
break;
default:
}
}
/**
* Callback for when UnitMenu widget is modified.
* Triggers update action.
*/
void StrokeStyle::unitChangedCB()
{
}
widthSpin->set_value(Inkscape::Util::Quantity::convert(widthSpin->get_value(), _old_unit, new_unit));
}
/**
* Callback for when stroke style widget is modified.
* Triggers update action.
*/
void
{
updateLine();
}
}
/**
* Callback for when stroke style widget is changed.
* Triggers update action.
*/
void
{
updateLine();
}
/*
* Fork marker if necessary and set the referencing items url to the new marker
* Return the new marker
*/
SPObject *
{
return NULL;
}
/*
* Optimization when all the references to this marker are from this item
* then we can reuse it and dont need to fork
*/
unsigned int refs = 0;
for (int i = SP_MARKER_LOC_START; i < SP_MARKER_LOC_QTY; i++) {
refs++;
}
}
return marker;
}
// Update the items url to new marker
sp_repr_css_set_property(css_item, marker_id, g_strconcat("url(#", mark_repr->attribute("id"), ")", NULL));
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
{
return;
}
return;
}
// Check if we need to fork this marker
if (!repr) {
return;
};
// Current line style
// Current marker style
// Create new marker style with the lines stroke
// 1. If the line has fill, use that for the marker fill
}
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
}
// 3. If the marker has fill color, use the marker fill color
//sp_repr_css_set_property(css, "fill-opacity", mfill_opacity);
}
// Tell the combos to update its image cache of this marker
css = 0;
}
/*
* Get the fill or stroke color of the item
* If its a gradient, then return first or last stop color
*/
const char *
{
const char *color;
if (fill_or_stroke == FOR_FILL)
else
// If the item has a gradient use the first stop color for the marker
if (grad) {
if (loc == SP_MARKER_LOC_END) {
}
if (stop) {
gchar c[64];
sp_svg_write_color(c, sizeof(c), c1);
//lstroke_opacity = Glib::ustring::format(stop->opacity).c_str();
}
}
}
return color;
}
/**
* Sets selector widgets' dash style from an SPStyle object.
*/
void
{
double d[64];
for (unsigned i = 0; i < len; i++) {
else
}
} else {
}
}
/**
* Sets the join type for a line, and updates the stroke style widget's buttons
*/
void
{
switch (jointype) {
case SP_STROKE_LINEJOIN_MITER:
break;
case SP_STROKE_LINEJOIN_ROUND:
break;
case SP_STROKE_LINEJOIN_BEVEL:
break;
default:
// Should not happen
break;
}
}
/**
* Sets the cap type for a line, and updates the stroke style widget's buttons
*/
void
{
switch (captype) {
case SP_STROKE_LINECAP_BUTT:
break;
case SP_STROKE_LINECAP_ROUND:
break;
case SP_STROKE_LINECAP_SQUARE:
break;
default:
// Should not happen
break;
}
}
/**
* Callback for when stroke style widget is updated, including markers, cap type,
* join type, etc.
*/
void
{
if (update) {
return;
}
update = true;
// create temporary style
// query into it
int result_sw = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_STROKEWIDTH);
int result_ml = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_STROKEMITERLIMIT);
int result_cap = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_STROKECAP);
int result_join = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_STROKEJOIN);
// Nothing selected, grey-out all controls in the stroke-style dialog
table->set_sensitive(false);
update = false;
return;
} else {
table->set_sensitive(true);
if (result_sw == QUERY_STYLE_MULTIPLE_AVERAGED) {
} else {
// same width, or only one object; no sense to keep percent, switch to absolute
}
}
#if WITH_GTKMM_3_0
#else
#endif
} else {
#if WITH_GTKMM_3_0
#else
#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
/* No objects stroked, set insensitive */
}
if (result_ml != QUERY_STYLE_NOTHING)
#if WITH_GTKMM_3_0
#else
#endif
if (result_join != QUERY_STYLE_MULTIPLE_DIFFERENT &&
result_join != QUERY_STYLE_NOTHING ) {
} else {
}
if (result_cap != QUERY_STYLE_MULTIPLE_DIFFERENT &&
result_cap != QUERY_STYLE_NOTHING ) {
} else {
}
return;
/* Markers */
/* Dash */
table->set_sensitive(true);
update = false;
}
/**
* Sets a line's dash properties in a CSS style object.
*/
void
double scale)
{
if (ndash > 0) {
for (int i = 0; i < ndash; i++) {
if (i < (ndash - 1)) {
osarray << ",";
}
}
} else {
}
}
/**
* Sets line properties like width, dashes, markers, etc. on all currently selected items.
*/
void
{
if (update) {
return;
}
update = true;
/* TODO: Create some standardized method */
#if WITH_GTKMM_3_0
#else
#endif
int ndash;
/* Set stroke width */
double width;
} else { // percentage
}
{
}
{
os_ml << miterlimit;
}
/* Set dash */
}
// reset to 100 percent
#if WITH_GTKMM_3_0
#else
#endif
}
}
// we have already changed the items, so set style without changing selection
// FIXME: move the above stroke-setting stuff, including percentages, to desktop-style
css = 0;
_("Set stroke style"));
update = false;
}
/**
* Callback for when the stroke style's width changes.
* Causes all line styles to be applied to all selected items.
*/
void
{
if (update) {
return;
}
scaleLine();
}
/**
* Callback for when the stroke style's miterlimit changes.
* Causes all line styles to be applied to all selected items.
*/
void
{
if (update) {
return;
}
scaleLine();
}
/**
* Callback for when the stroke style's dash changes.
* Causes all line styles to be applied to all selected items.
*/
void
{
if (update) {
return;
}
scaleLine();
}
/**
* This routine handles toggle events for buttons in the stroke style dialog.
*
* When activated, this routine gets the data for the various widgets, and then
* calls the respective routines to update css properties, etc.
*
*/
{
return;
}
if (tb->get_active()) {
}
/* TODO: Create some standardized method */
switch (tb->get_button_type()) {
case STROKE_STYLE_BUTTON_JOIN:
break;
case STROKE_STYLE_BUTTON_CAP:
}
css = 0;
}
}
/**
* Updates the join style toggle buttons
*/
void
{
}
/**
* Updates the cap style toggle buttons
*/
void
{
}
/**
* Updates the marker combobox to highlight the appropriate marker and scroll to
* that marker.
*/
void
{
};
bool all_texts = true;
if (!SP_IS_TEXT (*i)) {
all_texts = false;
}
}
for (unsigned i = 0; i < G_N_ELEMENTS(keyloc); ++i) {
// Per SVG spec, text objects cannot have markers; disable combobox if only texts are selected
}
// We show markers of the first object in the list only
// FIXME: use the first in the list that has the marker of each type, if any
for (unsigned i = 0; i < G_N_ELEMENTS(keyloc); ++i) {
// For all three marker types,
// find the corresponding combobox item
// Quit if we're in update state
return;
}
// If the object has this type of markers,
// Extract the name of the marker that the object uses
SPObject *marker = getMarkerObj(object->style->marker_ptrs[keyloc[i].loc]->value, object->document);
// Scroll the combobox to that marker
// Set the marker color
if (update) {
_("Set marker color"));
}
} else {
}
}
}
} // namespace Inkscape
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :