export.cpp revision ab5b79df9e6fa31f3482d118900c2dcd1b98664a
/** @file
* @brief PNG export dialog
*/
/* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* bulia byak <buliabyak@users.sf.net>
* Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
*
* Copyright (C) 1999-2007 Authors
* Copyright (C) 2001-2002 Ximian, Inc.
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
// This has to be included prior to anything that includes setjmp.h, it croaks otherwise
#include <png.h>
#include <gtkmm/buttonbox.h>
#include <gtkmm/togglebutton.h>
#ifdef WITH_GNOME_VFS
#endif
#include "helper/unit-menu.h"
#include "unit-constants.h"
#include "inkscape-private.h"
#include "document.h"
#include "desktop-handles.h"
#include "sp-item.h"
#include "selection.h"
#include "file.h"
#include "macros.h"
#include "sp-namedview.h"
#include "selection-chemistry.h"
#include "dialog-events.h"
#include "preferences.h"
#include "verbs.h"
#include "interface.h"
#include "helper/png-write.h"
#ifdef WIN32
#include <windows.h>
#include <COMMDLG.h>
#include <gdk/gdkwin32.h>
#endif
#define SP_EXPORT_MIN_SIZE 1.0
#define EXPORT_COORD_PRECISION 3
#define MIN_ONSCREEN_DISTANCE 50
// these all need to be reinitialized to their defaults during dialog_destroy
static gint x = -1000, y = -1000, w = 0, h = 0; // impossible original values to make sure they are read from prefs
/** What type of button is being pressed */
enum selection_type {
SELECTION_PAGE = 0, /**< Export the whole page */
SELECTION_DRAWING, /**< Export everything drawn on the page */
SELECTION_SELECTION, /**< Export everything that is selected */
SELECTION_CUSTOM, /**< Allows the user to set the region exported */
SELECTION_NUMBER_OF /**< A counter for the number of these guys */
};
/** A list of strings that is used both in the preferences, and in the
data fields to describe the various values of \c selection_type. */
static const char * selection_names[SELECTION_NUMBER_OF] = {
"page", "drawing", "selection", "custom"};
/** The names on the buttons for the various selection types. */
static const char * selection_labels[SELECTION_NUMBER_OF] = {
static void
{
x = -1000; y = -1000; w = 0; h = 0;
return;
} // end of sp_export_dialog_destroy()
/// Called when dialog is closed or inkscape is shut down.
static bool
{
if (x<0) x=0;
if (y<0) y=0;
return FALSE; // which means, go ahead and destroy it
} // end of sp_export_dialog_delete()
/**
\brief Creates a new spin button for the export dialog
\param key The name of the spin button
\param val A default value for the spin button
\param min Minimum value for the spin button
\param max Maximum value for the spin button
\param step The step size for the spin button
\param page Size of the page increment
\param us Unit selector that effects this spin button
\param t Table to put the spin button in
\param x X location in the table \c t to start with
\param y Y location in the table \c t to start with
\param ll Text to put on the left side of the spin button (optional)
\param lr Text to put on the right side of the spin button (optional)
\param digits Number of digits to display after the decimal
\param sensitive Whether the spin button is sensitive or not
\param cb Callback for when this spin button is changed (optional)
\param dlg Export dialog the spin button is being placed in
*/
static void
GtkWidget *t, int x, int y,
{
if (us) {
GTK_ADJUSTMENT (adj) );
}
int pos = 0;
if (ll) {
(GtkAttachOptions)0, (GtkAttachOptions)0, 0, 0 );
pos += 1;
}
(GtkAttachOptions)0, (GtkAttachOptions)0, 0, 0 );
pos += 1;
if (lr) {
(GtkAttachOptions)0, (GtkAttachOptions)0, 0, 0 );
pos += 1;
}
if (cb)
return;
} // end of sp_export_spinbutton_new()
{
lbl->set_use_markup(true);
/* Units box */
/* gets added to the vbox later, but the unit selector is needed
earlier than that */
if (desktop)
Gtk::ToggleButton* b;
for (int i = 0; i < SELECTION_NUMBER_OF; i++) {
togglebox->pack_start(*b, false, true, 0);
}
t->set_row_spacings (4);
t->set_col_spacings (4);
dlg );
dlg );
dlg );
dlg );
dlg );
dlg );
vb->pack_start(*t, false, false, 0);
return vb;
} // end of sp_export_dialog_area_box
id = "bitmap";
// std::cout << "Directory from dialog" << std::endl;
}
/* Grab document directory */
if (SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT)) {
// std::cout << "Directory from document" << std::endl;
}
}
// std::cout << "Home Directory" << std::endl;
}
return filename;
}
static void
{
vb_singleexport->set_sensitive(false);
} else {
vb_singleexport->set_sensitive(true);
}
}
void
sp_export_dialog (void)
{
if (!dlg) {
if (x == -1000 || y == -1000) {
}
if (w ==0 || h == 0) {
}
// if (x<0) x=0;
// if (y<0) y=0;
if (x >= 0 && y >= 0 && (x < (gdk_screen_width()-MIN_ONSCREEN_DISTANCE)) && (y < (gdk_screen_height()-MIN_ONSCREEN_DISTANCE)))
else
/* Export area frame */
{
}
/* Bitmap size frame */
{
lbl->set_use_markup(true);
const int rows = 2;
const int cols = 5;
const bool homogeneous = false;
t->set_row_spacings (4);
t->set_col_spacings (4);
size_box->pack_start(*t);
_("_Width:"), _("pixels at"), 0, 1,
dlg );
sp_export_spinbutton_new ( "xdpi",
dlg );
_("_Height:"), _("pixels at"), 0, 1,
dlg );
/** \todo
* Needs fixing: there's no way to set ydpi currently, so we use
* the defaultxdpi value here, too...
*/
}
/* File entry */
{
// true = has mnemonic
Gtk::Label *flabel = new Gtk::Label(_("<big><b>_Filename</b></big>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, true);
flabel->set_use_markup(true);
/*
* set the default filename to be that of the current path + document
* with .png extension
*
* One thing to notice here is that this filename may get
* overwritten, but it won't happen here. The filename gets
* written into the text field, but then the button to select
* the area gets set. In that code the filename can be changed
* if there are some with presidence in the document. So, while
* this code sets the name first, it may not be the one users
* really see.
*/
{
const gchar *text_extension = get_file_save_extension (Inkscape::Extension::FILE_SAVE_METHOD_SAVE_AS).c_str();
if (text_extension != NULL) {
oextension = dynamic_cast<Inkscape::Extension::Output *>(Inkscape::Extension::db.get(text_extension));
}
if (oextension != NULL) {
gchar * final_name;
extension_point[0] = '\0';
}
} else {
}
}
{
// true = has mnemonic
l->set_markup_with_mnemonic(_("_Browse..."));
pixlabel->pack_start(*l);
}
// pressing enter in the filename field is the same as clicking export:
// focus is in the filename initially:
fe->grab_focus();
// mnemonic in frame label moves focus to filename:
}
{
gtk_tooltips_set_tip(tt, be, _("Export each selected object into its own PNG file, using export hints if any (caution, overwrites without asking!)"), NULL);
}
{
gtk_tooltips_set_tip(tt, he, _("In the exported image, hide all objects except those that are selected"), NULL);
}
/* Buttons */
{
l->set_markup_with_mnemonic(_("_Export"));
image_label->pack_start(*l);
b->add(*image_label);
gtk_tooltips_set_tip (tt, GTK_WIDGET(b->gobj()), _("Export the bitmap file with these settings"), NULL);
}
} // end of if (!dlg)
return;
} // end of sp_export_dialog()
static void
{
if (num >= 2) {
gtk_widget_set_sensitive (be, true);
gtk_button_set_label (GTK_BUTTON(be), g_strdup_printf (ngettext("Batch export %d selected object","Batch export %d selected objects",num), num));
} else {
}
if (num > 0) {
gtk_widget_set_sensitive (he, true);
} else {
gtk_widget_set_sensitive (he, false);
}
}
static inline void
{
}
/* Try using the preferences */
if (key == SELECTION_NUMBER_OF) {
int i = SELECTION_NUMBER_OF;
for (i = 0; i < SELECTION_NUMBER_OF; i++) {
if (what == selection_names[i]) {
break;
}
}
}
key = (selection_type)i;
}
if (key == SELECTION_NUMBER_OF) {
}
}
/**
* \brief If selection changed or a different document activated, we must
* recalculate any chosen areas
*
*/
static void
{
current_key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
was_empty) {
TRUE );
}
current_key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
if (inkscape &&
SP_IS_INKSCAPE (inkscape) &&
selection &&
SELECTION_CUSTOM != current_key) {
}
}
static void
guint /*flags*/,
{
current_key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
switch (current_key) {
case SELECTION_DRAWING:
if ( SP_ACTIVE_DESKTOP ) {
if (bbox) {
}
}
break;
case SELECTION_SELECTION:
}
break;
default:
/* Do nothing for page or for custom */
break;
}
return;
}
/// Called when one of the selection buttons was toggled.
static void
{
return;
old_key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
/* Ignore all "turned off" events unless we're the only active button */
if (!gtk_toggle_button_get_active (tb) ) {
/* Don't let the current selection be deactived - but rerun the
activate to allow the user to renew the values */
}
return;
}
/* Turn off the currently active button unless it's us */
FALSE );
}
if ( SP_ACTIVE_DESKTOP )
{
/* Notice how the switch is used to 'fall through' here to get
various backups. If you modify this without noticing you'll
probabaly screw something up. */
switch (key) {
case SELECTION_SELECTION:
{
/* Only if there is a selection that we can set
do we break, otherwise we fall through to the
drawing */
// std::cout << "Using selection: SELECTION" << std::endl;
break;
}
case SELECTION_DRAWING:
/** \todo
* This returns wrong values if the document has a viewBox.
*/
/* If the drawing is valid, then we'll use it and break
otherwise we drop through to the page settings */
if (bbox) {
// std::cout << "Using selection: DRAWING" << std::endl;
break;
}
case SELECTION_PAGE:
// std::cout << "Using selection: PAGE" << std::endl;
break;
case SELECTION_CUSTOM:
default:
break;
} // switch
// remember area setting
}
} // end of if ( SP_ACTIVE_DESKTOP )
switch (key) {
case SELECTION_PAGE:
case SELECTION_DRAWING: {
if (doc_export_name != NULL) {
} else {
}
}
break;
}
case SELECTION_SELECTION:
/* If we still don't have a filename -- let's build
one that's nice */
break;
}
}
}
}
break;
case SELECTION_CUSTOM:
default:
break;
}
}
if (xdpi != 0.0) {
}
/* These can't be separate, and setting x sets y, so for
now setting this is disabled. Hopefully it won't be in
the future */
}
}
return;
} // end of sp_export_area_toggled()
/// Called when dialog is deleted
static gint
{
return TRUE;
} // end of sp_export_progress_delete()
/// Called when progress is cancelled
static void
{
} // end of sp_export_progress_cancel()
/// Called for every progress iteration
static unsigned int
{
int evtcount;
return FALSE;
evtcount = 0;
evtcount += 1;
}
return TRUE;
} // end of sp_export_progress_callback()
dlg = gtk_dialog_new ();
prg = gtk_progress_bar_new ();
return dlg;
}
// FIXME: Some lib function should be available to do this ...
static gchar *
{
if ( !dot )
{
else
{
else
{
}
}
}
}
/// Called when export button is clicked
static void
{
if (!SP_ACTIVE_DESKTOP) return;
// Batch export of selected objects
gint n = 0;
if (num < 1)
return;
i != NULL;
i = i->next) {
// retrieve export filename hint
if (!filename) {
} else {
//Make relative paths go from the document location, if possible:
if (dirname) {
}
}
if (!path) {
}
}
// retrieve export dpi hints
const gchar *dpi_hint = SP_OBJECT_REPR(item)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
if (dpi_hint) {
}
if (dpi == 0.0) {
}
if (area) {
/* Do export */
)) {
}
}
}
n++;
}
} else {
sp_ui_error_dialog(_("You have to enter a filename"));
return;
}
sp_ui_error_dialog (_("The chosen area to be exported is invalid"));
return;
}
{
safeDir);
return;
}
// make sure that .png is the extension of the file:
/* Do export */
)) {
}
/* Reset the filename so that it can be changed again by changing
selections and all that */
/* Setup the values in the document */
switch ((selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")))) {
case SELECTION_PAGE:
case SELECTION_DRAWING: {
bool modified = false;
const gchar * temp_string;
sp_document_set_undo_sensitive(doc, false);
modified = true;
}
modified = true;
}
modified = true;
}
if (modified) {
}
break;
}
case SELECTION_SELECTION: {
bool modified = false;
sp_document_set_undo_sensitive(doc, false);
const gchar * temp_string;
modified = true;
}
}
modified = true;
}
modified = true;
}
}
if (modified) {
}
break;
}
default:
break;
}
}
} // end of sp_export_export_clicked()
/// Called when Browse button is clicked
/// @todo refactor this code to use ui/dialogs/filedialog.cpp
static void
{
NULL );
#ifdef WITH_GNOME_VFS
if (gnome_vfs_initialized()) {
}
#endif
if (*filename == '\0') {
}
#ifdef WIN32
// code in this section is borrowed from ui/dialogs/filedialogimpl-win32.cpp
WCHAR* title_string = (WCHAR*)g_utf8_to_utf16(_("Select a filename for exporting"), -1, NULL, NULL, NULL);
// Copy the selected file name, converting from UTF-8 to UTF-16
opf.lpstrCustomFilter = 0;
opf.nMaxCustFilter = 0L;
opf.nMaxFileTitle=0;
opf.lpstrInitialDir = 0;
opf.nFileOffset = 0;
if (GetSaveFileNameW(&opf) != 0)
{
// Copy the selected file name, converting from UTF-16 to UTF-8
}
#else
{
}
#endif
return;
} // end of sp_export_browse_clicked()
// TODO: Move this to nr-rect-fns.h.
static bool
{
return (
);
}
/**
\brief This function is used to detect the current selection setting
based on the values in the x0, y0, x1 and y0 fields.
\param base The export dialog itself
One of the most confusing parts of this function is why the array
is built at the beginning. What needs to happen here is that we
should always check the current selection to see if it is the valid
one. While this is a performance improvement it is also a usability
one during the cases where things like selections and drawings match
size. This way buttons change less 'randomly' (atleast in the eyes
of the user). To do this an array is built where the current selection
type is placed first, and then the others in an order from smallest
to largest (this can be configured by reshuffling \c test_order).
All of the values in this function are rounded to two decimal places
because that is what is shown to the user. While everything is kept
more accurate than that, the user can't control more acurrate than
that, so for this to work for them - it needs to check on that level
of accuracy.
\todo finish writing this up
*/
static void
static const selection_type test_order[SELECTION_NUMBER_OF] = {SELECTION_SELECTION, SELECTION_DRAWING, SELECTION_PAGE, SELECTION_CUSTOM};
//std::cout << "Current " << current_bbox;
this_test[0] = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
for (int i = 0; i < SELECTION_NUMBER_OF; i++) {
}
for (int i = 0;
i < SELECTION_NUMBER_OF + 1 &&
key == SELECTION_NUMBER_OF &&
i++) {
// std::cout << "Looking at: " << selection_names[this_test[i]] << std::endl;
switch (this_test[i]) {
case SELECTION_SELECTION:
//std::cout << "Selection " << bbox;
}
}
break;
case SELECTION_DRAWING: {
// std::cout << "Drawing " << bbox2;
}
break;
}
case SELECTION_PAGE: {
// std::cout << "Page " << bbox;
}
break;
}
default:
break;
}
}
// std::cout << std::endl;
if (key == SELECTION_NUMBER_OF) {
}
/* We're now using a custom size, not a fixed one */
/* printf("Detecting state: %s\n", selection_names[key]); */
selection_type old = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gtk_object_get_data(base, selection_names[old])), FALSE);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gtk_object_get_data(base, selection_names[key])), TRUE);
return;
} /* sp_export_detect_size */
/// Called when area x0 value is changed
static void
{
return;
(base, "units")))
{
return;
}
if (width < SP_EXPORT_MIN_SIZE) {
} else {
}
}
return;
} // end of sp_export_area_x_value_changed()
/// Called when area y0 value is changed.
static void
{
return;
(base, "units")))
{
return;
}
if (height < SP_EXPORT_MIN_SIZE) {
} else {
}
}
return;
} // end of sp_export_area_y_value_changed()
/// Called when x1-x0 or area width is changed
static void
{
return;
(base, "units"))) {
return;
}
if (bmwidth < SP_EXPORT_MIN_SIZE) {
}
return;
} // end of sp_export_area_width_value_changed()
/// Called when y1-y0 or area height is changed.
static void
{
return;
(base, "units"))) {
return;
}
if (bmheight < SP_EXPORT_MIN_SIZE) {
}
return;
} // end of sp_export_area_height_value_changed()
/**
\brief A function to set the ydpi
\param base The export dialog
This function grabs all of the y values and then figures out the
new bitmap size based on the changing dpi value. The dpi value is
gotten from the xdpi setting as these can not currently be independent.
*/
static void
{
return;
} // end of sp_export_set_image_y()
/**
\brief A function to set the xdpi
\param base The export dialog
This function grabs all of the x values and then figures out the
new bitmap size based on the changing dpi value. The dpi value is
gotten from the xdpi setting as these can not currently be independent.
*/
static void
{
return;
} // end of sp_export_set_image_x()
/// Called when pixel width is changed
static void
{
return;
(base, "units"))) {
return;
}
if (bmwidth < SP_EXPORT_MIN_SIZE) {
}
return;
} // end of sp_export_bitmap_width_value_changed()
/// Called when pixel height is changed
static void
{
return;
(base, "units"))) {
return;
}
if (bmheight < SP_EXPORT_MIN_SIZE) {
}
return;
} // end of sp_export_bitmap_width_value_changed()
/**
\brief A function to adjust the bitmap width when the xdpi value changes
\param adj The adjustment that was changed
\param base The export dialog itself
The first thing this function checks is to see if we are doing an
update. If we are, this function just returns because there is another
instance of it that will handle everything for us. If there is a
units change, we also assume that everyone is being updated appropriately
and there is nothing for us to do.
If we're the highest level function, we set the update flag, and
continue on our way.
All of the values are grabbed using the \c sp_export_value_get functions
(call to the _pt ones for x0 and x1 but just standard for xdpi). The
xdpi value is saved in the preferences for the next time the dialog
is opened. (does the selection dpi need to be set here?)
A check is done to to ensure that we aren't outputing an invalid width,
this is set by SP_EXPORT_MIN_SIZE. If that is the case the dpi is
changed to make it valid.
After all of this the bitmap width is changed.
We also change the ydpi. This is a temporary hack as these can not
currently be independent. This is likely to change in the future.
*/
void
{
return;
(base, "units"))) {
return;
}
// remember xdpi setting
if (bmwidth < SP_EXPORT_MIN_SIZE) {
else
}
return;
} // end of sp_export_xdpi_value_changed()
/**
\brief A function to change the area that is used for the exported
bitmap.
\param base This is the export dialog
\param x0 Horizontal upper left hand corner of the picture in points
\param y0 Vertical upper left hand corner of the picture in points
\param x1 Horizontal lower right hand corner of the picture in points
\param y1 Vertical lower right hand corner of the picture in points
This function just calls \c sp_export_value_set_px for each of the
parameters that is passed in. This allows for setting them all in
one convient area.
Update is set to suspend all of the other test running while all the
values are being set up. This allows for a performance increase, but
it also means that the wrong type won't be detected with only some of
the values set. After all the values are set everyone is told that
there has been an update.
*/
static void
{
return;
}
/**
\brief Sets the value of an adjustment
\param base The export dialog
\param key Which adjustment to set
\param val What value to set it to
This function finds the adjustment using the data stored in the
export dialog. After finding the adjustment it then sets
the value of it.
*/
static void
{
}
/**
\brief A function to set a value using the units points
\param base The export dialog
\param key Which value should be set
\param val What the value should be in points
This function first gets the adjustment for the key that is passed
in. It then figures out what units are currently being used in the
dialog. After doing all of that, it then converts the incoming
value and sets the adjustment.
*/
static void
{
const SPUnit *unit = sp_unit_selector_get_unit ((SPUnitSelector *)gtk_object_get_data (base, "units") );
return;
}
/**
\brief Get the value of an adjustment in the export dialog
\param base The export dialog
\param key Which adjustment is being looked for
\return The value in the specified adjustment
This function gets the adjustment from the data field in the export
dialog. It then grabs the value from the adjustment.
*/
static float
{
}
/**
\brief Grabs a value in the export dialog and converts the unit
to points
\param base The export dialog
\param key Which value should be returned
\return The value in the adjustment in points
This function, at its most basic, is a call to \c sp_export_value_get
to get the value of the adjustment. It then finds the units that
are being used by looking at the "units" attribute of the export
dialog. Using that it converts the returned value into points.
*/
static float
{
const SPUnit *unit = sp_unit_selector_get_unit ((SPUnitSelector *)gtk_object_get_data (base, "units"));
} // end of sp_export_value_get_px()
/**
\brief This function is called when the filename is changed by
anyone. It resets the virgin bit.
\param object Text entry box
\param data The export dialog
\return None
This function gets called when the text area is modified. It is
looking for the case where the text area is modified from its
original value. In that case it sets the "filename-modified" bit
to TRUE. If the text dialog returns back to the original text, the
bit gets reset. This should stop simple mistakes.
*/
static void
{
// printf("Modified: FALSE\n");
} else {
// printf("Modified: TRUE\n");
}
return;
} // end sp_export_filename_modified
/*
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:encoding=utf-8:textwidth=99 :