19#include <glibmm/convert.h>
20#include <glibmm/i18n.h>
21#include <glibmm/miscutils.h>
22#include <gtkmm/builder.h>
23#include <gtkmm/button.h>
24#include <gtkmm/checkbutton.h>
25#include <gtkmm/filefilter.h>
26#include <gtkmm/flowbox.h>
27#include <gtkmm/grid.h>
28#include <gtkmm/label.h>
29#include <gtkmm/menubutton.h>
30#include <gtkmm/progressbar.h>
31#include <gtkmm/recentmanager.h>
32#include <gtkmm/scrolledwindow.h>
33#include <gtkmm/spinbutton.h>
34#include <gtkmm/togglebutton.h>
36#include <sigc++/adaptors/bind.h>
37#include <sigc++/functors/mem_fun.h>
118 auto &pref_button_box = get_widget<Gtk::Box>(
builder,
"si_prefs");
120 pref_button_box.append(pref_button);
121 pref_button.set_expand(
false);
122 pref_button_box.set_expand(
false);
123 pref_button.set_valign(Gtk::Align::BASELINE_CENTER);
124 pref_button_box.set_valign(Gtk::Align::BASELINE_CENTER);
135 if (!(flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
148 Glib::ustring pref_key_name =
prefs->
getString(
"/dialogs/export/exportarea/value");
268 int digits,
bool sensitive,
void (
SingleExport::*cb)(T), T param)
271 sb->set_digits(digits);
272 sb->set_increments(step,
page);
273 sb->set_range(min, max);
275 sb->set_sensitive(sensitive);
276 sb->set_width_chars(0);
277 sb->set_max_width_chars(0);
279 auto signal = sb->signal_value_changed().connect(sigc::bind(sigc::mem_fun(*
this, cb), param));
305 if (sel.size() == 1) {
306 bbox = sel[0]->getDesktopRect();
328 bool multi =
pages_list.get_selection_mode() == Gtk::SelectionMode::MULTIPLE;
333 size_box.set_visible(!has_pages || !multi);
341 item->on_mode_changed(Gtk::SelectionMode::NONE);
345 pages_list.set_selection_mode(multi ? Gtk::SelectionMode::MULTIPLE : Gtk::SelectionMode::SINGLE);
349 item->update_selected();
361 item->set_selected(true);
370 std::vector<SPPage const *> pages;
371 pages_list.selected_foreach([&pages](Gtk::FlowBox *box, Gtk::FlowBoxChild *
child) {
373 pages.push_back(
item->getPage());
380 std::map<std::string, SPObject*> itemsList;
384 if (pm.getPageCount() > 1) {
385 for (
auto page : pm.getPages()) {
386 if (
auto id =
page->getId()) {
387 itemsList[id] =
page;
408 if (
pages_list.get_selection_mode() != Gtk::SelectionMode::MULTIPLE) {
425 std::string filename;
431 if (pages.size() == 1) {
432 dpi = pages[0]->getExportDpi();
434 auto page_filename = pages[0]->getExportFilename();
435 if (page_filename.empty()) {
436 page_filename = pages[0]->getLabel();
457 if (selection->isEmpty())
break;
460 for (
auto item : selection->items()) {
464 if (filename.empty()) {
470 if (filename.empty()) {
478 if (filename.empty()) {
479 filename = old_raw_filepath;
485 ext->add_extension(filename);
495 if (dpi.
x() != 0.0) {
535 Glib::ustring filename_label = Glib::filename_to_utf8(filename);
569 auto px = UnitTable::get().getUnit(
"px");
697 bool exportSuccessful =
false;
700 std::cerr <<
"SingleExport::onExport(): Cannot find export extension!" << std::endl;
712 Glib::ustring filename_label =
726 if (omod->is_raster()) {
735 std::vector<SPItem const *> selected(selection->items().begin(), selection->items().end());
742 setExporting(
true, Glib::ustring::compose(_(
"Exporting %1"), filename_label));
746 std::vector<SPItem const *>
items;
748 auto itemlist = selection->items();
749 items.insert(
items.end(), itemlist.begin(), itemlist.end());
755 if (page_manager.getPageCount() == 1) {
756 pages.emplace_back(page_manager.getPage(0));
762 auto const page = copy_doc->getPageManager().newDocumentPage(area);
767 if (exportSuccessful) {
769 auto recentmanager = Gtk::RecentManager::get_default();
770 if (recentmanager && Glib::path_is_absolute(path)) {
771 Glib::ustring uri = Glib::filename_to_uri(path);
772 recentmanager->add_item(uri);
784 if (pages.size() == 1) {
785 if ((target = page_manager.getSelected()))
821 if (filename.empty()) {
827 std::string basename = Glib::path_get_basename(filename);
828 std::string dirname = Glib::path_get_dirname(filename);
835 Glib::ustring filename_utf8 = file->get_parse_name();
849 signal.block(status);
859 float x0, x1, dpi,
width, bmwidth;
863 x0 = unit->convert(x0_adj->get_value(),
"px");
864 x1 = unit->convert(x1_adj->get_value(),
"px");
865 width = unit->convert(width_adj->get_value(),
"px");
871 bmwidth = (x1 - x0) * dpi / DPI_BASE;
877 bmwidth = (x1 - x0) * dpi / DPI_BASE;
883 bmwidth =
width * dpi / DPI_BASE;
894 bmwidth =
floor(
width * dpi / DPI_BASE + 0.5);
896 auto px = UnitTable::get().getUnit(
"px");
897 x0_adj->set_value(px->convert(x0, unit));
898 x1_adj->set_value(px->convert(x1, unit));
899 width_adj->set_value(px->convert(
width, unit));
909 float y0, y1, dpi,
height, bmheight;
913 y0 = unit->convert(y0_adj->get_value(),
"px");
914 y1 = unit->convert(y1_adj->get_value(),
"px");
915 height = unit->convert(height_adj->get_value(),
"px");
921 bmheight = (y1 - y0) * dpi / DPI_BASE;
927 bmheight = (y1 - y0) * dpi / DPI_BASE;
933 bmheight =
height * dpi / DPI_BASE;
946 auto px = UnitTable::get().getUnit(
"px");
947 y0_adj->set_value(px->convert(y0, unit));
948 y1_adj->set_value(px->convert(y1, unit));
949 height_adj->set_value(px->convert(
height, unit));
970 dpi = bmheight * DPI_BASE /
height;
976 dpi = bmwidth * DPI_BASE /
width;
985 bmwidth =
floor(
width * dpi / DPI_BASE + 0.5);
997 Glib::ustring pref_key_name =
prefs->
getString(
"/dialogs/export/exportarea/value");
999 if (pref_key_name ==
name) {
1025 prefs->
setString(
"/dialogs/export/exportarea/value", pref_key_name);
1046 auto main_context = Glib::MainContext::get_default();
1047 main_context->iteration(
false);
1054 si->progress_bar.set_fraction(value);
1055 auto main_context = Glib::MainContext::get_default();
1056 main_context->iteration(
false);
1057 return !si->interrupted;
1069 std::vector<SPItem const *> selected;
1073 selected = {sel_range.begin(), sel_range.end()};
1079 bool have_pages =
false;
Axis-aligned rectangle that can be empty.
Two-dimensional point that doubles as a vector.
constexpr Coord x() const noexcept
Axis aligned, non-empty rectangle.
InkscapeWindow * get_active_window()
uint32_t toRGBA(double opacity=1.0) const
Return an sRGB conversion of the color in RGBA int32 format.
static void done(SPDocument *document, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
SPItemRange items()
Returns a range of selected SPItems.
bool isEmpty()
Returns true if no items are selected.
SPItem * firstItem() const
Returns the first selected item, returns nullptr if no items selected.
Geom::OptRect visualBounds() const
sigc::connection connectPageSelected(const sigc::slot< void(SPPage *)> &slot)
Geom::Rect getSelectedPageRect() const
Returns the selected page rect, OR the viewbox rect.
double getDouble(Glib::ustring const &pref_path, double def=0.0, Glib::ustring const &unit="")
Retrieve a floating point value.
Glib::ustring getString(Glib::ustring const &pref_path, Glib::ustring const &def="")
Retrieve an UTF-8 string.
static Preferences * get()
Access the singleton Preferences object.
void setString(Glib::ustring const &pref_path, Glib::ustring const &value)
Set an UTF-8 string value.
void setDouble(Glib::ustring const &pref_path, double value)
Set a floating point value.
The set of selected SPObjects for a given document and layer model.
static void syncItems(BatchItems &items, std::map< std::string, SPObject * > const &objects, Gtk::FlowBox &container, std::shared_ptr< PreviewDrawing > preview, bool isolate_items)
Add and remove batch items and their previews carefully and insert new ones into the container FlowBo...
void resetPixels(bool new_size=false)
void setBox(Geom::Rect const &bbox)
void setDrawing(std::shared_ptr< PreviewDrawing > drawing)
void setBackgroundColor(std::uint32_t bg_color)
static bool exportRaster(Geom::Rect const &area, unsigned long int const &width, unsigned long int const &height, float const &dpi, guint32 bg_color, Glib::ustring const &filename, bool overwrite, unsigned(*callback)(float, void *), void *data, Inkscape::Extension::Output *extension, std::vector< SPItem const * > *items=nullptr)
Export to raster graphics.
static bool exportVector(Inkscape::Extension::Output *extension, SPDocument *doc, Glib::ustring const &filename, bool overwrite, Geom::Rect const &area)
static std::string prependDirectory(const std::string &name, const std::string &orig, SPDocument *doc=nullptr)
Adds the full directory path to the final part of a file name.
static std::string absolutizePath(SPDocument *doc, const std::string &filename)
Convert path to absolute path.
static std::string filePathFromObject(SPDocument *doc, SPObject *obj, const std::string &file_entry_text)
static bool checkOrCreateDirectory(std::string const &filename)
Checks if the directory exists and if not, tries to create the directory and if failed,...
static std::string defaultFilename(SPDocument *doc, const std::string &filename_entry_text, const std::string &extension)
Inkscape::Extension::Output * getExtension()
Returns the Output extension currently selected in this dropdown.
void removeExtension(std::string &filename)
Removes the file extension, if it's one of the extensions in the list.
Gtk::MenuButton * getPrefButton() const
void setExtensionFromFilename(std::string const &filename)
sigc::scoped_connection _page_selected_connection
SingleExport(BaseObjectType *cobject, const Glib::RefPtr< Gtk::Builder > &refGlade)
void setupSpinButton(Gtk::SpinButton *sb, double val, double min, double max, double step, double page, int digits, bool sensitive, void(SingleExport::*cb)(T), T param)
void onAreaTypeToggle(selection_mode key)
void selectionChanged(Inkscape::Selection *selection)
InkscapeApplication * _app
void selectPage(SPPage *page)
void setDesktop(SPDesktop *desktop)
sigc::scoped_connection _page_modified_connection
void setArea(double x0, double y0, double x1, double y1)
Gtk::ScrolledWindow & pages_list_box
Inkscape::UI::Widget::UnitMenu & units
void onFilenameModified()
Filename in filename entry field was changed.
Gtk::Entry & si_filename_entry
std::string filepath_native
File path as returned by the file chooser.
Gtk::Button & cancel_button
void setPagesMode(bool multi)
Glib::ustring filename_entry_original_value
Last value of filename entry field that was set programmatically. Used to detect modification by the ...
std::map< selection_mode, Gtk::ToggleButton * > selection_buttons
Gtk::CheckButton & si_show_preview
void onAreaXChange(sb_type type)
void setFilename(std::string filename, bool modified_by_user)
Set filename and update filename entry box.
void toggleSpinButtonVisibility()
sigc::scoped_connection extensionConn
void dpiChange(sb_type type)
void loadExportHints()
Update suggested DPI and filename when the selection has changed.
Inkscape::Preferences * prefs
sigc::scoped_connection exportConn
static unsigned int onProgressCallback(float value, void *data)
Callback to be used in for loop to update the progress bar.
void selectionModified(Inkscape::Selection *selection, guint flags)
void areaYChange(sb_type type)
sigc::scoped_connection cancelConn
std::shared_ptr< PreviewDrawing > _preview_drawing
bool filename_modified_by_user
True if the value of the selected filename was changed by the user since the last export.
void onDpiChange(sb_type type)
void onPagesModified(SPPage *page)
void setExporting(bool exporting, Glib::ustring const &text="")
std::vector< sigc::scoped_connection > spinButtonConns
sigc::scoped_connection filenameConn
std::map< sb_type, Gtk::SpinButton * > spin_buttons
void onExtensionChanged()
sigc::scoped_connection browseConn
std::map< sb_type, Gtk::Label * > spin_labels
ExtensionList & si_extension_cb
Gtk::ProgressBar & progress_bar
sigc::scoped_connection _pages_list_changed
std::map< selection_mode, Glib::ustring > selection_names
UI::Widget::ColorPicker & _background_color
void areaXChange(sb_type type)
void setDocument(SPDocument *document)
void onPagesChanged()
Page functions.
void onAreaYChange(sb_type type)
void setDefaultSelectionMode()
Gtk::Widget & progress_box
sigc::scoped_connection _page_changed_connection
void blockSpinConns(bool status)
void onPagesSelected(SPPage *page)
Gtk::CheckButton & si_hide_all
void saveExportHints(SPObject *target)
Gtk::FlowBox & pages_list
Gtk::Button & si_filename_button
std::vector< SPPage const * > getSelectedPages() const
selection_mode current_key
Helperclass for Gtk::Entry widgets.
To do: update description of desktop.
Geom::Affine const & dt2doc() const
SPNamedView * getNamedView() const
Inkscape::Selection * getSelection() const
Typed SVG document implementation.
SPRoot * getRoot()
Returns our SPRoot.
std::unique_ptr< SPDocument > copy() const
Create a copy of the document, useful for modifying during save & export.
const Geom::Affine & dt2doc() const
Desktop to document coordinate transformation.
Geom::OptRect preferredBounds() const
Inkscape::PageManager & getPageManager()
SPNamedView * getNamedView()
Get the namedview for this document, creates it if it's not found.
Geom::OptRect desktopVisualBounds() const
Get item's visual bbox in desktop coordinate system.
Inkscape::Util::Unit const * display_units
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Glib::ustring getExportFilename() const
Get and set the exportable filename on this object.
Geom::Point getExportDpi() const
Get and set the exported DPI for this objet, if available.
void setExportDpi(Geom::Point dpi)
void setExportFilename(Glib::ustring filename)
Color picker button and window.
Editable view implementation.
TODO: insert short description here.
auto floor(Geom::Rect const &rect)
Macro for icon names used in Inkscape.
Inkscape - An SVG editor.
bool filesystem_is_sandboxed()
Query if the filesystem is "sandboxed", e.g., by using xdg-portal in flatpak/snap.
Glib::ustring filesystem_get_display_path(std::optional< Glib::RefPtr< Gio::File const > > path, Glib::ustring placeholder_if_empty)
Translate raw filesystem path to a path suitable for display.
Glib::RefPtr< Gio::ListStore< Gtk::FileFilter > > create_export_filters(bool for_save)
Create a Gtk::FileFilter for all export file types.
Inkscape::Colors::Color get_export_bg_color(SPObject *object, Inkscape::Colors::Color const &default_color)
static void set_sensitive(Gtk::SearchEntry2 &entry, bool const sensitive)
void set_export_bg_color(SPObject *object, Inkscape::Colors::Color const &color)
constexpr auto SP_EXPORT_MIN_SIZE
constexpr auto EXPORT_COORD_PRECISION
std::vector< Gtk::Widget * > get_children(Gtk::Widget &widget)
Get a vector of the widgetʼs children, from get_first_child() through each get_next_sibling().
W & get_widget(const Glib::RefPtr< Gtk::Builder > &builder, const char *id)
Gtk::Widget * for_each_child(Gtk::Widget &widget, Func &&func, bool const plus_self=false, bool const recurse=false, int const level=0)
Call Func with a reference to each child of parent, until it returns _break.
W & get_derived_widget(const Glib::RefPtr< Gtk::Builder > &builder, const char *id, Args &&... args)
Glib::RefPtr< Gio::File > choose_file_save(Glib::ustring const &title, Gtk::Window *parent, Glib::RefPtr< Gio::ListStore< Gtk::FileFilter > > const &filters_model, std::string const &file_name, std::string ¤t_folder)
Synchronously run a Gtk::FileDialog to select a file for saving data.
static cairo_user_data_key_t key
Singleton class to access the preferences file in a convenient way.
SPRoot: SVG <svg> implementation.
Glib::RefPtr< Gtk::Builder > builder