diff options
| author | Liam P. White <inkscapebronyat-signgmaildotcom> | 2014-05-17 02:00:23 +0000 |
|---|---|---|
| committer | Liam P. White <inkscapebronyat-signgmaildotcom> | 2014-05-17 02:00:23 +0000 |
| commit | c418ce3ee56b7b31832fa801996439ce8256e5e7 (patch) | |
| tree | 8972313381d2e410aedf674d66fef812a455b457 /src | |
| parent | Commit patch for "leaned" cap. Thanks Jabiertxof! (diff) | |
| parent | Fix GTK+ 3 build (diff) | |
| download | inkscape-c418ce3ee56b7b31832fa801996439ce8256e5e7.tar.gz inkscape-c418ce3ee56b7b31832fa801996439ce8256e5e7.zip | |
Update to experimental (r13376)
(bzr r13090.1.79)
Diffstat (limited to 'src')
49 files changed, 2291 insertions, 330 deletions
diff --git a/src/2geom/toposweep.cpp b/src/2geom/toposweep.cpp index cfb91857c..4da3f6922 100644 --- a/src/2geom/toposweep.cpp +++ b/src/2geom/toposweep.cpp @@ -53,6 +53,7 @@ TopoGraph::Edge TopoGraph::remove_edge(unsigned ix, unsigned jx) { } } assert(0); + return v[0]; // if assert is disabled, return first Edge. } void TopoGraph::cannonize() { diff --git a/src/desktop.h b/src/desktop.h index be2bf891f..ec240dd40 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -442,7 +442,7 @@ private: prefs->addObserver(*this); } private: - void notify(Inkscape::Preferences::Entry const &val) { + void notify(Inkscape::Preferences::Entry const &) { _desktop->redrawDesktop(); } SPDesktop *_desktop; diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h index d990bcb73..0d82087c3 100644 --- a/src/display/drawing-context.h +++ b/src/display/drawing-context.h @@ -61,6 +61,7 @@ public: cairo_curve_to(_ct, p1[Geom::X], p1[Geom::Y], p2[Geom::X], p2[Geom::Y], p3[Geom::X], p3[Geom::Y]); } void arc(Geom::Point const ¢er, double radius, Geom::AngleInterval const &angle); + void closePath() { cairo_close_path(_ct); } void rectangle(Geom::Rect const &r) { cairo_rectangle(_ct, r.left(), r.top(), r.width(), r.height()); } diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 4178cb1d8..05a2c3c2a 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -67,16 +67,14 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext _pick_bbox = Geom::IntRect(); _bbox = Geom::IntRect(); -/* orignally it did the one line below, - but it did not handle ws characters at all, and it had problems with scaling for overline/underline. - Replaced with the section below, which seems to be much more stable. - - Geom::OptRect b = bounds_exact_transformed(*_font->PathVector(_glyph), ctx.ctm); -*/ - /* Make a bounding box that is a little taller and lower (currently 10% extra) than the font's drawing box. Extra space is - to hold overline or underline, if present. All characters in a font use the same ascent and descent, - but different widths. This lets leading and trailing spaces have text decorations. If it is not done - the bounding box is limited to the box surrounding the drawn parts of visible glyphs only, and draws outside are ignored. + /* + Make a bounding box for drawing that is a little taller and lower (currently 10% extra) than + the font's drawing box. Extra space is to hold overline or underline, if present. All + characters in a font use the same ascent and descent, but different widths. This lets leading + and trailing spaces have text decorations. If it is not done the bounding box is limited to + the box surrounding the drawn parts of visible glyphs only, and draws outside are ignored. + The box is also a hair wider than the text, since the glyphs do not always start or end at + the left and right edges of the box defined in the font. */ float scale_bigbox = 1.0; @@ -84,9 +82,45 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext scale_bigbox /= _transform->descrim(); } - Geom::Rect bigbox(Geom::Point(0.0, _asc*scale_bigbox*1.1),Geom::Point(_width*scale_bigbox, -_dsc*scale_bigbox*1.1)); + Geom::Rect bigbox(Geom::Point(-_width*scale_bigbox*0.1, _asc*scale_bigbox*1.1),Geom::Point(_width*scale_bigbox, -_dsc*scale_bigbox*1.1)); Geom::Rect b = bigbox * ctx.ctm; + /* + The pick box matches the characters as best as it can, leaving no extra space above or below + for decorations. The pathvector may include spaces, and spaces have no drawable glyph. + Catch those and do not pass them to bounds_exact_transformed(), which crashes Inkscape if it + sees a nondrawable glyph. Instead mock up a pickbox for them using font characteristics. + There may also be some other similar white space characters in some other unforeseen context + which should be handled by this code as well.. + */ + + Geom::OptRect pb; + if(_drawable){ + pb = bounds_exact_transformed(*_font->PathVector(_glyph), ctx.ctm); + } + if(!pb){ // Fallback + Geom::Rect pbigbox(Geom::Point(0.0, _asc*scale_bigbox*0.66),Geom::Point(_width*scale_bigbox, 0.0)); + pb = pbigbox * ctx.ctm; + } + +#if 0 + /* FIXME if this is commented out then not even an approximation of pick on decorations */ + /* adjust the pick box up or down to include the decorations. + This is only approximate since at this point we don't know how wide that line is, if it has + an unusual offset, and so forth. The selection point is set at what is roughly the center of + the decoration (vertically) for the wide ones, like wavy and double line. + The text decorations are not actually selectable. + */ + if (_decorations.overline || _decorations.underline) { + double top = _asc*scale_bigbox*0.66; + double bot = 0; + if (_decorations.overline) { top = _asc * scale_bigbox * 1.025; } + if (_decorations.underline) { bot = -_dsc * scale_bigbox * 0.2; } + Geom::Rect padjbox(Geom::Point(0.0, top),Geom::Point(_width*scale_bigbox, bot)); + pb.unionWith(padjbox * ctx.ctm); + } +#endif + if (ggroup->_nrstyle.stroke.type != NRStyle::PAINT_NONE) { // this expands the selection box for cases where the stroke is "thick" float scale = ctx.ctm.descrim(); @@ -96,10 +130,11 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext float width = MAX(0.125, ggroup->_nrstyle.stroke_width * scale); if ( fabs(ggroup->_nrstyle.stroke_width * scale) > 0.01 ) { // FIXME: this is always true b.expandBy(0.5 * width); + pb->expandBy(0.5 * width); } // save bbox without miters for picking - _pick_bbox = b.roundOutwards(); + _pick_bbox = pb->roundOutwards(); float miterMax = width * ggroup->_nrstyle.miter_limit; if ( miterMax > 0.01 ) { @@ -110,14 +145,8 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext _bbox = b.roundOutwards(); } else { _bbox = b.roundOutwards(); - _pick_bbox = *_bbox; + _pick_bbox = pb->roundOutwards(); } -/* -std::cout << "DEBUG _bbox" -<< " { " << _bbox->min()[Geom::X] << " , " << _bbox->min()[Geom::Y] -<< " } , { " << _bbox->max()[Geom::X] << " , " << _bbox->max()[Geom::Y] -<< " }" << std::endl; -*/ return STATE_ALL; } @@ -136,7 +165,8 @@ DrawingGlyphs::_pickItem(Geom::Point const &p, double delta, unsigned /*flags*/) // With text we take a simple approach: pick if the point is in a character bbox Geom::Rect expanded(_pick_bbox); - expanded.expandBy(delta); + // FIXME, why expand by delta? When is the next line needed? + // expanded.expandBy(delta); if (expanded.contains(p)) return this; return NULL; } @@ -195,7 +225,7 @@ DrawingText::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, un return DrawingGroup::_updateItem(area, ctx, flags, reset); } -void DrawingText::decorateStyle(DrawingContext &dc, double vextent, double xphase, Geom::Point const &p1, Geom::Point const &p2) +void DrawingText::decorateStyle(DrawingContext &dc, double vextent, double xphase, Geom::Point const &p1, Geom::Point const &p2, double thickness) { double wave[16]={ 0.000000, 0.382499, 0.706825, 0.923651, 1.000000, 0.923651, 0.706825, 0.382499, @@ -213,7 +243,6 @@ void DrawingText::decorateStyle(DrawingContext &dc, double vextent, double xphas 4, 3, 2, 1, -4, -3, -2, -1 }; - Geom::Point p3,p4,ps,pf; double step = vextent/32.0; unsigned i = 15 & (unsigned) round(xphase/step); // xphase is >= 0.0 @@ -221,26 +250,19 @@ void DrawingText::decorateStyle(DrawingContext &dc, double vextent, double xphas This allows decoration continuity within the line, and does not step outside the clip box off the end For the first/last section on the line though, stay well clear of the edge, or when the text is dragged it may "spray" pixels. - if(_nrstyle.tspan_line_end){ pf = p2 - Geom::Point(2*step, 0.0); } - else { pf = p2; } - if(_nrstyle.tspan_line_start){ ps = p1 + Geom::Point(2*step, 0.0); - i = 15 & (i + 2); - } - else { ps = p1; } */ /* snap to nearest step in X */ -ps = Geom::Point(step * round(p1[Geom::X]/step),p1[Geom::Y]); -pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); + Geom::Point ps = Geom::Point(step * round(p1[Geom::X]/step),p1[Geom::Y]); + Geom::Point pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); + Geom::Point poff = Geom::Point(0,thickness/2.0); if(_nrstyle.text_decoration_style & TEXT_DECORATION_STYLE_ISDOUBLE){ ps -= Geom::Point(0, vextent/12.0); pf -= Geom::Point(0, vextent/12.0); - dc.moveTo(ps); - dc.lineTo(pf); + dc.rectangle( Geom::Rect(ps + poff, pf - poff)); ps += Geom::Point(0, vextent/6.0); pf += Geom::Point(0, vextent/6.0); - dc.moveTo(ps); - dc.lineTo(pf); + dc.rectangle( Geom::Rect(ps + poff, pf - poff)); } /* The next three have a problem in that they are phase dependent. The bits of a line are not necessarily passing through this routine in order, so we have to use the xphase information @@ -248,43 +270,52 @@ pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); Huge possitive offset should keep the phase calculation from ever being negative. */ else if(_nrstyle.text_decoration_style & TEXT_DECORATION_STYLE_DOTTED){ + // FIXME: Per spec, this should produce round dots. + Geom::Point pv = ps; while(1){ + Geom::Point pvlast = pv; if(dots[i]>0){ - if(ps[Geom::X]> pf[Geom::X])break; - dc.moveTo(ps); - ps += Geom::Point(step * (double)dots[i], 0.0); - if(ps[Geom::X]>= pf[Geom::X]){ - dc.lineTo(pf); + if(pv[Geom::X] > pf[Geom::X]) break; + + pv += Geom::Point(step * (double)dots[i], 0.0); + + if(pv[Geom::X]>= pf[Geom::X]){ + // Last dot + dc.rectangle( Geom::Rect(pvlast + poff, pf - poff)); break; + } else { + dc.rectangle( Geom::Rect(pvlast + poff, pv - poff)); } - else { - dc.lineTo(ps); - } - ps += Geom::Point(step * 4.0, 0.0); - } - else { - ps += Geom::Point(step * -(double)dots[i], 0.0); + + pv += Geom::Point(step * 4.0, 0.0); + + } else { + pv += Geom::Point(step * -(double)dots[i], 0.0); } i = 0; // once in phase, it stays in phase } } else if(_nrstyle.text_decoration_style & TEXT_DECORATION_STYLE_DASHED){ + Geom::Point pv = ps; while(1){ + Geom::Point pvlast = pv; if(dashes[i]>0){ - if(ps[Geom::X]> pf[Geom::X])break; - dc.moveTo(ps); - ps += Geom::Point(step * (double)dashes[i], 0.0); - if(ps[Geom::X]>= pf[Geom::X]){ - dc.lineTo(pf); + if(pv[Geom::X]> pf[Geom::X]) break; + + pv += Geom::Point(step * (double)dashes[i], 0.0); + + if(pv[Geom::X]>= pf[Geom::X]){ + // Last dash + dc.rectangle( Geom::Rect(pvlast + poff, pf - poff)); break; + } else { + dc.rectangle( Geom::Rect(pvlast + poff, pv - poff)); } - else { - dc.lineTo(ps); - } - ps += Geom::Point(step * 8.0, 0.0); - } - else { - ps += Geom::Point(step * -(double)dashes[i], 0.0); + + pv += Geom::Point(step * 8.0, 0.0); + + } else { + pv += Geom::Point(step * -(double)dashes[i], 0.0); } i = 0; // once in phase, it stays in phase } @@ -292,7 +323,7 @@ pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); else if(_nrstyle.text_decoration_style & TEXT_DECORATION_STYLE_WAVY){ double amp = vextent/10.0; double x = ps[Geom::X]; - double y = ps[Geom::Y]; + double y = ps[Geom::Y] + poff[Geom::Y]; dc.moveTo(Geom::Point(x, y + amp * wave[i])); while(1){ i = ((i + 1) & 15); @@ -300,17 +331,25 @@ pf = Geom::Point(step * round(p2[Geom::X]/step),p2[Geom::Y]); dc.lineTo(Geom::Point(x, y + amp * wave[i])); if(x >= pf[Geom::X])break; } - } + y = ps[Geom::Y] - poff[Geom::Y]; + dc.lineTo(Geom::Point(x, y + amp * wave[i])); + while(1){ + i = ((i - 1) & 15); + x -= step; + dc.lineTo(Geom::Point(x, y + amp * wave[i])); + if(x <= ps[Geom::X])break; + } + dc.closePath(); + } else { // TEXT_DECORATION_STYLE_SOLID, also default in case it was not set for some reason - dc.moveTo(ps); - dc.lineTo(pf); -// dc.revrectangle(Geom::Rect(ps,pf)); + dc.rectangle( Geom::Rect(ps + poff, pf - poff)); } } /* returns scaled line thickness */ -double DrawingText::decorateItem(DrawingContext &dc, Geom::Affine const &aff, double phase_length) +void DrawingText::decorateItem(DrawingContext &dc, double phase_length, bool under) { + if (_nrstyle.font_size < 1.0e-32)return; // would cause a divide by zero and nothing would be visible anyway double tsp_width_adj = _nrstyle.tspan_width / _nrstyle.font_size; double tsp_asc_adj = _nrstyle.ascender / _nrstyle.font_size; double tsp_size_adj = (_nrstyle.ascender + _nrstyle.descender) / _nrstyle.font_size; @@ -318,49 +357,54 @@ double DrawingText::decorateItem(DrawingContext &dc, Geom::Affine const &aff, do double final_underline_thickness = CLAMP(_nrstyle.underline_thickness, tsp_size_adj/30.0, tsp_size_adj/10.0); double final_line_through_thickness = CLAMP(_nrstyle.line_through_thickness, tsp_size_adj/30.0, tsp_size_adj/10.0); - double scale = aff.descrim(); double xphase = phase_length/ _nrstyle.font_size; // used to figure out phase of patterns - Inkscape::DrawingContext::Save save(dc); - dc.transform(aff); // must be leftmost affine in span - Geom::Point p1; Geom::Point p2; // All lines must be the same thickness, in combinations, line_through trumps underline double thickness = final_underline_thickness; - if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_UNDERLINE){ - p1 = Geom::Point(0.0, -_nrstyle.underline_position); - p2 = Geom::Point(tsp_width_adj,-_nrstyle.underline_position); - decorateStyle(dc, tsp_size_adj, xphase, p1, p2); - } - if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_OVERLINE){ - p1 = Geom::Point(0.0, tsp_asc_adj -_nrstyle.underline_position + 1 * final_underline_thickness); - p2 = Geom::Point(tsp_width_adj,tsp_asc_adj -_nrstyle.underline_position + 1 * final_underline_thickness); - decorateStyle(dc, tsp_size_adj, xphase, p1, p2); - } - if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_LINETHROUGH){ - thickness = final_line_through_thickness; - p1 = Geom::Point(0.0, _nrstyle.line_through_position); - p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position); - decorateStyle(dc, tsp_size_adj, xphase, p1, p2); - } - // Obviously this does not blink, but it does indicate which text has been set with that attribute - if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_BLINK){ - thickness = final_line_through_thickness; - p1 = Geom::Point(0.0, _nrstyle.line_through_position - 2*final_line_through_thickness); - p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position - 2*final_line_through_thickness); - decorateStyle(dc, tsp_size_adj, xphase, p1, p2); - p1 = Geom::Point(0.0, _nrstyle.line_through_position + 2*final_line_through_thickness); - p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position + 2*final_line_through_thickness); - decorateStyle(dc, tsp_size_adj, xphase, p1, p2); + dc.setTolerance(0.5); // Is this really necessary... could effect dots. + + if( under ) { + + if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_UNDERLINE){ + p1 = Geom::Point(0.0, -_nrstyle.underline_position); + p2 = Geom::Point(tsp_width_adj,-_nrstyle.underline_position); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2, thickness); + } + + if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_OVERLINE){ + p1 = Geom::Point(0.0, tsp_asc_adj -_nrstyle.underline_position + 1 * final_underline_thickness); + p2 = Geom::Point(tsp_width_adj,tsp_asc_adj -_nrstyle.underline_position + 1 * final_underline_thickness); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2, thickness); + } + + } else { + // Over + + if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_LINETHROUGH){ + thickness = final_line_through_thickness; + p1 = Geom::Point(0.0, _nrstyle.line_through_position); + p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2, thickness); + } + + // Obviously this does not blink, but it does indicate which text has been set with that attribute + if(_nrstyle.text_decoration_line & TEXT_DECORATION_LINE_BLINK){ + thickness = final_line_through_thickness; + p1 = Geom::Point(0.0, _nrstyle.line_through_position - 2*final_line_through_thickness); + p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position - 2*final_line_through_thickness); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2, thickness); + p1 = Geom::Point(0.0, _nrstyle.line_through_position + 2*final_line_through_thickness); + p2 = Geom::Point(tsp_width_adj,_nrstyle.line_through_position + 2*final_line_through_thickness); + decorateStyle(dc, tsp_size_adj, xphase, p1, p2, thickness); + } } - thickness *= scale; - return(thickness); } unsigned DrawingText::_renderItem(DrawingContext &dc, Geom::IntRect const &/*area*/, unsigned /*flags*/, DrawingItem * /*stop_at*/) { - if (_drawing.outline()) { + if (_drawing.outline()) { guint32 rgba = _drawing.outlinecolor; Inkscape::DrawingContext::Save save(dc); dc.setSource(rgba); @@ -382,124 +426,187 @@ unsigned DrawingText::_renderItem(DrawingContext &dc, Geom::IntRect const &/*are return RENDER_OK; } - // NOTE: this is very similar to drawing-shape.cpp; the only difference is in path feeding - double leftmost = DBL_MAX; - double phase_length = 0.0; - bool firsty = true; - bool decorate = true; - double starty = 0.0; - Geom::Affine aff; - using Geom::X; - using Geom::Y; - - // NOTE: + // NOTE: This is very similar to drawing-shape.cpp; the only differences are in path feeding + // and in applying text decorations. + + + // Do we have text decorations? + bool decorate = (_nrstyle.text_decoration_line != TEXT_DECORATION_LINE_CLEAR ); + // prepareFill / prepareStroke need to be called with _ctm in effect. // However, we might need to apply a different ctm for glyphs. // Therefore, only apply this ctm temporarily. - bool has_stroke, has_fill; + bool has_stroke = false; + bool has_fill = false; + bool has_td_fill = false; + bool has_td_stroke = false; { Inkscape::DrawingContext::Save save(dc); dc.transform(_ctm); - has_fill = _nrstyle.prepareFill( dc, _item_bbox); - has_stroke = _nrstyle.prepareStroke(dc, _item_bbox); + has_fill = _nrstyle.prepareFill( dc, _item_bbox); + has_stroke = _nrstyle.prepareStroke( dc, _item_bbox); + + // Avoid creating patterns if not needed + if( decorate ) { + has_td_fill = _nrstyle.prepareTextDecorationFill( dc, _item_bbox); + has_td_stroke = _nrstyle.prepareTextDecorationStroke(dc, _item_bbox); + } } - if (has_fill || has_stroke) { - Geom::Affine rotinv; - bool invset = false; + if (has_fill || has_stroke || has_td_fill || has_td_stroke) { - // accumulate the path that represents the glyphs - for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { - DrawingGlyphs *g = dynamic_cast<DrawingGlyphs *>(&*i); - if (!g) throw InvalidItemException(); - if (!invset) { - rotinv = g->_ctm.withoutTranslation().inverse(); - invset = true; - } + // Determine order for fill and stroke. + // Text doesn't have markers, we can do paint-order quick and dirty. + bool fill_first = false; + if( _nrstyle.paint_order_layer[0] == NRStyle::PAINT_ORDER_NORMAL || + _nrstyle.paint_order_layer[0] == NRStyle::PAINT_ORDER_FILL || + _nrstyle.paint_order_layer[2] == NRStyle::PAINT_ORDER_STROKE ) { + fill_first = true; + } // Won't get "stroke fill stroke" but that isn't 'valid' + + + // Determine geometry of text decoration + double phase_length = 0.0; + Geom::Affine aff; + if( decorate ) { + + Geom::Affine rotinv; + bool invset = false; + double leftmost = DBL_MAX; + bool first_y = true; + double start_y = 0.0; + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + + DrawingGlyphs *g = dynamic_cast<DrawingGlyphs *>(&*i); + if (!g) throw InvalidItemException(); + + if (!invset) { + rotinv = g->_ctm.withoutTranslation().inverse(); + invset = true; + } - Inkscape::DrawingContext::Save save(dc); - if (g->_ctm.isSingular()) continue; - dc.transform(g->_ctm); - if (g->_drawable) { - dc.path(*g->_font->PathVector(g->_glyph)); - } - // get the leftmost affine transform (leftmost defined with respect to the x axis of the first transform). - // That way the decoration will work no matter what mix of L->R, R->L text is in the span. - if (_nrstyle.text_decoration_line != TEXT_DECORATION_LINE_CLEAR) { Geom::Point pt = g->_ctm.translation() * rotinv; - if (pt[X] < leftmost) { - leftmost = pt[X]; + if (pt[Geom::X] < leftmost) { + leftmost = pt[Geom::X]; aff = g->_ctm; phase_length = g->_pl; } - /* If the text has been mapped onto a path, which causes y to vary, drop the text decorations. - To handle that properly would need a conformal map - */ - if (firsty) { - firsty = false; - starty = pt[Y]; + + // Check for text on a path. FIXME: This needs better test (and probably not here). + if (first_y) { + first_y = false; + start_y = pt[Geom::Y]; } - else if (fabs(pt[Y] - starty) > 1.0e-6) { + else if (fabs(pt[Geom::Y] - start_y) > 1.0e-6) { + // If the text has been mapped onto a path, which causes y to vary, drop the + // text decorations. To handle that properly would need a conformal map. decorate = false; } } } - // draw the text itself - // we need to apply this object's ctm again - Inkscape::DrawingContext::Save save(dc); - dc.transform(_ctm); + // Draw text decorations that go UNDER the text (underline, over-line) + if( decorate ) { - // Text doesn't have markers, we can do paint-order quick and dirty. - bool fill_first = false; - if( _nrstyle.paint_order_layer[0] == NRStyle::PAINT_ORDER_NORMAL || - _nrstyle.paint_order_layer[0] == NRStyle::PAINT_ORDER_FILL || - _nrstyle.paint_order_layer[2] == NRStyle::PAINT_ORDER_STROKE ) { - fill_first = true; - } // Won't get "stroke fill stroke" but that isn't 'valid' + { + Inkscape::DrawingContext::Save save(dc); + dc.transform(aff); // must be leftmost affine in span + decorateItem(dc, phase_length, true); + } + + { + Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); // Needed so that fill pattern rotates with text + + if (has_td_fill && fill_first) { + _nrstyle.applyTextDecorationFill(dc); + dc.fillPreserve(); + } + + if (has_td_stroke) { + _nrstyle.applyTextDecorationStroke(dc); + dc.strokePreserve(); + } + + if (has_td_fill && !fill_first) { + _nrstyle.applyTextDecorationFill(dc); + dc.fillPreserve(); + } - if (has_fill && fill_first) { - _nrstyle.applyFill(dc); - dc.fillPreserve(); + } + + dc.newPath(); // Clear text-decoration path } - if (has_stroke) { - _nrstyle.applyStroke(dc); - dc.strokePreserve(); + // accumulate the path that represents the glyphs + for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) { + DrawingGlyphs *g = dynamic_cast<DrawingGlyphs *>(&*i); + if (!g) throw InvalidItemException(); + + Inkscape::DrawingContext::Save save(dc); + if (g->_ctm.isSingular()) continue; + dc.transform(g->_ctm); + if (g->_drawable) { + dc.path(*g->_font->PathVector(g->_glyph)); + } } - if (has_fill && !fill_first) { - _nrstyle.applyFill(dc); - dc.fillPreserve(); + // Draw the glyphs. + { + Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); + + if (has_fill && fill_first) { + _nrstyle.applyFill(dc); + dc.fillPreserve(); + } + + if (has_stroke) { + _nrstyle.applyStroke(dc); + dc.strokePreserve(); + } + + if (has_fill && !fill_first) { + _nrstyle.applyFill(dc); + dc.fillPreserve(); + } } + dc.newPath(); // Clear glyphs path + + // Draw text decorations that go OVER the text (line through, blink) + if (decorate) { - dc.newPath(); // clear path - - // draw text decoration - if (_nrstyle.text_decoration_line != TEXT_DECORATION_LINE_CLEAR && decorate) { - guint32 ergba; - if (_nrstyle.text_decoration_useColor) { // color different from the glyph - ergba = SP_RGBA32_F_COMPOSE( - _nrstyle.text_decoration_color.color.v.c[0], - _nrstyle.text_decoration_color.color.v.c[1], - _nrstyle.text_decoration_color.color.v.c[2], - 1.0); + { + Inkscape::DrawingContext::Save save(dc); + dc.transform(aff); // must be leftmost affine in span + decorateItem(dc, phase_length, false); } - else { // whatever the current fill color is - ergba = SP_RGBA32_F_COMPOSE( - _nrstyle.fill.color.v.c[0], - _nrstyle.fill.color.v.c[1], - _nrstyle.fill.color.v.c[2], - 1.0); + + { + Inkscape::DrawingContext::Save save(dc); + dc.transform(_ctm); // Needed so that fill pattern rotates with text + + if (has_td_fill && fill_first) { + _nrstyle.applyTextDecorationFill(dc); + dc.fillPreserve(); + } + + if (has_td_stroke) { + _nrstyle.applyTextDecorationStroke(dc); + dc.strokePreserve(); + } + + if (has_td_fill && !fill_first) { + _nrstyle.applyTextDecorationFill(dc); + dc.fillPreserve(); + } + } - dc.setSource(ergba); - dc.setTolerance(0.5); - double thickness = decorateItem(dc, aff, phase_length); - dc.setLineWidth(thickness); - dc.strokePreserve(); - dc.newPath(); // clear path + + dc.newPath(); // Clear text-decoration path } + } return RENDER_OK; } diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h index 41039d85d..4453a3db4 100644 --- a/src/display/drawing-text.h +++ b/src/display/drawing-text.h @@ -68,8 +68,8 @@ protected: virtual DrawingItem *_pickItem(Geom::Point const &p, double delta, unsigned flags); virtual bool _canClip(); - double decorateItem(DrawingContext &dc, Geom::Affine const &aff, double phase_length); - void decorateStyle(DrawingContext &dc, double vextent, double xphase, Geom::Point const &p1, Geom::Point const &p2); + void decorateItem(DrawingContext &dc, double phase_length, bool under); + void decorateStyle(DrawingContext &dc, double vextent, double xphase, Geom::Point const &p1, Geom::Point const &p2, double thickness); NRStyle _nrstyle; friend class DrawingGlyphs; diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp index 09a28e63c..a9f101f69 100644 --- a/src/display/nr-style.cpp +++ b/src/display/nr-style.cpp @@ -54,8 +54,13 @@ NRStyle::NRStyle() , line_join(CAIRO_LINE_JOIN_MITER) , fill_pattern(NULL) , stroke_pattern(NULL) + , text_decoration_fill_pattern(NULL) + , text_decoration_stroke_pattern(NULL) , text_decoration_line(TEXT_DECORATION_LINE_CLEAR) , text_decoration_style(TEXT_DECORATION_STYLE_CLEAR) + , text_decoration_fill() + , text_decoration_stroke() + , text_decoration_stroke_width(0.0) , phase_length(0.0) , tspan_line_start(false) , tspan_line_end(false) @@ -76,17 +81,28 @@ NRStyle::~NRStyle() { if (fill_pattern) cairo_pattern_destroy(fill_pattern); if (stroke_pattern) cairo_pattern_destroy(stroke_pattern); + if (text_decoration_fill_pattern) cairo_pattern_destroy(text_decoration_fill_pattern); + if (text_decoration_stroke_pattern) cairo_pattern_destroy(text_decoration_stroke_pattern); if (dash){ delete [] dash; } fill.clear(); stroke.clear(); + text_decoration_fill.clear(); + text_decoration_stroke.clear(); } void NRStyle::set(SPStyle *style) { if ( style->fill.isPaintserver() ) { - fill.set(style->getFillPaintServer()); + SPPaintServer* server = style->getFillPaintServer(); + if ( server && server->isValid() ) { + fill.set(server); + } else if ( style->fill.colorSet ) { + fill.set(style->fill.value.color); + } else { + fill.clear(); + } } else if ( style->fill.isColor() ) { fill.set(style->fill.value.color); } else if ( style->fill.isNone() ) { @@ -108,7 +124,14 @@ void NRStyle::set(SPStyle *style) } if ( style->stroke.isPaintserver() ) { - stroke.set(style->getStrokePaintServer()); + SPPaintServer* server = style->getStrokePaintServer(); + if ( server && server->isValid() ) { + stroke.set(server); + } else if ( style->stroke.isColor() ) { + stroke.set(style->stroke.colorSet); + } else { + stroke.clear(); + } } else if ( style->stroke.isColor() ) { stroke.set(style->stroke.value.color); } else if ( style->stroke.isNone() ) { @@ -195,15 +218,65 @@ void NRStyle::set(SPStyle *style) if(style->text_decoration_style.dashed ){ text_decoration_style |= TEXT_DECORATION_STYLE_DASHED + TEXT_DECORATION_STYLE_SET; } if(style->text_decoration_style.wavy ){ text_decoration_style |= TEXT_DECORATION_STYLE_WAVY + TEXT_DECORATION_STYLE_SET; } + /* FIXME + The meaning of text-decoration-color in CSS3 for SVG is ambiguous (2014-05-06). Set + it for fill, for stroke, for both? Both would seem like the obvious choice but what happens + is that for text which is just fill (very common) it makes the lines fatter because it + enables stroke on the decorations when it wasn't present on the text. That contradicts the + usual behavior where the text and decorations by default have the same fill/stroke. + + The behavior here is that if color is defined it is applied to text_decoration_fill/stroke + ONLY if the corresponding fill/stroke is also present. + + Hopefully the standard will be clarified to resolve this issue. + */ + + SPStyle* style_td = style; + if ( style->text_decoration.style_td ) style_td = style->text_decoration.style_td; + text_decoration_stroke.opacity = SP_SCALE24_TO_FLOAT(style_td->stroke_opacity.value); + text_decoration_stroke_width = style_td->stroke_width.computed; + if( style->text_decoration_color.set || style->text_decoration_color.inherit || - style->text_decoration_color.currentcolor ){ - text_decoration_color.set(style->text_decoration_color.value.color); - text_decoration_useColor = true; - } - else { - text_decoration_color.clear(); - text_decoration_useColor = false; + style->text_decoration_color.currentcolor ) { + + if(style->fill.isPaintserver() || style->fill.isColor()) { + // SVG sets color specifically + text_decoration_fill.set(style->text_decoration_color.value.color); + } else { + // No decoration fill because no text fill + text_decoration_fill.clear(); + } + + if(style->stroke.isPaintserver() || style->stroke.isColor()) { + // SVG sets color specifically + text_decoration_stroke.set(style->text_decoration_color.value.color); + } else { + // No decoration stroke because no text stroke + text_decoration_stroke.clear(); + } + + } else { + // Pick color/pattern from text + if ( style_td->fill.isPaintserver() ) { + text_decoration_fill.set(style_td->getFillPaintServer()); + } else if ( style_td->fill.isColor() ) { + text_decoration_fill.set(style_td->fill.value.color); + } else if ( style_td->fill.isNone() ) { + text_decoration_fill.clear(); + } else { + g_assert_not_reached(); + } + + if ( style_td->stroke.isPaintserver() ) { + text_decoration_stroke.set(style_td->getStrokePaintServer()); + } else if ( style_td->stroke.isColor() ) { + text_decoration_stroke.set(style_td->stroke.value.color); + } else if ( style_td->stroke.isNone() ) { + text_decoration_stroke.clear(); + } else { + g_assert_not_reached(); + } } if(text_decoration_line != TEXT_DECORATION_LINE_CLEAR){ @@ -232,10 +305,8 @@ bool NRStyle::prepareFill(Inkscape::DrawingContext &dc, Geom::OptRect const &pai if (!fill_pattern) { switch (fill.type) { case PAINT_SERVER: { - //fill_pattern = sp_paint_server_create_pattern(fill.server, dc.raw(), paintbox, fill.opacity); - fill_pattern = fill.server->pattern_new(dc.raw(), paintbox, fill.opacity); - - } break; + fill_pattern = fill.server->pattern_new(dc.raw(), paintbox, fill.opacity); + } break; case PAINT_COLOR: { SPColor const &c = fill.color; fill_pattern = cairo_pattern_create_rgba( @@ -254,14 +325,38 @@ void NRStyle::applyFill(Inkscape::DrawingContext &dc) dc.setFillRule(fill_rule); } +bool NRStyle::prepareTextDecorationFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox) +{ + // update text decoration pattern + if (!text_decoration_fill_pattern) { + switch (text_decoration_fill.type) { + case PAINT_SERVER: { + text_decoration_fill_pattern = text_decoration_fill.server->pattern_new(dc.raw(), paintbox, text_decoration_fill.opacity); + } break; + case PAINT_COLOR: { + SPColor const &c = text_decoration_fill.color; + text_decoration_fill_pattern = cairo_pattern_create_rgba( + c.v.c[0], c.v.c[1], c.v.c[2], text_decoration_fill.opacity); + } break; + default: break; + } + } + if (!text_decoration_fill_pattern) return false; + return true; +} + +void NRStyle::applyTextDecorationFill(Inkscape::DrawingContext &dc) +{ + dc.setSource(text_decoration_fill_pattern); + // Fill rule does not matter, no intersections. +} + bool NRStyle::prepareStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox) { if (!stroke_pattern) { switch (stroke.type) { case PAINT_SERVER: { - //stroke_pattern = sp_paint_server_create_pattern(stroke.server, dc.raw(), paintbox, stroke.opacity); stroke_pattern = stroke.server->pattern_new(dc.raw(), paintbox, stroke.opacity); - } break; case PAINT_COLOR: { SPColor const &c = stroke.color; @@ -285,13 +380,46 @@ void NRStyle::applyStroke(Inkscape::DrawingContext &dc) cairo_set_dash(dc.raw(), dash, n_dash, dash_offset); // fixme } +bool NRStyle::prepareTextDecorationStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox) +{ + if (!text_decoration_stroke_pattern) { + switch (text_decoration_stroke.type) { + case PAINT_SERVER: { + text_decoration_stroke_pattern = text_decoration_stroke.server->pattern_new(dc.raw(), paintbox, text_decoration_stroke.opacity); + } break; + case PAINT_COLOR: { + SPColor const &c = text_decoration_stroke.color; + text_decoration_stroke_pattern = cairo_pattern_create_rgba( + c.v.c[0], c.v.c[1], c.v.c[2], text_decoration_stroke.opacity); + } break; + default: break; + } + } + if (!text_decoration_stroke_pattern) return false; + return true; +} + +void NRStyle::applyTextDecorationStroke(Inkscape::DrawingContext &dc) +{ + dc.setSource(text_decoration_stroke_pattern); + dc.setLineWidth(text_decoration_stroke_width); + dc.setLineCap(CAIRO_LINE_CAP_BUTT); + dc.setLineJoin(CAIRO_LINE_JOIN_MITER); + dc.setMiterLimit(miter_limit); + cairo_set_dash(dc.raw(), 0, 0, 0.0); // fixme (no dash) +} + void NRStyle::update() { // force pattern update if (fill_pattern) cairo_pattern_destroy(fill_pattern); if (stroke_pattern) cairo_pattern_destroy(stroke_pattern); + if (text_decoration_fill_pattern) cairo_pattern_destroy(text_decoration_fill_pattern); + if (text_decoration_stroke_pattern) cairo_pattern_destroy(text_decoration_stroke_pattern); fill_pattern = NULL; stroke_pattern = NULL; + text_decoration_fill_pattern = NULL; + text_decoration_stroke_pattern = NULL; } /* diff --git a/src/display/nr-style.h b/src/display/nr-style.h index ca880c00b..83bcb1ab7 100644 --- a/src/display/nr-style.h +++ b/src/display/nr-style.h @@ -30,8 +30,12 @@ struct NRStyle { void set(SPStyle *); bool prepareFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox); bool prepareStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox); + bool prepareTextDecorationFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox); + bool prepareTextDecorationStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox); void applyFill(Inkscape::DrawingContext &dc); void applyStroke(Inkscape::DrawingContext &dc); + void applyTextDecorationFill(Inkscape::DrawingContext &dc); + void applyTextDecorationStroke(Inkscape::DrawingContext &dc); void update(); enum PaintType { @@ -67,6 +71,8 @@ struct NRStyle { cairo_pattern_t *fill_pattern; cairo_pattern_t *stroke_pattern; + cairo_pattern_t *text_decoration_fill_pattern; + cairo_pattern_t *text_decoration_stroke_pattern; enum PaintOrderType { PAINT_ORDER_NORMAL, @@ -97,8 +103,9 @@ struct NRStyle { int text_decoration_line; int text_decoration_style; - Paint text_decoration_color; - bool text_decoration_useColor; // if false, use whatever the glyph color was + Paint text_decoration_fill; + Paint text_decoration_stroke; + float text_decoration_stroke_width; // These are the same as in style.h float phase_length; bool tspan_line_start; diff --git a/src/inkscape-manifest-x64.xml b/src/inkscape-manifest-x64.xml new file mode 100644 index 000000000..38526cfe6 --- /dev/null +++ b/src/inkscape-manifest-x64.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<dependency> +<dependentAssembly> +<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" processorArchitecture="amd64" + publicKeyToken="6595b64144ccf1df" language="*"/> +</dependentAssembly> +</dependency> +</assembly>
\ No newline at end of file diff --git a/src/inkscape-x64.rc b/src/inkscape-x64.rc new file mode 100644 index 000000000..ce286c2ca --- /dev/null +++ b/src/inkscape-x64.rc @@ -0,0 +1,30 @@ + +APPLICATION_ICON ICON DISCARDABLE "../inkscape.ico" +1 24 DISCARDABLE "./inkscape-manifest-x64.xml" + +1 VERSIONINFO + FILEVERSION 0,48,0,9 + PRODUCTVERSION 0,48,0,9 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040901b5" + BEGIN + VALUE "Comments", "Published under the GNU GPL" + VALUE "CompanyName", "inkscape.org" + VALUE "FileDescription", "Inkscape" + VALUE "FileVersion", "0.48+devel" + VALUE "InternalName", "Inkscape" + VALUE "LegalCopyright", "© 2014 Inkscape" + VALUE "ProductName", "Inkscape" + VALUE "ProductVersion", "0.48+devel" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 1033, 437 + END +END + +1000 BITMAP "./show-preview.bmp" + diff --git a/src/inkview-manifest-x64.xml b/src/inkview-manifest-x64.xml new file mode 100644 index 000000000..38526cfe6 --- /dev/null +++ b/src/inkview-manifest-x64.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<dependency> +<dependentAssembly> +<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" processorArchitecture="amd64" + publicKeyToken="6595b64144ccf1df" language="*"/> +</dependentAssembly> +</dependency> +</assembly>
\ No newline at end of file diff --git a/src/inkview-x64.rc b/src/inkview-x64.rc new file mode 100644 index 000000000..2de16060b --- /dev/null +++ b/src/inkview-x64.rc @@ -0,0 +1,29 @@ + +APPLICATION_ICON ICON DISCARDABLE "../inkscape.ico" +1 24 DISCARDABLE "./inkview-manifest-x64.xml" + +1 VERSIONINFO + FILEVERSION 0,48,0,9 + PRODUCTVERSION 0,48,0,9 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040901b5" + BEGIN + VALUE "Comments", "Published under the GNU GPL" + VALUE "CompanyName", "inkscape.org" + VALUE "FileDescription", "Inkview" + VALUE "FileVersion", "0.48+devel" + VALUE "InternalName", "Inkview" + VALUE "LegalCopyright", "© 2014 Inkscape" + VALUE "ProductName", "Inkview" + VALUE "ProductVersion", "0.48+devel" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 1033, 437 + END +END + +1000 BITMAP "./show-preview.bmp" diff --git a/src/libdepixelize/kopftracer2011.cpp b/src/libdepixelize/kopftracer2011.cpp index e2f387c86..bbb73d445 100644 --- a/src/libdepixelize/kopftracer2011.cpp +++ b/src/libdepixelize/kopftracer2011.cpp @@ -26,13 +26,15 @@ # include <config.h> #endif + +#include "kopftracer2011.h" + // Build fix under Inkscape build tree #if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H #include <glibmm/threads.h> #endif #include <algorithm> -#include "kopftracer2011.h" #include "priv/colorspace.h" #include "priv/homogeneoussplines.h" #include "priv/branchless.h" diff --git a/src/libdepixelize/kopftracer2011.h b/src/libdepixelize/kopftracer2011.h index 598f6c79c..c60d0a61a 100644 --- a/src/libdepixelize/kopftracer2011.h +++ b/src/libdepixelize/kopftracer2011.h @@ -27,6 +27,7 @@ #include <string> +#include <glibmm.h> // Contains exception definitions #include <glibmm/fileutils.h> #include <gdkmm/pixbuf.h> diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 58bd7a7dc..c7547ded3 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -34,6 +34,7 @@ set(live_effects_SRC lpe-recursiveskeleton.cpp lpe-rough-hatches.cpp lpe-ruler.cpp + lpe-simplify.cpp # lpe-skeleton.cpp lpe-sketch.cpp lpe-spiro.cpp @@ -60,6 +61,7 @@ set(live_effects_SRC parameter/random.cpp parameter/text.cpp paramter/transformedpoint.cpp + parameter/togglebutton.cpp parameter/unit.cpp parameter/vector.cpp @@ -102,6 +104,7 @@ set(live_effects_SRC lpe-recursiveskeleton.h lpe-rough-hatches.h lpe-ruler.h + lpe-simplify.h lpe-skeleton.h lpe-sketch.h lpe-spiro.h @@ -128,6 +131,7 @@ set(live_effects_SRC parameter/powerstrokepointarray.h parameter/random.h parameter/text.h + parameter/togglebutton.h parameter/unit.h parameter/vector.h diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index 5dcd3ee28..922a4a966 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -42,6 +42,10 @@ ink_common_sources += \ live_effects/lpe-bspline.h \ live_effects/lpe-lattice.cpp \ live_effects/lpe-lattice.h \ + live_effects/lpe-lattice2.cpp \ + live_effects/lpe-lattice2.h \ + live_effects/lpe-simplify.cpp \ + live_effects/lpe-simplify.h \ live_effects/lpe-envelope.cpp \ live_effects/lpe-envelope.h \ live_effects/lpe-spiro.cpp \ diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 8295196d5..82ce36225 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -28,6 +28,8 @@ enum EffectType { PERSPECTIVE_PATH, SPIRO, LATTICE, + LATTICE2, + SIMPLIFY, ENVELOPE, CONSTRUCT_GRID, PERP_BISECTOR, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index d94f1e242..3c13ee9a9 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -27,6 +27,8 @@ #include "live_effects/lpe-perspective_path.h" #include "live_effects/lpe-spiro.h" #include "live_effects/lpe-lattice.h" +#include "live_effects/lpe-lattice2.h" +#include "live_effects/lpe-simplify.h" #include "live_effects/lpe-envelope.h" #include "live_effects/lpe-constructgrid.h" #include "live_effects/lpe-perp_bisector.h" @@ -139,6 +141,9 @@ const Util::EnumData<EffectType> LPETypeData[] = { {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"}, {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"}, +/* 0.91 */ + {SIMPLIFY, N_("Simplify"), "simplify"}, + {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, }; const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -285,9 +290,14 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) break; case TAPER_STROKE: neweffect = static_cast<Effect*> ( new LPETaperStroke(lpeobj) ); + case SIMPLIFY: + neweffect = static_cast<Effect*> ( new LPESimplify(lpeobj) ); + break; + case LATTICE2: + neweffect = static_cast<Effect*> ( new LPELattice2(lpeobj) ); break; default: - g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); + g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; break; } @@ -564,9 +574,12 @@ Effect::getCanvasIndicators(SPLPEItem const* lpeitem) { std::vector<Geom::PathVector> hp_vec; - if (!SP_IS_SHAPE(lpeitem)) { -// g_print ("How to handle helperpaths for non-shapes?\n"); // non-shapes are for example SPGroups. - return hp_vec; + // TODO: we can probably optimize this by using a lot more references + // rather than copying PathVectors all over the place + if (SP_IS_SHAPE(lpeitem) && show_orig_path) { + // add original path to helperpaths + SPCurve* curve = SP_SHAPE(lpeitem)->getCurve (); + hp_vec.push_back(curve->get_pathvector()); } // add indicators provided by the effect itself diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index edf19d1e5..b19b697c0 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -1,14 +1,27 @@ #define INKSCAPE_LPE_BSPLINE_C + /* * Released under GNU GPL, read the file 'COPYING' for more information */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if WITH_GLIBMM_2_32 +# include <glibmm/threads.h> +#endif + #include <gtkmm/box.h> #include <gtkmm/entry.h> #include <gtkmm/box.h> #include <gtkmm/button.h> #include <gtkmm/checkbutton.h> + #include <glib.h> #include <glibmm/i18n.h> + + #include "display/curve.h" #include <2geom/bezier-curve.h> #include <2geom/point.h> @@ -96,7 +109,7 @@ void LPEBSpline::createAndApply(const char *name, SPDocument *doc, } void LPEBSpline::doEffect(SPCurve *curve) { - if (curve->get_segment_count() < 2) + if (curve->get_segment_count() < 1) return; // Make copy of old path as it is changed during processing Geom::PathVector const original_pathv = curve->get_pathvector(); @@ -216,10 +229,26 @@ void LPEBSpline::doEffect(SPCurve *curve) { ++curve_it1; ++curve_it2; } + SPCurve *out = new SPCurve(); + out->moveto(curve_it1->initialPoint()); + out->lineto(curve_it1->finalPoint()); + cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); + if (cubic) { + SBasisOut = out->first_segment()->toSBasis(); + nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); + nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2], *out->first_segment())); + nextPointAt3 = out->first_segment()->finalPoint(); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); + } + out->reset(); + delete out; //Si está cerrada la curva, la cerramos sobre el valor guardado //previamente //Si no finalizamos en el punto final - Geom::Point startNode(0, 0); + Geom::Point startNode = path_it->begin()->initialPoint(); if (path_it->closed()) { SPCurve *start = new SPCurve(); start->moveto(path_it->begin()->initialPoint()); @@ -421,7 +450,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weightValue) { } } //bool hasNodesSelected = LPEBspline::hasNodesSelected(); - if (curve->get_segment_count() < 2) + if (curve->get_segment_count() < 1) return; // Make copy of old path as it is changed during processing Geom::PathVector const original_pathv = curve->get_pathvector(); diff --git a/src/live_effects/lpe-lattice.h b/src/live_effects/lpe-lattice.h index a44dda3fd..5eb48909b 100644 --- a/src/live_effects/lpe-lattice.h +++ b/src/live_effects/lpe-lattice.h @@ -58,7 +58,6 @@ private: PointParam grid_point13; PointParam grid_point14; PointParam grid_point15; - LPELattice(const LPELattice&); LPELattice& operator=(const LPELattice&); }; diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp new file mode 100644 index 000000000..db609c9e1 --- /dev/null +++ b/src/live_effects/lpe-lattice2.cpp @@ -0,0 +1,496 @@ +/** \file + * LPE <lattice2> implementation + + */ +/* + * Authors: + * Johan Engelen <j.b.c.engelen@utwente.nl> + * Steren Giannini + * Noé Falzon + * Victor Navez + * ~suv + * Jabiertxo Arraiza +* +* Copyright (C) 2007-2008 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/lpe-lattice2.h" + +#include "sp-shape.h" +#include "sp-item.h" +#include "sp-path.h" +#include "display/curve.h" +#include "svg/svg.h" + +#include <2geom/sbasis.h> +#include <2geom/sbasis-2d.h> +#include <2geom/sbasis-geometric.h> +#include <2geom/bezier-to-sbasis.h> +#include <2geom/sbasis-to-bezier.h> +#include <2geom/d2.h> +#include <2geom/piecewise.h> +#include <2geom/transforms.h> +#include <tools-switch.h> + +#include "desktop.h" // TODO: should be factored out (see below) + +using namespace Geom; + +namespace Inkscape { +namespace LivePathEffect { + +LPELattice2::LPELattice2(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + // initialise your parameters here: + grid_point0(_("Control handle 0:"), _("Control handle 0 - Ctrl+Alt+Click to reset"), "gridpoint0", &wr, this), + grid_point1(_("Control handle 1:"), _("Control handle 1 - Ctrl+Alt+Click to reset"), "gridpoint1", &wr, this), + grid_point2(_("Control handle 2:"), _("Control handle 2 - Ctrl+Alt+Click to reset"), "gridpoint2", &wr, this), + grid_point3(_("Control handle 3:"), _("Control handle 3 - Ctrl+Alt+Click to reset"), "gridpoint3", &wr, this), + grid_point4(_("Control handle 4:"), _("Control handle 4 - Ctrl+Alt+Click to reset"), "gridpoint4", &wr, this), + grid_point5(_("Control handle 5:"), _("Control handle 5 - Ctrl+Alt+Click to reset"), "gridpoint5", &wr, this), + grid_point6(_("Control handle 6:"), _("Control handle 6 - Ctrl+Alt+Click to reset"), "gridpoint6", &wr, this), + grid_point7(_("Control handle 7:"), _("Control handle 7 - Ctrl+Alt+Click to reset"), "gridpoint7", &wr, this), + grid_point8x9(_("Control handle 8x9:"), _("Control handle 8x9 - Ctrl+Alt+Click to reset"), "gridpoint8x9", &wr, this), + grid_point10x11(_("Control handle 10x11:"), _("Control handle 10x11 - Ctrl+Alt+Click to reset"), "gridpoint10x11", &wr, this), + grid_point12(_("Control handle 12:"), _("Control handle 12 - Ctrl+Alt+Click to reset"), "gridpoint12", &wr, this), + grid_point13(_("Control handle 13:"), _("Control handle 13 - Ctrl+Alt+Click to reset"), "gridpoint13", &wr, this), + grid_point14(_("Control handle 14:"), _("Control handle 14 - Ctrl+Alt+Click to reset"), "gridpoint14", &wr, this), + grid_point15(_("Control handle 15:"), _("Control handle 15 - Ctrl+Alt+Click to reset"), "gridpoint15", &wr, this), + grid_point16(_("Control handle 16:"), _("Control handle 16 - Ctrl+Alt+Click to reset"), "gridpoint16", &wr, this), + grid_point17(_("Control handle 17:"), _("Control handle 17 - Ctrl+Alt+Click to reset"), "gridpoint17", &wr, this), + grid_point18(_("Control handle 18:"), _("Control handle 18 - Ctrl+Alt+Click to reset"), "gridpoint18", &wr, this), + grid_point19(_("Control handle 19:"), _("Control handle 19 - Ctrl+Alt+Click to reset"), "gridpoint19", &wr, this), + grid_point20x21(_("Control handle 20x21:"), _("Control handle 20x21 - Ctrl+Alt+Click to reset"), "gridpoint20x21", &wr, this), + grid_point22x23(_("Control handle 22x23:"), _("Control handle 22x23 - Ctrl+Alt+Click to reset"), "gridpoint22x23", &wr, this), + grid_point24x26(_("Control handle 24x26:"), _("Control handle 24x26 - Ctrl+Alt+Click to reset"), "gridpoint24x26", &wr, this), + grid_point25x27(_("Control handle 25x27:"), _("Control handle 25x27 - Ctrl+Alt+Click to reset"), "gridpoint25x27", &wr, this), + grid_point28x30(_("Control handle 28x30:"), _("Control handle 28x30 - Ctrl+Alt+Click to reset"), "gridpoint28x30", &wr, this), + grid_point29x31(_("Control handle 29x31:"), _("Control handle 29x31 - Ctrl+Alt+Click to reset"), "gridpoint29x31", &wr, this), + grid_point32x33x34x35(_("Control handle 32x33x34x35:"), _("Control handle 32x33x34x35 - Ctrl+Alt+Click to reset"), "gridpoint32x33x34x35", &wr, this) + + +{ + // register all your parameters here, so Inkscape knows which parameters this effect has: + registerParameter( dynamic_cast<Parameter *>(&grid_point0) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point1) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point2) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point3) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point4) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point5) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point6) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point7) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point8x9) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point10x11) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point12) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point13) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point14) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point15) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point16) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point17) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point18) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point19) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point20x21) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point22x23) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point24x26) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point25x27) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point28x30) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point29x31) ); + registerParameter( dynamic_cast<Parameter *>(&grid_point32x33x34x35) ); +} + +LPELattice2::~LPELattice2() +{ +} + +Geom::Piecewise<Geom::D2<Geom::SBasis> > +LPELattice2::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) +{ + D2<SBasis2d> sb2; + + //Initialisation of the sb2 + for(unsigned dim = 0; dim < 2; dim++) { + sb2[dim].us = 3; + sb2[dim].vs = 3; + const int depth = sb2[dim].us*sb2[dim].vs; + sb2[dim].resize(depth, Linear2d(0)); + } + + //Grouping the point params in a convenient vector + std::vector<Geom::Point *> handles(36); + + handles[0] = &grid_point0; + handles[1] = &grid_point1; + handles[2] = &grid_point2; + handles[3] = &grid_point3; + handles[4] = &grid_point4; + handles[5] = &grid_point5; + handles[6] = &grid_point6; + handles[7] = &grid_point7; + handles[8] = &grid_point8x9; + handles[9] = &grid_point8x9; + handles[10] = &grid_point10x11; + handles[11] = &grid_point10x11; + handles[12] = &grid_point12; + handles[13] = &grid_point13; + handles[14] = &grid_point14; + handles[15] = &grid_point15; + handles[16] = &grid_point16; + handles[17] = &grid_point17; + handles[18] = &grid_point18; + handles[19] = &grid_point19; + handles[20] = &grid_point20x21; + handles[21] = &grid_point20x21; + handles[22] = &grid_point22x23; + handles[23] = &grid_point22x23; + handles[24] = &grid_point24x26; + handles[25] = &grid_point25x27; + handles[26] = &grid_point24x26; + handles[27] = &grid_point25x27; + handles[28] = &grid_point28x30; + handles[29] = &grid_point29x31; + handles[30] = &grid_point28x30; + handles[31] = &grid_point29x31; + handles[32] = &grid_point32x33x34x35; + handles[33] = &grid_point32x33x34x35; + handles[34] = &grid_point32x33x34x35; + handles[35] = &grid_point32x33x34x35; + + Geom::Point origin = Geom::Point(boundingbox_X.min(),boundingbox_Y.min()); + + double width = boundingbox_X.extent(); + double height = boundingbox_Y.extent(); + + //numbering is based on 4 rectangles.16 + for(unsigned dim = 0; dim < 2; dim++) { + Geom::Point dir(0,0); + dir[dim] = 1; + for(unsigned vi = 0; vi < sb2[dim].vs; vi++) { + for(unsigned ui = 0; ui < sb2[dim].us; ui++) { + for(unsigned iv = 0; iv < 2; iv++) { + for(unsigned iu = 0; iu < 2; iu++) { + unsigned corner = iu + 2*iv; + unsigned i = ui + vi*sb2[dim].us; + + //This is the offset from the Upperleft point + Geom::Point base( (ui + iu*(4-2*ui))*width/4., + (vi + iv*(4-2*vi))*height/4.); + + //Special action for corners + if(vi == 0 && ui == 0) { + base = Geom::Point(0,0); + } + + // i = Upperleft corner of the considerated rectangle + // corner = actual corner of the rectangle + // origin = Upperleft point + double dl = dot((*handles[corner+4*i] - (base + origin)), dir)/dot(dir,dir); + sb2[dim][i][corner] = dl/( dim ? height : width )*pow(4.0,ui+vi); + } + } + } + } + } + + Piecewise<D2<SBasis> > output; + output.push_cut(0.); + for(unsigned i = 0; i < pwd2_in.size(); i++) { + D2<SBasis> B = pwd2_in[i]; + B[Geom::X] -= origin[Geom::X]; + B[Geom::X]*= 1/width; + B[Geom::Y] -= origin[Geom::Y]; + B[Geom::Y]*= 1/height; + //Here comes the magic + D2<SBasis> tB = compose_each(sb2,B); + tB[Geom::X] = tB[Geom::X] * width + origin[Geom::X]; + tB[Geom::Y] = tB[Geom::Y] * height + origin[Geom::Y]; + + output.push(tB,i+1); + } + return output; +} + +Gtk::Widget * +LPELattice2::newWidget() +{ + // use manage here, because after deletion of Effect object, others might still be pointing to this widget. + Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox(Effect::newWidget()) ); + + vbox->set_border_width(5); + Gtk::Button* resetButton = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset grid")))); + resetButton->set_alignment(0.0, 0.5); + resetButton->signal_clicked().connect(sigc::mem_fun (*this,&LPELattice2::resetGrid)); + Gtk::Widget* resetButtonWidget = dynamic_cast<Gtk::Widget *>(resetButton); + resetButtonWidget->set_tooltip_text("Reset grid"); + vbox->pack_start(*resetButtonWidget, true, true,2); + std::vector<Parameter *>::iterator it = param_vector.begin(); + while (it != param_vector.end()) { + if ((*it)->widget_is_visible) { + Parameter * param = *it; + Gtk::Widget * widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget()); + if(param->param_key == "grid"){ + widg = NULL; + } + Glib::ustring * tip = param->param_getTooltip(); + if (widg) { + vbox->pack_start(*widg, true, true, 2); + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } + + ++it; + } + return dynamic_cast<Gtk::Widget *>(vbox); +} + +void +LPELattice2::doBeforeEffect (SPLPEItem const* lpeitem) +{ + original_bbox(lpeitem); + setDefaults(); +} + +void +LPELattice2::setDefaults() +{ + Geom::Point gp0((boundingbox_X.max()-boundingbox_X.min())/4*0+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*0+boundingbox_Y.min()); + + Geom::Point gp1((boundingbox_X.max()-boundingbox_X.min())/4*4+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*0+boundingbox_Y.min()); + + Geom::Point gp2((boundingbox_X.max()-boundingbox_X.min())/4*0+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*4+boundingbox_Y.min()); + + Geom::Point gp3((boundingbox_X.max()-boundingbox_X.min())/4*4+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*4+boundingbox_Y.min()); + + Geom::Point gp4((boundingbox_X.max()-boundingbox_X.min())/4*1+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*0+boundingbox_Y.min()); + + Geom::Point gp5((boundingbox_X.max()-boundingbox_X.min())/4*3+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*0+boundingbox_Y.min()); + + Geom::Point gp6((boundingbox_X.max()-boundingbox_X.min())/4*1+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*4+boundingbox_Y.min()); + + Geom::Point gp7((boundingbox_X.max()-boundingbox_X.min())/4*3+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*4+boundingbox_Y.min()); + + Geom::Point gp8x9((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*0+boundingbox_Y.min()); + + Geom::Point gp10x11((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*4+boundingbox_Y.min()); + + Geom::Point gp12((boundingbox_X.max()-boundingbox_X.min())/4*0+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + + Geom::Point gp13((boundingbox_X.max()-boundingbox_X.min())/4*4+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + + Geom::Point gp14((boundingbox_X.max()-boundingbox_X.min())/4*0+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + + Geom::Point gp15((boundingbox_X.max()-boundingbox_X.min())/4*4+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + + Geom::Point gp16((boundingbox_X.max()-boundingbox_X.min())/4*1+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + + Geom::Point gp17((boundingbox_X.max()-boundingbox_X.min())/4*3+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + + Geom::Point gp18((boundingbox_X.max()-boundingbox_X.min())/4*1+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + + Geom::Point gp19((boundingbox_X.max()-boundingbox_X.min())/4*3+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + + Geom::Point gp20x21((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*1+boundingbox_Y.min()); + + Geom::Point gp22x23((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*3+boundingbox_Y.min()); + + Geom::Point gp24x26((boundingbox_X.max()-boundingbox_X.min())/4*0+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + + Geom::Point gp25x27((boundingbox_X.max()-boundingbox_X.min())/4*4+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + + Geom::Point gp28x30((boundingbox_X.max()-boundingbox_X.min())/4*1+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + + Geom::Point gp29x31((boundingbox_X.max()-boundingbox_X.min())/4*3+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + + Geom::Point gp32x33x34x35((boundingbox_X.max()-boundingbox_X.min())/4*2+boundingbox_X.min(), + (boundingbox_Y.max()-boundingbox_Y.min())/4*2+boundingbox_Y.min()); + + grid_point0.param_update_default(gp0); + grid_point1.param_update_default(gp1); + grid_point2.param_update_default(gp2); + grid_point3.param_update_default(gp3); + grid_point4.param_update_default(gp4); + grid_point5.param_update_default(gp5); + grid_point6.param_update_default(gp6); + grid_point7.param_update_default(gp7); + grid_point8x9.param_update_default(gp8x9); + grid_point10x11.param_update_default(gp10x11); + grid_point12.param_update_default(gp12); + grid_point13.param_update_default(gp13); + grid_point14.param_update_default(gp14); + grid_point15.param_update_default(gp15); + grid_point16.param_update_default(gp16); + grid_point17.param_update_default(gp17); + grid_point18.param_update_default(gp18); + grid_point19.param_update_default(gp19); + grid_point20x21.param_update_default(gp20x21); + grid_point22x23.param_update_default(gp22x23); + grid_point24x26.param_update_default(gp24x26); + grid_point25x27.param_update_default(gp25x27); + grid_point28x30.param_update_default(gp28x30); + grid_point29x31.param_update_default(gp29x31); + grid_point32x33x34x35.param_update_default(gp32x33x34x35); +} + +void +LPELattice2::resetGrid() +{ + grid_point0.param_set_and_write_default(); + grid_point1.param_set_and_write_default(); + grid_point2.param_set_and_write_default(); + grid_point3.param_set_and_write_default(); + grid_point4.param_set_and_write_default(); + grid_point5.param_set_and_write_default(); + grid_point6.param_set_and_write_default(); + grid_point7.param_set_and_write_default(); + grid_point8x9.param_set_and_write_default(); + grid_point10x11.param_set_and_write_default(); + grid_point12.param_set_and_write_default(); + grid_point13.param_set_and_write_default(); + grid_point14.param_set_and_write_default(); + grid_point15.param_set_and_write_default(); + grid_point16.param_set_and_write_default(); + grid_point17.param_set_and_write_default(); + grid_point18.param_set_and_write_default(); + grid_point19.param_set_and_write_default(); + grid_point20x21.param_set_and_write_default(); + grid_point22x23.param_set_and_write_default(); + grid_point24x26.param_set_and_write_default(); + grid_point25x27.param_set_and_write_default(); + grid_point28x30.param_set_and_write_default(); + grid_point29x31.param_set_and_write_default(); + grid_point32x33x34x35.param_set_and_write_default(); + //todo:this hack is only to reposition the knots on reser grid button + //Better update path effect in LPEITEM + SPDesktop * desktop = inkscape_active_desktop(); + tools_switch(desktop, TOOLS_SELECT); + tools_switch(desktop, TOOLS_NODES); +} + +void +LPELattice2::resetDefaults(SPItem const* item) +{ + Effect::resetDefaults(item); + original_bbox(SP_LPE_ITEM(item)); + setDefaults(); + resetGrid(); +} + +void +LPELattice2::calculateCurve(Geom::Point a,Geom::Point b, SPCurve* c, bool horizontal, bool move) +{ + using Geom::X; + using Geom::Y; + if(move) c->moveto(a); + Geom::Point cubic1 = a + (1./3)* (b - a); + Geom::Point cubic2 = b + (1./3)* (a - b); + if(horizontal) c->curveto(Geom::Point(cubic1[X],a[Y]),Geom::Point(cubic2[X],b[Y]),b); + else c->curveto(Geom::Point(a[X],cubic1[Y]),Geom::Point(b[X],cubic2[Y]),b); +} + +void +LPELattice2::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec) +{ + hp_vec.clear(); + + SPCurve *c = new SPCurve(); + calculateCurve(grid_point0,grid_point4, c,true, true); + calculateCurve(grid_point4,grid_point8x9, c,true, false); + calculateCurve(grid_point8x9,grid_point5, c,true, false); + calculateCurve(grid_point5,grid_point1, c,true, false); + + calculateCurve(grid_point12,grid_point16, c,true, true); + calculateCurve(grid_point16,grid_point20x21, c,true, false); + calculateCurve(grid_point20x21,grid_point17, c,true, false); + calculateCurve(grid_point17,grid_point13, c,true, false); + + calculateCurve(grid_point24x26,grid_point28x30, c,true, true); + calculateCurve(grid_point28x30,grid_point32x33x34x35, c,true, false); + calculateCurve(grid_point32x33x34x35,grid_point29x31, c,true, false); + calculateCurve(grid_point29x31,grid_point25x27, c,true, false); + + calculateCurve(grid_point14,grid_point18, c,true, true); + calculateCurve(grid_point18,grid_point22x23, c,true, false); + calculateCurve(grid_point22x23,grid_point19, c,true, false); + calculateCurve(grid_point19,grid_point15, c,true, false); + + calculateCurve(grid_point2,grid_point6, c,true, true); + calculateCurve(grid_point6,grid_point10x11, c,true, false); + calculateCurve(grid_point10x11,grid_point7, c,true, false); + calculateCurve(grid_point7,grid_point3, c,true, false); + + calculateCurve(grid_point0,grid_point12, c,false, true); + calculateCurve(grid_point12,grid_point24x26, c,false, false); + calculateCurve(grid_point24x26,grid_point14, c,false, false); + calculateCurve(grid_point14,grid_point2, c,false, false); + + calculateCurve(grid_point4,grid_point16, c,false, true); + calculateCurve(grid_point16,grid_point28x30, c,false, false); + calculateCurve(grid_point28x30,grid_point18, c,false, false); + calculateCurve(grid_point18,grid_point6, c,false, false); + + calculateCurve(grid_point8x9,grid_point20x21, c,false, true); + calculateCurve(grid_point20x21,grid_point32x33x34x35, c,false, false); + calculateCurve(grid_point32x33x34x35,grid_point22x23, c,false, false); + calculateCurve(grid_point22x23,grid_point10x11, c,false, false); + + calculateCurve(grid_point5,grid_point17, c, false, true); + calculateCurve(grid_point17,grid_point29x31, c,false, false); + calculateCurve(grid_point29x31,grid_point19, c,false, false); + calculateCurve(grid_point19,grid_point7, c,false, false); + + calculateCurve(grid_point1,grid_point13, c, false, true); + calculateCurve(grid_point13,grid_point25x27, c,false, false); + calculateCurve(grid_point25x27,grid_point15, c,false, false); + calculateCurve(grid_point15,grid_point3, c, false, false); + hp_vec.push_back(c->get_pathvector()); +} + + +/* ######################## */ + +} //namespace LivePathEffect +} /* 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 : diff --git a/src/live_effects/lpe-lattice2.h b/src/live_effects/lpe-lattice2.h new file mode 100644 index 000000000..461f835c6 --- /dev/null +++ b/src/live_effects/lpe-lattice2.h @@ -0,0 +1,92 @@ +#ifndef INKSCAPE_LPE_LATTICE2_H +#define INKSCAPE_LPE_LATTICE2_H + +/** \file + * LPE <lattice2> implementation, see lpe-lattice2.cpp. + */ + +/* + * Authors: + * Johan Engelen + * Steren Giannini + * Noé Falzon + * Victor Navez + * ~suv + * Jabiertxo Arraiza +* +* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/parameter/enum.h" +#include "live_effects/effect.h" +#include "live_effects/parameter/pointreseteable.h" +#include "live_effects/lpegroupbbox.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPELattice2 : public Effect, GroupBBoxEffect { +public: + + LPELattice2(LivePathEffectObject *lpeobject); + virtual ~LPELattice2(); + + virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); + + virtual void resetDefaults(SPItem const* item); + + virtual void doBeforeEffect(SPLPEItem const* lpeitem); + + virtual Gtk::Widget * newWidget(); + + virtual void calculateCurve(Geom::Point a,Geom::Point b, SPCurve *c, bool horizontal, bool move); + + virtual void setDefaults(); + + virtual void resetGrid(); + + //virtual void original_bbox(SPLPEItem const* lpeitem, bool absolute = false); + + //virtual void addCanvasIndicators(SPLPEItem const*/*lpeitem*/, std::vector<Geom::PathVector> &/*hp_vec*/); + + //virtual std::vector<Geom::PathVector> getHelperPaths(SPLPEItem const* lpeitem); +protected: + void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec); +private: + + PointReseteableParam grid_point0; + PointReseteableParam grid_point1; + PointReseteableParam grid_point2; + PointReseteableParam grid_point3; + PointReseteableParam grid_point4; + PointReseteableParam grid_point5; + PointReseteableParam grid_point6; + PointReseteableParam grid_point7; + PointReseteableParam grid_point8x9; + PointReseteableParam grid_point10x11; + PointReseteableParam grid_point12; + PointReseteableParam grid_point13; + PointReseteableParam grid_point14; + PointReseteableParam grid_point15; + PointReseteableParam grid_point16; + PointReseteableParam grid_point17; + PointReseteableParam grid_point18; + PointReseteableParam grid_point19; + PointReseteableParam grid_point20x21; + PointReseteableParam grid_point22x23; + PointReseteableParam grid_point24x26; + PointReseteableParam grid_point25x27; + PointReseteableParam grid_point28x30; + PointReseteableParam grid_point29x31; + PointReseteableParam grid_point32x33x34x35; + + LPELattice2(const LPELattice2&); + LPELattice2& operator=(const LPELattice2&); +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +#endif diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp new file mode 100644 index 000000000..d010e75a2 --- /dev/null +++ b/src/live_effects/lpe-simplify.cpp @@ -0,0 +1,287 @@ +#define INKSCAPE_LPE_SIMPLIFY_C +/* + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#include <gtkmm/box.h> +#include <gtkmm/entry.h> +#include "live_effects/lpe-simplify.h" +#include "display/curve.h" +#include "live_effects/parameter/parameter.h" +#include <glibmm/i18n.h> +#include "helper/geom.h" +#include "livarot/Path.h" +#include "splivarot.h" +#include <2geom/svg-path-parser.h> +#include "desktop.h" +#include "inkscape.h" +#include "svg/svg.h" +#include "ui/tools/node-tool.h" +#include <2geom/d2.h> +#include <2geom/generic-rect.h> +#include <2geom/interval.h> + + +namespace Inkscape { +namespace LivePathEffect { + +LPESimplify::LPESimplify(LivePathEffectObject *lpeobject) + : Effect(lpeobject), + steps(_("Steps:"),_("Change number of simplify steps "), "steps", &wr, this,1), + threshold(_("Roughly threshold:"), _("Roughly threshold:"), "threshold", &wr, this, 0.003), + helper_size(_("Helper size:"), _("Helper size"), "helper_size", &wr, this, 2.), + nodes(_("Helper nodes"), _("Show helper nodes"), "nodes", &wr, this, false), + handles(_("Helper handles"), _("Show helper handles"), "handles", &wr, this, false), + simplifyindividualpaths(_("Paths separately"), _("Simplifying paths (separately)"), "simplifyindividualpaths", &wr, this, false), + simplifyJustCoalesce(_("Just coalesce"), _("Simplify just coalesce"), "simplifyJustCoalesce", &wr, this, false) + { + registerParameter(dynamic_cast<Parameter *>(&steps)); + registerParameter(dynamic_cast<Parameter *>(&threshold)); + registerParameter(dynamic_cast<Parameter *>(&helper_size)); + registerParameter(dynamic_cast<Parameter *>(&nodes)); + registerParameter(dynamic_cast<Parameter *>(&handles)); + registerParameter(dynamic_cast<Parameter *>(&simplifyindividualpaths)); + registerParameter(dynamic_cast<Parameter *>(&simplifyJustCoalesce)); + threshold.param_set_range(0., Geom::infinity()); + threshold.param_set_increments(0.0001, 0.0001); + threshold.param_set_digits(6); + steps.param_set_range(0, 100); + steps.param_set_increments(1, 1); + steps.param_set_digits(0); + helper_size.param_set_range(0.1, 100); + helper_size.param_set_increments(1, 1); + helper_size.param_set_digits(1); +} + +LPESimplify::~LPESimplify() {} + +void +LPESimplify::doBeforeEffect (SPLPEItem const* lpeitem) +{ + if(!hp.empty()){ + hp.clear(); + } + bbox = SP_ITEM(lpeitem)->visualBounds(); + +} + +Gtk::Widget * +LPESimplify::newWidget() +{ + // use manage here, because after deletion of Effect object, others might still be pointing to this widget. + Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox(Effect::newWidget()) ); + vbox->set_border_width(5); + vbox->set_homogeneous(false); + vbox->set_spacing(2); + std::vector<Parameter *>::iterator it = param_vector.begin(); + Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true,0)); + Gtk::HBox * buttonsTwo = Gtk::manage(new Gtk::HBox(true,0)); + while (it != param_vector.end()) { + if ((*it)->widget_is_visible) { + Parameter * param = *it; + Gtk::Widget * widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget()); + if (param->param_key == "simplifyindividualpaths" || + param->param_key == "simplifyJustCoalesce") + { + Glib::ustring * tip = param->param_getTooltip(); + if (widg) { + buttonsTwo->pack_start(*widg, true, true, 2); + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } else if (param->param_key == "nodes" || + param->param_key == "handles") + { + Glib::ustring * tip = param->param_getTooltip(); + if (widg) { + buttons->pack_start(*widg, true, true, 2); + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + }else{ + Glib::ustring * tip = param->param_getTooltip(); + if (widg) { + Gtk::HBox * scalarParameter = dynamic_cast<Gtk::HBox *>(widg); + std::vector< Gtk::Widget* > childList = scalarParameter->get_children(); + Gtk::Entry* entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]); + entryWidg->set_width_chars(8); + vbox->pack_start(*widg, true, true, 2); + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } + } + + ++it; + } + vbox->pack_start(*buttons,true, true, 2); + vbox->pack_start(*buttonsTwo,true, true, 2); + return dynamic_cast<Gtk::Widget *>(vbox); +} + +void +LPESimplify::doEffect(SPCurve *curve) { + Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); + gdouble size = Geom::L2(bbox->dimensions()); + //size /= Geom::Affine(0,0,0,0,0,0).descrim(); + Path* pathliv = Path_for_pathvector(original_pathv); + if(simplifyindividualpaths){ + size = Geom::L2(Geom::bounds_fast(original_pathv)->dimensions()); + } + for (int unsigned i = 0; i < steps; i++){ + if ( simplifyJustCoalesce ) { + pathliv->Coalesce(threshold * size); + }else{ + pathliv->ConvertEvenLines(threshold * size); + pathliv->Simplify(threshold * size); + } + } + Geom::PathVector outres = Geom::parse_svg_path(pathliv->svg_dump_path()); + generateHelperPath(outres); + curve->set_pathvector(outres); + if(SP_ACTIVE_DESKTOP && INK_IS_NODE_TOOL(SP_ACTIVE_DESKTOP->event_context)){ + SPDesktop* desktop = SP_ACTIVE_DESKTOP; + Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(desktop->event_context); + nt->update_helperpath(); + } +} + +void +LPESimplify::generateHelperPath(Geom::PathVector result) +{ + if(!handles && !nodes){ + return; + } + + if(steps < 1){ + return; + } + + Geom::CubicBezier const *cubic = NULL; + for (Geom::PathVector::iterator path_it = result.begin(); path_it != result.end(); ++path_it) { + //Si está vacÃo... + if (path_it->empty()){ + continue; + } + //Itreadores + Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve + Geom::Path::const_iterator curve_it2 = + ++(path_it->begin()); // outgoing curve + Geom::Path::const_iterator curve_endit = + path_it->end_default(); // this determines when the loop has to stop + + if (path_it->closed()) { + // if the path is closed, maybe we have to stop a bit earlier because the + // closing line segment has zerolength. + const Geom::Curve &closingline = + path_it->back_closed(); // the closing line segment is always of type + // Geom::LineSegment. + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + // closingline.isDegenerate() did not work, because it only checks for + // *exact* zero length, which goes wrong for relative coordinates and + // rounding errors... + // the closing line segment has zero-length. So stop before that one! + curve_endit = path_it->end_open(); + } + } + if(nodes){ + drawNode(curve_it1->initialPoint()); + } + while (curve_it2 != curve_endit) { + cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); + if (cubic) { + if(handles){ + drawHandle((*cubic)[1]); + drawHandle((*cubic)[2]); + drawHandleLine((*cubic)[0],(*cubic)[1]); + drawHandleLine((*cubic)[2],(*cubic)[3]); + } + } + if(nodes){ + drawNode(curve_it1->finalPoint()); + } + ++curve_it1; + ++curve_it2; + } + cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); + if (cubic) { + if(handles){ + drawHandle((*cubic)[1]); + drawHandle((*cubic)[2]); + drawHandleLine((*cubic)[0],(*cubic)[1]); + drawHandleLine((*cubic)[2],(*cubic)[3]); + } + } + if(nodes){ + drawNode(curve_it1->finalPoint()); + } + } +} + +void +LPESimplify::drawNode(Geom::Point p) +{ + double r = helper_size/0.67; + char const * svgd; + svgd = "M 0.999993,0.5 C 1.000065,0.7757576 0.7761859,1 0.4999926,1 0.2237994,1 -7.933901e-5,0.7757576 -7.339015e-6,0.5 -7.933901e-5,0.2242424 0.2237994,0 0.4999926,0 0.7761859,0 1.000065,0.2242424 0.999993,0.5 Z m -0.058561,0 C 0.9414949,0.74327 0.7438375,0.9416286 0.4999928,0.9416286 0.2561481,0.9416286 0.0584908,0.74327 0.0585543,0.5 0.0584908,0.25673 0.2561481,0.0583714 0.4999928,0.0583714 0.7438375,0.0583714 0.9414949,0.25673 0.9414313,0.5 Z m -0.3828447,0 c 8.5e-6,0.030303 -0.026228,0.060606 -0.058593,0.060606 -0.032366,0 -0.058603,-0.030303 -0.058593,-0.060606 -8.5e-6,-0.030303 0.026227,-0.060606 0.058593,-0.060606 0.032366,0 0.058603,0.030303 0.058593,0.060606 z"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + pathv *= Geom::Affine(r,0,0,r,0,0); + pathv += p - Geom::Point(0.5*r,0.5*r); + hp.push_back(pathv[0]); + hp.push_back(pathv[1]); + hp.push_back(pathv[2]); +} + +void +LPESimplify::drawHandle(Geom::Point p) +{ + double r = helper_size/0.67; + char const * svgd; + svgd = "M 0.6999623,0.35 C 0.7000128,0.5430303 0.5433044,0.7 0.3499775,0.7 0.1566506,0.7 -5.778776e-5,0.5430303 -7.344202e-6,0.35 -5.778776e-5,0.1569697 0.1566506,0 0.3499775,0 0.5433044,0 0.7000128,0.1569697 0.6999623,0.35 Z"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + pathv *= Geom::Affine(r,0,0,r,0,0); + pathv += p - Geom::Point(0.35*r,0.35*r); + hp.push_back(pathv[0]); +} + + +void +LPESimplify::drawHandleLine(Geom::Point p,Geom::Point p2) +{ + Geom::Path path; + path.start( p ); + path.appendNew<Geom::LineSegment>( p2 ); + hp.push_back(path); +} + +void +LPESimplify::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec) +{ + hp_vec.push_back(hp); +} + + +}; //namespace LivePathEffect +}; /* 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 : diff --git a/src/live_effects/lpe-simplify.h b/src/live_effects/lpe-simplify.h new file mode 100644 index 000000000..6acf2f2d4 --- /dev/null +++ b/src/live_effects/lpe-simplify.h @@ -0,0 +1,59 @@ +#ifndef INKSCAPE_LPE_SIMPLIFY_H +#define INKSCAPE_LPE_SIMPLIFY_H + +/* + * Inkscape::LPESimplify + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/effect.h" +#include "live_effects/parameter/togglebutton.h" +#include "live_effects/lpegroupbbox.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPESimplify : public Effect , GroupBBoxEffect{ + +public: + LPESimplify(LivePathEffectObject *lpeobject); + virtual ~LPESimplify(); + + virtual void doEffect(SPCurve *curve); + + virtual void doBeforeEffect (SPLPEItem const* lpeitem); + + virtual void generateHelperPath(Geom::PathVector result); + + virtual Gtk::Widget * newWidget(); + + virtual void drawNode(Geom::Point p); + + virtual void drawHandle(Geom::Point p); + + virtual void drawHandleLine(Geom::Point p,Geom::Point p2); + +protected: + void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec); + +private: + ScalarParam steps; + ScalarParam threshold; + ScalarParam helper_size; + ToggleButtonParam nodes; + ToggleButtonParam handles; + ToggleButtonParam simplifyindividualpaths; + ToggleButtonParam simplifyJustCoalesce; + + Geom::PathVector hp; + Geom::OptRect bbox; + + LPESimplify(const LPESimplify &); + LPESimplify &operator=(const LPESimplify &); + +}; + +}; //namespace LivePathEffect +}; //namespace Inkscape +#endif diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index c0050fa60..8b0b716fe 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -4,11 +4,10 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include <cstdio> +#include "live_effects/lpe-vonkoch.h" #include <glibmm/i18n.h> -#include "live_effects/lpe-vonkoch.h" #include <2geom/transforms.h> //using std::vector; diff --git a/src/live_effects/parameter/Makefile_insert b/src/live_effects/parameter/Makefile_insert index 37cc3dc62..330035ad6 100644 --- a/src/live_effects/parameter/Makefile_insert +++ b/src/live_effects/parameter/Makefile_insert @@ -11,6 +11,8 @@ ink_common_sources += \ live_effects/parameter/random.h \ live_effects/parameter/point.cpp \ live_effects/parameter/point.h \ + live_effects/parameter/pointreseteable.cpp \ + live_effects/parameter/pointreseteable.h \ live_effects/parameter/enum.h \ live_effects/parameter/path-reference.cpp \ live_effects/parameter/path-reference.h \ @@ -26,6 +28,8 @@ ink_common_sources += \ live_effects/parameter/text.h \ live_effects/parameter/transformedpoint.cpp \ live_effects/parameter/transformedpoint.h \ + live_effects/parameter/togglebutton.cpp \ + live_effects/parameter/togglebutton.h \ live_effects/parameter/unit.cpp \ live_effects/parameter/unit.h \ live_effects/parameter/vector.cpp \ diff --git a/src/live_effects/parameter/pointreseteable.cpp b/src/live_effects/parameter/pointreseteable.cpp new file mode 100644 index 000000000..ec36fc035 --- /dev/null +++ b/src/live_effects/parameter/pointreseteable.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "ui/widget/registered-widget.h" +#include "live_effects/parameter/pointreseteable.h" +#include "live_effects/effect.h" +#include "svg/svg.h" +#include "svg/stringstream.h" +#include "ui/widget/point.h" +#include "widgets/icon.h" +#include "inkscape.h" +#include "verbs.h" +#include "knotholder.h" +#include <glibmm/i18n.h> +#include "tools-switch.h" +#include "ui/tools/node-tool.h" + +// needed for on-canvas editting: +#include "desktop.h" + +namespace Inkscape { + +namespace LivePathEffect { + +PointReseteableParam::PointReseteableParam( const Glib::ustring& label, const Glib::ustring& tip, + const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, + Effect* effect, const gchar *htip, Geom::Point default_value) + : Geom::Point(default_value), Parameter(label, tip, key, wr, effect), defvalue(default_value) +{ + knot_shape = SP_KNOT_SHAPE_DIAMOND; + knot_mode = SP_KNOT_MODE_XOR; + knot_color = 0xffffff00; + handle_tip = g_strdup(htip); +} + +PointReseteableParam::~PointReseteableParam() +{ + if (handle_tip) + g_free(handle_tip); +} + +void +PointReseteableParam::param_set_default() +{ + param_setValue(defvalue); +} + +void +PointReseteableParam::param_set_and_write_default() +{ + param_set_and_write_new_value(defvalue); +} + +void +PointReseteableParam::param_update_default(Geom::Point newpoint) +{ + this->defvalue = newpoint; +} + +bool +PointReseteableParam::param_readSVGValue(const gchar * strvalue) +{ + gchar ** strarray = g_strsplit(strvalue, ",", 2); + double newx, newy; + unsigned int success = sp_svg_number_read_d(strarray[0], &newx); + success += sp_svg_number_read_d(strarray[1], &newy); + g_strfreev (strarray); + if (success == 2) { + param_setValue( Geom::Point(newx, newy) ); + return true; + } + return false; +} + +gchar * +PointReseteableParam::param_getSVGValue() const +{ + Inkscape::SVGOStringStream os; + os << *dynamic_cast<Geom::Point const *>( this ); + gchar * str = g_strdup(os.str().c_str()); + return str; +} + +Gtk::Widget * +PointReseteableParam::param_newWidget() +{ + Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg = Gtk::manage( + new Inkscape::UI::Widget::RegisteredTransformedPoint( param_label, + param_tooltip, + param_key, + *param_wr, + param_effect->getRepr(), + param_effect->getSPDoc() ) ); + // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP) + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + Geom::Affine transf = desktop->doc2dt(); + pointwdg->setTransform(transf); + pointwdg->setValue( *this ); + pointwdg->clearProgrammatically(); + pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change point parameter")); + + Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() ); + static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true); + static_cast<Gtk::HBox*>(hbox)->show_all_children(); + + return dynamic_cast<Gtk::Widget *> (hbox); +} + +void +PointReseteableParam::param_setValue(Geom::Point newpoint) +{ + *dynamic_cast<Geom::Point *>( this ) = newpoint; + if(SP_ACTIVE_DESKTOP){ + SPDesktop* desktop = SP_ACTIVE_DESKTOP; + if (tools_isactive( desktop, TOOLS_NODES)) { + Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>( desktop->event_context); + nt->update_helperpath(); + } + } +} + +void +PointReseteableParam::param_set_and_write_new_value (Geom::Point newpoint) +{ + Inkscape::SVGOStringStream os; + os << newpoint; + gchar * str = g_strdup(os.str().c_str()); + param_write_to_repr(str); + g_free(str); +} + +void +PointReseteableParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) +{ + param_set_and_write_new_value( (*this) * postmul ); +} + + +void +PointReseteableParam::set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color) +{ + knot_shape = shape; + knot_mode = mode; + knot_color = color; +} + +class PointReseteableParamKnotHolderEntity : public KnotHolderEntity { +public: + PointReseteableParamKnotHolderEntity(PointReseteableParam *p) { this->pparam = p; } + virtual ~PointReseteableParamKnotHolderEntity() {} + + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); + virtual Geom::Point knot_get() const; + virtual void knot_click(guint state); + +private: + PointReseteableParam *pparam; +}; + +void +PointReseteableParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) +{ + Geom::Point const s = snap_knot_position(p, state); + pparam->param_setValue(s); + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); +} + +Geom::Point +PointReseteableParamKnotHolderEntity::knot_get() const +{ + return *pparam; +} + +void +PointReseteableParamKnotHolderEntity::knot_click(guint state) +{ + if (state & GDK_CONTROL_MASK) { + if (state & GDK_MOD1_MASK) { + this->pparam->param_set_default(); + sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); + } + } +} + +void +PointReseteableParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +{ + PointReseteableParamKnotHolderEntity *e = new PointReseteableParamKnotHolderEntity(this); + // TODO: can we ditch handleTip() etc. because we have access to handle_tip etc. itself??? + e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), knot_shape, knot_mode, knot_color); + knotholder->add(e); +} + +} /* namespace LivePathEffect */ + +} /* 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 : diff --git a/src/live_effects/parameter/pointreseteable.h b/src/live_effects/parameter/pointreseteable.h new file mode 100644 index 000000000..5ae1fdf02 --- /dev/null +++ b/src/live_effects/parameter/pointreseteable.h @@ -0,0 +1,74 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_POINT_RESETEABLE_H +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_POINT_RESETEABLE_H + +/* + * Inkscape::LivePathEffectParameters + * +* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <glib.h> +#include <2geom/point.h> + +#include "live_effects/parameter/parameter.h" + +#include "knot-holder-entity.h" + +namespace Inkscape { + +namespace LivePathEffect { + +class PointReseteableParamKnotHolderEntity; + +class PointReseteableParam : public Geom::Point, public Parameter { +public: + PointReseteableParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect, + const gchar *handle_tip = NULL, + Geom::Point default_value = Geom::Point(0,0) ); // tip for automatically associated on-canvas handle + virtual ~PointReseteableParam(); + + virtual Gtk::Widget * param_newWidget(); + + bool param_readSVGValue(const gchar * strvalue); + gchar * param_getSVGValue() const; + inline const gchar *handleTip() const { return handle_tip ? handle_tip : param_tooltip.c_str(); } + + void param_setValue(Geom::Point newpoint); + void param_set_default(); + void param_set_and_write_default(); + void param_update_default(Geom::Point newpoint); + + void param_set_and_write_new_value(Geom::Point newpoint); + + virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/); + + void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); + + virtual bool providesKnotHolderEntities() const { return true; } + virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); + + friend class PointReseteableParamKnotHolderEntity; +private: + PointReseteableParam(const PointReseteableParam&); + PointReseteableParam& operator=(const PointReseteableParam&); + + Geom::Point defvalue; + + SPKnotShapeType knot_shape; + SPKnotModeType knot_mode; + guint32 knot_color; + gchar *handle_tip; +}; + + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp new file mode 100644 index 000000000..03238f935 --- /dev/null +++ b/src/live_effects/parameter/togglebutton.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> + * Copyright (C) Jabiertxo Arraiza Cenoz 2014 <j.b.c.engelen@utwente.nl> + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "ui/widget/registered-widget.h" +#include "live_effects/parameter/togglebutton.h" +#include "live_effects/effect.h" +#include "svg/svg.h" +#include "svg/stringstream.h" +#include "widgets/icon.h" +#include "inkscape.h" +#include "verbs.h" +#include "helper-fns.h" +#include <glibmm/i18n.h> + +namespace Inkscape { + +namespace LivePathEffect { + +ToggleButtonParam::ToggleButtonParam( const Glib::ustring& label, const Glib::ustring& tip, + const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, + Effect* effect, bool default_value ) + : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value) +{ +} + +ToggleButtonParam::~ToggleButtonParam() +{ +} + +void +ToggleButtonParam::param_set_default() +{ + param_setValue(defvalue); +} + +bool +ToggleButtonParam::param_readSVGValue(const gchar * strvalue) +{ + param_setValue(helperfns_read_bool(strvalue, defvalue)); + return true; // not correct: if value is unacceptable, should return false! +} + +gchar * +ToggleButtonParam::param_getSVGValue() const +{ + gchar * str = g_strdup(value ? "true" : "false"); + return str; +} + +Gtk::Widget * +ToggleButtonParam::param_newWidget() +{ + Inkscape::UI::Widget::RegisteredToggleButton * checkwdg = Gtk::manage( + new Inkscape::UI::Widget::RegisteredToggleButton( param_label, + param_tooltip, + param_key, + *param_wr, + false, + param_effect->getRepr(), + param_effect->getSPDoc()) ); + + checkwdg->setActive(value); + checkwdg->setProgrammatically = false; + checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change togglebutton parameter")); + + return dynamic_cast<Gtk::Widget *> (checkwdg); +} + +void +ToggleButtonParam::param_setValue(bool newvalue) +{ + value = newvalue; +} + +} /* namespace LivePathEffect */ + +} /* 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 : diff --git a/src/live_effects/parameter/togglebutton.h b/src/live_effects/parameter/togglebutton.h new file mode 100644 index 000000000..9b1c71185 --- /dev/null +++ b/src/live_effects/parameter/togglebutton.h @@ -0,0 +1,56 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_TOGGLEBUTTON_H +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_TOGGLEBUTTON_H + +/* + * Inkscape::LivePathEffectParameters + * +* Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl> + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <glib.h> + +#include "live_effects/parameter/parameter.h" + +namespace Inkscape { + +namespace LivePathEffect { + + +class ToggleButtonParam : public Parameter { +public: + ToggleButtonParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect, + bool default_value = false); + virtual ~ToggleButtonParam(); + + virtual Gtk::Widget * param_newWidget(); + + virtual bool param_readSVGValue(const gchar * strvalue); + virtual gchar * param_getSVGValue() const; + + void param_setValue(bool newvalue); + virtual void param_set_default(); + + bool get_value() const { return value; }; + + inline operator bool() const { return value; }; + +private: + ToggleButtonParam(const ToggleButtonParam&); + ToggleButtonParam& operator=(const ToggleButtonParam&); + + bool value; + bool defvalue; +}; + + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif diff --git a/src/prefix.cpp b/src/prefix.cpp index 99e20171f..630d6caa8 100644 --- a/src/prefix.cpp +++ b/src/prefix.cpp @@ -44,9 +44,6 @@ extern "C" { #endif /* __cplusplus */ -#undef NULL -#define NULL ((void *) 0) - #ifdef __GNUC__ #define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "** BinReloc (%s): assertion %s failed\n", __PRETTY_FUNCTION__, #expr); return val;} #else diff --git a/src/sp-paint-server.cpp b/src/sp-paint-server.cpp index 692265bd8..77ad7a35f 100644 --- a/src/sp-paint-server.cpp +++ b/src/sp-paint-server.cpp @@ -58,6 +58,11 @@ bool SPPaintServer::isSolid() const return solid; } +bool SPPaintServer::isValid() const +{ + return true; +} + /* Local Variables: mode:c++ diff --git a/src/sp-paint-server.h b/src/sp-paint-server.h index 02e2f10ec..c1c8d651e 100644 --- a/src/sp-paint-server.h +++ b/src/sp-paint-server.h @@ -29,6 +29,7 @@ public: bool isSwatch() const; bool isSolid() const; + virtual bool isValid() const; virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity) = 0; diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index e465565c4..9aa54eadf 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -541,6 +541,16 @@ static bool pattern_hasItemChildren (SPPattern const *pat) return hasChildren; } +bool SPPattern::isValid() const +{ + double tile_width = pattern_width(this); + double tile_height = pattern_height(this); + + if (tile_width <= 0 || tile_height <= 0) + return false; + return true; +} + cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &bbox, double opacity) { bool needs_opacity = (1.0 - opacity) >= 1e-3; @@ -593,7 +603,7 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b double tile_y = pattern_y(this); double tile_width = pattern_width(this); double tile_height = pattern_height(this); - if (pattern_patternUnits(this) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { + if ( bbox && (pattern_patternUnits(this) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) ) { tile_x *= bbox->width(); tile_y *= bbox->height(); tile_width *= bbox->width(); @@ -614,7 +624,7 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b } else { // Content to bbox - if (pattern_patternContentUnits (this) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { + if (bbox && (pattern_patternContentUnits(this) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) ) { content2ps = Geom::Affine(bbox->width(), 0.0, 0.0, bbox->height(), 0,0); } } diff --git a/src/sp-pattern.h b/src/sp-pattern.h index f69ba10b3..eb34b6714 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -56,6 +56,8 @@ public: sigc::connection modified_connection; + bool isValid() const; + virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); protected: diff --git a/src/sp-tag-use-reference.h b/src/sp-tag-use-reference.h index b38e45837..f4c0e6a94 100644 --- a/src/sp-tag-use-reference.h +++ b/src/sp-tag-use-reference.h @@ -19,7 +19,7 @@ class Path; namespace Inkscape { namespace XML { - struct Node; + class Node; } } diff --git a/src/style-internal.cpp b/src/style-internal.cpp index df08d0adf..b15892128 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -65,13 +65,13 @@ SPIFloat::read( gchar const *str ) { if( !str ) return; if ( !strcmp(str, "inherit") ) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else { gfloat value_tmp; if (sp_svg_number_read_f(str, &value_tmp)) { - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; value = value_tmp; } } @@ -140,13 +140,13 @@ SPIScale24::read( gchar const *str ) { if( !str ) return; if ( !strcmp(str, "inherit") ) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else { gfloat value_in; if (sp_svg_number_read_f(str, &value_in)) { - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; value_in = CLAMP(value_in, 0.0, 1.0); value = SP_SCALE24_FROM_FLOAT( value_in ); } @@ -228,8 +228,8 @@ SPILength::read( gchar const *str ) { if( !str ) return; if (!strcmp(str, "inherit")) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; unit = SP_CSS_UNIT_NONE; value = computed = 0.0; } else { @@ -291,8 +291,8 @@ SPILength::read( gchar const *str ) { /* Invalid */ return; } - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; } } } @@ -439,11 +439,11 @@ SPILengthOrNormal::read( gchar const *str ) { if( !str ) return; if ( !strcmp(str, "normal") ) { - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; unit = SP_CSS_UNIT_NONE; value = computed = 0.0; - normal = TRUE; + normal = true; } else { SPILength::read( str ); normal = false; @@ -501,13 +501,13 @@ SPIEnum::read( gchar const *str ) { if( !str ) return; if( !strcmp(str, "inherit") ) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else { for (unsigned i = 0; enums[i].key; i++) { if (!strcmp(str, enums[i].key)) { - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; value = enums[i].value; /* Save copying for values not needing it */ computed = value; @@ -648,17 +648,20 @@ SPIString::read( gchar const *str ) { if( !str ) return; - g_free(value); + // libcroco puts quotes around some strings... remove + gchar *str_unquoted = attribute_unquote(str); if (!strcmp(str, "inherit")) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; value = NULL; } else { - set = TRUE; - inherit = FALSE; - value = g_strdup(str); + set = true; + inherit = false; + value = g_strdup(str_unquoted); } + + g_free( str_unquoted ); } @@ -762,13 +765,13 @@ void SPIColor::read( gchar const *str ) { if( name.compare( "color") == 0 ) { inherit = true; // CSS3 } else { - value.color = style->color.value.color; + setColor( style->color.value.color ); } } else { guint32 const rgb0 = sp_svg_read_color(str, 0xff); if (rgb0 != 0xff) { setColor(rgb0); - set = TRUE; + set = true; } } } @@ -821,7 +824,7 @@ SPIColor::cascade( const SPIBase* const parent ) { if( const SPIColor* p = dynamic_cast<const SPIColor*>(parent) ) { if( (inherits && !set) || inherit) { // FIXME verify for 'color' if( !(inherit && currentcolor) ) currentcolor = p->currentcolor; - value.color = p->value.color; + setColor( p->value.color ); } else { // Add CSS4 Color: Lighter, Darker } @@ -910,8 +913,8 @@ SPIPaint::read( gchar const *str ) { } if (streq(str, "inherit")) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else { // Read any URL first. The other values can be stand-alone or backup to the URL. @@ -924,7 +927,7 @@ SPIPaint::read( gchar const *str ) { } else if (!style ) { std::cerr << "SPIPaint::read: url with empty SPStyle pointer" << std::endl; } else { - set = TRUE; + set = true; SPDocument *document = (style->object) ? style->object->document : NULL; // Create href if not done already @@ -946,17 +949,17 @@ SPIPaint::read( gchar const *str ) { } if (streq(str, "currentColor")) { - set = TRUE; - currentcolor = TRUE; - value.color = style->color.value.color; + set = true; + currentcolor = true; + setColor( style->color.value.color ); } else if (streq(str, "none")) { - set = TRUE; - noneSet = TRUE; + set = true; + noneSet = true; } else { guint32 const rgb0 = sp_svg_read_color(str, &str, 0xff); if (rgb0 != 0xff) { setColor( rgb0 ); - set = TRUE; + set = true; while (g_ascii_isspace(*str)) { ++str; @@ -1076,7 +1079,7 @@ SPIPaint::reset( bool init ) { setColor(0.0, 0.0, 0.0); } if( name.compare( "text-decoration-color" ) == 0 ) { - currentcolor = true; + // currentcolor = true; } } } @@ -1100,10 +1103,10 @@ SPIPaint::cascade( const SPIBase* const parent ) { } else if( p->isColor() ) { setColor( p->value.color ); } else if( p->isNoneSet() ) { - noneSet = TRUE; + noneSet = true; } else if( p->currentcolor ) { - currentcolor = TRUE; - value.color = style->color.value.color; + currentcolor = true; + setColor( style->color.value.color ); } else if( isNone() ) { // } else { @@ -1112,7 +1115,7 @@ SPIPaint::cascade( const SPIBase* const parent ) { } else { if( currentcolor ) { // Update in case color value changed. - value.color = style->color.value.color; + setColor( style->color.value.color ); } } @@ -1179,14 +1182,14 @@ SPIPaintOrder::read( gchar const *str ) { if( !str ) return; g_free(value); - set = FALSE; - inherit = FALSE; + set = false; + inherit = false; if (!strcmp(str, "inherit")) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else { - set = TRUE; + set = true; value = g_strdup(str); if (!strcmp(value, "normal")) { @@ -1347,10 +1350,10 @@ SPIFilter::read( gchar const *str ) { clear(); if ( streq(str, "inherit") ) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else if(streq(str, "none")) { - set = TRUE; + set = true; } else if (strneq(str, "url", 3)) { gchar *uri = extract_uri(str); if(uri == NULL || uri[0] == '\0') { @@ -1360,7 +1363,7 @@ SPIFilter::read( gchar const *str ) { std::cerr << "SPIFilter::read: url with empty SPStyle pointer" << std::endl; return; } - set = TRUE; + set = true; // Create href if not already done. if (!href && style->object) { @@ -1592,14 +1595,14 @@ SPIFontSize::read( gchar const *str ) { if( !str ) return; if (!strcmp(str, "inherit")) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else if ((*str == 'x') || (*str == 's') || (*str == 'm') || (*str == 'l')) { // xx-small, x-small, etc. for (unsigned i = 0; enum_font_size[i].key; i++) { if (!strcmp(str, enum_font_size[i].key)) { - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; type = SP_FONT_SIZE_LITERAL; literal = enum_font_size[i].value; return; @@ -1609,10 +1612,10 @@ SPIFontSize::read( gchar const *str ) { return; } else { SPILength length("temp"); - length.set = FALSE; + length.set = false; length.read( str ); if( length.set ) { - set = TRUE; + set = true; inherit = length.inherit; unit = length.unit; value = length.value; @@ -1824,8 +1827,8 @@ SPIFont::read( gchar const *str ) { } if ( !strcmp(str, "inherit") ) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else { // Break string into white space separated tokens @@ -1957,14 +1960,14 @@ SPIBaselineShift::read( gchar const *str ) { if( !str ) return; if (!strcmp(str, "inherit")) { - set = TRUE; - inherit = TRUE; + set = true; + inherit = true; } else if ((*str == 'b') || (*str == 's')) { // baseline or sub or super for (unsigned i = 0; enum_baseline_shift[i].key; i++) { if (!strcmp(str, enum_baseline_shift[i].key)) { - set = TRUE; - inherit = FALSE; + set = true; + inherit = false; type = SP_BASELINE_SHIFT_LITERAL; literal = enum_baseline_shift[i].value; return; @@ -2405,31 +2408,65 @@ SPITextDecoration::read( gchar const *str ) { if( !str ) return; - style->text_decoration_line.read( str ); - style->text_decoration_style.read( str ); + bool is_css3 = false; + + SPITextDecorationLine test_line; + test_line.read( str ); + if( test_line.set ) { + style->text_decoration_line = test_line; + } + + SPITextDecorationStyle test_style; + test_style.read( str ); + if( test_style.set ) { + style->text_decoration_style = test_style; + is_css3 = true; + } + // the color routine must be fed one token at a time - if multiple colors are found the LAST // one is used ???? then why break on set? - const gchar *hstr = str; - style->text_decoration_color.read( "currentColor" ); // Default value - style->text_decoration_color.set = false; + // This could certainly be designed better + SPIColor test_color("text-decoration-color"); + test_color.setStylePointer( style ); + test_color.read( "currentColor" ); // Default value + test_color.set = false; + const gchar *hstr = str; while (1) { if (*str == ' ' || *str == ',' || *str == '\0'){ int slen = str - hstr; gchar *frag = g_strndup(hstr,slen+1); // only send one piece at a time, since keywords may be intermixed if( strcmp( frag, "none" ) != 0 ) { // 'none' not allowed - style->text_decoration_color.read( frag ); + test_color.read( frag ); } free(frag); - if( style->text_decoration_color.set ) break; - style->text_decoration_color.read( "currentColor" ); // Default value + if( test_color.set ) { + style->text_decoration_color = test_color; + is_css3 = true; + break; + } + test_color.read( "currentColor" ); // Default value + test_color.set = false; if( *str == '\0' )break; hstr = str + 1; } str++; } + + // If we read a style or color then we have CSS3 which require any non-set values to be + // set to their default values. + if( is_css3 ) { + style->text_decoration_line.set = true; + style->text_decoration_style.set = true; + style->text_decoration_color.set = true; + } + + // If we set text_decoration_line, then update style_td (for CSS2 text-decoration) + if( style->text_decoration_line.set == true ) { + style_td = style; + } } // Returns CSS2 'text-decoration' (using settings in SPTextDecorationLine) @@ -2464,14 +2501,29 @@ SPITextDecoration::write( guint const flags, SPIBase const *const base) const { return Glib::ustring(""); } -// Done in SPITextDecorationLine -// void -// SPITextDecoration::cascade( const SPIBase* const parent ) { -// } +void +SPITextDecoration::cascade( const SPIBase* const parent ) { + if( const SPITextDecoration* p = dynamic_cast<const SPITextDecoration*>(parent) ) { + if( style_td == NULL ) { + style_td = p->style_td; + } + } else { + std::cerr << "SPITextDecoration::cascade(): Incorrect parent type" << std::endl; + } -// void -// SPITextDecoration::merge( const SPIBase* const parent ) { -// } +} + +void +SPITextDecoration::merge( const SPIBase* const parent ) { + if( const SPITextDecoration* p = dynamic_cast<const SPITextDecoration*>(parent) ) { + if( style_td == NULL ) { + style_td = p->style_td; + } + } else { + std::cerr << "SPITextDecoration::merge(): Incorrect parent type" << std::endl; + } + +} // Use CSS2 value bool diff --git a/src/style-internal.h b/src/style-internal.h index e9cf6e604..e76f9faaf 100644 --- a/src/style-internal.h +++ b/src/style-internal.h @@ -116,8 +116,8 @@ class SPIBase { virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET, SPIBase const *const base = NULL ) const = 0; virtual void clear() { set = false, inherit = false; }; - virtual void cascade( const SPIBase* const parent ) {}; - virtual void merge( const SPIBase* const parent ) {}; // To do: Set to 0 + virtual void cascade( const SPIBase* const parent ) = 0; + virtual void merge( const SPIBase* const parent ) = 0; virtual void setStylePointer( SPStyle *style_in ) { style = style_in; }; @@ -698,8 +698,8 @@ class SPIFont : public SPIBase { virtual void clear() { SPIBase::clear(); }; - virtual void cascade( const SPIBase* const parent ) {}; // Done in dependent properties - virtual void merge( const SPIBase* const parent ) {}; + virtual void cascade( const SPIBase* const parent ) { (void)parent; }; // Done in dependent properties + virtual void merge( const SPIBase* const parent ) { (void)parent; }; SPIFont& operator=(const SPIFont& rhs) { SPIBase::operator=(rhs); @@ -837,19 +837,20 @@ class SPITextDecorationStyle : public SPIBase { // the right style. (See http://www.w3.org/TR/css-text-decor-3/#text-decoration-property ) /// Text decoration type internal to SPStyle. -class SPITextDecoration: public SPIBase { +class SPITextDecoration : public SPIBase { public: - SPITextDecoration() : SPIBase( "text-decoration" ) {}; + SPITextDecoration() : SPIBase( "text-decoration" ), style_td( NULL ) {}; virtual ~SPITextDecoration() {}; virtual void read( gchar const *str ); virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET, SPIBase const *const base = NULL ) const; virtual void clear() { SPIBase::clear(); + style_td = NULL; }; - virtual void cascade( const SPIBase* const parent ) {}; // Done in SPITextDecorationLine - virtual void merge( const SPIBase* const parent ) {}; // Done in SPITextDecorationLine + virtual void cascade( const SPIBase* const parent ); + virtual void merge( const SPIBase* const parent ); SPITextDecoration& operator=(const SPITextDecoration& rhs) { SPIBase::operator=(rhs); @@ -859,6 +860,9 @@ class SPITextDecoration: public SPIBase { // Use CSS2 value virtual bool operator==(const SPIBase& rhs); virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); }; + + public: + SPStyle* style_td; // Style to be used for drawing CSS2 text decorations }; diff --git a/src/ui/dialog/filedialogimpl-win32.cpp b/src/ui/dialog/filedialogimpl-win32.cpp index 9d91f5d56..06153a2d8 100644 --- a/src/ui/dialog/filedialogimpl-win32.cpp +++ b/src/ui/dialog/filedialogimpl-win32.cpp @@ -72,13 +72,6 @@ const unsigned long MaxPreviewFileSize = 10240; // kB #define IDC_SHOW_PREVIEW 1000 -// Windows 2000 version of OPENFILENAMEW -struct OPENFILENAMEEXW : public OPENFILENAMEW { - void * pvReserved; - DWORD dwReserved; - DWORD FlagsEx; -}; - struct Filter { gunichar2* name; @@ -483,7 +476,7 @@ void FileOpenDialogImplWin32::createFilterMenu() void FileOpenDialogImplWin32::GetOpenFileName_thread() { - OPENFILENAMEEXW ofn; + OPENFILENAMEW ofn; g_assert(this != NULL); g_assert(_mutex != NULL); @@ -1829,7 +1822,7 @@ void FileSaveDialogImplWin32::addFileType(Glib::ustring name, Glib::ustring patt void FileSaveDialogImplWin32::GetSaveFileName_thread() { - OPENFILENAMEEXW ofn; + OPENFILENAMEW ofn; g_assert(this != NULL); g_assert(_main_loop != NULL); @@ -1860,7 +1853,6 @@ void FileSaveDialogImplWin32::GetSaveFileName_thread() ofn.nFilterIndex = _filter_index; ofn.lpfnHook = GetSaveFileName_hookproc; ofn.lCustData = (LPARAM)this; - _result = GetSaveFileNameW(&ofn) != 0; g_assert(ofn.nFilterIndex >= 1 && ofn.nFilterIndex <= _filter_count); diff --git a/src/ui/dialog/filedialogimpl-win32.h b/src/ui/dialog/filedialogimpl-win32.h index 29bcb9a45..c523f041d 100644 --- a/src/ui/dialog/filedialogimpl-win32.h +++ b/src/ui/dialog/filedialogimpl-win32.h @@ -13,14 +13,20 @@ # include "config.h" #endif +#include <glibmm.h> + #ifdef WIN32 #if WITH_GLIBMM_2_32 #if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H # include <glibmm/threads.h> #endif - #endif + #include "gc-core.h" + // define WINVER high enough so we get the correct OPENFILENAMEW size +#ifndef WINVER +#define WINVER 0x0500 +#endif #include <windows.h> #include "filedialogimpl-gtkmm.h" diff --git a/src/ui/dialog/tags.cpp b/src/ui/dialog/tags.cpp index 1b5dd9400..b2ca1b6da 100644 --- a/src/ui/dialog/tags.cpp +++ b/src/ui/dialog/tags.cpp @@ -8,16 +8,22 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ + #ifdef HAVE_CONFIG_H # include <config.h> #endif +#if WITH_GLIBMM_2_32 +# include <glibmm/threads.h> +#endif + #include "tags.h" #include <gtkmm/widget.h> #include <gtkmm/icontheme.h> #include <gtkmm/imagemenuitem.h> #include <gtkmm/separatormenuitem.h> +#include <glibmm/main.h> #include <glibmm/i18n.h> #include "desktop.h" diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index 17c29c69f..c1ebb32e0 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -404,12 +404,12 @@ void TextEdit::setPreviewText (Glib::ustring font_spec, Glib::ustring phrase) double pt_size = Inkscape::Util::Quantity::convert(sp_style_css_size_units_to_px(sp_font_selector_get_size(fsel), unit), "px", "pt"); // Pango font size is in 1024ths of a point - // C++11: Glib::ustring size = std::to_string( pt_size * PANGO_SCALE ); + // C++11: Glib::ustring size = std::to_string( int(pt_size * PANGO_SCALE) ); std::ostringstream size_st; - size_st << pt_size * PANGO_SCALE; + size_st << int(pt_size * PANGO_SCALE); // Markup code expects integers - Glib::ustring markup = "<span font=\"" + font_spec + - "\" size=\"" + size_st.str() + "\">" + phrase_escaped + "</span>"; + Glib::ustring markup = "<span font=\'" + font_spec + + "\' size=\'" + size_st.str() + "\'>" + phrase_escaped + "</span>"; preview_label.set_markup(markup.c_str()); } diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index 1434a5c5b..ed0843b65 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -371,7 +371,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) std::vector<Inkscape::SnapCandidatePoint> unselected; //if the snap adjustment is activated and it is not bspline - if (snap && !_pm().isBSpline()) { + if (snap && !_pm().isBSpline(false)) { ControlPointSelection::Set &nodes = _parent->_selection.allPoints(); for (ControlPointSelection::Set::iterator i = nodes.begin(); i != nodes.end(); ++i) { Node *n = static_cast<Node*>(*i); @@ -623,7 +623,7 @@ void Node::move(Geom::Point const &new_pos) Node *n = this; Node * nextNode = n->nodeToward(n->front()); Node * prevNode = n->nodeToward(n->back()); - nodeWeight = _pm().BSplineHandlePosition(n->front()); + nodeWeight = fmax(_pm().BSplineHandlePosition(n->front()),_pm().BSplineHandlePosition(n->back())); if(prevNode){ if(prevNode->isEndNode()){ prevNodeWeight = _pm().BSplineHandlePosition(prevNode->front(),prevNode->front()); @@ -659,7 +659,7 @@ void Node::move(Geom::Point const &new_pos) if(nextNode->isEndNode()){ nextNode->back()->setPosition(_pm().BSplineHandleReposition(nextNode->back(),nextNodeWeight)); }else{ - nextNode->back()->setPosition(_pm().BSplineHandleReposition(nextNode->back(),nextNode->back())); + nextNode->back()->setPosition(_pm().BSplineHandleReposition(nextNode->back(),nextNode->front())); } } } diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h index 5971956e1..101af4817 100644 --- a/src/ui/tool/node.h +++ b/src/ui/tool/node.h @@ -41,6 +41,7 @@ template <typename> class NodeIterator; } } +/* #if HAVE_TR1_UNORDERED_SET namespace std { namespace tr1 { @@ -48,6 +49,8 @@ template <typename N> struct hash< Inkscape::UI::NodeIterator<N> >; } } #endif +#endif +*/ namespace Inkscape { namespace UI { diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index 719b67108..72f5159ae 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -23,6 +23,8 @@ #include "message-context.h" #include "selection.h" #include "shape-editor.h" // temporary! +#include "live_effects/effect.h" +#include "display/curve.h" #include "sp-clippath.h" #include "sp-item-group.h" #include "sp-mask.h" @@ -167,6 +169,10 @@ NodeTool::~NodeTool() { this->desktop->remove_temporary_canvasitem(this->flash_tempitem); } + if (this->helperpath_tmpitem) { + this->desktop->remove_temporary_canvasitem(this->helperpath_tmpitem); + } + this->_selection_changed_connection.disconnect(); //this->_selection_modified_connection.disconnect(); this->_mouseover_changed_connection.disconnect(); @@ -252,6 +258,7 @@ void NodeTool::setup() { this->flash_tempitem = NULL; this->flashed_item = NULL; this->_last_over = NULL; + this->helperpath_tmpitem = NULL; // read prefs before adding items to selection to prevent momentarily showing the outline sp_event_context_read(this, "show_handles"); @@ -278,6 +285,41 @@ void NodeTool::setup() { } this->desktop->emitToolSubselectionChanged(NULL); // sets the coord entry fields to inactive + this->update_helperpath(); +} + +void NodeTool::update_helperpath(){ + Inkscape::Selection *selection = sp_desktop_selection (this->desktop); + if (this->helperpath_tmpitem) { + this->desktop->remove_temporary_canvasitem(this->helperpath_tmpitem); + this->helperpath_tmpitem = NULL; + } + if (SP_IS_LPE_ITEM(selection->singleItem())) { + Inkscape::LivePathEffect::Effect *lpe = SP_LPE_ITEM(selection->singleItem())->getCurrentLPE(); + if (lpe && lpe->isVisible()/* && lpe->showOrigPath()*/) { + if (lpe) { + SPCurve *c = new SPCurve(); + SPCurve *cc = new SPCurve(); + std::vector<Geom::PathVector> cs = lpe->getCanvasIndicators(SP_LPE_ITEM(selection->singleItem())); + for (std::vector<Geom::PathVector>::iterator p = cs.begin(); p != cs.end(); ++p) { + cc->set_pathvector(*p); + c->append(cc, false); + cc->reset(); + } + if (!c->is_empty()) { + c->transform(selection->singleItem()->i2dt_affine()); + SPCanvasItem *helperpath = sp_canvas_bpath_new(sp_desktop_tempgroup(this->desktop), c); + sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(helperpath), + 0x0000ff9A, 1.0, + SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); + sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(helperpath), 0, SP_WIND_RULE_NONZERO); + this->helperpath_tmpitem = this->desktop->add_temporary_canvasitem(helperpath,0); + } + c->unref(); + cc->unref(); + } + } + } } void NodeTool::set(const Inkscape::Preferences::Entry& value) { @@ -392,7 +434,7 @@ void NodeTool::selection_changed(Inkscape::Selection *sel) { for (std::set<ShapeRecord>::iterator i = shapes.begin(); i != shapes.end(); ++i) { ShapeRecord const &r = *i; - if ((SP_IS_SHAPE(r.item) || SP_IS_TEXT(r.item)) && + if ((SP_IS_SHAPE(r.item) || SP_IS_TEXT(r.item) || SP_IS_GROUP(r.item) || SP_IS_OBJECTGROUP(r.item)) && this->_shape_editors.find(r.item) == this->_shape_editors.end()) { ShapeEditor *si = new ShapeEditor(this->desktop); @@ -416,7 +458,7 @@ bool NodeTool::root_handler(GdkEvent* event) { Inkscape::Selection *selection = desktop->selection; static Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - + if (this->_multipath->event(this, event)) { return true; } @@ -433,6 +475,7 @@ bool NodeTool::root_handler(GdkEvent* event) { { case GDK_MOTION_NOTIFY: { combine_motion_events(desktop->canvas, event->motion, 0); + this->update_helperpath(); SPItem *over_item = sp_event_context_find_item (desktop, event_point(event->button), FALSE, TRUE); @@ -441,7 +484,6 @@ bool NodeTool::root_handler(GdkEvent* event) { //ink_node_tool_update_tip(nt, event); this->update_tip(event); } - // create pathflash outline if (prefs->getBool("/tools/nodes/pathflash_enabled")) { if (over_item == this->flashed_item) { diff --git a/src/ui/tools/node-tool.h b/src/ui/tools/node-tool.h index 42f89cd1c..9f0c40aa8 100644 --- a/src/ui/tools/node-tool.h +++ b/src/ui/tools/node-tool.h @@ -54,6 +54,7 @@ public: static const std::string prefsPath; virtual void setup(); + virtual void update_helperpath(); virtual void set(const Inkscape::Preferences::Entry& val); virtual bool root_handler(GdkEvent* event); @@ -66,6 +67,7 @@ private: SPItem *flashed_item; Inkscape::Display::TemporaryItem *flash_tempitem; + Inkscape::Display::TemporaryItem *helperpath_tmpitem; Inkscape::UI::Selector* _selector; Inkscape::UI::PathSharedData* _path_data; SPCanvasGroup *_transform_handle_group; diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index 9e4df5031..386dc43e9 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -1811,9 +1811,9 @@ void PenTool::_bspline_spiro_build() void PenTool::_bspline_doEffect(SPCurve * curve) { // commenting the function doEffect in src/live_effects/lpe-bspline.cpp - if(curve->get_segment_count() < 2) - return; Geom::PathVector const original_pathv = curve->get_pathvector(); + if (curve->get_segment_count() < 1) + return; curve->reset(); for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { @@ -1890,9 +1890,25 @@ void PenTool::_bspline_doEffect(SPCurve * curve) ++curve_it1; ++curve_it2; } + SPCurve *out = new SPCurve(); + out->moveto(curve_it1->initialPoint()); + out->lineto(curve_it1->finalPoint()); + cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); + if (cubic) { + SBasisOut = out->first_segment()->toSBasis(); + nextPointAt1 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); + nextPointAt2 = SBasisOut.valueAt(Geom::nearest_point((*cubic)[2], *out->first_segment())); + nextPointAt3 = out->first_segment()->finalPoint(); + } else { + nextPointAt1 = out->first_segment()->initialPoint(); + nextPointAt2 = out->first_segment()->finalPoint(); + nextPointAt3 = out->first_segment()->finalPoint(); + } + out->reset(); + delete out; SPCurve *curveHelper = new SPCurve(); curveHelper->moveto(node); - Geom::Point startNode(0,0); + Geom::Point startNode = path_it->begin()->initialPoint(); if (path_it->closed()) { SPCurve * start = new SPCurve(); start->moveto(path_it->begin()->initialPoint()); diff --git a/src/ui/widget/registered-widget.cpp b/src/ui/widget/registered-widget.cpp index 92cb3f03d..83da1a6d6 100644 --- a/src/ui/widget/registered-widget.cpp +++ b/src/ui/widget/registered-widget.cpp @@ -99,6 +99,59 @@ RegisteredCheckButton::on_toggled() _wr->setUpdating (false); } +/*######################################### + * Registered TOGGLEBUTTON + */ + +RegisteredToggleButton::~RegisteredToggleButton() +{ + _toggled_connection.disconnect(); +} + +RegisteredToggleButton::RegisteredToggleButton (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Registry& wr, bool right, Inkscape::XML::Node* repr_in, SPDocument *doc_in, char const *active_str, char const *inactive_str) + : RegisteredWidget<Gtk::ToggleButton>(label) + , _active_str(active_str) + , _inactive_str(inactive_str) +{ + init_parent(key, wr, repr_in, doc_in); + setProgrammatically = false; + set_tooltip_text (tip); + set_alignment (right? 1.0 : 0.0, 0.5); + _toggled_connection = signal_toggled().connect (sigc::mem_fun (*this, &RegisteredToggleButton::on_toggled)); +} + +void +RegisteredToggleButton::setActive (bool b) +{ + setProgrammatically = true; + set_active (b); + //The slave button is greyed out if the master button is untoggled + for (std::list<Gtk::Widget*>::const_iterator i = _slavewidgets.begin(); i != _slavewidgets.end(); ++i) { + (*i)->set_sensitive(b); + } + setProgrammatically = false; +} + +void +RegisteredToggleButton::on_toggled() +{ + if (setProgrammatically) { + setProgrammatically = false; + return; + } + + if (_wr->isUpdating()) + return; + _wr->setUpdating (true); + + write_to_xml(get_active() ? _active_str : _inactive_str); + //The slave button is greyed out if the master button is untoggled + for (std::list<Gtk::Widget*>::const_iterator i = _slavewidgets.begin(); i != _slavewidgets.end(); ++i) { + (*i)->set_sensitive(get_active()); + } + + _wr->setUpdating (false); +} /*######################################### * Registered UNITMENU diff --git a/src/ui/widget/registered-widget.h b/src/ui/widget/registered-widget.h index d64c09c16..d8c0e6602 100644 --- a/src/ui/widget/registered-widget.h +++ b/src/ui/widget/registered-widget.h @@ -163,6 +163,31 @@ protected: void on_toggled(); }; +class RegisteredToggleButton : public RegisteredWidget<Gtk::ToggleButton> { +public: + virtual ~RegisteredToggleButton(); + RegisteredToggleButton (const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Registry& wr, bool right=true, Inkscape::XML::Node* repr_in=NULL, SPDocument *doc_in=NULL, char const *active_str = "true", char const *inactive_str = "false"); + + void setActive (bool); + + std::list<Gtk::Widget*> _slavewidgets; + + // a slave button is only sensitive when the master button is active + // i.e. a slave button is greyed-out when the master button is not checked + + void setSlaveWidgets(std::list<Gtk::Widget*> btns) { + _slavewidgets = btns; + } + + bool setProgrammatically; // true if the value was set by setActive, not changed by the user; + // if a callback checks it, it must reset it back to false + +protected: + char const *_active_str, *_inactive_str; + sigc::connection _toggled_connection; + void on_toggled(); +}; + class RegisteredUnitMenu : public RegisteredWidget<Labelled> { public: ~RegisteredUnitMenu(); diff --git a/src/widgets/ege-paint-def.cpp b/src/widgets/ege-paint-def.cpp index 542205b53..1a8ad041a 100644 --- a/src/widgets/ege-paint-def.cpp +++ b/src/widgets/ege-paint-def.cpp @@ -44,7 +44,6 @@ #include <string> #include <iostream> #include <sstream> -#include <stdlib.h> #include <string.h> #include <stdio.h> #include <glibmm/i18n.h> |
