23#include <gdk/gdkkeysyms.h>
24#include <glibmm/i18n.h>
48#define INKSCAPE_LPE_SPIRO_C
51#define INKSCAPE_LPE_BSPLINE_C
60 return p->get_pathvector();
75 , _acc_to_line{
"tool.pen.to-line"}
76 , _acc_to_curve{
"tool.pen.to-curve"}
77 , _acc_to_guides{
"tool.pen.to-guides"}
84 cl0 = make_canvasitem<CanvasItemCurve>(canvas);
85 cl1 = make_canvasitem<CanvasItemCurve>(canvas);
86 cl0->set_visible(
false);
87 cl1->set_visible(
false);
89 for (
int i = 0; i < 4; i++) {
91 ctrl[i]->set_visible(
false);
101 if (prefs->
getBool(
"/tools/freehand/pen/selcue")) {
120 for (
auto &
c :
ctrl) {
134 guint
mode = prefs->
getInt(
"/tools/freehand/pen/freehand-mode", 0);
138 this->
spiro = (mode == 1);
150 for (
auto &
c :
ctrl) {
151 c->set_visible(
false);
153 cl0->set_visible(
false);
154 cl1->set_visible(
false);
166 if (
name ==
"mode") {
188 if ((state & GDK_CONTROL_MASK) && !poly) {
192 std::optional<Geom::Point>
origin = std::optional<Geom::Point>();
199 if ((this->
npoints > 0) && poly) {
204 std::optional<Geom::Point>
origin = this->
npoints > 0 ?
p_array[0] : std::optional<Geom::Point>();
214 g_return_if_fail(( this->
npoints == 2 ||
217 if ((state & GDK_CONTROL_MASK)) {
220 if (!(
state & GDK_SHIFT_MASK)) {
253 if (event.num_press == 1) {
254 ret = _handleButtonPress(event);
255 }
else if (event.num_press == 2) {
256 ret = _handle2ButtonPress(event);
341 if (!(event.
modifiers & GDK_SHIFT_MASK)) {
421 g_warning(
"Button down in CONTROL state");
424 g_warning(
"Button down in CLOSE state");
478 if (event.
modifiers & GDK_BUTTON2_MASK) {
690 ctrl[1]->set_visible(
false);
715 ctrl[1]->set_visible(
false);
786 for (
auto &
c :
ctrl) {
787 c->set_visible(
false);
793 ctrl[0]->set_visible(
true);
795 ctrl[3]->set_visible(
true);
800 ctrl[1]->set_visible(
true);
802 cl1->set_visible(
true);
804 cl1->set_visible(
false);
815 ctrl[2]->set_position(p2);
816 ctrl[2]->set_visible(
true);
818 cl0->set_visible(
true);
820 cl0->set_visible(
false);
837 bool const rotated = prefs->getBool(
"/options/moverotated/value",
true);
887 A = this->
green_curve->last_segment()->initialPoint();
888 B = this->
green_curve->last_segment()->initialPoint();
896 auto previous = std::make_shared<SPCurve>();
909 if (this->
green_curve->is_unset() && this->sa && !this->sa->curve->is_unset()) {
930 auto previous = std::make_shared<SPCurve>();
969 double const nudge = prefs->getDoubleLimited(
"/options/nudgedistance/value", 2, 0, 1000,
"px");
991 case GDK_KEY_KP_Left:
1035 case GDK_KEY_KP_Right:
1057 case GDK_KEY_KP_Down:
1113 case GDK_KEY_Return:
1114 case GDK_KEY_KP_Enter:
1132 case GDK_KEY_Escape:
1139 case GDK_KEY_BackSpace:
1140 case GDK_KEY_Delete:
1141 case GDK_KEY_KP_Delete:
1177 g_assert( this->
npoints == 0 );
1191 g_assert((pc_point_to_compare == 0) || (pc_point_to_compare == 3));
1192 g_assert(message !=
nullptr);
1199 if (prefs->
getBool(
"/options/compassangledisplay/value",
false) != 0) {
1203 angle = 180 - angle;
1219 auto other = prefs->
getColor(
"/tools/nodes/highlight_color",
"#ff0000ff");
1225 if(other == highlight) {
1235 if(other == highlight) {
1293 if(this->
sa->
curve->is_unset()){
1323 this->
spiro =
false;
1341 auto last_segment = std::make_shared<SPCurve>();
1344 Geom::Point point_c = point_d + (1./3)*(point_a - point_d);
1346 last_segment->moveto(point_a);
1347 last_segment->curveto((*cubic)[1],point_c,point_d);
1349 last_segment->moveto(point_a);
1350 last_segment->curveto(point_a,point_c,point_d);
1366 auto last_segment = std::make_shared<SPCurve>();
1367 last_segment->moveto((*cubic)[0]);
1368 last_segment->curveto((*cubic)[1],(*cubic)[3],(*cubic)[3]);
1408 SPCurve previous_weight_power;
1415 tmp_curve.
moveto(initial);
1420 tmp_curve.
curveto(SBasisweight_power.valueAt(0.33334), SBasisweight_power.valueAt(0.66667),
p_array[0]);
1421 }
else if(this->
bspline && cubic) {
1434 green_curve = std::make_shared<SPCurve>(std::move(tmp_curve));
1442 p_array[1] = SBasisweight_power.valueAt(0.33334);
1453 p_array[1] = (*cubic)[3] + ((*cubic)[3] - (*cubic)[2] );
1502 }
else if(this->
sa){
1514 last_segment.
moveto((*cubic)[0]);
1515 last_segment.
curveto((*cubic)[1],point_c,(*cubic)[3]);
1521 tmp_curve = std::move(last_segment);
1531 green_curve = std::make_shared<SPCurve>(std::move(tmp_curve));
1534 sa_overwrited = std::make_shared<SPCurve>(std::move(tmp_curve));
1555 last_segment.
moveto((*cubic)[0]);
1556 last_segment.
curveto((*cubic)[1],(*cubic)[3],(*cubic)[3]);
1562 tmp_curve = std::move(last_segment);
1573 green_curve = std::make_shared<SPCurve>(std::move(tmp_curve));
1576 sa_overwrited = std::make_shared<SPCurve>(std::move(tmp_curve));
1614 curve.closepath_current();
1625 Glib::ustring pref_path =
"/live_effects/bspline/uniform";
1638 for (
auto &
c :
ctrl) {
1639 c->set_visible(
false);
1643 ctrl[1]->set_visible(
true);
1645 cl0->set_visible(
false);
1646 cl1->set_visible(
false);
1654 g_assert( this->
npoints != 0 );
1693 message = is_curve ?
1694 _(
"<b>Curve segment</b>: angle %3.2f°; <b>Shift+Click</b> creates cusp node, <b>ALT</b> moves previous, <b>Enter</b> or <b>Shift+Enter</b> to finish" ):
1695 _(
"<b>Line segment</b>: angle %3.2f°; <b>Shift+Click</b> creates cusp node, <b>ALT</b> moves previous, <b>Enter</b> or <b>Shift+Enter</b> to finish");
1698 message = is_curve ?
1699 _(
"<b>Curve segment</b>: angle %3.2f°, distance %s; with <b>Ctrl</b> to snap angle, <b>Enter</b> or <b>Shift+Enter</b> to finish the path" ):
1700 _(
"<b>Line segment</b>: angle %3.2f°, distance %s; with <b>Ctrl</b> to snap angle, <b>Enter</b> or <b>Shift+Enter</b> to finish the path");
1710 for (
auto &
c :
ctrl) {
1711 c->set_visible(
false);
1714 ctrl[1]->set_visible(
true);
1715 cl1->set_visible(
true);
1719 cl0->set_visible(
false);
1721 ctrl[1]->set_visible(
true);
1724 }
else if ( this->
npoints == 5 ) {
1726 cl0->set_visible(
true);
1727 bool is_symm =
false;
1741 ctrl[0]->set_visible(
true);
1744 ctrl[3]->set_visible(
true);
1746 ctrl[2]->set_visible(
true);
1748 ctrl[1]->set_visible(
true);
1753 gchar *message = is_symm ?
1754 _(
"<b>Curve handle, symmetric</b>: angle %3.2f°, length %s; with <b>Ctrl</b> to snap angle, with <b>Shift</b> to move this handle only") :
1755 _(
"<b>Curve handle</b>: angle %3.2f°, length %s; with <b>Ctrl</b> to snap angle, with <b>Shift</b> to move this handle only");
1758 g_warning(
"Something bad happened - npoints is %d", this->
npoints);
1775 lsegment.
moveto((*cubic)[0]);
1778 green_curve->append_continuous(std::move(lsegment));
1802 if ( this->
green_curve->is_unset() || (this->green_curve->last_segment() ==
nullptr) ) {
1836 if (this->
green_curve->get_segment_count() == 1) {
1855 p_array[1] = (*cubic)[3] + (*cubic)[3] - (*cubic)[2];
1862 for (
auto &
c :
ctrl) {
1863 c->set_visible(
false);
1865 cl0->set_visible(
false);
1866 cl1->set_visible(
false);
1900 if (
auto const *last_seg =
green_curve->last_segment()) {
1902 freshly_added.
append(*last_seg);
1908 auto const last_point =
green_curve->last_point();
1940 for (
auto &
c :
ctrl) {
1941 c->set_visible(
false);
1944 cl0->set_visible(
false);
1945 cl1->set_visible(
false);
1988 if(!(
state & GDK_SHIFT_MASK)) {
Bezier curve with compile-time specified order.
Abstract continuous curve on a plane defined on [0,1].
virtual D2< SBasis > toSBasis() const =0
Convert the curve to a symmetric power basis polynomial.
virtual Point initialPoint() const =0
Retrieve the start of the curve.
virtual Point finalPoint() const =0
Retrieve the end of the curve.
Sequence of contiguous curves, aka spline.
void append(Curve *curve)
Add a new curve to the end of the path.
Two-dimensional point that doubles as a vector.
constexpr Point ccw() const
Return a point like this point but rotated -90 degrees.
constexpr Point cw() const
Return a point like this point but rotated +90 degrees.
uint32_t toRGBA(double opacity=1.0) const
Return an sRGB conversion of the color in RGBA int32 format.
LivePathEffectObject * getLPEObj()
virtual void acceptParamPath(SPPath const *param_path)
If the effect expects a path parameter (specified by a number of mouse clicks) before it is applied,...
MessageId flash(MessageType type, char const *message)
Temporarily pushes a message onto the stack.
void clear()
Unselects all selected objects.
SPItem * singleItem()
Returns a single selected item.
Data type representing a typeless value of a preference.
Glib::ustring getEntryName() const
Get the last component of the preference's path.
Glib::ustring getString(Glib::ustring const &def="") const
Interpret the preference as an UTF-8 string.
Preference storage class.
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
static Preferences * get()
Access the singleton Preferences object.
Colors::Color getColor(Glib::ustring const &pref_path, std::string const &def="black")
int getInt(Glib::ustring const &pref_path, int def=0)
Retrieve an integer.
int getIntLimited(Glib::ustring const &pref_path, int def=0, int min=INT_MIN, int max=INT_MAX)
Retrieve a limited integer.
The set of selected SPObjects for a given document and layer model.
void add(XML::Node *repr)
Add an XML node's SPObject to the set of selected objects.
Class to store data for points which are snap candidates, either as a source or as a target.
bool isTriggeredBy(KeyEvent const &key) const
Checks whether a given key event triggers this action.
Glib::ustring string(Unit const *u) const
Return a printable string of the value in the specified unit.
Inkscape::LivePathEffect::Effect * get_lpe()
Wrapper around a Geom::PathVector object.
size_t get_segment_count() const
Returns the number of segments of all paths summed.
Geom::Curve const * last_segment() const
Return last pathsegment (possibly the closing path segment) of the last path in PathVector or NULL.
void moveto(Geom::Point const &p)
Perform a moveto to a point, thus starting a new subpath.
bool is_unset() const
True if paths are in curve.
void reverse()
Reverse the direction of all paths.
void reset()
Set curve to empty curve.
SPCurve reversed() const
Return a copy with the direction of all paths reversed.
void lineto(Geom::Point const &p)
Adds a line to the current subpath.
std::optional< Geom::Point > last_point() const
Return last point of last subpath or nothing when the curve is empty.
std::optional< Geom::Point > first_point() const
Return first point of first subpath or nothing when the path is empty.
void backspace()
Remove last segment of curve.
void curveto(Geom::Point const &p0, Geom::Point const &p1, Geom::Point const &p2)
Adds a bezier segment to the current subpath.
bool append_continuous(SPCurve const &c1, double tolerance=0.0625)
Append c1 to this with possible fusing of close endpoints.
Geom::Curve const * first_segment() const
Return first pathsegment in PathVector or NULL.
To do: update description of desktop.
double current_zoom() const
Inkscape::CanvasItemGroup * getCanvasControls() const
Inkscape::CanvasItemGroup * getCanvasSketch() const
Inkscape::MessageStack * messageStack() const
SPNamedView * getNamedView() const
Inkscape::Selection * getSelection() const
sigc::connection connectDestroy(F &&slot)
Geom::Rotate const & current_rotation() const
bool is_yaxisdown() const
Geom::Affine const & w2d() const
Transformation from window to desktop coordinates (zoom/rotate).
std::shared_ptr< SPCurve > curve
Inkscape::Colors::Color highlight_color() const override
Generate a highlight colour if one isn't set and return it.
Base class for visual SVG elements.
SPLPEItem * removeCurrentPathEffect(bool keep_paths)
If keep_path is true, the item should not be updated, effectively 'flattening' the LPE.
Inkscape::Util::Unit const * display_units
Class to coordinate snapping operations.
void constrainedSnapReturnByRef(Geom::Point &p, Inkscape::SnapSourceType const source_type, Inkscape::Snapper::SnapConstraint const &constraint, Geom::OptRect const &bbox_to_snap=Geom::OptRect()) const
Try to snap a point along a constraint line to grids, guides or objects.
void setup(SPDesktop const *desktop, bool snapindicator=true, SPObject const *item_to_ignore=nullptr, std::vector< Inkscape::SnapCandidatePoint > *unselected_nodes=nullptr)
Convenience shortcut when there is only one item to ignore.
void preSnap(Inkscape::SnapCandidatePoint const &p, bool to_path_only=false)
Editable view implementation.
The nodes at the ends of the path in the pen/pencil tools.
static Glib::ustring const prefs_path
void shift(T &a, T &b, T const &c)
Interface for locally managing a current status message.
Raw stack of active status messages.
SBasis L2(D2< SBasis > const &a, unsigned k)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
Coord LInfty(Point const &p)
void sp_bspline_do_effect(SPCurve &curve, double helper_size, Geom::PathVector &hp, bool uniform)
void sp_spiro_do_effect(SPCurve &curve)
Helper class to stream background task notifications as a series of messages.
bool mod_alt(unsigned modifiers)
void inspect_event(E &&event, Fs... funcs)
Perform pattern-matching on a CanvasEvent.
bool mod_ctrl(unsigned modifiers)
bool mod_shift_only(unsigned modifiers)
bool mod_shift(unsigned modifiers)
bool have_viable_layer(SPDesktop *desktop, MessageContext *message)
Check to see if the current layer is both unhidden and unlocked.
Abstract base class for events.
unsigned modifiers
The modifiers mask immediately before the event.
Movement of the mouse pointer.
Geom::Point pos
Location of the cursor.