summaryrefslogtreecommitdiffstats
path: root/src/ui/dialog/export-single.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/dialog/export-single.cpp')
-rw-r--r--src/ui/dialog/export-single.cpp990
1 files changed, 990 insertions, 0 deletions
diff --git a/src/ui/dialog/export-single.cpp b/src/ui/dialog/export-single.cpp
new file mode 100644
index 0000000..dc17227
--- /dev/null
+++ b/src/ui/dialog/export-single.cpp
@@ -0,0 +1,990 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * bulia byak <buliabyak@users.sf.net>
+ * Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
+ * Anshudhar Kumar Singh <anshudhar2001@gmail.com>
+ *
+ * Copyright (C) 1999-2007, 2021 Authors
+ * Copyright (C) 2001-2002 Ximian, Inc.
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "export-single.h"
+
+#include <glibmm/convert.h>
+#include <glibmm/i18n.h>
+#include <glibmm/miscutils.h>
+#include <gtkmm.h>
+#include <png.h>
+
+#include "desktop.h"
+#include "document-undo.h"
+#include "document.h"
+#include "extension/db.h"
+#include "extension/output.h"
+#include "file.h"
+#include "helper/png-write.h"
+#include "inkscape-window.h"
+#include "inkscape.h"
+#include "io/resource.h"
+#include "io/sys.h"
+#include "message-stack.h"
+#include "object/object-set.h"
+#include "object/sp-namedview.h"
+#include "object/sp-root.h"
+#include "object/sp-page.h"
+#include "page-manager.h"
+#include "preferences.h"
+#include "selection-chemistry.h"
+#include "ui/dialog-events.h"
+#include "ui/dialog/dialog-notebook.h"
+#include "ui/dialog/export.h"
+#include "ui/dialog/filedialog.h"
+#include "ui/icon-names.h"
+#include "ui/interface.h"
+#include "ui/widget/export-lists.h"
+#include "ui/widget/export-preview.h"
+#include "ui/widget/scrollprotected.h"
+#include "ui/widget/unit-menu.h"
+#ifdef _WIN32
+
+#endif
+
+using Inkscape::Util::unit_table;
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+
+/**
+ * Initialise Builder Objects. Called in Export constructor.
+ */
+void SingleExport::initialise(const Glib::RefPtr<Gtk::Builder> &builder)
+{
+ builder->get_widget("si_s_document", selection_buttons[SELECTION_DRAWING]);
+ selection_names[SELECTION_DRAWING] = "drawing";
+ builder->get_widget("si_s_page", selection_buttons[SELECTION_PAGE]);
+ selection_names[SELECTION_PAGE] = "page";
+ builder->get_widget("si_s_selection", selection_buttons[SELECTION_SELECTION]);
+ selection_names[SELECTION_SELECTION] = "selection";
+ builder->get_widget("si_s_custom", selection_buttons[SELECTION_CUSTOM]);
+ selection_names[SELECTION_CUSTOM] = "custom";
+
+ builder->get_widget_derived("si_left_sb", spin_buttons[SPIN_X0]);
+ builder->get_widget_derived("si_right_sb", spin_buttons[SPIN_X1]);
+ builder->get_widget_derived("si_top_sb", spin_buttons[SPIN_Y0]);
+ builder->get_widget_derived("si_bottom_sb", spin_buttons[SPIN_Y1]);
+ builder->get_widget_derived("si_height_sb", spin_buttons[SPIN_HEIGHT]);
+ builder->get_widget_derived("si_width_sb", spin_buttons[SPIN_WIDTH]);
+
+ builder->get_widget("si_label_left", spin_labels[SPIN_X0]);
+ builder->get_widget("si_label_right", spin_labels[SPIN_X1]);
+ builder->get_widget("si_label_top", spin_labels[SPIN_Y0]);
+ builder->get_widget("si_label_bottom", spin_labels[SPIN_Y1]);
+ builder->get_widget("si_label_height", spin_labels[SPIN_HEIGHT]);
+ builder->get_widget("si_label_width", spin_labels[SPIN_WIDTH]);
+
+ builder->get_widget_derived("si_img_height_sb", spin_buttons[SPIN_BMHEIGHT]);
+ builder->get_widget_derived("si_img_width_sb", spin_buttons[SPIN_BMWIDTH]);
+ builder->get_widget_derived("si_dpi_sb", spin_buttons[SPIN_DPI]);
+
+ builder->get_widget("page_prev", page_prev);
+ page_prev->signal_clicked().connect([=]() {
+ if (_document && _document->getPageManager().selectPrevPage()) {
+ _document->getPageManager().zoomToSelectedPage(_desktop);
+ }
+ });
+
+ builder->get_widget("page_next", page_next);
+ page_next->signal_clicked().connect([=]() {
+ if (_document && _document->getPageManager().selectNextPage()) {
+ _document->getPageManager().zoomToSelectedPage(_desktop);
+ }
+ });
+
+ // builder->get_widget("si_show_export_area", show_export_area);
+ builder->get_widget_derived("si_units", units);
+ builder->get_widget("si_units_row", si_units_row);
+ builder->get_widget("si_area_name", si_name_label);
+
+ builder->get_widget("si_hide_all", si_hide_all);
+ builder->get_widget("si_show_preview", si_show_preview);
+ builder->get_widget("si_default_opts", si_default_opts);
+ builder->get_widget_derived("si_preview", preview);
+
+ builder->get_widget_derived("si_extention", si_extension_cb);
+ builder->get_widget("si_filename", si_filename_entry);
+ builder->get_widget("si_export", si_export);
+
+ builder->get_widget("si_progress", _prog);
+}
+
+// Inkscape Selection Modified CallBack
+void SingleExport::selectionModified(Inkscape::Selection *selection, guint flags)
+{
+ if (!_desktop || _desktop->getSelection() != selection) {
+ return;
+ }
+ if (!(flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
+ return;
+ }
+ refreshArea();
+ // Do not load export hits for modifications
+}
+
+void SingleExport::selectionChanged(Inkscape::Selection *selection)
+{
+ if (!_desktop || _desktop->getSelection() != selection) {
+ return;
+ }
+
+ Glib::ustring pref_key_name = prefs->getString("/dialogs/export/exportarea/value");
+ for (auto [key, name] : selection_names) {
+ if (name == pref_key_name && current_key != key && key != SELECTION_SELECTION) {
+ selection_buttons[key]->set_active(true);
+ current_key = key;
+ break;
+ }
+ }
+ if (selection->isEmpty()) {
+ selection_buttons[SELECTION_SELECTION]->set_sensitive(false);
+ if (current_key == SELECTION_SELECTION) {
+ selection_buttons[(selection_mode)0]->set_active(true); // This causes refresh area
+ // even though we are at default key, selection is the one which was original key.
+ prefs->setString("/dialogs/export/exportarea/value", selection_names[SELECTION_SELECTION]);
+ // return otherwise refreshArea will be called again
+ return;
+ }
+ } else {
+ selection_buttons[SELECTION_SELECTION]->set_sensitive(true);
+ if (selection_names[SELECTION_SELECTION] == pref_key_name && current_key != SELECTION_SELECTION) {
+ selection_buttons[SELECTION_SELECTION]->set_active();
+ return;
+ }
+ }
+
+ refreshArea();
+ loadExportHints();
+}
+
+// Setup Single Export.Called by export on realize
+void SingleExport::setup()
+{
+ if (setupDone) {
+ // We need to setup only once
+ return;
+ }
+ setupDone = true;
+ prefs = Inkscape::Preferences::get();
+ si_extension_cb->setup();
+
+ setupUnits();
+ setupSpinButtons();
+
+ // set them before connecting to signals
+ setDefaultSelectionMode();
+
+ // Refresh values to sync them with defaults.
+ refreshArea();
+ refreshPage();
+ loadExportHints();
+
+ // Connect Signals Here
+ for (auto [key, button] : selection_buttons) {
+ button->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &SingleExport::onAreaTypeToggle), key));
+ }
+ units->signal_changed().connect(sigc::mem_fun(*this, &SingleExport::onUnitChanged));
+ extensionConn = si_extension_cb->signal_changed().connect(sigc::mem_fun(*this, &SingleExport::onExtensionChanged));
+ exportConn = si_export->signal_clicked().connect(sigc::mem_fun(*this, &SingleExport::onExport));
+ filenameConn = si_filename_entry->signal_changed().connect(sigc::mem_fun(*this, &SingleExport::onFilenameModified));
+ browseConn = si_filename_entry->signal_icon_release().connect(sigc::mem_fun(*this, &SingleExport::onBrowse));
+ si_filename_entry->signal_activate().connect(sigc::mem_fun(*this, &SingleExport::onExport));
+ si_show_preview->signal_toggled().connect(sigc::mem_fun(*this, &SingleExport::refreshPreview));
+ si_hide_all->signal_toggled().connect(sigc::mem_fun(*this, &SingleExport::refreshPreview));
+
+ si_default_opts->set_active(prefs->getBool("/dialogs/export/defaultopts", true));
+}
+
+// Setup units combobox
+void SingleExport::setupUnits()
+{
+ units->setUnitType(Inkscape::Util::UNIT_TYPE_LINEAR);
+ if (_desktop) {
+ units->setUnit(_desktop->getNamedView()->display_units->abbr);
+ }
+}
+
+// Create all spin buttons
+void SingleExport::setupSpinButtons()
+{
+ setupSpinButton<sb_type>(spin_buttons[SPIN_X0], 0.0, -1000000.0, 1000000.0, 0.1, 1.0, EXPORT_COORD_PRECISION, true,
+ &SingleExport::onAreaXChange, SPIN_X0);
+ setupSpinButton<sb_type>(spin_buttons[SPIN_X1], 0.0, -1000000.0, 1000000.0, 0.1, 1.0, EXPORT_COORD_PRECISION, true,
+ &SingleExport::onAreaXChange, SPIN_X1);
+ setupSpinButton<sb_type>(spin_buttons[SPIN_Y0], 0.0, -1000000.0, 1000000.0, 0.1, 1.0, EXPORT_COORD_PRECISION, true,
+ &SingleExport::onAreaYChange, SPIN_Y0);
+ setupSpinButton<sb_type>(spin_buttons[SPIN_Y1], 0.0, -1000000.0, 1000000.0, 0.1, 1.0, EXPORT_COORD_PRECISION, true,
+ &SingleExport::onAreaYChange, SPIN_Y1);
+
+ setupSpinButton<sb_type>(spin_buttons[SPIN_HEIGHT], 0.0, 0.0, PNG_UINT_31_MAX, 0.1, 1.0, EXPORT_COORD_PRECISION,
+ true, &SingleExport::onAreaYChange, SPIN_HEIGHT);
+ setupSpinButton<sb_type>(spin_buttons[SPIN_WIDTH], 0.0, 0.0, PNG_UINT_31_MAX, 0.1, 1.0, EXPORT_COORD_PRECISION,
+ true, &SingleExport::onAreaXChange, SPIN_WIDTH);
+
+ setupSpinButton<sb_type>(spin_buttons[SPIN_BMHEIGHT], 1.0, 1.0, 1000000.0, 1.0, 10.0, 0, true,
+ &SingleExport::onDpiChange, SPIN_BMHEIGHT);
+ setupSpinButton<sb_type>(spin_buttons[SPIN_BMWIDTH], 1.0, 1.0, 1000000.0, 1.0, 10.0, 0, true,
+ &SingleExport::onDpiChange, SPIN_BMWIDTH);
+ setupSpinButton<sb_type>(spin_buttons[SPIN_DPI], prefs->getDouble("/dialogs/export/defaultxdpi/value", DPI_BASE),
+ 1.0, 100000.0, 0.1, 1.0, 2, true, &SingleExport::onDpiChange, SPIN_DPI);
+}
+
+template <typename T>
+void SingleExport::setupSpinButton(Gtk::SpinButton *sb, double val, double min, double max, double step, double page,
+ int digits, bool sensitive, void (SingleExport::*cb)(T), T param)
+{
+ if (sb) {
+ sb->set_digits(digits);
+ sb->set_increments(step, page);
+ sb->set_range(min, max);
+ sb->set_value(val);
+ sb->set_sensitive(sensitive);
+ sb->set_width_chars(0);
+ sb->set_max_width_chars(0);
+ if (cb) {
+ auto signal = sb->signal_value_changed().connect(sigc::bind(sigc::mem_fun(*this, cb), param));
+ // add signals to list to block all easily
+ spinButtonConns.push_back(signal);
+ }
+ }
+}
+
+void SingleExport::refreshArea()
+{
+ if (_document) {
+ Geom::OptRect bbox;
+
+ switch (current_key) {
+ case SELECTION_SELECTION:
+ if ((_desktop->getSelection())->isEmpty() == false) {
+ bbox = _desktop->getSelection()->visualBounds();
+ break;
+ }
+ case SELECTION_DRAWING:
+ bbox = _document->getRoot()->desktopVisualBounds();
+ if (bbox) {
+ break;
+ }
+ case SELECTION_PAGE:
+ bbox = _document->getPageManager().getSelectedPageRect();
+ break;
+ case SELECTION_CUSTOM:
+ break;
+ default:
+ break;
+ }
+ if (current_key != SELECTION_CUSTOM && bbox) {
+ setArea(bbox->min()[Geom::X], bbox->min()[Geom::Y], bbox->max()[Geom::X], bbox->max()[Geom::Y]);
+ }
+ }
+ refreshPreview();
+}
+
+void SingleExport::refreshPage()
+{
+ bool pages = current_key == SELECTION_PAGE;
+ si_name_label->set_visible(pages);
+ page_prev->set_visible(pages);
+ page_next->set_visible(pages);
+
+ auto &page_manager = _document->getPageManager();
+ page_prev->set_sensitive(page_manager.hasPrevPage());
+ page_next->set_sensitive(page_manager.hasNextPage());
+
+ if (auto page = page_manager.getSelected()) {
+ if (auto label = page->label()) {
+ si_name_label->set_text(label);
+ } else {
+ si_name_label->set_text(page->getDefaultLabel());
+ }
+ } else {
+ si_name_label->set_text(_("First Page"));
+ }
+}
+
+void SingleExport::loadExportHints()
+{
+ if (filename_modified) return;
+
+ Glib::ustring old_filename = si_filename_entry->get_text();
+ Glib::ustring filename;
+ Geom::Point dpi;
+ switch (current_key) {
+ case SELECTION_PAGE:
+ if (auto page = _document->getPageManager().getSelected()) {
+ dpi = page->getExportDpi();
+ filename = page->getExportFilename();
+ if (filename.empty()) {
+ filename = Export::filePathFromId(_document, page->getLabel(), old_filename);
+ }
+ break;
+ }
+ // No page means page is drawing, continue.
+ case SELECTION_CUSTOM:
+ case SELECTION_DRAWING:
+ {
+ dpi = _document->getRoot()->getExportDpi();
+ filename = _document->getRoot()->getExportFilename();
+ break;
+ }
+ case SELECTION_SELECTION:
+ {
+ auto selection = _desktop->getSelection();
+ if (selection->isEmpty()) break;
+
+ // Get filename and dpi from selected items
+ for (auto item : selection->items()) {
+ if (!dpi.x()) {
+ dpi = item->getExportDpi();
+ }
+ if (filename.empty()) {
+ filename = item->getExportFilename();
+ }
+ }
+
+ if (filename.empty()) {
+ filename = Export::filePathFromObject(_document, selection->firstItem(), old_filename);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (filename.empty()) {
+ filename = Export::defaultFilename(_document, old_filename, ".png");
+ }
+ if (auto ext = si_extension_cb->getExtension()) {
+ si_extension_cb->removeExtension(filename);
+ ext->add_extension(filename);
+ }
+
+ original_name = filename;
+ si_filename_entry->set_text(filename);
+ si_filename_entry->set_position(filename.length());
+
+ if (dpi.x() != 0.0) { // XXX Should this deal with dpi.y() ?
+ spin_buttons[SPIN_DPI]->set_value(dpi.x());
+ }
+}
+
+void SingleExport::saveExportHints(SPObject *target)
+{
+ if (target) {
+ target->setExportFilename(si_filename_entry->get_text());
+ target->setExportDpi(Geom::Point(
+ spin_buttons[SPIN_DPI]->get_value(),
+ spin_buttons[SPIN_DPI]->get_value()
+ ));
+ }
+}
+
+void SingleExport::setArea(double x0, double y0, double x1, double y1)
+{
+ blockSpinConns(true);
+
+ Unit const *unit = units->getUnit();
+ auto px = unit_table.getUnit("px");
+ spin_buttons[SPIN_X0]->get_adjustment()->set_value(px->convert(x0, unit));
+ spin_buttons[SPIN_X1]->get_adjustment()->set_value(px->convert(x1, unit));
+ spin_buttons[SPIN_Y0]->get_adjustment()->set_value(px->convert(y0, unit));
+ spin_buttons[SPIN_Y1]->get_adjustment()->set_value(px->convert(y1, unit));
+
+ areaXChange(SPIN_X1);
+ areaYChange(SPIN_Y1);
+
+ blockSpinConns(false);
+}
+
+// Signals CallBack
+
+void SingleExport::onUnitChanged()
+{
+ refreshArea();
+}
+
+void SingleExport::onAreaTypeToggle(selection_mode key)
+{
+ // Prevent executing function twice
+ if (!selection_buttons[key]->get_active()) {
+ return;
+ }
+ // If you have reached here means the current key is active one ( not sure if multiple transitions happen but
+ // last call will change values)
+ current_key = key;
+ prefs->setString("/dialogs/export/exportarea/value", selection_names[current_key]);
+
+ refreshPage();
+ refreshArea();
+ loadExportHints();
+ toggleSpinButtonVisibility();
+}
+
+void SingleExport::toggleSpinButtonVisibility()
+{
+ bool show = current_key == SELECTION_CUSTOM;
+ spin_buttons[SPIN_X0]->set_visible(show);
+ spin_buttons[SPIN_X1]->set_visible(show);
+ spin_buttons[SPIN_Y0]->set_visible(show);
+ spin_buttons[SPIN_Y1]->set_visible(show);
+ spin_buttons[SPIN_WIDTH]->set_visible(show);
+ spin_buttons[SPIN_HEIGHT]->set_visible(show);
+
+ spin_labels[SPIN_X0]->set_visible(show);
+ spin_labels[SPIN_X1]->set_visible(show);
+ spin_labels[SPIN_Y0]->set_visible(show);
+ spin_labels[SPIN_Y1]->set_visible(show);
+ spin_labels[SPIN_WIDTH]->set_visible(show);
+ spin_labels[SPIN_HEIGHT]->set_visible(show);
+
+ si_units_row->set_visible(show);
+}
+
+void SingleExport::onAreaXChange(sb_type type)
+{
+ blockSpinConns(true);
+ areaXChange(type);
+ selection_buttons[SELECTION_CUSTOM]->set_active(true);
+ refreshPreview();
+ blockSpinConns(false);
+}
+void SingleExport::onAreaYChange(sb_type type)
+{
+ blockSpinConns(true);
+ areaYChange(type);
+ selection_buttons[SELECTION_CUSTOM]->set_active(true);
+ refreshPreview();
+ blockSpinConns(false);
+}
+void SingleExport::onDpiChange(sb_type type)
+{
+ blockSpinConns(true);
+ dpiChange(type);
+ blockSpinConns(false);
+}
+
+void SingleExport::onFilenameModified()
+{
+ extensionConn.block();
+ Glib::ustring filename = si_filename_entry->get_text();
+
+ if (original_name == filename) {
+ filename_modified = false;
+ } else {
+ filename_modified = true;
+ }
+
+ si_extension_cb->setExtensionFromFilename(filename);
+
+ extensionConn.unblock();
+}
+
+void SingleExport::onExtensionChanged()
+{
+ filenameConn.block();
+ Glib::ustring filename = si_filename_entry->get_text();
+ if (auto ext = si_extension_cb->getExtension()) {
+ si_extension_cb->removeExtension(filename);
+ ext->add_extension(filename);
+ }
+ si_filename_entry->set_text(filename);
+ si_filename_entry->set_position(filename.length());
+ filenameConn.unblock();
+}
+
+void SingleExport::onExport()
+{
+ interrupted = false;
+ if (!_desktop || !_document)
+ return;
+
+ auto &page_manager = _document->getPageManager();
+ auto selection = _desktop->getSelection();
+ si_export->set_sensitive(false);
+ bool exportSuccessful = false;
+ auto omod = si_extension_cb->getExtension();
+ if (!omod) {
+ si_export->set_sensitive(true);
+ return;
+ }
+
+ bool selected_only = si_hide_all->get_active();
+ Unit const *unit = units->getUnit();
+ Glib::ustring filename = si_filename_entry->get_text();
+
+ float x0 = unit->convert(spin_buttons[SPIN_X0]->get_value(), "px");
+ float x1 = unit->convert(spin_buttons[SPIN_X1]->get_value(), "px");
+ float y0 = unit->convert(spin_buttons[SPIN_Y0]->get_value(), "px");
+ float y1 = unit->convert(spin_buttons[SPIN_Y1]->get_value(), "px");
+ auto area = Geom::Rect(Geom::Point(x0, y0), Geom::Point(x1, y1));
+
+ bool default_opts = si_default_opts->get_active();
+ prefs->setBool("/dialogs/export/defaultopts", default_opts);
+ if (!default_opts && !omod->prefs()) {
+ si_export->set_sensitive(true);
+ return; // cancel button
+ }
+
+ if (omod->is_raster()) {
+ area *= _desktop->dt2doc();
+ unsigned long int width = int(spin_buttons[SPIN_BMWIDTH]->get_value() + 0.5);
+ unsigned long int height = int(spin_buttons[SPIN_BMHEIGHT]->get_value() + 0.5);
+
+ float dpi = spin_buttons[SPIN_DPI]->get_value();
+
+ /* TRANSLATORS: %1 will be the filename, %2 the width, and %3 the height of the image */
+ prog_dlg = create_progress_dialog(Glib::ustring::compose(_("Exporting %1 (%2 x %3)"), filename, width, height));
+ prog_dlg->set_export_panel(this);
+ setExporting(true, Glib::ustring::compose(_("Exporting %1 (%2 x %3)"), filename, width, height));
+ prog_dlg->set_current(0);
+ prog_dlg->set_total(0);
+
+ std::vector<SPItem *> selected(selection->items().begin(), selection->items().end());
+
+ exportSuccessful = Export::exportRaster(
+ area, width, height, dpi, filename, false, onProgressCallback, prog_dlg,
+ omod, selected_only ? &selected : nullptr);
+
+ } else {
+ setExporting(true, Glib::ustring::compose(_("Exporting %1"), filename));
+
+ auto copy_doc = _document->copy();
+
+ std::vector<SPItem *> items;
+ if (selected_only) {
+ auto itemlist = selection->items();
+ for (auto i = itemlist.begin(); i != itemlist.end(); ++i) {
+ SPItem *item = *i;
+ items.push_back(item);
+ }
+ }
+
+ SPPage *page;
+ if (current_key == SELECTION_PAGE && page_manager.hasPages()) {
+ page = page_manager.getSelected();
+ } else {
+ // To get the right kind of export, we're going to make a page
+ // This allows all the same raster options to work for vectors
+ page = copy_doc->getPageManager().newDocumentPage(area);
+ }
+
+ exportSuccessful = Export::exportVector(omod, copy_doc.get(), filename, false, &items, page);
+ }
+ if (prog_dlg) {
+ delete prog_dlg;
+ prog_dlg = nullptr;
+ }
+ // Save the export hints back to the svg document
+ if (exportSuccessful) {
+ SPObject *target;
+ switch (current_key) {
+ case SELECTION_CUSTOM:
+ case SELECTION_DRAWING:
+ target = _document->getRoot();
+ break;
+ case SELECTION_PAGE:
+ target = page_manager.getSelected();
+ if (!target)
+ target = _document->getRoot();
+ break;
+ case SELECTION_SELECTION:
+ target = _desktop->getSelection()->firstItem();
+ break;
+ default:
+ break;
+ }
+ if (target) {
+ saveExportHints(target);
+ DocumentUndo::done(_document, _("Set Export Options"), INKSCAPE_ICON("export"));
+ }
+ }
+ setExporting(false);
+ original_name = filename;
+ filename_modified = false;
+ interrupted = false;
+}
+
+void SingleExport::onBrowse(Gtk::EntryIconPosition pos, const GdkEventButton *ev)
+{
+ if (!_app || !_app->get_active_window() || !_document) {
+ return;
+ }
+ Gtk::Window *window = _app->get_active_window();
+ browseConn.block();
+ Glib::ustring filename = Glib::filename_from_utf8(si_filename_entry->get_text());
+
+ if (filename.empty()) {
+ filename = Export::defaultFilename(_document, filename, ".png");
+ }
+
+ Inkscape::UI::Dialog::FileSaveDialog *dialog = Inkscape::UI::Dialog::FileSaveDialog::create(
+ *window, filename, Inkscape::UI::Dialog::RASTER_TYPES, _("Select a filename for exporting"), "", "",
+ Inkscape::Extension::FILE_SAVE_METHOD_EXPORT);
+
+ if (dialog->show()) {
+ filename = dialog->getFilename();
+ if (auto ext = si_extension_cb->getExtension()) {
+ si_extension_cb->removeExtension(filename);
+ ext->add_extension(filename);
+ }
+ si_filename_entry->set_text(filename);
+ si_filename_entry->set_position(filename.length());
+ // deleting dialog before exporting is important
+ delete dialog;
+ onExport();
+ } else {
+ delete dialog;
+ }
+ browseConn.unblock();
+}
+
+// Utils Functions
+
+void SingleExport::blockSpinConns(bool status = true)
+{
+ for (auto signal : spinButtonConns) {
+ if (status) {
+ signal.block();
+ } else {
+ signal.unblock();
+ }
+ }
+}
+
+void SingleExport::areaXChange(sb_type type)
+{
+ auto x0_adj = spin_buttons[SPIN_X0]->get_adjustment();
+ auto x1_adj = spin_buttons[SPIN_X1]->get_adjustment();
+ auto width_adj = spin_buttons[SPIN_WIDTH]->get_adjustment();
+
+ float x0, x1, dpi, width, bmwidth;
+
+ // Get all values in px
+ Unit const *unit = units->getUnit();
+ x0 = unit->convert(x0_adj->get_value(), "px");
+ x1 = unit->convert(x1_adj->get_value(), "px");
+ width = unit->convert(width_adj->get_value(), "px");
+ bmwidth = spin_buttons[SPIN_BMWIDTH]->get_value();
+ dpi = spin_buttons[SPIN_DPI]->get_value();
+
+ switch (type) {
+ case SPIN_X0:
+ bmwidth = (x1 - x0) * dpi / DPI_BASE;
+ if (bmwidth < SP_EXPORT_MIN_SIZE) {
+ x0 = x1 - (SP_EXPORT_MIN_SIZE * DPI_BASE) / dpi;
+ }
+ break;
+ case SPIN_X1:
+ bmwidth = (x1 - x0) * dpi / DPI_BASE;
+ if (bmwidth < SP_EXPORT_MIN_SIZE) {
+ x1 = x0 + (SP_EXPORT_MIN_SIZE * DPI_BASE) / dpi;
+ }
+ break;
+ case SPIN_WIDTH:
+ bmwidth = width * dpi / DPI_BASE;
+ if (bmwidth < SP_EXPORT_MIN_SIZE) {
+ width = (SP_EXPORT_MIN_SIZE * DPI_BASE) / dpi;
+ }
+ x1 = x0 + width;
+ break;
+ default:
+ break;
+ }
+
+ width = x1 - x0;
+ bmwidth = floor(width * dpi / DPI_BASE + 0.5);
+
+ auto px = unit_table.getUnit("px");
+ x0_adj->set_value(px->convert(x0, unit));
+ x1_adj->set_value(px->convert(x1, unit));
+ width_adj->set_value(px->convert(width, unit));
+ spin_buttons[SPIN_BMWIDTH]->set_value(bmwidth);
+}
+
+void SingleExport::areaYChange(sb_type type)
+{
+ auto y0_adj = spin_buttons[SPIN_Y0]->get_adjustment();
+ auto y1_adj = spin_buttons[SPIN_Y1]->get_adjustment();
+ auto height_adj = spin_buttons[SPIN_HEIGHT]->get_adjustment();
+
+ float y0, y1, dpi, height, bmheight;
+
+ // Get all values in px
+ Unit const *unit = units->getUnit();
+ y0 = unit->convert(y0_adj->get_value(), "px");
+ y1 = unit->convert(y1_adj->get_value(), "px");
+ height = unit->convert(height_adj->get_value(), "px");
+ bmheight = spin_buttons[SPIN_BMHEIGHT]->get_value();
+ dpi = spin_buttons[SPIN_DPI]->get_value();
+
+ switch (type) {
+ case SPIN_Y0:
+ bmheight = (y1 - y0) * dpi / DPI_BASE;
+ if (bmheight < SP_EXPORT_MIN_SIZE) {
+ y0 = y1 - (SP_EXPORT_MIN_SIZE * DPI_BASE) / dpi;
+ }
+ break;
+ case SPIN_Y1:
+ bmheight = (y1 - y0) * dpi / DPI_BASE;
+ if (bmheight < SP_EXPORT_MIN_SIZE) {
+ y1 = y0 + (SP_EXPORT_MIN_SIZE * DPI_BASE) / dpi;
+ }
+ break;
+ case SPIN_HEIGHT:
+ bmheight = height * dpi / DPI_BASE;
+ if (bmheight < SP_EXPORT_MIN_SIZE) {
+ height = (SP_EXPORT_MIN_SIZE * DPI_BASE) / dpi;
+ }
+ y1 = y0 + height;
+ break;
+ default:
+ break;
+ }
+
+ height = y1 - y0;
+ bmheight = floor(height * dpi / DPI_BASE + 0.5);
+
+ auto px = unit_table.getUnit("px");
+ y0_adj->set_value(px->convert(y0, unit));
+ y1_adj->set_value(px->convert(y1, unit));
+ height_adj->set_value(px->convert(height, unit));
+ spin_buttons[SPIN_BMHEIGHT]->set_value(bmheight);
+}
+
+void SingleExport::dpiChange(sb_type type)
+{
+ float dpi, height, width, bmheight, bmwidth;
+
+ // Get all values in px
+ Unit const *unit = units->getUnit();
+ height = unit->convert(spin_buttons[SPIN_HEIGHT]->get_value(), "px");
+ width = unit->convert(spin_buttons[SPIN_WIDTH]->get_value(), "px");
+ bmheight = spin_buttons[SPIN_BMHEIGHT]->get_value();
+ bmwidth = spin_buttons[SPIN_BMWIDTH]->get_value();
+ dpi = spin_buttons[SPIN_DPI]->get_value();
+
+ switch (type) {
+ case SPIN_BMHEIGHT:
+ if (bmheight < SP_EXPORT_MIN_SIZE) {
+ bmheight = SP_EXPORT_MIN_SIZE;
+ }
+ dpi = bmheight * DPI_BASE / height;
+ break;
+ case SPIN_BMWIDTH:
+ if (bmwidth < SP_EXPORT_MIN_SIZE) {
+ bmwidth = SP_EXPORT_MIN_SIZE;
+ }
+ dpi = bmwidth * DPI_BASE / width;
+ break;
+ case SPIN_DPI:
+ prefs->setDouble("/dialogs/export/defaultdpi/value", dpi);
+ break;
+ default:
+ break;
+ }
+
+ bmwidth = floor(width * dpi / DPI_BASE + 0.5);
+ bmheight = floor(height * dpi / DPI_BASE + 0.5);
+
+ spin_buttons[SPIN_BMHEIGHT]->set_value(bmheight);
+ spin_buttons[SPIN_BMWIDTH]->set_value(bmwidth);
+ spin_buttons[SPIN_DPI]->set_value(dpi);
+}
+
+void SingleExport::setDefaultSelectionMode()
+{
+ current_key = (selection_mode)0; // default key
+ bool found = false;
+ Glib::ustring pref_key_name = prefs->getString("/dialogs/export/exportarea/value");
+ for (auto [key, name] : selection_names) {
+ if (pref_key_name == name) {
+ current_key = key;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ pref_key_name = selection_names[current_key];
+ }
+
+ if (_desktop) {
+ if (current_key == SELECTION_SELECTION && (_desktop->getSelection())->isEmpty()) {
+ current_key = (selection_mode)0;
+ }
+ if ((_desktop->getSelection())->isEmpty()) {
+ selection_buttons[SELECTION_SELECTION]->set_sensitive(false);
+ }
+ if (current_key == SELECTION_CUSTOM &&
+ (spin_buttons[SPIN_HEIGHT]->get_value() == 0 || spin_buttons[SPIN_WIDTH]->get_value() == 0)) {
+ Geom::OptRect bbox = _document->preferredBounds();
+ setArea(bbox->min()[Geom::X], bbox->min()[Geom::Y], bbox->max()[Geom::X], bbox->max()[Geom::Y]);
+ }
+ } else {
+ current_key = (selection_mode)0;
+ }
+ selection_buttons[current_key]->set_active(true);
+ prefs->setString("/dialogs/export/exportarea/value", pref_key_name);
+
+ toggleSpinButtonVisibility();
+}
+
+void SingleExport::setExporting(bool exporting, Glib::ustring const &text)
+{
+ if (exporting) {
+ _prog->set_text(text);
+ _prog->set_fraction(0.0);
+ _prog->set_sensitive(true);
+ si_export->set_sensitive(false);
+ } else {
+ _prog->set_text("");
+ _prog->set_fraction(0.0);
+ _prog->set_sensitive(false);
+ si_export->set_sensitive(true);
+ }
+}
+
+ExportProgressDialog *SingleExport::create_progress_dialog(Glib::ustring progress_text)
+{
+ // dont forget to delete it later
+ auto dlg = new ExportProgressDialog(_("Export in progress"), true);
+ dlg->set_transient_for(*(INKSCAPE.active_desktop()->getToplevel()));
+
+ Gtk::ProgressBar *prg = Gtk::manage(new Gtk::ProgressBar());
+ prg->set_text(progress_text);
+ dlg->set_progress(prg);
+ auto CA = dlg->get_content_area();
+ CA->pack_start(*prg, FALSE, FALSE, 4);
+
+ Gtk::Button *btn = dlg->add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
+
+ btn->signal_clicked().connect(sigc::mem_fun(*this, &SingleExport::onProgressCancel));
+ dlg->signal_delete_event().connect(sigc::mem_fun(*this, &SingleExport::onProgressDelete));
+
+ dlg->show_all();
+ return dlg;
+}
+
+/// Called when dialog is deleted
+bool SingleExport::onProgressDelete(GdkEventAny * /*event*/)
+{
+ interrupted = true;
+ prog_dlg->set_stopped();
+ return TRUE;
+}
+/// Called when progress is cancelled
+void SingleExport::onProgressCancel()
+{
+ interrupted = true;
+ prog_dlg->set_stopped();
+}
+
+// Called for every progress iteration
+unsigned int SingleExport::onProgressCallback(float value, void *dlg)
+{
+ auto dlg2 = reinterpret_cast<ExportProgressDialog *>(dlg);
+
+ auto self = dynamic_cast<SingleExport *>(dlg2->get_export_panel());
+
+ if (!self || self->interrupted)
+ return FALSE;
+
+ auto current = dlg2->get_current();
+ auto total = dlg2->get_total();
+ if (total > 0) {
+ double completed = current;
+ completed /= static_cast<double>(total);
+
+ value = completed + (value / static_cast<double>(total));
+ }
+
+ auto prg = dlg2->get_progress();
+ prg->set_fraction(value);
+
+ if (self) {
+ self->_prog->set_fraction(value);
+ }
+
+ int evtcount = 0;
+ while ((evtcount < 16) && gdk_events_pending()) {
+ Gtk::Main::iteration(false);
+ evtcount += 1;
+ }
+
+ Gtk::Main::iteration(false);
+ return TRUE;
+}
+
+void SingleExport::refreshPreview()
+{
+ if (!_desktop) {
+ return;
+ }
+ if (!si_show_preview->get_active()) {
+ preview->resetPixels();
+ return;
+ }
+
+ std::vector<SPItem *> selected;
+ if (si_hide_all->get_active()) {
+ // This is because selection items is not a std::vector yet. FIXME.
+ selected = std::vector<SPItem *>(_desktop->getSelection()->items().begin(), _desktop->getSelection()->items().end());
+ }
+
+ Unit const *unit = units->getUnit();
+ float x0 = unit->convert(spin_buttons[SPIN_X0]->get_value(), "px");
+ float x1 = unit->convert(spin_buttons[SPIN_X1]->get_value(), "px");
+ float y0 = unit->convert(spin_buttons[SPIN_Y0]->get_value(), "px");
+ float y1 = unit->convert(spin_buttons[SPIN_Y1]->get_value(), "px");
+ preview->setDbox(x0, x1, y0, y1);
+ preview->refreshHide(selected);
+ preview->queueRefresh();
+}
+
+void SingleExport::setDesktop(SPDesktop *desktop)
+{
+ if (desktop != _desktop) {
+ _page_selected_connection.disconnect();
+ _desktop = desktop;
+ }
+}
+
+void SingleExport::setDocument(SPDocument *document)
+{
+ _document = document;
+ _page_selected_connection.disconnect();
+ if (document) {
+ // when the page selected is changes, update the export area
+ _page_selected_connection = document->getPageManager().connectPageSelected([=](SPPage *page) {
+ refreshPage();
+ refresh();
+ });
+ }
+ preview->setDocument(document);
+}
+
+} // namespace Dialog
+} // namespace UI
+} // 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:fileencoding=utf-8:textwidth=99 :