17#include <glibmm/i18n.h>
18#include <glibmm/value.h>
19#include <glibmm/miscutils.h>
20#include <giomm/inputstream.h>
21#include <giomm/memoryoutputstream.h>
22#include <gtkmm/droptarget.h>
60template <
typename T,
typename F>
61void foreach(GSList *list, F &&f)
63 g_slist_foreach(list, +[] (
void *ptr,
void *
data) {
64 auto t =
reinterpret_cast<T *
>(ptr);
65 auto f =
reinterpret_cast<F *
>(
data);
70std::span<char const> get_span(Glib::RefPtr<Glib::Bytes>
const &bytes)
73 return {
reinterpret_cast<char const *
>(bytes->get_data(
size)),
size};
77Glib::RefPtr<Glib::Bytes> make_bytes(T &&t)
79 using Td = std::decay_t<T>;
80 auto const p =
new Td(std::forward<T>(t));
81 auto const span = std::span<char const>(*p);
82 return Glib::wrap(g_bytes_new_with_free_func(span.data(), span.size_bytes(), +[] (
void *p) {
83 delete reinterpret_cast<Td *>(p);
88Glib::ValueBase from_bytes(Glib::RefPtr<Glib::Bytes> &&bytes,
char const *mime_type) =
delete;
91void deserialize_func(GdkContentDeserializer *deserializer)
93 auto const in = Glib::wrap(gdk_content_deserializer_get_input_stream(deserializer),
true);
94 auto const out = Gio::MemoryOutputStream::create();
95 out->splice_async(in, [deserializer, out] (Glib::RefPtr<Gio::AsyncResult> &
result) {
97 out->splice_finish(
result);
99 *gdk_content_deserializer_get_value(deserializer) =
GlibValue::release(from_bytes<T>(out->steal_as_bytes(), gdk_content_deserializer_get_mime_type(deserializer)));
100 gdk_content_deserializer_return_success(deserializer);
101 }
catch (Glib::Error
const &error) {
102 gdk_content_deserializer_return_error(deserializer, g_error_copy(error.gobj()));
104 }, Gio::OutputStream::SpliceFlags::CLOSE_SOURCE);
108void register_deserializer(
char const *mime_type)
110 gdk_content_register_deserializer(mime_type, GlibValue::type<T>(), deserialize_func<T>,
nullptr,
nullptr);
114Glib::RefPtr<Glib::Bytes> to_bytes(T
const &t,
char const *mime_type) =
delete;
117void serialize_func(GdkContentSerializer *serializer)
119 auto const out = Glib::wrap(gdk_content_serializer_get_output_stream(serializer),
true);
120 auto const bytes = to_bytes(*GlibValue::get<T>(gdk_content_serializer_get_value(serializer)), gdk_content_serializer_get_mime_type(serializer));
121 auto const span = get_span(bytes);
122 out->write_all_async(span.data(), span.size_bytes(), [serializer, out, bytes] (Glib::RefPtr<Gio::AsyncResult> &
result) {
125 out->write_all_finish(result, _);
126 gdk_content_serializer_return_success(serializer);
127 } catch (Glib::Error
const &error) {
128 gdk_content_serializer_return_error(serializer, g_error_copy(error.gobj()));
134void register_serializer(
char const *mime_type)
136 gdk_content_register_serializer(GlibValue::type<T>(), mime_type, serialize_func<T>,
nullptr,
nullptr);
145 Glib::RefPtr<Glib::Bytes> bytes;
149Glib::ValueBase from_bytes<DnDSvg>(Glib::RefPtr<Glib::Bytes> &&bytes,
char const *)
151 return GlibValue::create<DnDSvg>(DnDSvg{std::move(bytes)});
155Glib::ValueBase from_bytes<Colors::Paint>(Glib::RefPtr<Glib::Bytes> &&bytes,
char const *mime_type)
158 return GlibValue::create<Colors::Paint>(Colors::fromMIMEData(get_span(bytes), mime_type));
160 throw Glib::Error(G_FILE_ERROR, 0,
c.what());
165Glib::RefPtr<Glib::Bytes> to_bytes<Colors::Paint>(
Colors::Paint const &paint,
char const *mime_type)
171Glib::RefPtr<Glib::Bytes> to_bytes<DnDSymbol>(
DnDSymbol const &symbol,
char const *)
173 return make_bytes(symbol.
id.raw());
176std::vector<GType>
const &get_drop_types()
178 static auto const instance = [] () -> std::vector<GType> {
179 for (
auto mime_type : {
"image/svg",
"image/svg+xml"}) {
180 register_deserializer<DnDSvg>(mime_type);
183 for (
auto mime_type : {Colors::mimeOSWB_COLOR, Colors::mimeX_COLOR}) {
184 register_deserializer<Colors::Paint>(mime_type);
187 for (
auto mime_type : {Colors::mimeOSWB_COLOR, Colors::mimeX_COLOR, Colors::mimeTEXT}) {
188 register_serializer<Colors::Paint>(mime_type);
191 register_serializer<DnDSymbol>(
"text/plain;charset=utf-8");
194 GlibValue::type<Colors::Paint>(),
195 GlibValue::type<DnDSvg>(),
197 GlibValue::type<DnDSymbol>(),
205bool on_drop(Glib::ValueBase
const &value,
double x,
double y,
SPDesktopWidget *dtw, Glib::RefPtr<Gtk::DropTarget>
const &drop_target)
212 auto const canvas_pos =
Geom::Point{std::round(x), std::round(y)};
213 auto const world_pos = canvas->canvas_to_world(canvas_pos);
216 if (
auto const ptr = GlibValue::get<Colors::Paint>(value)) {
224 for (
auto obj : doc->getResourceList(
"gradient")) {
225 auto const grad = cast_unsafe<SPGradient>(obj);
226 if (grad->hasStops() && grad->getId() == color.getName()) {
233 std::string colorspec;
234 if (std::holds_alternative<Colors::NoColor>(paint)) {
237 auto &color = std::get<Colors::Color>(paint);
238 if (
auto const grad = find_gradient(color)) {
239 colorspec = std::string{
"url(#"} + grad->getId() +
")";
241 colorspec = color.toString();
259 bool fillnotstroke = drop_target->get_current_drop()->get_actions() != Gdk::DragAction::MOVE;
260 if (fillnotstroke && (is<SPShape>(
item) || is<SPText>(
item) || is<SPFlowtext>(
item))) {
265 pathv.nearestTime(world_pos, &dist);
267 double const stroke_tolerance =
273 + prefs->getIntLimited(
"/options/dragtolerance/value", 0, 0, 100);
275 if (dist < stroke_tolerance) {
276 fillnotstroke =
false;
289 }
else if (
auto const dndsvg = GlibValue::get<DnDSvg>(value)) {
290 auto const data = get_span(dndsvg->bytes);
301 auto const root = newdoc->root();
302 auto const style =
root->attribute(
"style");
304 auto const xml_doc = doc->getReprDoc();
305 auto const newgroup = xml_doc->createElement(
"svg:g");
306 newgroup->setAttribute(
"style", style);
308 newgroup->appendChild(
child->duplicate(xml_doc));
319 selection->
set(cast<SPItem>(new_obj));
323 if (
auto const sel_bbox = selection->visualBounds()) {
324 selection->moveRelative(
desktop->
point() - sel_bbox->midpoint(),
false);
330 }
else if (G_VALUE_HOLDS(value.gobj(), GDK_TYPE_FILE_LIST)) {
331 auto list =
reinterpret_cast<GSList *
>(g_value_get_boxed(value.gobj()));
332 foreach<GFile>(list, [&] (GFile *f) {
333 auto const path = g_file_get_path(f);
334 if (path && std::strlen(path) > 2) {
340 }
else if (GlibValue::holds<DnDSymbol>(value)) {
342 cm->insertSymbol(
desktop, dt_pos,
false);
345 }
else if (G_VALUE_HOLDS(value.gobj(), GDK_TYPE_TEXTURE)) {
347 bool const save = std::strcmp(ext->get_param_optiongroup(
"link"),
"embed") == 0;
348 ext->set_param_optiongroup(
"link",
"embed");
352 auto const filename = Glib::build_filename(Glib::get_user_cache_dir(),
"inkscape-dnd-import");
353 auto const img = Glib::wrap(GDK_TEXTURE(g_value_get_object(value.gobj())),
true);
354 img->save_to_png(filename);
356 unlink(filename.c_str());
358 ext->set_param_optiongroup(
"link", save ?
"embed" :
"link");
371 auto drop_target = Gtk::DropTarget::create(G_TYPE_INVALID, Gdk::DragAction::COPY | Gdk::DragAction::MOVE);
372 drop_target->set_gtypes(get_drop_types());
373 drop_target->signal_drop().connect(sigc::bind(&on_drop, dtw, drop_target),
false);
374 widget->add_controller(drop_target);
Rewrite of code originally in desktop-widget.cpp.
Coord descrim() const
Calculate the descriminant.
Two-dimensional point that doubles as a vector.
void updateDraggers()
Regenerates the draggers list from the current selection; is called when selection is changed or modi...
bool dropColor(SPItem *item, gchar const *c, Geom::Point p)
static void done(SPDocument *document, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
SPGroup * currentLayer() const
Returns current top layer.
static Preferences * get()
Access the singleton Preferences object.
void set(XML::Node *repr)
Set the selection to an XML node's SPObject.
static ClipboardManager * get()
double current_zoom() const
SPDocument * getDocument() const
Geom::Affine const & d2w() const
Transformation from desktop to window coordinates.
Geom::Point point() const
Returns the mouse point in desktop coordinates; if mouse is outside the canvas, returns the center of...
SPItem * getItemAtPoint(Geom::Point const &p, bool into_groups, SPItem *upto=nullptr) const
Inkscape::Selection * getSelection() const
Inkscape::UI::Tools::ToolBase * getTool() const
Inkscape::LayerManager & layerManager()
Geom::Affine const & w2d() const
Transformation from window to desktop coordinates (zoom/rotate).
int ensureUpToDate(unsigned int object_modified_tag=0)
Repeatedly works on getting the document updated, since sometimes it takes more than one pass to get ...
Geom::Affine i2dt_affine() const
Returns the transformation from item to desktop coords.
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
Inkscape::XML::Node * updateRepr(unsigned int flags=SP_OBJECT_WRITE_EXT)
Updates the object's repr based on the object's state.
SPObject * appendChildRepr(Inkscape::XML::Node *repr)
Append repr as child of this object.
T< SPAttr::STROKE, SPIPaint > stroke
stroke
T< SPAttr::STROKE_WIDTH, SPILength > stroke_width
stroke-width
System-wide clipboard management - class declaration.
std::shared_ptr< Css const > css
void sp_desktop_apply_css_recursive(SPObject *o, SPCSSAttr *css, bool skip_lines)
Apply style on object and children, recursively.
Editable view implementation.
TODO: insert short description here.
void ink_drag_setup(SPDesktopWidget *dtw, Gtk::Widget *widget)
Drag and drop of drawings onto canvas.
SPObject * file_import(SPDocument *in_doc, const std::string &path, Inkscape::Extension::Extension *key)
Import a resource.
void sp_ui_error_dialog(char const *message)
double dist(const Point &a, const Point &b)
std::vector< char > getMIMEData(Paint const &paint, char const *mime_type)
Convert a paint into a draggable object.
std::variant< NoColor, Color > Paint
void save(Extension *key, SPDocument *doc, gchar const *filename, bool check_overwrite, bool official, Inkscape::Extension::FileSaveMethod save_method)
This is a generic function to use the save function of a module (including Autodetect)
static R & release(R &r)
Decrements the reference count of a anchored object.
GValue release(Glib::ValueBase &&value)
Release the value from its owning wrapper, leaving the original in an empty state.
Miscellaneous supporting code.
std::optional< Geom::PathVector > curve_for_item(SPItem *item)
Gets an SPCurve from the SPItem.
SPCSSAttr * sp_repr_css_attr_new()
Creates an empty SPCSSAttr (a class for manipulating CSS style properties).
void sp_repr_css_attr_unref(SPCSSAttr *css)
Unreferences an SPCSSAttr (will be garbage collected if no references remain).
void sp_repr_css_set_property_string(SPCSSAttr *css, char const *name, std::string const &value)
Set a style property to a standard string.
Document * sp_repr_read_mem(const gchar *buffer, gint length, const gchar *default_ns)
Reads and parses XML from a buffer, returning it as an Document.
TODO: insert short description here.
SPStyle - a style object for SPItem objects.
Wrapper for the GLib value API.