1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) Johan Engelen 2007 <j.b.c.engelen@utwente.nl>
4 *
5 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
6 */
7
8 #include "live_effects/parameter/point.h"
9 #include "live_effects/effect.h"
10
11 #include "inkscape.h"
12 #include "verbs.h"
13
14 #include "svg/stringstream.h"
15 #include "svg/svg.h"
16 #include "ui/knot/knot-holder.h"
17 #include "ui/knot/knot-holder-entity.h"
18 #include "ui/widget/point.h"
19
20 #include <glibmm/i18n.h>
21
22 namespace Inkscape {
23
24 namespace LivePathEffect {
25
PointParam(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,bool live_update)26 PointParam::PointParam( const Glib::ustring& label, const Glib::ustring& tip,
27 const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
28 Effect* effect, const gchar *htip, Geom::Point default_value,
29 bool live_update )
30 : Parameter(label, tip, key, wr, effect)
31 , defvalue(default_value)
32 , liveupdate(live_update)
33 {
34 handle_tip = g_strdup(htip);
35 }
36
~PointParam()37 PointParam::~PointParam()
38 {
39 if (handle_tip)
40 g_free(handle_tip);
41 }
42
43 void
param_set_default()44 PointParam::param_set_default()
45 {
46 param_setValue(defvalue,true);
47 }
48
49 void
param_set_liveupdate(bool live_update)50 PointParam::param_set_liveupdate( bool live_update)
51 {
52 liveupdate = live_update;
53 }
54
55 Geom::Point
param_get_default() const56 PointParam::param_get_default() const{
57 return defvalue;
58 }
59
60 void
param_update_default(Geom::Point default_point)61 PointParam::param_update_default(Geom::Point default_point)
62 {
63 defvalue = default_point;
64 }
65
66 void
param_update_default(const gchar * default_point)67 PointParam::param_update_default(const gchar * default_point)
68 {
69 gchar ** strarray = g_strsplit(default_point, ",", 2);
70 double newx, newy;
71 unsigned int success = sp_svg_number_read_d(strarray[0], &newx);
72 success += sp_svg_number_read_d(strarray[1], &newy);
73 g_strfreev (strarray);
74 if (success == 2) {
75 param_update_default( Geom::Point(newx, newy) );
76 }
77 }
78
79 void
param_hide_knot(bool hide)80 PointParam::param_hide_knot(bool hide) {
81 if (_knot_entity) {
82 bool update = false;
83 if (hide && _knot_entity->knot->flags & SP_KNOT_VISIBLE) {
84 update = true;
85 _knot_entity->knot->hide();
86 } else if(!hide && !(_knot_entity->knot->flags & SP_KNOT_VISIBLE)) {
87 update = true;
88 _knot_entity->knot->show();
89 }
90 if (update) {
91 _knot_entity->update_knot();
92 }
93 }
94 }
95
96 void
param_setValue(Geom::Point newpoint,bool write)97 PointParam::param_setValue(Geom::Point newpoint, bool write)
98 {
99 *dynamic_cast<Geom::Point *>( this ) = newpoint;
100 if(write){
101 Inkscape::SVGOStringStream os;
102 os << newpoint;
103 gchar * str = g_strdup(os.str().c_str());
104 param_write_to_repr(str);
105 g_free(str);
106 }
107 if(_knot_entity && liveupdate){
108 _knot_entity->update_knot();
109 }
110 }
111
112 bool
param_readSVGValue(const gchar * strvalue)113 PointParam::param_readSVGValue(const gchar * strvalue)
114 {
115 gchar ** strarray = g_strsplit(strvalue, ",", 2);
116 double newx, newy;
117 unsigned int success = sp_svg_number_read_d(strarray[0], &newx);
118 success += sp_svg_number_read_d(strarray[1], &newy);
119 g_strfreev (strarray);
120 if (success == 2) {
121 param_setValue( Geom::Point(newx, newy) );
122 return true;
123 }
124 return false;
125 }
126
127 Glib::ustring
param_getSVGValue() const128 PointParam::param_getSVGValue() const
129 {
130 Inkscape::SVGOStringStream os;
131 os << *dynamic_cast<Geom::Point const *>( this );
132 return os.str();
133 }
134
135 Glib::ustring
param_getDefaultSVGValue() const136 PointParam::param_getDefaultSVGValue() const
137 {
138 Inkscape::SVGOStringStream os;
139 os << defvalue;
140 return os.str();
141 }
142
143 void
param_transform_multiply(Geom::Affine const & postmul,bool)144 PointParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/)
145 {
146 param_setValue( (*this) * postmul, true);
147 }
148
149 Gtk::Widget *
param_newWidget()150 PointParam::param_newWidget()
151 {
152 Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg = Gtk::manage(
153 new Inkscape::UI::Widget::RegisteredTransformedPoint( param_label,
154 param_tooltip,
155 param_key,
156 *param_wr,
157 param_effect->getRepr(),
158 param_effect->getSPDoc() ) );
159 Geom::Affine transf = SP_ACTIVE_DESKTOP->doc2dt();
160 pointwdg->setTransform(transf);
161 pointwdg->setValue( *this );
162 pointwdg->clearProgrammatically();
163 pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change point parameter"));
164 pointwdg->signal_button_release_event().connect(sigc::mem_fun (*this, &PointParam::on_button_release));
165
166 Gtk::Box * hbox = Gtk::manage( new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL) );
167 hbox->pack_start(*pointwdg, true, true);
168 hbox->show_all_children();
169 return dynamic_cast<Gtk::Widget *> (hbox);
170 }
171
on_button_release(GdkEventButton * button_event)172 bool PointParam::on_button_release(GdkEventButton* button_event) {
173 param_effect->refresh_widgets = true;
174 return false;
175 }
176
177 void
set_oncanvas_looks(Inkscape::CanvasItemCtrlShape shape,Inkscape::CanvasItemCtrlMode mode,guint32 color)178 PointParam::set_oncanvas_looks(Inkscape::CanvasItemCtrlShape shape,
179 Inkscape::CanvasItemCtrlMode mode,
180 guint32 color)
181 {
182 knot_shape = shape;
183 knot_mode = mode;
184 knot_color = color;
185 }
186
187 class PointParamKnotHolderEntity : public KnotHolderEntity {
188 public:
PointParamKnotHolderEntity(PointParam * p)189 PointParamKnotHolderEntity(PointParam *p) { this->pparam = p; }
~PointParamKnotHolderEntity()190 ~PointParamKnotHolderEntity() override { this->pparam->_knot_entity = nullptr;}
191
192 void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state) override;
193 Geom::Point knot_get() const override;
194 void knot_ungrabbed(Geom::Point const &p, Geom::Point const &origin, guint state) override;
195 void knot_click(guint state) override;
196
197 private:
198 PointParam *pparam;
199 };
200
201 void
knot_set(Geom::Point const & p,Geom::Point const & origin,guint state)202 PointParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &origin, guint state)
203 {
204 Geom::Point s = snap_knot_position(p, state);
205 if (state & GDK_CONTROL_MASK) {
206 Geom::Point A(origin[Geom::X],p[Geom::Y]);
207 Geom::Point B(p[Geom::X],origin[Geom::Y]);
208 double distanceA = Geom::distance(A,p);
209 double distanceB = Geom::distance(B,p);
210 if(distanceA > distanceB){
211 s = B;
212 } else {
213 s = A;
214 }
215 }
216 if(this->pparam->liveupdate){
217 pparam->param_setValue(s, true);
218 } else {
219 pparam->param_setValue(s);
220 }
221 }
222
223 void
knot_ungrabbed(Geom::Point const & p,Geom::Point const & origin,guint state)224 PointParamKnotHolderEntity::knot_ungrabbed(Geom::Point const &p, Geom::Point const &origin, guint state)
225 {
226 pparam->param_effect->refresh_widgets = true;
227 pparam->write_to_SVG();
228 }
229
230 Geom::Point
knot_get() const231 PointParamKnotHolderEntity::knot_get() const
232 {
233 return *pparam;
234 }
235
236 void
knot_click(guint state)237 PointParamKnotHolderEntity::knot_click(guint state)
238 {
239 if (state & GDK_CONTROL_MASK) {
240 if (state & GDK_MOD1_MASK) {
241 this->pparam->param_set_default();
242 pparam->param_setValue(*pparam,true);
243 }
244 }
245 }
246
247 void
addKnotHolderEntities(KnotHolder * knotholder,SPItem * item)248 PointParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
249 {
250 _knot_entity = new PointParamKnotHolderEntity(this);
251 // TODO: can we ditch handleTip() etc. because we have access to handle_tip etc. itself???
252 _knot_entity->create(nullptr, item, knotholder, Inkscape::CANVAS_ITEM_CTRL_TYPE_LPE, "LPE:Point",
253 handleTip(), knot_color);
254 knotholder->add(_knot_entity);
255 }
256
257 } /* namespace LivePathEffect */
258
259 } /* namespace Inkscape */
260
261 /*
262 Local Variables:
263 mode:c++
264 c-file-style:"stroustrup"
265 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
266 indent-tabs-mode:nil
267 fill-column:99
268 End:
269 */
270 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
271