da5a8c541306e6ee7eb6b770b7684d065751a9de
1 #define __SP_EXPORT_C__
3 /** \file
4 * \brief PNG export dialog
5 */
7 /*
8 * Authors:
9 * Lauris Kaplinski <lauris@kaplinski.com>
10 * bulia byak <buliabyak@users.sf.net>
11 * Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
12 *
13 * Copyright (C) 1999-2007 Authors
14 * Copyright (C) 2001-2002 Ximian, Inc.
15 *
16 * Released under GNU GPL, read the file 'COPYING' for more information
17 */
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
23 #include <gtk/gtk.h>
24 #include <gtkmm/box.h>
25 #include <gtkmm/buttonbox.h>
26 #include <gtkmm/label.h>
27 #include <gtkmm/widget.h>
28 #include <gtkmm/togglebutton.h>
29 #include <gtkmm/entry.h>
30 #include <gtkmm/image.h>
31 #include <gtkmm/stockid.h>
32 #include <gtkmm/stock.h>
34 #include <glibmm/i18n.h>
35 #include "helper/unit-menu.h"
36 #include "helper/units.h"
37 #include "unit-constants.h"
38 #include "helper/window.h"
39 #include "inkscape-private.h"
40 #include "document.h"
41 #include "desktop-handles.h"
42 #include "sp-item.h"
43 #include "selection.h"
44 #include "file.h"
45 #include "macros.h"
46 #include "sp-namedview.h"
47 #include "selection-chemistry.h"
49 #include "dialog-events.h"
50 #include "../prefs-utils.h"
51 #include "../verbs.h"
52 #include "../interface.h"
54 #include "extension/output.h"
55 #include "extension/db.h"
57 #include "io/sys.h"
59 #include "helper/png-write.h"
62 #define SP_EXPORT_MIN_SIZE 1.0
64 #define DPI_BASE PX_PER_IN
66 #define EXPORT_COORD_PRECISION 3
68 #define MIN_ONSCREEN_DISTANCE 50
70 static void sp_export_area_toggled ( GtkToggleButton *tb, GtkObject *base );
71 static void sp_export_export_clicked ( GtkButton *button, GtkObject *base );
72 static void sp_export_browse_clicked ( GtkButton *button, gpointer userdata );
74 static void sp_export_area_x_value_changed ( GtkAdjustment *adj,
75 GtkObject *base);
77 static void sp_export_area_y_value_changed ( GtkAdjustment *adj,
78 GtkObject *base);
80 static void sp_export_area_width_value_changed ( GtkAdjustment *adj,
81 GtkObject *base);
83 static void sp_export_area_height_value_changed ( GtkAdjustment *adj,
84 GtkObject *base);
86 static void sp_export_bitmap_width_value_changed ( GtkAdjustment *adj,
87 GtkObject *base);
89 static void sp_export_bitmap_height_value_changed ( GtkAdjustment *adj,
90 GtkObject *base);
92 static void sp_export_xdpi_value_changed ( GtkAdjustment *adj,
93 GtkObject *base);
95 static void sp_export_selection_changed ( Inkscape::Application *inkscape,
96 Inkscape::Selection *selection,
97 GtkObject *base);
98 static void sp_export_selection_modified ( Inkscape::Application *inkscape,
99 Inkscape::Selection *selection,
100 guint flags,
101 GtkObject *base );
103 static void sp_export_set_area (GtkObject *base, double x0, double y0, double x1, double y1);
104 static void sp_export_value_set (GtkObject *base, const gchar *key, double val);
105 static void sp_export_value_set_px (GtkObject *base, const gchar *key, double val);
106 static float sp_export_value_get ( GtkObject *base, const gchar *key );
107 static float sp_export_value_get_px ( GtkObject *base, const gchar *key );
109 static void sp_export_filename_modified (GtkObject * object, gpointer data);
110 static inline void sp_export_find_default_selection(GtkWidget * dlg);
111 static void sp_export_detect_size(GtkObject * base);
113 static const gchar *prefs_path = "dialogs.export";
115 // these all need to be reinitialized to their defaults during dialog_destroy
116 static GtkWidget *dlg = NULL;
117 static win_data wd;
118 static gint x = -1000, y = -1000, w = 0, h = 0; // impossible original values to make sure they are read from prefs
119 static gchar * original_name = NULL;
120 static gchar * doc_export_name = NULL;
121 static bool was_empty = TRUE;
123 /** What type of button is being pressed */
124 enum selection_type {
125 SELECTION_PAGE = 0, /**< Export the whole page */
126 SELECTION_DRAWING, /**< Export everything drawn on the page */
127 SELECTION_SELECTION, /**< Export everything that is selected */
128 SELECTION_CUSTOM, /**< Allows the user to set the region exported */
129 SELECTION_NUMBER_OF /**< A counter for the number of these guys */
130 };
132 /** A list of strings that is used both in the preferences, and in the
133 data fields to describe the various values of \c selection_type. */
134 static const char * selection_names[SELECTION_NUMBER_OF] = {
135 "page", "drawing", "selection", "custom"};
137 /** The names on the buttons for the various selection types. */
138 static const char * selection_labels[SELECTION_NUMBER_OF] = {
139 N_("_Page"), N_("_Drawing"), N_("_Selection"), N_("_Custom")};
141 static void
142 sp_export_dialog_destroy ( GtkObject *object, gpointer data )
143 {
144 sp_signal_disconnect_by_data (INKSCAPE, dlg);
146 wd.win = dlg = NULL;
147 wd.stop = 0;
148 x = -1000; y = -1000; w = 0; h = 0;
149 g_free(original_name);
150 original_name = NULL;
151 g_free(doc_export_name);
152 doc_export_name = NULL;
153 was_empty = TRUE;
155 return;
156 } // end of sp_export_dialog_destroy()
158 /// Called when dialog is closed or inkscape is shut down.
159 static bool
160 sp_export_dialog_delete ( GtkObject *object, GdkEvent *event, gpointer data )
161 {
163 gtk_window_get_position ((GtkWindow *) dlg, &x, &y);
164 gtk_window_get_size ((GtkWindow *) dlg, &w, &h);
166 if (x<0) x=0;
167 if (y<0) y=0;
169 prefs_set_int_attribute (prefs_path, "x", x);
170 prefs_set_int_attribute (prefs_path, "y", y);
171 prefs_set_int_attribute (prefs_path, "w", w);
172 prefs_set_int_attribute (prefs_path, "h", h);
174 return FALSE; // which means, go ahead and destroy it
176 } // end of sp_export_dialog_delete()
178 /**
179 \brief Creates a new spin button for the export dialog
180 \param key The name of the spin button
181 \param val A default value for the spin button
182 \param min Minimum value for the spin button
183 \param max Maximum value for the spin button
184 \param step The step size for the spin button
185 \param page Size of the page increment
186 \param us Unit selector that effects this spin button
187 \param t Table to put the spin button in
188 \param x X location in the table \c t to start with
189 \param y Y location in the table \c t to start with
190 \param ll Text to put on the left side of the spin button (optional)
191 \param lr Text to put on the right side of the spin button (optional)
192 \param digits Number of digits to display after the decimal
193 \param sensitive Whether the spin button is sensitive or not
194 \param cb Callback for when this spin button is changed (optional)
195 \param dlg Export dialog the spin button is being placed in
197 */
198 static void
199 sp_export_spinbutton_new ( gchar *key, float val, float min, float max,
200 float step, float page, GtkWidget *us,
201 GtkWidget *t, int x, int y,
202 const gchar *ll, const gchar *lr,
203 int digits, unsigned int sensitive,
204 GCallback cb, GtkWidget *dlg )
205 {
206 GtkObject *a = gtk_adjustment_new (val, min, max, step, page, page);
207 gtk_object_set_data (a, "key", key);
208 gtk_object_set_data (GTK_OBJECT (dlg), (const gchar *)key, a);
210 if (us) {
211 sp_unit_selector_add_adjustment ( SP_UNIT_SELECTOR (us),
212 GTK_ADJUSTMENT (a) );
213 }
215 int pos = 0;
217 GtkWidget *l = NULL;
219 if (ll) {
221 l = gtk_label_new_with_mnemonic ((const gchar *)ll);
222 gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
223 gtk_table_attach ( GTK_TABLE (t), l, x + pos, x + pos + 1, y, y + 1,
224 (GtkAttachOptions)0, (GtkAttachOptions)0, 0, 0 );
225 gtk_widget_set_sensitive (l, sensitive);
226 pos += 1;
228 }
230 GtkWidget *sb = gtk_spin_button_new (GTK_ADJUSTMENT (a), 1.0, digits);
231 gtk_table_attach ( GTK_TABLE (t), sb, x + pos, x + pos + 1, y, y + 1,
232 (GtkAttachOptions)0, (GtkAttachOptions)0, 0, 0 );
233 gtk_widget_set_size_request (sb, 80, -1);
234 gtk_widget_set_sensitive (sb, sensitive);
235 pos += 1;
237 if (ll) { gtk_label_set_mnemonic_widget (GTK_LABEL(l), sb); }
239 if (lr) {
241 l = gtk_label_new_with_mnemonic ((const gchar *)lr);
242 gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
243 gtk_table_attach ( GTK_TABLE (t), l, x + pos, x + pos + 1, y, y + 1,
244 (GtkAttachOptions)0, (GtkAttachOptions)0, 0, 0 );
245 gtk_widget_set_sensitive (l, sensitive);
246 pos += 1;
248 gtk_label_set_mnemonic_widget (GTK_LABEL(l), sb);
249 }
251 if (cb)
252 gtk_signal_connect (a, "value_changed", cb, dlg);
254 return;
255 } // end of sp_export_spinbutton_new()
258 static Gtk::VBox *
259 sp_export_dialog_area_box (GtkWidget * dlg)
260 {
261 Gtk::VBox* vb = new Gtk::VBox(false, 3);
263 Gtk::Label* lbl = new Gtk::Label(_("<big><b>Export area</b></big>"), Gtk::ALIGN_LEFT);
264 lbl->set_use_markup(true);
265 vb->pack_start(*lbl);
267 /* Units box */
268 Gtk::HBox* unitbox = new Gtk::HBox(false, 0);
269 /* gets added to the vbox later, but the unit selector is needed
270 earlier than that */
272 Gtk::Widget* us = Glib::wrap(sp_unit_selector_new (SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE));
273 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
274 if (desktop)
275 sp_unit_selector_set_unit (SP_UNIT_SELECTOR(us->gobj()), sp_desktop_namedview(desktop)->doc_units);
276 unitbox->pack_end(*us, false, false, 0);
277 Gtk::Label* l = new Gtk::Label(_("Units:"));
278 unitbox->pack_end(*l, false, false, 3);
279 gtk_object_set_data (GTK_OBJECT (dlg), "units", us->gobj());
281 Gtk::HBox* togglebox = new Gtk::HBox(true, 0);
283 Gtk::ToggleButton* b;
284 for (int i = 0; i < SELECTION_NUMBER_OF; i++) {
285 b = new Gtk::ToggleButton(_(selection_labels[i]), true);
286 b->set_data("key", GINT_TO_POINTER(i));
287 gtk_object_set_data (GTK_OBJECT (dlg), selection_names[i], b->gobj());
288 togglebox->pack_start(*b, false, true, 0);
289 gtk_signal_connect ( GTK_OBJECT (b->gobj()), "clicked",
290 GTK_SIGNAL_FUNC (sp_export_area_toggled), dlg );
291 }
293 g_signal_connect ( G_OBJECT (INKSCAPE), "change_selection",
294 G_CALLBACK (sp_export_selection_changed), dlg );
295 g_signal_connect ( G_OBJECT (INKSCAPE), "modify_selection",
296 G_CALLBACK (sp_export_selection_modified), dlg );
297 g_signal_connect ( G_OBJECT (INKSCAPE), "activate_desktop",
298 G_CALLBACK (sp_export_selection_changed), dlg );
300 Gtk::Table* t = new Gtk::Table(2, 6, FALSE);
301 t->set_row_spacings (4);
302 t->set_col_spacings (4);
304 sp_export_spinbutton_new ( "x0", 0.0, -1000000.0, 1000000.0, 0.1, 1.0, us->gobj(),
305 GTK_WIDGET(t->gobj()), 0, 0, _("_x0:"), NULL, EXPORT_COORD_PRECISION, 1,
306 G_CALLBACK ( sp_export_area_x_value_changed),
307 dlg );
309 sp_export_spinbutton_new ( "x1", 0.0, -1000000.0, 1000000.0, 0.1, 1.0, us->gobj(),
310 GTK_WIDGET(t->gobj()), 2, 0, _("x_1:"), NULL, EXPORT_COORD_PRECISION, 1,
311 G_CALLBACK (sp_export_area_x_value_changed),
312 dlg );
314 sp_export_spinbutton_new ( "width", 0.0, -1000000.0, 1000000.0, 0.1, 1.0,
315 us->gobj(), GTK_WIDGET(t->gobj()), 4, 0, _("Width:"), NULL, EXPORT_COORD_PRECISION, 1,
316 G_CALLBACK
317 (sp_export_area_width_value_changed),
318 dlg );
320 sp_export_spinbutton_new ( "y0", 0.0, -1000000.0, 1000000.0, 0.1, 1.0, us->gobj(),
321 GTK_WIDGET(t->gobj()), 0, 1, _("_y0:"), NULL, EXPORT_COORD_PRECISION, 1,
322 G_CALLBACK (sp_export_area_y_value_changed),
323 dlg );
325 sp_export_spinbutton_new ( "y1", 0.0, -1000000.0, 1000000.0, 0.1, 1.0, us->gobj(),
326 GTK_WIDGET(t->gobj()), 2, 1, _("y_1:"), NULL, EXPORT_COORD_PRECISION, 1,
327 G_CALLBACK (sp_export_area_y_value_changed),
328 dlg );
330 sp_export_spinbutton_new ( "height", 0.0, -1000000.0, 1000000.0, 0.1, 1.0,
331 us->gobj(), GTK_WIDGET(t->gobj()), 4, 1, _("Height:"), NULL, EXPORT_COORD_PRECISION, 1,
332 G_CALLBACK (sp_export_area_height_value_changed),
333 dlg );
335 vb->pack_start(*togglebox, false, false, 3);
336 vb->pack_start(*t, false, false, 0);
337 vb->pack_start(*unitbox, false, false, 0);
339 return vb;
340 } // end of sp_export_dialog_area_box
343 gchar* create_filepath_from_id (const gchar *id, const gchar *file_entry_text) {
345 if (id == NULL) /* This should never happen */
346 id = "bitmap";
348 gchar * directory = NULL;
350 if (directory == NULL && file_entry_text != NULL && file_entry_text[0] != '\0') {
351 // std::cout << "Directory from dialog" << std::endl;
352 directory = g_dirname(file_entry_text);
353 }
355 if (directory == NULL) {
356 /* Grab document directory */
357 if (SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT)) {
358 // std::cout << "Directory from document" << std::endl;
359 directory = g_dirname(SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT));
360 }
361 }
363 if (directory == NULL) {
364 // std::cout << "Home Directory" << std::endl;
365 directory = homedir_path(NULL);
366 }
368 gchar * id_ext = g_strconcat(id, ".png", NULL);
369 gchar *filename = g_build_filename(directory, id_ext, NULL);
370 g_free(directory);
371 g_free(id_ext);
372 return filename;
373 }
375 static void
376 batch_export_clicked (GtkWidget *widget, GtkObject *base)
377 {
378 Gtk::Widget *vb_singleexport = (Gtk::Widget *)gtk_object_get_data(base, "vb_singleexport");
379 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget))) {
380 vb_singleexport->set_sensitive(false);
381 } else {
382 vb_singleexport->set_sensitive(true);
383 }
384 }
386 void
387 sp_export_dialog (void)
388 {
389 if (!dlg) {
391 gchar title[500];
392 sp_ui_dialog_title_string (Inkscape::Verb::get(SP_VERB_FILE_EXPORT), title);
394 dlg = sp_window_new (title, TRUE);
396 if (x == -1000 || y == -1000) {
397 x = prefs_get_int_attribute (prefs_path, "x", 0);
398 y = prefs_get_int_attribute (prefs_path, "y", 0);
399 }
401 if (w ==0 || h == 0) {
402 w = prefs_get_int_attribute (prefs_path, "w", 0);
403 h = prefs_get_int_attribute (prefs_path, "h", 0);
404 }
406 // if (x<0) x=0;
407 // if (y<0) y=0;
409 if (w && h) gtk_window_resize ((GtkWindow *) dlg, w, h);
410 if (x >= 0 && y >= 0 && (x < (gdk_screen_width()-MIN_ONSCREEN_DISTANCE)) && (y < (gdk_screen_height()-MIN_ONSCREEN_DISTANCE)))
411 gtk_window_move ((GtkWindow *) dlg, x, y);
412 else
413 gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
414 sp_transientize (dlg);
415 wd.win = dlg;
416 wd.stop = 0;
418 g_signal_connect ( G_OBJECT (INKSCAPE), "activate_desktop",
419 G_CALLBACK (sp_transientize_callback), &wd);
421 gtk_signal_connect ( GTK_OBJECT (dlg), "event",
422 GTK_SIGNAL_FUNC (sp_dialog_event_handler), dlg);
424 gtk_signal_connect ( GTK_OBJECT (dlg), "destroy",
425 G_CALLBACK (sp_export_dialog_destroy), dlg);
427 gtk_signal_connect ( GTK_OBJECT (dlg), "delete_event",
428 G_CALLBACK (sp_export_dialog_delete), dlg);
430 g_signal_connect ( G_OBJECT (INKSCAPE), "shut_down",
431 G_CALLBACK (sp_export_dialog_delete), dlg);
433 g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_hide",
434 G_CALLBACK (sp_dialog_hide), dlg);
436 g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_unhide",
437 G_CALLBACK (sp_dialog_unhide), dlg);
439 GtkTooltips *tt = gtk_tooltips_new();
441 Gtk::VBox *vb = new Gtk::VBox(false, 3);
442 vb->set_border_width(3);
443 gtk_container_add (GTK_CONTAINER (dlg), GTK_WIDGET(vb->gobj()));
445 Gtk::VBox *vb_singleexport = new Gtk::VBox(false, 0);
446 vb_singleexport->set_border_width(0);
447 vb->pack_start(*vb_singleexport);
448 gtk_object_set_data(GTK_OBJECT(dlg), "vb_singleexport", vb_singleexport);
450 /* Export area frame */
451 {
452 Gtk::VBox *area_box = sp_export_dialog_area_box(dlg);
453 area_box->set_border_width(3);
454 vb_singleexport->pack_start(*area_box, false, false, 0);
455 }
457 /* Bitmap size frame */
458 {
459 Gtk::VBox *size_box = new Gtk::VBox(false, 3);
460 size_box->set_border_width(3);
462 Gtk::Label* lbl = new Gtk::Label(_("<big><b>Bitmap size</b></big>"), Gtk::ALIGN_LEFT);
463 lbl->set_use_markup(true);
464 size_box->pack_start(*lbl, false, false, 0);
465 const int rows = 2;
466 const int cols = 5;
467 const bool homogeneous = false;
468 Gtk::Table *t = new Gtk::Table(rows, cols, homogeneous);
469 t->set_row_spacings (4);
470 t->set_col_spacings (4);
471 size_box->pack_start(*t);
473 sp_export_spinbutton_new ( "bmwidth", 16.0, 1.0, 1000000.0, 1.0, 10.0,
474 NULL, GTK_WIDGET(t->gobj()), 0, 0,
475 _("_Width:"), _("pixels at"), 0, 1,
476 G_CALLBACK
477 (sp_export_bitmap_width_value_changed),
478 dlg );
480 sp_export_spinbutton_new ( "xdpi",
481 prefs_get_double_attribute
482 ( "dialogs.export.defaultxdpi",
483 "value", DPI_BASE),
484 0.01, 100000.0, 0.1, 1.0, NULL, GTK_WIDGET(t->gobj()), 3, 0,
485 NULL, _("dp_i"), 2, 1,
486 G_CALLBACK (sp_export_xdpi_value_changed),
487 dlg );
489 sp_export_spinbutton_new ( "bmheight", 16.0, 1.0, 1000000.0, 1.0, 10.0,
490 NULL, GTK_WIDGET(t->gobj()), 0, 1,
491 _("Height:"), _("pixels at"), 0, 1,
492 G_CALLBACK
493 (sp_export_bitmap_height_value_changed),
494 dlg );
496 /** \todo
497 * Needs fixing: there's no way to set ydpi currently, so we use
498 * the defaultxdpi value here, too...
499 */
500 sp_export_spinbutton_new ( "ydpi", prefs_get_double_attribute
501 ( "dialogs.export.defaultxdpi",
502 "value", DPI_BASE),
503 0.01, 100000.0, 0.1, 1.0, NULL, GTK_WIDGET(t->gobj()), 3, 1,
504 NULL, _("dpi"), 2, 0, NULL, dlg );
506 vb_singleexport->pack_start(*size_box);
507 }
509 /* File entry */
510 {
511 Gtk::VBox* file_box = new Gtk::VBox(false, 3);
512 file_box->set_border_width(3);
514 // true = has mnemonic
515 Gtk::Label *flabel = new Gtk::Label(_("<big><b>_Filename</b></big>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, true);
516 flabel->set_use_markup(true);
517 file_box->pack_start(*flabel, false, false, 0);
519 Gtk::Entry *fe = new Gtk::Entry();
521 /*
522 * set the default filename to be that of the current path + document
523 * with .png extension
524 *
525 * One thing to notice here is that this filename may get
526 * overwritten, but it won't happen here. The filename gets
527 * written into the text field, but then the button to select
528 * the area gets set. In that code the filename can be changed
529 * if there are some with presidence in the document. So, while
530 * this code sets the name first, it may not be the one users
531 * really see.
532 */
533 if (SP_ACTIVE_DOCUMENT && SP_DOCUMENT_URI (SP_ACTIVE_DOCUMENT))
534 {
535 gchar *name;
536 SPDocument * doc = SP_ACTIVE_DOCUMENT;
537 const gchar *uri = SP_DOCUMENT_URI (doc);
538 Inkscape::XML::Node * repr = sp_document_repr_root(doc);
539 const gchar * text_extension = repr->attribute("inkscape:output_extension");
540 Inkscape::Extension::Output * oextension = NULL;
542 if (text_extension != NULL) {
543 oextension = dynamic_cast<Inkscape::Extension::Output *>(Inkscape::Extension::db.get(text_extension));
544 }
546 if (oextension != NULL) {
547 gchar * old_extension = oextension->get_extension();
548 if (g_str_has_suffix(uri, old_extension)) {
549 gchar * uri_copy;
550 gchar * extension_point;
551 gchar * final_name;
553 uri_copy = g_strdup(uri);
554 extension_point = g_strrstr(uri_copy, old_extension);
555 extension_point[0] = '\0';
557 final_name = g_strconcat(uri_copy, ".png", NULL);
558 fe->set_text(final_name);
560 g_free(final_name);
561 g_free(uri_copy);
562 }
563 } else {
564 name = g_strconcat(uri, ".png", NULL);
565 fe->set_text(name);
566 g_free(name);
567 }
569 doc_export_name = g_strdup(fe->get_text().c_str());
570 }
571 g_signal_connect ( G_OBJECT (fe->gobj()), "changed",
572 G_CALLBACK (sp_export_filename_modified), dlg);
574 Gtk::HBox *hb = new Gtk::HBox(FALSE, 5);
576 {
577 // true = has mnemonic
578 Gtk::Button *b = new Gtk::Button();
580 Gtk::HBox* pixlabel = new Gtk::HBox(false, 3);
581 Gtk::Image *im = new Gtk::Image(Gtk::StockID(Gtk::Stock::INDEX),
582 Gtk::ICON_SIZE_BUTTON);
583 pixlabel->pack_start(*im);
585 Gtk::Label *l = new Gtk::Label();
586 l->set_markup_with_mnemonic(_("_Browse..."));
587 pixlabel->pack_start(*l);
589 b->add(*pixlabel);
591 hb->pack_end (*b, false, false, 4);
592 g_signal_connect ( G_OBJECT (b->gobj()), "clicked",
593 G_CALLBACK (sp_export_browse_clicked), NULL );
594 }
596 hb->pack_start (*fe, true, true, 0);
597 file_box->add(*hb);
598 gtk_object_set_data (GTK_OBJECT (dlg), "filename", fe->gobj());
599 gtk_object_set_data (GTK_OBJECT (dlg), "filename-modified", (gpointer)FALSE);
600 original_name = g_strdup(fe->get_text().c_str());
601 // pressing enter in the filename field is the same as clicking export:
602 g_signal_connect ( G_OBJECT (fe->gobj()), "activate",
603 G_CALLBACK (sp_export_export_clicked), dlg );
604 // focus is in the filename initially:
605 fe->grab_focus();
607 // mnemonic in frame label moves focus to filename:
608 flabel->set_mnemonic_widget(*fe);
610 vb_singleexport->pack_start(*file_box);
611 }
613 {
614 Gtk::HBox* batch_box = new Gtk::HBox(FALSE, 5);
615 GtkWidget *be = gtk_check_button_new_with_label(_("Batch export all selected objects"));
616 gtk_widget_set_sensitive(GTK_WIDGET(be), TRUE);
617 gtk_object_set_data(GTK_OBJECT(dlg), "batch_checkbox", be);
618 batch_box->pack_start(*Glib::wrap(be), false, false);
619 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);
620 batch_box->show_all();
621 g_signal_connect(G_OBJECT(be), "toggled", GTK_SIGNAL_FUNC(batch_export_clicked), dlg);
622 vb->pack_start(*batch_box);
623 }
625 {
626 Gtk::HBox* hide_box = new Gtk::HBox(FALSE, 5);
627 GtkWidget *he = gtk_check_button_new_with_label(_("Hide all except selected"));
628 gtk_widget_set_sensitive(GTK_WIDGET(he), TRUE);
629 gtk_object_set_data(GTK_OBJECT(dlg), "hide_checkbox", he);
630 hide_box->pack_start(*Glib::wrap(he), false, false);
631 gtk_tooltips_set_tip(tt, he, _("In the exported image, hide all objects except those that are selected"), NULL);
632 hide_box->show_all();
633 vb->pack_start(*hide_box);
634 }
636 /* Buttons */
637 Gtk::HButtonBox* bb = new Gtk::HButtonBox(Gtk::BUTTONBOX_END);
638 bb->set_border_width(3);
640 {
641 Gtk::Button *b = new Gtk::Button();
642 Gtk::HBox* image_label = new Gtk::HBox(false, 3);
643 Gtk::Image *im = new Gtk::Image(Gtk::StockID(Gtk::Stock::APPLY),
644 Gtk::ICON_SIZE_BUTTON);
645 image_label->pack_start(*im);
647 Gtk::Label *l = new Gtk::Label();
648 l->set_markup_with_mnemonic(_("_Export"));
649 image_label->pack_start(*l);
651 b->add(*image_label);
652 gtk_tooltips_set_tip (tt, GTK_WIDGET(b->gobj()), _("Export the bitmap file with these settings"), NULL);
653 gtk_signal_connect ( GTK_OBJECT (b->gobj()), "clicked",
654 GTK_SIGNAL_FUNC (sp_export_export_clicked), dlg );
655 bb->pack_end(*b, false, false, 0);
656 }
658 vb->pack_end(*bb, false, false, 0);
659 vb->show_all();
661 } // end of if (!dlg)
663 sp_export_find_default_selection(dlg);
665 gtk_window_present ((GtkWindow *) dlg);
667 return;
668 } // end of sp_export_dialog()
670 static void
671 sp_export_update_checkbuttons (GtkObject *base)
672 {
673 gint num = g_slist_length((GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
674 GtkWidget *be = (GtkWidget *)gtk_object_get_data(base, "batch_checkbox");
675 GtkWidget *he = (GtkWidget *)gtk_object_get_data(base, "hide_checkbox");
676 if (num >= 2) {
677 gtk_widget_set_sensitive (be, true);
678 gtk_button_set_label (GTK_BUTTON(be), g_strdup_printf (_("Batch export %d selected objects"), num));
679 } else {
680 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(be), FALSE);
681 gtk_widget_set_sensitive (be, FALSE);
682 }
683 if (num > 0) {
684 gtk_widget_set_sensitive (he, true);
685 } else {
686 gtk_widget_set_sensitive (he, false);
687 }
688 }
690 static inline void
691 sp_export_find_default_selection(GtkWidget * dlg)
692 {
693 selection_type key = SELECTION_NUMBER_OF;
695 if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) {
696 key = SELECTION_SELECTION;
697 }
699 /* Try using the preferences */
700 if (key == SELECTION_NUMBER_OF) {
701 const gchar *what = NULL;
702 int i = SELECTION_NUMBER_OF;
704 what = prefs_get_string_attribute ("dialogs.export.exportarea", "value");
706 if (what != NULL) {
707 for (i = 0; i < SELECTION_NUMBER_OF; i++) {
708 if (!strcmp (what, selection_names[i])) {
709 break;
710 }
711 }
712 }
714 key = (selection_type)i;
715 }
717 if (key == SELECTION_NUMBER_OF) {
718 key = SELECTION_SELECTION;
719 }
721 GtkWidget *button = (GtkWidget *)g_object_get_data(G_OBJECT(dlg),
722 selection_names[key]);
723 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
725 sp_export_update_checkbuttons (GTK_OBJECT(dlg));
726 }
729 /**
730 * \brief If selection changed or a different document activated, we must
731 * recalculate any chosen areas
732 *
733 */
734 static void
735 sp_export_selection_changed ( Inkscape::Application *inkscape,
736 Inkscape::Selection *selection,
737 GtkObject *base )
738 {
739 selection_type current_key;
740 current_key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
742 if ((current_key == SELECTION_DRAWING || current_key == SELECTION_PAGE) &&
743 (sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false &&
744 was_empty) {
745 gtk_toggle_button_set_active
746 ( GTK_TOGGLE_BUTTON ( gtk_object_get_data (base, selection_names[SELECTION_SELECTION])),
747 TRUE );
748 }
749 was_empty = (sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty();
751 current_key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
753 if (inkscape &&
754 SP_IS_INKSCAPE (inkscape) &&
755 selection &&
756 SELECTION_CUSTOM != current_key) {
757 GtkToggleButton * button;
758 button = (GtkToggleButton *)gtk_object_get_data(base, selection_names[current_key]);
759 sp_export_area_toggled(button, base);
760 }
762 sp_export_update_checkbuttons (base);
763 }
765 static void
766 sp_export_selection_modified ( Inkscape::Application *inkscape,
767 Inkscape::Selection *selection,
768 guint flags,
769 GtkObject *base )
770 {
771 selection_type current_key;
772 current_key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
774 switch (current_key) {
775 case SELECTION_DRAWING:
776 if ( SP_ACTIVE_DESKTOP ) {
777 SPDocument *doc;
778 doc = sp_desktop_document (SP_ACTIVE_DESKTOP);
779 NR::Maybe<NR::Rect> bbox = sp_item_bbox_desktop (SP_ITEM (SP_DOCUMENT_ROOT (doc)));
780 if (bbox) {
781 sp_export_set_area (base, bbox->min()[NR::X],
782 bbox->min()[NR::Y],
783 bbox->max()[NR::X],
784 bbox->max()[NR::Y]);
785 }
786 }
787 break;
788 case SELECTION_SELECTION:
789 if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) {
790 NRRect bbox;
791 (sp_desktop_selection (SP_ACTIVE_DESKTOP))->bounds(&bbox);
792 sp_export_set_area (base, bbox.x0, bbox.y0, bbox.x1, bbox.y1);
793 }
794 break;
795 default:
796 /* Do nothing for page or for custom */
797 break;
798 }
800 return;
801 }
803 /// Called when one of the selection buttons was toggled.
804 static void
805 sp_export_area_toggled (GtkToggleButton *tb, GtkObject *base)
806 {
807 if (gtk_object_get_data (base, "update"))
808 return;
810 selection_type key, old_key;
811 key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data (GTK_OBJECT (tb), "key")));
812 old_key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
814 /* Ignore all "turned off" events unless we're the only active button */
815 if (!gtk_toggle_button_get_active (tb) ) {
817 /* Don't let the current selection be deactived - but rerun the
818 activate to allow the user to renew the values */
819 if (key == old_key) {
820 gtk_toggle_button_set_active ( tb, TRUE );
821 }
823 return;
824 }
826 /* Turn off the currently active button unless it's us */
827 gtk_object_set_data(GTK_OBJECT(base), "selection-type", (gpointer)key);
829 if (old_key != key) {
830 gtk_toggle_button_set_active
831 ( GTK_TOGGLE_BUTTON ( gtk_object_get_data (base, selection_names[old_key])),
832 FALSE );
833 }
835 if ( SP_ACTIVE_DESKTOP )
836 {
837 SPDocument *doc;
838 NR::Maybe<NR::Rect> bbox;
839 doc = sp_desktop_document (SP_ACTIVE_DESKTOP);
841 /* Notice how the switch is used to 'fall through' here to get
842 various backups. If you modify this without noticing you'll
843 probabaly screw something up. */
844 switch (key) {
845 case SELECTION_SELECTION:
846 if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false)
847 {
848 bbox = (sp_desktop_selection (SP_ACTIVE_DESKTOP))->bounds();
849 /* Only if there is a selection that we can set
850 do we break, otherwise we fall through to the
851 drawing */
852 // std::cout << "Using selection: SELECTION" << std::endl;
853 key = SELECTION_SELECTION;
854 break;
855 }
856 case SELECTION_DRAWING:
857 /** \todo
858 * This returns wrong values if the document has a viewBox.
859 */
860 bbox = sp_item_bbox_desktop (SP_ITEM (SP_DOCUMENT_ROOT (doc)));
861 /* If the drawing is valid, then we'll use it and break
862 otherwise we drop through to the page settings */
863 if (bbox) {
864 // std::cout << "Using selection: DRAWING" << std::endl;
865 key = SELECTION_DRAWING;
866 break;
867 }
868 case SELECTION_PAGE:
869 bbox = NR::Rect(NR::Point(0.0, 0.0),
870 NR::Point(sp_document_width(doc), sp_document_height(doc))
871 );
873 // std::cout << "Using selection: PAGE" << std::endl;
874 key = SELECTION_PAGE;
875 break;
876 case SELECTION_CUSTOM:
877 default:
878 break;
879 } // switch
881 // remember area setting
882 prefs_set_string_attribute ( "dialogs.export.exportarea",
883 "value", selection_names[key]);
885 if ( key != SELECTION_CUSTOM && bbox ) {
886 sp_export_set_area (base, bbox->min()[NR::X],
887 bbox->min()[NR::Y],
888 bbox->max()[NR::X],
889 bbox->max()[NR::Y]);
890 }
892 } // end of if ( SP_ACTIVE_DESKTOP )
895 if (SP_ACTIVE_DESKTOP && !gtk_object_get_data(GTK_OBJECT(base), "filename-modified")) {
896 GtkWidget * file_entry;
897 const gchar * filename = NULL;
898 float xdpi = 0.0, ydpi = 0.0;
900 file_entry = (GtkWidget *)gtk_object_get_data (base, "filename");
902 switch (key) {
903 case SELECTION_PAGE:
904 case SELECTION_DRAWING: {
905 SPDocument * doc = SP_ACTIVE_DOCUMENT;
906 sp_document_get_export_hints (doc, &filename, &xdpi, &ydpi);
908 if (filename == NULL) {
909 if (doc_export_name != NULL) {
910 filename = g_strdup(doc_export_name);
911 } else {
912 filename = g_strdup("");
913 }
914 }
915 break;
916 }
917 case SELECTION_SELECTION:
918 if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) {
920 sp_selection_get_export_hints (sp_desktop_selection(SP_ACTIVE_DESKTOP), &filename, &xdpi, &ydpi);
922 /* If we still don't have a filename -- let's build
923 one that's nice */
924 if (filename == NULL) {
925 const gchar * id = NULL;
926 const GSList * reprlst = sp_desktop_selection(SP_ACTIVE_DESKTOP)->reprList();
927 for(; reprlst != NULL; reprlst = reprlst->next) {
928 Inkscape::XML::Node * repr = (Inkscape::XML::Node *)reprlst->data;
929 if (repr->attribute("id")) {
930 id = repr->attribute("id");
931 break;
932 }
933 }
935 filename = create_filepath_from_id (id, gtk_entry_get_text(GTK_ENTRY(file_entry)));
936 }
937 }
938 break;
939 case SELECTION_CUSTOM:
940 default:
941 break;
942 }
944 if (filename != NULL) {
945 g_free(original_name);
946 original_name = g_strdup(filename);
947 gtk_entry_set_text(GTK_ENTRY(file_entry), filename);
948 }
950 if (xdpi != 0.0) {
951 sp_export_value_set(base, "xdpi", xdpi);
952 }
954 /* These can't be separate, and setting x sets y, so for
955 now setting this is disabled. Hopefully it won't be in
956 the future */
957 if (FALSE && ydpi != 0.0) {
958 sp_export_value_set(base, "ydpi", ydpi);
959 }
960 }
962 return;
963 } // end of sp_export_area_toggled()
965 /// Called when dialog is deleted
966 static gint
967 sp_export_progress_delete ( GtkWidget *widget, GdkEvent *event, GObject *base )
968 {
969 g_object_set_data (base, "cancel", (gpointer) 1);
970 return TRUE;
971 } // end of sp_export_progress_delete()
973 /// Called when progress is cancelled
974 static void
975 sp_export_progress_cancel ( GtkWidget *widget, GObject *base )
976 {
977 g_object_set_data (base, "cancel", (gpointer) 1);
978 } // end of sp_export_progress_cancel()
980 /// Called for every progress iteration
981 static unsigned int
982 sp_export_progress_callback (float value, void *data)
983 {
984 GtkWidget *prg;
985 int evtcount;
987 if (g_object_get_data ((GObject *) data, "cancel"))
988 return FALSE;
990 prg = (GtkWidget *) g_object_get_data ((GObject *) data, "progress");
991 gtk_progress_bar_set_fraction ((GtkProgressBar *) prg, value);
993 evtcount = 0;
994 while ((evtcount < 16) && gdk_events_pending ()) {
995 gtk_main_iteration_do (FALSE);
996 evtcount += 1;
997 }
999 gtk_main_iteration_do (FALSE);
1001 return TRUE;
1003 } // end of sp_export_progress_callback()
1005 GtkWidget *
1006 create_progress_dialog (GtkObject *base, gchar *progress_text) {
1007 GtkWidget *dlg, *prg, *btn; /* progressbar-stuff */
1009 dlg = gtk_dialog_new ();
1010 gtk_window_set_title (GTK_WINDOW (dlg), _("Export in progress"));
1011 prg = gtk_progress_bar_new ();
1012 sp_transientize (dlg);
1013 gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
1014 g_object_set_data ((GObject *) base, "progress", prg);
1016 gtk_progress_bar_set_text ((GtkProgressBar *) prg, progress_text);
1018 gtk_progress_bar_set_orientation ( (GtkProgressBar *) prg,
1019 GTK_PROGRESS_LEFT_TO_RIGHT);
1020 gtk_box_pack_start ((GtkBox *) ((GtkDialog *) dlg)->vbox,
1021 prg, FALSE, FALSE, 4 );
1022 btn = gtk_dialog_add_button ( GTK_DIALOG (dlg),
1023 GTK_STOCK_CANCEL,
1024 GTK_RESPONSE_CANCEL );
1026 g_signal_connect ( (GObject *) dlg, "delete_event",
1027 (GCallback) sp_export_progress_delete, base);
1028 g_signal_connect ( (GObject *) btn, "clicked",
1029 (GCallback) sp_export_progress_cancel, base);
1030 gtk_window_set_modal ((GtkWindow *) dlg, TRUE);
1031 gtk_widget_show_all (dlg);
1033 return dlg;
1034 }
1036 // FIXME: Some lib function should be available to do this ...
1037 static gchar *
1038 filename_add_extension (const gchar *filename, const gchar *extension)
1039 {
1040 gchar *dot;
1042 dot = strrchr (filename, '.');
1043 if ( !dot )
1044 return g_strconcat (filename, ".", extension, NULL);
1045 {
1046 if (dot[1] == '\0')
1047 return g_strconcat (filename, extension, NULL);
1048 else
1049 {
1050 if (g_strcasecmp (dot + 1, extension) == 0)
1051 return g_strdup (filename);
1052 else
1053 {
1054 return g_strconcat (filename, ".", extension, NULL);
1055 }
1056 }
1057 }
1058 }
1060 /// Called when export button is clicked
1061 static void
1062 sp_export_export_clicked (GtkButton *button, GtkObject *base)
1063 {
1064 if (!SP_ACTIVE_DESKTOP) return;
1066 SPNamedView *nv = sp_desktop_namedview(SP_ACTIVE_DESKTOP);
1068 GtkWidget *be = (GtkWidget *)gtk_object_get_data(base, "batch_checkbox");
1069 GtkWidget *he = (GtkWidget *)gtk_object_get_data(base, "hide_checkbox");
1070 bool hide = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (he));
1071 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (be))) {
1072 // Batch export of selected objects
1074 gint num = g_slist_length((GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
1075 gint n = 0;
1077 if (num < 1)
1078 return;
1080 gchar *progress_text = g_strdup_printf (_("Exporting %d files"), num);
1081 GtkWidget *prog_dlg = create_progress_dialog (base, progress_text);
1082 g_free (progress_text);
1084 for (GSList *i = (GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList();
1085 i != NULL;
1086 i = i->next) {
1087 SPItem *item = (SPItem *) i->data;
1088 // retrieve export filename hint
1089 const gchar *fn = SP_OBJECT_REPR(item)->attribute("inkscape:export-filename");
1090 if (!fn) {
1091 fn = create_filepath_from_id (SP_OBJECT_ID(item), NULL);
1092 }
1094 // retrieve export dpi hints
1095 const gchar *dpi_hint = SP_OBJECT_REPR(item)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
1096 gdouble dpi = 0.0;
1097 if (dpi_hint) {
1098 dpi = atof(dpi_hint);
1099 }
1100 if (dpi == 0.0) {
1101 dpi = DPI_BASE;
1102 }
1104 NRRect area;
1105 sp_item_invoke_bbox(item, &area, sp_item_i2r_affine((SPItem *) item), TRUE);
1107 gint width = (gint) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1108 gint height = (gint) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1110 if (width > 1 && height > 1) {
1111 /* Do export */
1112 if (!sp_export_png_file (sp_desktop_document (SP_ACTIVE_DESKTOP), fn,
1113 area.x0, area.y0, area.x1, area.y1, width, height, dpi, dpi,
1114 nv->pagecolor,
1115 NULL, NULL, TRUE, // overwrite without asking
1116 hide ? (GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList() : NULL
1117 )) {
1118 gchar * error;
1119 gchar * safeFile = Inkscape::IO::sanitizeString(fn);
1120 error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile);
1121 sp_ui_error_dialog(error);
1122 g_free(safeFile);
1123 g_free(error);
1124 }
1125 }
1126 n++;
1127 sp_export_progress_callback((float)n/num, base);
1128 }
1130 gtk_widget_destroy (prog_dlg);
1131 g_object_set_data (G_OBJECT (base), "cancel", (gpointer) 0);
1133 } else {
1135 GtkWidget *fe = (GtkWidget *)gtk_object_get_data(base, "filename");
1136 gchar const *filename = gtk_entry_get_text(GTK_ENTRY(fe));
1138 float const x0 = sp_export_value_get_px(base, "x0");
1139 float const y0 = sp_export_value_get_px(base, "y0");
1140 float const x1 = sp_export_value_get_px(base, "x1");
1141 float const y1 = sp_export_value_get_px(base, "y1");
1142 float const xdpi = sp_export_value_get(base, "xdpi");
1143 float const ydpi = sp_export_value_get(base, "ydpi");
1144 int const width = int(sp_export_value_get(base, "bmwidth") + 0.5);
1145 int const height = int(sp_export_value_get(base, "bmheight") + 0.5);
1147 if (filename == NULL || *filename == '\0') {
1148 sp_ui_error_dialog(_("You have to enter a filename"));
1149 return;
1150 }
1152 if (!((x1 > x0) && (y1 > y0) && (width > 0) && (height > 0))) {
1153 sp_ui_error_dialog (_("The chosen area to be exported is invalid"));
1154 return;
1155 }
1157 gchar *dirname = g_path_get_dirname(filename);
1158 if ( dirname == NULL
1159 || !Inkscape::IO::file_test(dirname, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) )
1160 {
1161 gchar *safeDir = Inkscape::IO::sanitizeString(dirname);
1162 gchar *error = g_strdup_printf(_("Directory %s does not exist or is not a directory.\n"),
1163 safeDir);
1164 sp_ui_error_dialog(error);
1165 g_free(safeDir);
1166 g_free(error);
1167 g_free(dirname);
1168 return;
1169 }
1170 g_free(dirname);
1172 // make sure that .png is the extension of the file:
1173 gchar * filename_ext = filename_add_extension(filename, "png");
1174 gtk_entry_set_text(GTK_ENTRY(fe), filename_ext);
1176 gchar *fn = g_path_get_basename (filename_ext);
1178 gchar *progress_text = g_strdup_printf (_("Exporting %s (%d x %d)"), fn, width, height);
1179 g_free (fn);
1180 GtkWidget *prog_dlg = create_progress_dialog (base, progress_text);
1181 g_free (progress_text);
1183 /* Do export */
1184 if (!sp_export_png_file (sp_desktop_document (SP_ACTIVE_DESKTOP), filename_ext,
1185 x0, y0, x1, y1, width, height, xdpi, ydpi,
1186 nv->pagecolor,
1187 sp_export_progress_callback, base, FALSE,
1188 hide ? (GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList() : NULL
1189 )) {
1190 gchar * error;
1191 gchar * safeFile = Inkscape::IO::sanitizeString(filename);
1192 error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile);
1193 sp_ui_error_dialog(error);
1194 g_free(safeFile);
1195 g_free(error);
1196 }
1198 /* Reset the filename so that it can be changed again by changing
1199 selections and all that */
1200 g_free(original_name);
1201 original_name = g_strdup(filename_ext);
1202 gtk_object_set_data (GTK_OBJECT (base), "filename-modified", (gpointer)FALSE);
1204 gtk_widget_destroy (prog_dlg);
1205 g_object_set_data (G_OBJECT (base), "cancel", (gpointer) 0);
1207 /* Setup the values in the document */
1208 switch ((selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")))) {
1209 case SELECTION_PAGE:
1210 case SELECTION_DRAWING: {
1211 SPDocument * doc = SP_ACTIVE_DOCUMENT;
1212 Inkscape::XML::Node * repr = sp_document_repr_root(doc);
1213 bool modified = false;
1214 const gchar * temp_string;
1216 bool saved = sp_document_get_undo_sensitive(doc);
1217 sp_document_set_undo_sensitive(doc, false);
1219 temp_string = repr->attribute("inkscape:export-filename");
1220 if (temp_string == NULL || strcmp(temp_string, filename_ext)) {
1221 repr->setAttribute("inkscape:export-filename", filename_ext);
1222 modified = true;
1223 }
1224 temp_string = repr->attribute("inkscape:export-xdpi");
1225 if (temp_string == NULL || xdpi != atof(temp_string)) {
1226 sp_repr_set_svg_double(repr, "inkscape:export-xdpi", xdpi);
1227 modified = true;
1228 }
1229 temp_string = repr->attribute("inkscape:export-ydpi");
1230 if (temp_string == NULL || xdpi != atof(temp_string)) {
1231 sp_repr_set_svg_double(repr, "inkscape:export-ydpi", ydpi);
1232 modified = true;
1233 }
1235 if (modified)
1236 repr->setAttribute("sodipodi:modified", "TRUE");
1237 sp_document_set_undo_sensitive(doc, saved);
1238 break;
1239 }
1240 case SELECTION_SELECTION: {
1241 const GSList * reprlst;
1242 SPDocument * doc = SP_ACTIVE_DOCUMENT;
1243 bool modified = false;
1245 bool saved = sp_document_get_undo_sensitive(doc);
1246 sp_document_set_undo_sensitive(doc, false);
1247 reprlst = sp_desktop_selection(SP_ACTIVE_DESKTOP)->reprList();
1249 for(; reprlst != NULL; reprlst = reprlst->next) {
1250 Inkscape::XML::Node * repr = (Inkscape::XML::Node *)reprlst->data;
1251 const gchar * temp_string;
1253 if (repr->attribute("id") == NULL ||
1254 !(g_strrstr(filename_ext, repr->attribute("id")) != NULL &&
1255 (!SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT) ||
1256 strcmp(g_dirname(filename), g_dirname(SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT))) == 0))) {
1257 temp_string = repr->attribute("inkscape:export-filename");
1258 if (temp_string == NULL || strcmp(temp_string, filename_ext)) {
1259 repr->setAttribute("inkscape:export-filename", filename_ext);
1260 modified = true;
1261 }
1262 }
1263 temp_string = repr->attribute("inkscape:export-xdpi");
1264 if (temp_string == NULL || xdpi != atof(temp_string)) {
1265 sp_repr_set_svg_double(repr, "inkscape:export-xdpi", xdpi);
1266 modified = true;
1267 }
1268 temp_string = repr->attribute("inkscape:export-ydpi");
1269 if (temp_string == NULL || xdpi != atof(temp_string)) {
1270 sp_repr_set_svg_double(repr, "inkscape:export-ydpi", ydpi);
1271 modified = true;
1272 }
1273 }
1275 if (modified) {
1276 Inkscape::XML::Node * repr = sp_document_repr_root(doc);
1277 repr->setAttribute("sodipodi:modified", "TRUE");
1278 }
1280 sp_document_set_undo_sensitive(doc, saved);
1281 break;
1282 }
1283 default:
1284 break;
1285 }
1287 g_free (filename_ext);
1289 }
1291 } // end of sp_export_export_clicked()
1293 /// Called when Browse button is clicked
1294 static void
1295 sp_export_browse_clicked (GtkButton *button, gpointer userdata)
1296 {
1297 GtkWidget *fs, *fe;
1298 const gchar *filename;
1300 fs = gtk_file_chooser_dialog_new (_("Select a filename for exporting"),
1301 NULL,
1302 GTK_FILE_CHOOSER_ACTION_SAVE,
1303 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1304 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1305 NULL );
1307 #ifdef WITH_GNOME_VFS
1308 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER (fs), false);
1309 #endif
1311 fe = (GtkWidget *)g_object_get_data (G_OBJECT (dlg), "filename");
1313 sp_transientize (fs);
1315 gtk_window_set_modal(GTK_WINDOW (fs), true);
1317 filename = gtk_entry_get_text (GTK_ENTRY (fe));
1319 if (*filename == '\0') {
1320 filename = homedir_path(NULL);
1321 }
1323 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (fs), filename);
1325 if (gtk_dialog_run (GTK_DIALOG (fs)) == GTK_RESPONSE_ACCEPT)
1326 {
1327 gchar *file;
1329 file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (fs));
1331 gchar * utf8file = g_filename_to_utf8( file, -1, NULL, NULL, NULL );
1332 gtk_entry_set_text (GTK_ENTRY (fe), utf8file);
1334 g_object_set_data (G_OBJECT (dlg), "filename", fe);
1336 g_free(utf8file);
1337 g_free(file);
1338 }
1340 gtk_widget_destroy (fs);
1342 return;
1343 } // end of sp_export_browse_clicked()
1345 // TODO: Move this to nr-rect-fns.h.
1346 static bool
1347 sp_export_bbox_equal(NR::Rect const &one, NR::Rect const &two)
1348 {
1349 double const epsilon = pow(10.0, -EXPORT_COORD_PRECISION);
1350 return (
1351 (fabs(one.min()[NR::X] - two.min()[NR::X]) < epsilon) &&
1352 (fabs(one.min()[NR::Y] - two.min()[NR::Y]) < epsilon) &&
1353 (fabs(one.max()[NR::X] - two.max()[NR::X]) < epsilon) &&
1354 (fabs(one.max()[NR::Y] - two.max()[NR::Y]) < epsilon)
1355 );
1356 }
1358 /**
1359 \brief This function is used to detect the current selection setting
1360 based on the values in the x0, y0, x1 and y0 fields.
1361 \param base The export dialog itself
1363 One of the most confusing parts of this function is why the array
1364 is built at the beginning. What needs to happen here is that we
1365 should always check the current selection to see if it is the valid
1366 one. While this is a performance improvement it is also a usability
1367 one during the cases where things like selections and drawings match
1368 size. This way buttons change less 'randomly' (atleast in the eyes
1369 of the user). To do this an array is built where the current selection
1370 type is placed first, and then the others in an order from smallest
1371 to largest (this can be configured by reshuffling \c test_order).
1373 All of the values in this function are rounded to two decimal places
1374 because that is what is shown to the user. While everything is kept
1375 more accurate than that, the user can't control more acurrate than
1376 that, so for this to work for them - it needs to check on that level
1377 of accuracy.
1379 \todo finish writing this up
1380 */
1381 static void
1382 sp_export_detect_size(GtkObject * base) {
1383 static const selection_type test_order[SELECTION_NUMBER_OF] = {SELECTION_SELECTION, SELECTION_DRAWING, SELECTION_PAGE, SELECTION_CUSTOM};
1384 selection_type this_test[SELECTION_NUMBER_OF + 1];
1385 selection_type key = SELECTION_NUMBER_OF;
1387 NR::Point x(sp_export_value_get_px (base, "x0"),
1388 sp_export_value_get_px (base, "y0"));
1389 NR::Point y(sp_export_value_get_px (base, "x1"),
1390 sp_export_value_get_px (base, "y1"));
1391 NR::Rect current_bbox(x, y);
1392 //std::cout << "Current " << current_bbox;
1394 this_test[0] = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
1395 for (int i = 0; i < SELECTION_NUMBER_OF; i++) {
1396 this_test[i + 1] = test_order[i];
1397 }
1399 for (int i = 0;
1400 i < SELECTION_NUMBER_OF + 1 &&
1401 key == SELECTION_NUMBER_OF &&
1402 SP_ACTIVE_DESKTOP != NULL;
1403 i++) {
1404 // std::cout << "Looking at: " << selection_names[this_test[i]] << std::endl;
1405 switch (this_test[i]) {
1406 case SELECTION_SELECTION:
1407 if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) {
1408 NR::Maybe<NR::Rect> bbox = (sp_desktop_selection (SP_ACTIVE_DESKTOP))->bounds();
1410 //std::cout << "Selection " << bbox;
1411 if ( bbox && sp_export_bbox_equal(*bbox,current_bbox)) {
1412 key = SELECTION_SELECTION;
1413 }
1414 }
1415 break;
1416 case SELECTION_DRAWING: {
1417 SPDocument *doc = sp_desktop_document (SP_ACTIVE_DESKTOP);
1419 NR::Maybe<NR::Rect> bbox = sp_item_bbox_desktop (SP_ITEM (SP_DOCUMENT_ROOT (doc)));
1421 // std::cout << "Drawing " << bbox2;
1422 if ( bbox && sp_export_bbox_equal(*bbox,current_bbox) ) {
1423 key = SELECTION_DRAWING;
1424 }
1425 break;
1426 }
1428 case SELECTION_PAGE: {
1429 SPDocument *doc;
1431 doc = sp_desktop_document (SP_ACTIVE_DESKTOP);
1433 NR::Point x(0.0, 0.0);
1434 NR::Point y(sp_document_width(doc),
1435 sp_document_height(doc));
1436 NR::Rect bbox(x, y);
1438 // std::cout << "Page " << bbox;
1439 if (sp_export_bbox_equal(bbox,current_bbox)) {
1440 key = SELECTION_PAGE;
1441 }
1443 break;
1444 }
1445 default:
1446 break;
1447 }
1448 }
1449 // std::cout << std::endl;
1451 if (key == SELECTION_NUMBER_OF) {
1452 key = SELECTION_CUSTOM;
1453 }
1455 /* We're now using a custom size, not a fixed one */
1456 /* printf("Detecting state: %s\n", selection_names[key]); */
1457 selection_type old = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
1458 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gtk_object_get_data(base, selection_names[old])), FALSE);
1459 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gtk_object_get_data(base, selection_names[key])), TRUE);
1460 gtk_object_set_data(GTK_OBJECT(base), "selection-type", (gpointer)key);
1462 return;
1463 } /* sp_export_detect_size */
1465 /// Called when area x0 value is changed
1466 static void
1467 sp_export_area_x_value_changed (GtkAdjustment *adj, GtkObject *base)
1468 {
1469 float x0, x1, xdpi, width;
1471 if (gtk_object_get_data (base, "update"))
1472 return;
1474 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1475 (base, "units")))
1476 {
1477 return;
1478 }
1480 gtk_object_set_data ( base, "update", GUINT_TO_POINTER (TRUE) );
1482 x0 = sp_export_value_get_px (base, "x0");
1483 x1 = sp_export_value_get_px (base, "x1");
1484 xdpi = sp_export_value_get (base, "xdpi");
1486 width = floor ((x1 - x0) * xdpi / DPI_BASE + 0.5);
1488 if (width < SP_EXPORT_MIN_SIZE) {
1489 const gchar *key;
1490 width = SP_EXPORT_MIN_SIZE;
1491 key = (const gchar *)gtk_object_get_data (GTK_OBJECT (adj), "key");
1493 if (!strcmp (key, "x0")) {
1494 x1 = x0 + width * DPI_BASE / xdpi;
1495 sp_export_value_set_px (base, "x1", x1);
1496 } else {
1497 x0 = x1 - width * DPI_BASE / xdpi;
1498 sp_export_value_set_px (base, "x0", x0);
1499 }
1500 }
1502 sp_export_value_set_px (base, "width", x1 - x0);
1503 sp_export_value_set (base, "bmwidth", width);
1505 sp_export_detect_size(base);
1507 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1509 return;
1510 } // end of sp_export_area_x_value_changed()
1512 /// Called when area y0 value is changed.
1513 static void
1514 sp_export_area_y_value_changed (GtkAdjustment *adj, GtkObject *base)
1515 {
1516 float y0, y1, ydpi, height;
1518 if (gtk_object_get_data (base, "update"))
1519 return;
1521 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1522 (base, "units")))
1523 {
1524 return;
1525 }
1527 gtk_object_set_data (base, "update", GUINT_TO_POINTER (TRUE));
1529 y0 = sp_export_value_get_px (base, "y0");
1530 y1 = sp_export_value_get_px (base, "y1");
1531 ydpi = sp_export_value_get (base, "ydpi");
1533 height = floor ((y1 - y0) * ydpi / DPI_BASE + 0.5);
1535 if (height < SP_EXPORT_MIN_SIZE) {
1536 const gchar *key;
1537 height = SP_EXPORT_MIN_SIZE;
1538 key = (const gchar *)gtk_object_get_data (GTK_OBJECT (adj), "key");
1539 if (!strcmp (key, "y0")) {
1540 y1 = y0 + height * DPI_BASE / ydpi;
1541 sp_export_value_set_px (base, "y1", y1);
1542 } else {
1543 y0 = y1 - height * DPI_BASE / ydpi;
1544 sp_export_value_set_px (base, "y0", y0);
1545 }
1546 }
1548 sp_export_value_set_px (base, "height", y1 - y0);
1549 sp_export_value_set (base, "bmheight", height);
1551 sp_export_detect_size(base);
1553 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1555 return;
1556 } // end of sp_export_area_y_value_changed()
1558 /// Called when x1-x0 or area width is changed
1559 static void
1560 sp_export_area_width_value_changed (GtkAdjustment *adj, GtkObject *base)
1561 {
1562 float x0, x1, xdpi, width, bmwidth;
1564 if (gtk_object_get_data (base, "update"))
1565 return;
1567 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1568 (base, "units"))) {
1569 return;
1570 }
1572 gtk_object_set_data (base, "update", GUINT_TO_POINTER (TRUE));
1574 x0 = sp_export_value_get_px (base, "x0");
1575 x1 = sp_export_value_get_px (base, "x1");
1576 xdpi = sp_export_value_get (base, "xdpi");
1577 width = sp_export_value_get_px (base, "width");
1578 bmwidth = floor (width * xdpi / DPI_BASE + 0.5);
1580 if (bmwidth < SP_EXPORT_MIN_SIZE) {
1582 bmwidth = SP_EXPORT_MIN_SIZE;
1583 width = bmwidth * DPI_BASE / xdpi;
1584 sp_export_value_set_px (base, "width", width);
1585 }
1587 sp_export_value_set_px (base, "x1", x0 + width);
1588 sp_export_value_set (base, "bmwidth", bmwidth);
1590 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1592 return;
1593 } // end of sp_export_area_width_value_changed()
1595 /// Called when y1-y0 or area height is changed.
1596 static void
1597 sp_export_area_height_value_changed (GtkAdjustment *adj, GtkObject *base)
1598 {
1600 float y0, y1, ydpi, height, bmheight;
1602 if (gtk_object_get_data (base, "update"))
1603 return;
1605 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1606 (base, "units"))) {
1607 return;
1608 }
1610 gtk_object_set_data (base, "update", GUINT_TO_POINTER (TRUE));
1612 y0 = sp_export_value_get_px (base, "y0");
1613 y1 = sp_export_value_get_px (base, "y1");
1614 ydpi = sp_export_value_get (base, "ydpi");
1615 height = sp_export_value_get_px (base, "height");
1616 bmheight = floor (height * ydpi / DPI_BASE + 0.5);
1618 if (bmheight < SP_EXPORT_MIN_SIZE) {
1619 bmheight = SP_EXPORT_MIN_SIZE;
1620 height = bmheight * DPI_BASE / ydpi;
1621 sp_export_value_set_px (base, "height", height);
1622 }
1624 sp_export_value_set_px (base, "y1", y0 + height);
1625 sp_export_value_set (base, "bmheight", bmheight);
1627 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1629 return;
1630 } // end of sp_export_area_height_value_changed()
1632 /**
1633 \brief A function to set the ydpi
1634 \param base The export dialog
1636 This function grabs all of the y values and then figures out the
1637 new bitmap size based on the changing dpi value. The dpi value is
1638 gotten from the xdpi setting as these can not currently be independent.
1639 */
1640 static void
1641 sp_export_set_image_y (GtkObject *base)
1642 {
1643 float y0, y1, xdpi;
1645 y0 = sp_export_value_get_px (base, "y0");
1646 y1 = sp_export_value_get_px (base, "y1");
1647 xdpi = sp_export_value_get (base, "xdpi");
1649 sp_export_value_set (base, "ydpi", xdpi);
1650 sp_export_value_set (base, "bmheight", (y1 - y0) * xdpi / DPI_BASE);
1652 return;
1653 } // end of sp_export_set_image_y()
1655 /**
1656 \brief A function to set the xdpi
1657 \param base The export dialog
1659 This function grabs all of the x values and then figures out the
1660 new bitmap size based on the changing dpi value. The dpi value is
1661 gotten from the xdpi setting as these can not currently be independent.
1662 */
1663 static void
1664 sp_export_set_image_x (GtkObject *base)
1665 {
1666 float x0, x1, xdpi;
1668 x0 = sp_export_value_get_px (base, "x0");
1669 x1 = sp_export_value_get_px (base, "x1");
1670 xdpi = sp_export_value_get (base, "xdpi");
1672 sp_export_value_set (base, "ydpi", xdpi);
1673 sp_export_value_set (base, "bmwidth", (x1 - x0) * xdpi / DPI_BASE);
1675 return;
1676 } // end of sp_export_set_image_x()
1678 /// Called when pixel width is changed
1679 static void
1680 sp_export_bitmap_width_value_changed (GtkAdjustment *adj, GtkObject *base)
1681 {
1682 float x0, x1, bmwidth, xdpi;
1684 if (gtk_object_get_data (base, "update"))
1685 return;
1687 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1688 (base, "units"))) {
1689 return;
1690 }
1692 gtk_object_set_data (base, "update", GUINT_TO_POINTER (TRUE));
1694 x0 = sp_export_value_get_px (base, "x0");
1695 x1 = sp_export_value_get_px (base, "x1");
1696 bmwidth = sp_export_value_get (base, "bmwidth");
1698 if (bmwidth < SP_EXPORT_MIN_SIZE) {
1699 bmwidth = SP_EXPORT_MIN_SIZE;
1700 sp_export_value_set (base, "bmwidth", bmwidth);
1701 }
1703 xdpi = bmwidth * DPI_BASE / (x1 - x0);
1704 sp_export_value_set (base, "xdpi", xdpi);
1706 sp_export_set_image_y (base);
1708 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1710 return;
1711 } // end of sp_export_bitmap_width_value_changed()
1713 /// Called when pixel height is changed
1714 static void
1715 sp_export_bitmap_height_value_changed (GtkAdjustment *adj, GtkObject *base)
1716 {
1717 float y0, y1, bmheight, xdpi;
1719 if (gtk_object_get_data (base, "update"))
1720 return;
1722 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1723 (base, "units"))) {
1724 return;
1725 }
1727 gtk_object_set_data (base, "update", GUINT_TO_POINTER (TRUE));
1729 y0 = sp_export_value_get_px (base, "y0");
1730 y1 = sp_export_value_get_px (base, "y1");
1731 bmheight = sp_export_value_get (base, "bmheight");
1733 if (bmheight < SP_EXPORT_MIN_SIZE) {
1734 bmheight = SP_EXPORT_MIN_SIZE;
1735 sp_export_value_set (base, "bmheight", bmheight);
1736 }
1738 xdpi = bmheight * DPI_BASE / (y1 - y0);
1739 sp_export_value_set (base, "xdpi", xdpi);
1741 sp_export_set_image_x (base);
1743 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1745 return;
1746 } // end of sp_export_bitmap_width_value_changed()
1748 /**
1749 \brief A function to adjust the bitmap width when the xdpi value changes
1750 \param adj The adjustment that was changed
1751 \param base The export dialog itself
1753 The first thing this function checks is to see if we are doing an
1754 update. If we are, this function just returns because there is another
1755 instance of it that will handle everything for us. If there is a
1756 units change, we also assume that everyone is being updated appropriately
1757 and there is nothing for us to do.
1759 If we're the highest level function, we set the update flag, and
1760 continue on our way.
1762 All of the values are grabbed using the \c sp_export_value_get functions
1763 (call to the _pt ones for x0 and x1 but just standard for xdpi). The
1764 xdpi value is saved in the preferences for the next time the dialog
1765 is opened. (does the selection dpi need to be set here?)
1767 A check is done to to ensure that we aren't outputing an invalid width,
1768 this is set by SP_EXPORT_MIN_SIZE. If that is the case the dpi is
1769 changed to make it valid.
1771 After all of this the bitmap width is changed.
1773 We also change the ydpi. This is a temporary hack as these can not
1774 currently be independent. This is likely to change in the future.
1775 */
1776 void
1777 sp_export_xdpi_value_changed (GtkAdjustment *adj, GtkObject *base)
1778 {
1779 float x0, x1, xdpi, bmwidth;
1781 if (gtk_object_get_data (base, "update"))
1782 return;
1784 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1785 (base, "units"))) {
1786 return;
1787 }
1789 gtk_object_set_data (base, "update", GUINT_TO_POINTER (TRUE));
1791 x0 = sp_export_value_get_px (base, "x0");
1792 x1 = sp_export_value_get_px (base, "x1");
1793 xdpi = sp_export_value_get (base, "xdpi");
1795 // remember xdpi setting
1796 prefs_set_double_attribute ("dialogs.export.defaultxdpi", "value", xdpi);
1798 bmwidth = (x1 - x0) * xdpi / DPI_BASE;
1800 if (bmwidth < SP_EXPORT_MIN_SIZE) {
1801 bmwidth = SP_EXPORT_MIN_SIZE;
1802 if (x1 != x0)
1803 xdpi = bmwidth * DPI_BASE / (x1 - x0);
1804 else
1805 xdpi = DPI_BASE;
1806 sp_export_value_set (base, "xdpi", xdpi);
1807 }
1809 sp_export_value_set (base, "bmwidth", bmwidth);
1811 sp_export_set_image_y (base);
1813 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1815 return;
1816 } // end of sp_export_xdpi_value_changed()
1819 /**
1820 \brief A function to change the area that is used for the exported
1821 bitmap.
1822 \param base This is the export dialog
1823 \param x0 Horizontal upper left hand corner of the picture in points
1824 \param y0 Vertical upper left hand corner of the picture in points
1825 \param x1 Horizontal lower right hand corner of the picture in points
1826 \param y1 Vertical lower right hand corner of the picture in points
1828 This function just calls \c sp_export_value_set_px for each of the
1829 parameters that is passed in. This allows for setting them all in
1830 one convient area.
1832 Update is set to suspend all of the other test running while all the
1833 values are being set up. This allows for a performance increase, but
1834 it also means that the wrong type won't be detected with only some of
1835 the values set. After all the values are set everyone is told that
1836 there has been an update.
1837 */
1838 static void
1839 sp_export_set_area ( GtkObject *base, double x0, double y0, double x1, double y1 )
1840 {
1841 gtk_object_set_data ( base, "update", GUINT_TO_POINTER (TRUE) );
1842 sp_export_value_set_px (base, "x1", x1);
1843 sp_export_value_set_px (base, "y1", y1);
1844 sp_export_value_set_px (base, "x0", x0);
1845 sp_export_value_set_px (base, "y0", y0);
1846 gtk_object_set_data ( base, "update", GUINT_TO_POINTER (FALSE) );
1848 sp_export_area_x_value_changed ((GtkAdjustment *)gtk_object_get_data (base, "x1"), base);
1849 sp_export_area_y_value_changed ((GtkAdjustment *)gtk_object_get_data (base, "y1"), base);
1851 return;
1852 }
1854 /**
1855 \brief Sets the value of an adjustment
1856 \param base The export dialog
1857 \param key Which adjustment to set
1858 \param val What value to set it to
1860 This function finds the adjustment using the data stored in the
1861 export dialog. After finding the adjustment it then sets
1862 the value of it.
1863 */
1864 static void
1865 sp_export_value_set ( GtkObject *base, const gchar *key, double val )
1866 {
1867 GtkAdjustment *adj;
1869 adj = (GtkAdjustment *)gtk_object_get_data (base, key);
1871 gtk_adjustment_set_value (adj, val);
1872 }
1874 /**
1875 \brief A function to set a value using the units points
1876 \param base The export dialog
1877 \param key Which value should be set
1878 \param val What the value should be in points
1880 This function first gets the adjustment for the key that is passed
1881 in. It then figures out what units are currently being used in the
1882 dialog. After doing all of that, it then converts the incoming
1883 value and sets the adjustment.
1884 */
1885 static void
1886 sp_export_value_set_px (GtkObject *base, const gchar *key, double val)
1887 {
1888 const SPUnit *unit = sp_unit_selector_get_unit ((SPUnitSelector *)gtk_object_get_data (base, "units") );
1890 sp_export_value_set (base, key, sp_pixels_get_units (val, *unit));
1892 return;
1893 }
1895 /**
1896 \brief Get the value of an adjustment in the export dialog
1897 \param base The export dialog
1898 \param key Which adjustment is being looked for
1899 \return The value in the specified adjustment
1901 This function gets the adjustment from the data field in the export
1902 dialog. It then grabs the value from the adjustment.
1903 */
1904 static float
1905 sp_export_value_get ( GtkObject *base, const gchar *key )
1906 {
1907 GtkAdjustment *adj;
1909 adj = (GtkAdjustment *)gtk_object_get_data (base, key);
1911 return adj->value;
1912 }
1914 /**
1915 \brief Grabs a value in the export dialog and converts the unit
1916 to points
1917 \param base The export dialog
1918 \param key Which value should be returned
1919 \return The value in the adjustment in points
1921 This function, at its most basic, is a call to \c sp_export_value_get
1922 to get the value of the adjustment. It then finds the units that
1923 are being used by looking at the "units" attribute of the export
1924 dialog. Using that it converts the returned value into points.
1925 */
1926 static float
1927 sp_export_value_get_px ( GtkObject *base, const gchar *key )
1928 {
1929 float value = sp_export_value_get(base, key);
1930 const SPUnit *unit = sp_unit_selector_get_unit ((SPUnitSelector *)gtk_object_get_data (base, "units"));
1932 return sp_units_get_pixels (value, *unit);
1933 } // end of sp_export_value_get_px()
1935 /**
1936 \brief This function is called when the filename is changed by
1937 anyone. It resets the virgin bit.
1938 \param object Text entry box
1939 \param data The export dialog
1940 \return None
1942 This function gets called when the text area is modified. It is
1943 looking for the case where the text area is modified from its
1944 original value. In that case it sets the "filename-modified" bit
1945 to TRUE. If the text dialog returns back to the original text, the
1946 bit gets reset. This should stop simple mistakes.
1947 */
1948 static void
1949 sp_export_filename_modified (GtkObject * object, gpointer data)
1950 {
1951 GtkWidget * text_entry = (GtkWidget *)object;
1952 GtkWidget * export_dialog = (GtkWidget *)data;
1954 if (!strcmp(original_name, gtk_entry_get_text(GTK_ENTRY(text_entry)))) {
1955 gtk_object_set_data (GTK_OBJECT (export_dialog), "filename-modified", (gpointer)FALSE);
1956 // printf("Modified: FALSE\n");
1957 } else {
1958 gtk_object_set_data (GTK_OBJECT (export_dialog), "filename-modified", (gpointer)TRUE);
1959 // printf("Modified: TRUE\n");
1960 }
1962 return;
1963 } // end sp_export_filename_modified
1965 /*
1966 Local Variables:
1967 mode:c++
1968 c-file-style:"stroustrup"
1969 c-file-offsets:((innamespace . 0)(inline-open . 0))
1970 indent-tabs-mode:nil
1971 fill-column:99
1972 End:
1973 */
1974 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :