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>
33 #ifdef WITH_GNOME_VFS
34 # include <libgnomevfs/gnome-vfs-init.h> // gnome_vfs_initialized
35 #endif
37 #include <glibmm/i18n.h>
38 #include "helper/unit-menu.h"
39 #include "helper/units.h"
40 #include "unit-constants.h"
41 #include "helper/window.h"
42 #include "inkscape-private.h"
43 #include "document.h"
44 #include "desktop-handles.h"
45 #include "sp-item.h"
46 #include "selection.h"
47 #include "file.h"
48 #include "macros.h"
49 #include "sp-namedview.h"
50 #include "selection-chemistry.h"
52 #include "dialog-events.h"
53 #include "../prefs-utils.h"
54 #include "../verbs.h"
55 #include "../interface.h"
57 #include "extension/output.h"
58 #include "extension/db.h"
60 #include "io/sys.h"
62 #include "helper/png-write.h"
65 #define SP_EXPORT_MIN_SIZE 1.0
67 #define DPI_BASE PX_PER_IN
69 #define EXPORT_COORD_PRECISION 3
71 #define MIN_ONSCREEN_DISTANCE 50
73 static void sp_export_area_toggled ( GtkToggleButton *tb, GtkObject *base );
74 static void sp_export_export_clicked ( GtkButton *button, GtkObject *base );
75 static void sp_export_browse_clicked ( GtkButton *button, gpointer userdata );
77 static void sp_export_area_x_value_changed ( GtkAdjustment *adj,
78 GtkObject *base);
80 static void sp_export_area_y_value_changed ( GtkAdjustment *adj,
81 GtkObject *base);
83 static void sp_export_area_width_value_changed ( GtkAdjustment *adj,
84 GtkObject *base);
86 static void sp_export_area_height_value_changed ( GtkAdjustment *adj,
87 GtkObject *base);
89 static void sp_export_bitmap_width_value_changed ( GtkAdjustment *adj,
90 GtkObject *base);
92 static void sp_export_bitmap_height_value_changed ( GtkAdjustment *adj,
93 GtkObject *base);
95 static void sp_export_xdpi_value_changed ( GtkAdjustment *adj,
96 GtkObject *base);
98 static void sp_export_selection_changed ( Inkscape::Application *inkscape,
99 Inkscape::Selection *selection,
100 GtkObject *base);
101 static void sp_export_selection_modified ( Inkscape::Application *inkscape,
102 Inkscape::Selection *selection,
103 guint flags,
104 GtkObject *base );
106 static void sp_export_set_area (GtkObject *base, double x0, double y0, double x1, double y1);
107 static void sp_export_value_set (GtkObject *base, const gchar *key, double val);
108 static void sp_export_value_set_px (GtkObject *base, const gchar *key, double val);
109 static float sp_export_value_get ( GtkObject *base, const gchar *key );
110 static float sp_export_value_get_px ( GtkObject *base, const gchar *key );
112 static void sp_export_filename_modified (GtkObject * object, gpointer data);
113 static inline void sp_export_find_default_selection(GtkWidget * dlg);
114 static void sp_export_detect_size(GtkObject * base);
116 static const gchar *prefs_path = "dialogs.export";
118 // these all need to be reinitialized to their defaults during dialog_destroy
119 static GtkWidget *dlg = NULL;
120 static win_data wd;
121 static gint x = -1000, y = -1000, w = 0, h = 0; // impossible original values to make sure they are read from prefs
122 static gchar * original_name = NULL;
123 static gchar * doc_export_name = NULL;
124 static bool was_empty = TRUE;
126 /** What type of button is being pressed */
127 enum selection_type {
128 SELECTION_PAGE = 0, /**< Export the whole page */
129 SELECTION_DRAWING, /**< Export everything drawn on the page */
130 SELECTION_SELECTION, /**< Export everything that is selected */
131 SELECTION_CUSTOM, /**< Allows the user to set the region exported */
132 SELECTION_NUMBER_OF /**< A counter for the number of these guys */
133 };
135 /** A list of strings that is used both in the preferences, and in the
136 data fields to describe the various values of \c selection_type. */
137 static const char * selection_names[SELECTION_NUMBER_OF] = {
138 "page", "drawing", "selection", "custom"};
140 /** The names on the buttons for the various selection types. */
141 static const char * selection_labels[SELECTION_NUMBER_OF] = {
142 N_("_Page"), N_("_Drawing"), N_("_Selection"), N_("_Custom")};
144 static void
145 sp_export_dialog_destroy ( GtkObject *object, gpointer data )
146 {
147 sp_signal_disconnect_by_data (INKSCAPE, dlg);
149 wd.win = dlg = NULL;
150 wd.stop = 0;
151 x = -1000; y = -1000; w = 0; h = 0;
152 g_free(original_name);
153 original_name = NULL;
154 g_free(doc_export_name);
155 doc_export_name = NULL;
156 was_empty = TRUE;
158 return;
159 } // end of sp_export_dialog_destroy()
161 /// Called when dialog is closed or inkscape is shut down.
162 static bool
163 sp_export_dialog_delete ( GtkObject *object, GdkEvent *event, gpointer data )
164 {
166 gtk_window_get_position ((GtkWindow *) dlg, &x, &y);
167 gtk_window_get_size ((GtkWindow *) dlg, &w, &h);
169 if (x<0) x=0;
170 if (y<0) y=0;
172 prefs_set_int_attribute (prefs_path, "x", x);
173 prefs_set_int_attribute (prefs_path, "y", y);
174 prefs_set_int_attribute (prefs_path, "w", w);
175 prefs_set_int_attribute (prefs_path, "h", h);
177 return FALSE; // which means, go ahead and destroy it
179 } // end of sp_export_dialog_delete()
181 /**
182 \brief Creates a new spin button for the export dialog
183 \param key The name of the spin button
184 \param val A default value for the spin button
185 \param min Minimum value for the spin button
186 \param max Maximum value for the spin button
187 \param step The step size for the spin button
188 \param page Size of the page increment
189 \param us Unit selector that effects this spin button
190 \param t Table to put the spin button in
191 \param x X location in the table \c t to start with
192 \param y Y location in the table \c t to start with
193 \param ll Text to put on the left side of the spin button (optional)
194 \param lr Text to put on the right side of the spin button (optional)
195 \param digits Number of digits to display after the decimal
196 \param sensitive Whether the spin button is sensitive or not
197 \param cb Callback for when this spin button is changed (optional)
198 \param dlg Export dialog the spin button is being placed in
200 */
201 static void
202 sp_export_spinbutton_new ( gchar *key, float val, float min, float max,
203 float step, float page, GtkWidget *us,
204 GtkWidget *t, int x, int y,
205 const gchar *ll, const gchar *lr,
206 int digits, unsigned int sensitive,
207 GCallback cb, GtkWidget *dlg )
208 {
209 GtkObject *a = gtk_adjustment_new (val, min, max, step, page, page);
210 gtk_object_set_data (a, "key", key);
211 gtk_object_set_data (GTK_OBJECT (dlg), (const gchar *)key, a);
213 if (us) {
214 sp_unit_selector_add_adjustment ( SP_UNIT_SELECTOR (us),
215 GTK_ADJUSTMENT (a) );
216 }
218 int pos = 0;
220 GtkWidget *l = NULL;
222 if (ll) {
224 l = gtk_label_new_with_mnemonic ((const gchar *)ll);
225 gtk_misc_set_alignment (GTK_MISC (l), 1.0, 0.5);
226 gtk_table_attach ( GTK_TABLE (t), l, x + pos, x + pos + 1, y, y + 1,
227 (GtkAttachOptions)0, (GtkAttachOptions)0, 0, 0 );
228 gtk_widget_set_sensitive (l, sensitive);
229 pos += 1;
231 }
233 GtkWidget *sb = gtk_spin_button_new (GTK_ADJUSTMENT (a), 1.0, digits);
234 gtk_table_attach ( GTK_TABLE (t), sb, x + pos, x + pos + 1, y, y + 1,
235 (GtkAttachOptions)0, (GtkAttachOptions)0, 0, 0 );
236 gtk_widget_set_size_request (sb, 80, -1);
237 gtk_widget_set_sensitive (sb, sensitive);
238 pos += 1;
240 if (ll) { gtk_label_set_mnemonic_widget (GTK_LABEL(l), sb); }
242 if (lr) {
244 l = gtk_label_new_with_mnemonic ((const gchar *)lr);
245 gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
246 gtk_table_attach ( GTK_TABLE (t), l, x + pos, x + pos + 1, y, y + 1,
247 (GtkAttachOptions)0, (GtkAttachOptions)0, 0, 0 );
248 gtk_widget_set_sensitive (l, sensitive);
249 pos += 1;
251 gtk_label_set_mnemonic_widget (GTK_LABEL(l), sb);
252 }
254 if (cb)
255 gtk_signal_connect (a, "value_changed", cb, dlg);
257 return;
258 } // end of sp_export_spinbutton_new()
261 static Gtk::VBox *
262 sp_export_dialog_area_box (GtkWidget * dlg)
263 {
264 Gtk::VBox* vb = new Gtk::VBox(false, 3);
266 Gtk::Label* lbl = new Gtk::Label(_("<big><b>Export area</b></big>"), Gtk::ALIGN_LEFT);
267 lbl->set_use_markup(true);
268 vb->pack_start(*lbl);
270 /* Units box */
271 Gtk::HBox* unitbox = new Gtk::HBox(false, 0);
272 /* gets added to the vbox later, but the unit selector is needed
273 earlier than that */
275 Gtk::Widget* us = Glib::wrap(sp_unit_selector_new (SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE));
276 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
277 if (desktop)
278 sp_unit_selector_set_unit (SP_UNIT_SELECTOR(us->gobj()), sp_desktop_namedview(desktop)->doc_units);
279 unitbox->pack_end(*us, false, false, 0);
280 Gtk::Label* l = new Gtk::Label(_("Units:"));
281 unitbox->pack_end(*l, false, false, 3);
282 gtk_object_set_data (GTK_OBJECT (dlg), "units", us->gobj());
284 Gtk::HBox* togglebox = new Gtk::HBox(true, 0);
286 Gtk::ToggleButton* b;
287 for (int i = 0; i < SELECTION_NUMBER_OF; i++) {
288 b = new Gtk::ToggleButton(_(selection_labels[i]), true);
289 b->set_data("key", GINT_TO_POINTER(i));
290 gtk_object_set_data (GTK_OBJECT (dlg), selection_names[i], b->gobj());
291 togglebox->pack_start(*b, false, true, 0);
292 gtk_signal_connect ( GTK_OBJECT (b->gobj()), "clicked",
293 GTK_SIGNAL_FUNC (sp_export_area_toggled), dlg );
294 }
296 g_signal_connect ( G_OBJECT (INKSCAPE), "change_selection",
297 G_CALLBACK (sp_export_selection_changed), dlg );
298 g_signal_connect ( G_OBJECT (INKSCAPE), "modify_selection",
299 G_CALLBACK (sp_export_selection_modified), dlg );
300 g_signal_connect ( G_OBJECT (INKSCAPE), "activate_desktop",
301 G_CALLBACK (sp_export_selection_changed), dlg );
303 Gtk::Table* t = new Gtk::Table(2, 6, FALSE);
304 t->set_row_spacings (4);
305 t->set_col_spacings (4);
307 sp_export_spinbutton_new ( "x0", 0.0, -1000000.0, 1000000.0, 0.1, 1.0, us->gobj(),
308 GTK_WIDGET(t->gobj()), 0, 0, _("_x0:"), NULL, EXPORT_COORD_PRECISION, 1,
309 G_CALLBACK ( sp_export_area_x_value_changed),
310 dlg );
312 sp_export_spinbutton_new ( "x1", 0.0, -1000000.0, 1000000.0, 0.1, 1.0, us->gobj(),
313 GTK_WIDGET(t->gobj()), 2, 0, _("x_1:"), NULL, EXPORT_COORD_PRECISION, 1,
314 G_CALLBACK (sp_export_area_x_value_changed),
315 dlg );
317 sp_export_spinbutton_new ( "width", 0.0, -1000000.0, 1000000.0, 0.1, 1.0,
318 us->gobj(), GTK_WIDGET(t->gobj()), 4, 0, _("Width:"), NULL, EXPORT_COORD_PRECISION, 1,
319 G_CALLBACK
320 (sp_export_area_width_value_changed),
321 dlg );
323 sp_export_spinbutton_new ( "y0", 0.0, -1000000.0, 1000000.0, 0.1, 1.0, us->gobj(),
324 GTK_WIDGET(t->gobj()), 0, 1, _("_y0:"), NULL, EXPORT_COORD_PRECISION, 1,
325 G_CALLBACK (sp_export_area_y_value_changed),
326 dlg );
328 sp_export_spinbutton_new ( "y1", 0.0, -1000000.0, 1000000.0, 0.1, 1.0, us->gobj(),
329 GTK_WIDGET(t->gobj()), 2, 1, _("y_1:"), NULL, EXPORT_COORD_PRECISION, 1,
330 G_CALLBACK (sp_export_area_y_value_changed),
331 dlg );
333 sp_export_spinbutton_new ( "height", 0.0, -1000000.0, 1000000.0, 0.1, 1.0,
334 us->gobj(), GTK_WIDGET(t->gobj()), 4, 1, _("Height:"), NULL, EXPORT_COORD_PRECISION, 1,
335 G_CALLBACK (sp_export_area_height_value_changed),
336 dlg );
338 vb->pack_start(*togglebox, false, false, 3);
339 vb->pack_start(*t, false, false, 0);
340 vb->pack_start(*unitbox, false, false, 0);
342 return vb;
343 } // end of sp_export_dialog_area_box
346 gchar* create_filepath_from_id (const gchar *id, const gchar *file_entry_text) {
348 if (id == NULL) /* This should never happen */
349 id = "bitmap";
351 gchar * directory = NULL;
353 if (directory == NULL && file_entry_text != NULL && file_entry_text[0] != '\0') {
354 // std::cout << "Directory from dialog" << std::endl;
355 directory = g_dirname(file_entry_text);
356 }
358 if (directory == NULL) {
359 /* Grab document directory */
360 if (SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT)) {
361 // std::cout << "Directory from document" << std::endl;
362 directory = g_dirname(SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT));
363 }
364 }
366 if (directory == NULL) {
367 // std::cout << "Home Directory" << std::endl;
368 directory = homedir_path(NULL);
369 }
371 gchar * id_ext = g_strconcat(id, ".png", NULL);
372 gchar *filename = g_build_filename(directory, id_ext, NULL);
373 g_free(directory);
374 g_free(id_ext);
375 return filename;
376 }
378 static void
379 batch_export_clicked (GtkWidget *widget, GtkObject *base)
380 {
381 Gtk::Widget *vb_singleexport = (Gtk::Widget *)gtk_object_get_data(base, "vb_singleexport");
382 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget))) {
383 vb_singleexport->set_sensitive(false);
384 } else {
385 vb_singleexport->set_sensitive(true);
386 }
387 }
389 void
390 sp_export_dialog (void)
391 {
392 if (!dlg) {
394 gchar title[500];
395 sp_ui_dialog_title_string (Inkscape::Verb::get(SP_VERB_FILE_EXPORT), title);
397 dlg = sp_window_new (title, TRUE);
399 if (x == -1000 || y == -1000) {
400 x = prefs_get_int_attribute (prefs_path, "x", 0);
401 y = prefs_get_int_attribute (prefs_path, "y", 0);
402 }
404 if (w ==0 || h == 0) {
405 w = prefs_get_int_attribute (prefs_path, "w", 0);
406 h = prefs_get_int_attribute (prefs_path, "h", 0);
407 }
409 // if (x<0) x=0;
410 // if (y<0) y=0;
412 if (w && h) gtk_window_resize ((GtkWindow *) dlg, w, h);
413 if (x >= 0 && y >= 0 && (x < (gdk_screen_width()-MIN_ONSCREEN_DISTANCE)) && (y < (gdk_screen_height()-MIN_ONSCREEN_DISTANCE)))
414 gtk_window_move ((GtkWindow *) dlg, x, y);
415 else
416 gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
417 sp_transientize (dlg);
418 wd.win = dlg;
419 wd.stop = 0;
421 g_signal_connect ( G_OBJECT (INKSCAPE), "activate_desktop",
422 G_CALLBACK (sp_transientize_callback), &wd);
424 gtk_signal_connect ( GTK_OBJECT (dlg), "event",
425 GTK_SIGNAL_FUNC (sp_dialog_event_handler), dlg);
427 gtk_signal_connect ( GTK_OBJECT (dlg), "destroy",
428 G_CALLBACK (sp_export_dialog_destroy), dlg);
430 gtk_signal_connect ( GTK_OBJECT (dlg), "delete_event",
431 G_CALLBACK (sp_export_dialog_delete), dlg);
433 g_signal_connect ( G_OBJECT (INKSCAPE), "shut_down",
434 G_CALLBACK (sp_export_dialog_delete), dlg);
436 g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_hide",
437 G_CALLBACK (sp_dialog_hide), dlg);
439 g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_unhide",
440 G_CALLBACK (sp_dialog_unhide), dlg);
442 GtkTooltips *tt = gtk_tooltips_new();
444 Gtk::VBox *vb = new Gtk::VBox(false, 3);
445 vb->set_border_width(3);
446 gtk_container_add (GTK_CONTAINER (dlg), GTK_WIDGET(vb->gobj()));
448 Gtk::VBox *vb_singleexport = new Gtk::VBox(false, 0);
449 vb_singleexport->set_border_width(0);
450 vb->pack_start(*vb_singleexport);
451 gtk_object_set_data(GTK_OBJECT(dlg), "vb_singleexport", vb_singleexport);
453 /* Export area frame */
454 {
455 Gtk::VBox *area_box = sp_export_dialog_area_box(dlg);
456 area_box->set_border_width(3);
457 vb_singleexport->pack_start(*area_box, false, false, 0);
458 }
460 /* Bitmap size frame */
461 {
462 Gtk::VBox *size_box = new Gtk::VBox(false, 3);
463 size_box->set_border_width(3);
465 Gtk::Label* lbl = new Gtk::Label(_("<big><b>Bitmap size</b></big>"), Gtk::ALIGN_LEFT);
466 lbl->set_use_markup(true);
467 size_box->pack_start(*lbl, false, false, 0);
468 const int rows = 2;
469 const int cols = 5;
470 const bool homogeneous = false;
471 Gtk::Table *t = new Gtk::Table(rows, cols, homogeneous);
472 t->set_row_spacings (4);
473 t->set_col_spacings (4);
474 size_box->pack_start(*t);
476 sp_export_spinbutton_new ( "bmwidth", 16.0, 1.0, 1000000.0, 1.0, 10.0,
477 NULL, GTK_WIDGET(t->gobj()), 0, 0,
478 _("_Width:"), _("pixels at"), 0, 1,
479 G_CALLBACK
480 (sp_export_bitmap_width_value_changed),
481 dlg );
483 sp_export_spinbutton_new ( "xdpi",
484 prefs_get_double_attribute
485 ( "dialogs.export.defaultxdpi",
486 "value", DPI_BASE),
487 0.01, 100000.0, 0.1, 1.0, NULL, GTK_WIDGET(t->gobj()), 3, 0,
488 NULL, _("dp_i"), 2, 1,
489 G_CALLBACK (sp_export_xdpi_value_changed),
490 dlg );
492 sp_export_spinbutton_new ( "bmheight", 16.0, 1.0, 1000000.0, 1.0, 10.0,
493 NULL, GTK_WIDGET(t->gobj()), 0, 1,
494 _("Height:"), _("pixels at"), 0, 1,
495 G_CALLBACK
496 (sp_export_bitmap_height_value_changed),
497 dlg );
499 /** \todo
500 * Needs fixing: there's no way to set ydpi currently, so we use
501 * the defaultxdpi value here, too...
502 */
503 sp_export_spinbutton_new ( "ydpi", prefs_get_double_attribute
504 ( "dialogs.export.defaultxdpi",
505 "value", DPI_BASE),
506 0.01, 100000.0, 0.1, 1.0, NULL, GTK_WIDGET(t->gobj()), 3, 1,
507 NULL, _("dpi"), 2, 0, NULL, dlg );
509 vb_singleexport->pack_start(*size_box);
510 }
512 /* File entry */
513 {
514 Gtk::VBox* file_box = new Gtk::VBox(false, 3);
515 file_box->set_border_width(3);
517 // true = has mnemonic
518 Gtk::Label *flabel = new Gtk::Label(_("<big><b>_Filename</b></big>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, true);
519 flabel->set_use_markup(true);
520 file_box->pack_start(*flabel, false, false, 0);
522 Gtk::Entry *fe = new Gtk::Entry();
524 /*
525 * set the default filename to be that of the current path + document
526 * with .png extension
527 *
528 * One thing to notice here is that this filename may get
529 * overwritten, but it won't happen here. The filename gets
530 * written into the text field, but then the button to select
531 * the area gets set. In that code the filename can be changed
532 * if there are some with presidence in the document. So, while
533 * this code sets the name first, it may not be the one users
534 * really see.
535 */
536 if (SP_ACTIVE_DOCUMENT && SP_DOCUMENT_URI (SP_ACTIVE_DOCUMENT))
537 {
538 gchar *name;
539 SPDocument * doc = SP_ACTIVE_DOCUMENT;
540 const gchar *uri = SP_DOCUMENT_URI (doc);
541 Inkscape::XML::Node * repr = sp_document_repr_root(doc);
542 const gchar * text_extension = repr->attribute("inkscape:output_extension");
543 Inkscape::Extension::Output * oextension = NULL;
545 if (text_extension != NULL) {
546 oextension = dynamic_cast<Inkscape::Extension::Output *>(Inkscape::Extension::db.get(text_extension));
547 }
549 if (oextension != NULL) {
550 gchar * old_extension = oextension->get_extension();
551 if (g_str_has_suffix(uri, old_extension)) {
552 gchar * uri_copy;
553 gchar * extension_point;
554 gchar * final_name;
556 uri_copy = g_strdup(uri);
557 extension_point = g_strrstr(uri_copy, old_extension);
558 extension_point[0] = '\0';
560 final_name = g_strconcat(uri_copy, ".png", NULL);
561 fe->set_text(final_name);
563 g_free(final_name);
564 g_free(uri_copy);
565 }
566 } else {
567 name = g_strconcat(uri, ".png", NULL);
568 fe->set_text(name);
569 g_free(name);
570 }
572 doc_export_name = g_strdup(fe->get_text().c_str());
573 }
574 g_signal_connect ( G_OBJECT (fe->gobj()), "changed",
575 G_CALLBACK (sp_export_filename_modified), dlg);
577 Gtk::HBox *hb = new Gtk::HBox(FALSE, 5);
579 {
580 // true = has mnemonic
581 Gtk::Button *b = new Gtk::Button();
583 Gtk::HBox* pixlabel = new Gtk::HBox(false, 3);
584 Gtk::Image *im = new Gtk::Image(Gtk::StockID(Gtk::Stock::INDEX),
585 Gtk::ICON_SIZE_BUTTON);
586 pixlabel->pack_start(*im);
588 Gtk::Label *l = new Gtk::Label();
589 l->set_markup_with_mnemonic(_("_Browse..."));
590 pixlabel->pack_start(*l);
592 b->add(*pixlabel);
594 hb->pack_end (*b, false, false, 4);
595 g_signal_connect ( G_OBJECT (b->gobj()), "clicked",
596 G_CALLBACK (sp_export_browse_clicked), NULL );
597 }
599 hb->pack_start (*fe, true, true, 0);
600 file_box->add(*hb);
601 gtk_object_set_data (GTK_OBJECT (dlg), "filename", fe->gobj());
602 gtk_object_set_data (GTK_OBJECT (dlg), "filename-modified", (gpointer)FALSE);
603 original_name = g_strdup(fe->get_text().c_str());
604 // pressing enter in the filename field is the same as clicking export:
605 g_signal_connect ( G_OBJECT (fe->gobj()), "activate",
606 G_CALLBACK (sp_export_export_clicked), dlg );
607 // focus is in the filename initially:
608 fe->grab_focus();
610 // mnemonic in frame label moves focus to filename:
611 flabel->set_mnemonic_widget(*fe);
613 vb_singleexport->pack_start(*file_box);
614 }
616 {
617 Gtk::HBox* batch_box = new Gtk::HBox(FALSE, 5);
618 GtkWidget *be = gtk_check_button_new_with_label(_("Batch export all selected objects"));
619 gtk_widget_set_sensitive(GTK_WIDGET(be), TRUE);
620 gtk_object_set_data(GTK_OBJECT(dlg), "batch_checkbox", be);
621 batch_box->pack_start(*Glib::wrap(be), false, false);
622 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);
623 batch_box->show_all();
624 g_signal_connect(G_OBJECT(be), "toggled", GTK_SIGNAL_FUNC(batch_export_clicked), dlg);
625 vb->pack_start(*batch_box);
626 }
628 {
629 Gtk::HBox* hide_box = new Gtk::HBox(FALSE, 5);
630 GtkWidget *he = gtk_check_button_new_with_label(_("Hide all except selected"));
631 gtk_widget_set_sensitive(GTK_WIDGET(he), TRUE);
632 gtk_object_set_data(GTK_OBJECT(dlg), "hide_checkbox", he);
633 hide_box->pack_start(*Glib::wrap(he), false, false);
634 gtk_tooltips_set_tip(tt, he, _("In the exported image, hide all objects except those that are selected"), NULL);
635 hide_box->show_all();
636 vb->pack_start(*hide_box);
637 }
639 /* Buttons */
640 Gtk::HButtonBox* bb = new Gtk::HButtonBox(Gtk::BUTTONBOX_END);
641 bb->set_border_width(3);
643 {
644 Gtk::Button *b = new Gtk::Button();
645 Gtk::HBox* image_label = new Gtk::HBox(false, 3);
646 Gtk::Image *im = new Gtk::Image(Gtk::StockID(Gtk::Stock::APPLY),
647 Gtk::ICON_SIZE_BUTTON);
648 image_label->pack_start(*im);
650 Gtk::Label *l = new Gtk::Label();
651 l->set_markup_with_mnemonic(_("_Export"));
652 image_label->pack_start(*l);
654 b->add(*image_label);
655 gtk_tooltips_set_tip (tt, GTK_WIDGET(b->gobj()), _("Export the bitmap file with these settings"), NULL);
656 gtk_signal_connect ( GTK_OBJECT (b->gobj()), "clicked",
657 GTK_SIGNAL_FUNC (sp_export_export_clicked), dlg );
658 bb->pack_end(*b, false, false, 0);
659 }
661 vb->pack_end(*bb, false, false, 0);
662 vb->show_all();
664 } // end of if (!dlg)
666 sp_export_find_default_selection(dlg);
668 gtk_window_present ((GtkWindow *) dlg);
670 return;
671 } // end of sp_export_dialog()
673 static void
674 sp_export_update_checkbuttons (GtkObject *base)
675 {
676 gint num = g_slist_length((GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
677 GtkWidget *be = (GtkWidget *)gtk_object_get_data(base, "batch_checkbox");
678 GtkWidget *he = (GtkWidget *)gtk_object_get_data(base, "hide_checkbox");
679 if (num >= 2) {
680 gtk_widget_set_sensitive (be, true);
681 gtk_button_set_label (GTK_BUTTON(be), g_strdup_printf (_("Batch export %d selected objects"), num));
682 } else {
683 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(be), FALSE);
684 gtk_widget_set_sensitive (be, FALSE);
685 }
686 if (num > 0) {
687 gtk_widget_set_sensitive (he, true);
688 } else {
689 gtk_widget_set_sensitive (he, false);
690 }
691 }
693 static inline void
694 sp_export_find_default_selection(GtkWidget * dlg)
695 {
696 selection_type key = SELECTION_NUMBER_OF;
698 if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) {
699 key = SELECTION_SELECTION;
700 }
702 /* Try using the preferences */
703 if (key == SELECTION_NUMBER_OF) {
704 const gchar *what = NULL;
705 int i = SELECTION_NUMBER_OF;
707 what = prefs_get_string_attribute ("dialogs.export.exportarea", "value");
709 if (what != NULL) {
710 for (i = 0; i < SELECTION_NUMBER_OF; i++) {
711 if (!strcmp (what, selection_names[i])) {
712 break;
713 }
714 }
715 }
717 key = (selection_type)i;
718 }
720 if (key == SELECTION_NUMBER_OF) {
721 key = SELECTION_SELECTION;
722 }
724 GtkWidget *button = (GtkWidget *)g_object_get_data(G_OBJECT(dlg),
725 selection_names[key]);
726 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
728 sp_export_update_checkbuttons (GTK_OBJECT(dlg));
729 }
732 /**
733 * \brief If selection changed or a different document activated, we must
734 * recalculate any chosen areas
735 *
736 */
737 static void
738 sp_export_selection_changed ( Inkscape::Application *inkscape,
739 Inkscape::Selection *selection,
740 GtkObject *base )
741 {
742 selection_type current_key;
743 current_key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
745 if ((current_key == SELECTION_DRAWING || current_key == SELECTION_PAGE) &&
746 (sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false &&
747 was_empty) {
748 gtk_toggle_button_set_active
749 ( GTK_TOGGLE_BUTTON ( gtk_object_get_data (base, selection_names[SELECTION_SELECTION])),
750 TRUE );
751 }
752 was_empty = (sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty();
754 current_key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
756 if (inkscape &&
757 SP_IS_INKSCAPE (inkscape) &&
758 selection &&
759 SELECTION_CUSTOM != current_key) {
760 GtkToggleButton * button;
761 button = (GtkToggleButton *)gtk_object_get_data(base, selection_names[current_key]);
762 sp_export_area_toggled(button, base);
763 }
765 sp_export_update_checkbuttons (base);
766 }
768 static void
769 sp_export_selection_modified ( Inkscape::Application *inkscape,
770 Inkscape::Selection *selection,
771 guint flags,
772 GtkObject *base )
773 {
774 selection_type current_key;
775 current_key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
777 switch (current_key) {
778 case SELECTION_DRAWING:
779 if ( SP_ACTIVE_DESKTOP ) {
780 SPDocument *doc;
781 doc = sp_desktop_document (SP_ACTIVE_DESKTOP);
782 NR::Maybe<NR::Rect> bbox = sp_item_bbox_desktop (SP_ITEM (SP_DOCUMENT_ROOT (doc)));
783 if (bbox) {
784 sp_export_set_area (base, bbox->min()[NR::X],
785 bbox->min()[NR::Y],
786 bbox->max()[NR::X],
787 bbox->max()[NR::Y]);
788 }
789 }
790 break;
791 case SELECTION_SELECTION:
792 if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) {
793 NRRect bbox;
794 (sp_desktop_selection (SP_ACTIVE_DESKTOP))->bounds(&bbox);
795 sp_export_set_area (base, bbox.x0, bbox.y0, bbox.x1, bbox.y1);
796 }
797 break;
798 default:
799 /* Do nothing for page or for custom */
800 break;
801 }
803 return;
804 }
806 /// Called when one of the selection buttons was toggled.
807 static void
808 sp_export_area_toggled (GtkToggleButton *tb, GtkObject *base)
809 {
810 if (gtk_object_get_data (base, "update"))
811 return;
813 selection_type key, old_key;
814 key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data (GTK_OBJECT (tb), "key")));
815 old_key = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
817 /* Ignore all "turned off" events unless we're the only active button */
818 if (!gtk_toggle_button_get_active (tb) ) {
820 /* Don't let the current selection be deactived - but rerun the
821 activate to allow the user to renew the values */
822 if (key == old_key) {
823 gtk_toggle_button_set_active ( tb, TRUE );
824 }
826 return;
827 }
829 /* Turn off the currently active button unless it's us */
830 gtk_object_set_data(GTK_OBJECT(base), "selection-type", (gpointer)key);
832 if (old_key != key) {
833 gtk_toggle_button_set_active
834 ( GTK_TOGGLE_BUTTON ( gtk_object_get_data (base, selection_names[old_key])),
835 FALSE );
836 }
838 if ( SP_ACTIVE_DESKTOP )
839 {
840 SPDocument *doc;
841 NR::Maybe<NR::Rect> bbox;
842 doc = sp_desktop_document (SP_ACTIVE_DESKTOP);
844 /* Notice how the switch is used to 'fall through' here to get
845 various backups. If you modify this without noticing you'll
846 probabaly screw something up. */
847 switch (key) {
848 case SELECTION_SELECTION:
849 if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false)
850 {
851 bbox = (sp_desktop_selection (SP_ACTIVE_DESKTOP))->bounds();
852 /* Only if there is a selection that we can set
853 do we break, otherwise we fall through to the
854 drawing */
855 // std::cout << "Using selection: SELECTION" << std::endl;
856 key = SELECTION_SELECTION;
857 break;
858 }
859 case SELECTION_DRAWING:
860 /** \todo
861 * This returns wrong values if the document has a viewBox.
862 */
863 bbox = sp_item_bbox_desktop (SP_ITEM (SP_DOCUMENT_ROOT (doc)));
864 /* If the drawing is valid, then we'll use it and break
865 otherwise we drop through to the page settings */
866 if (bbox) {
867 // std::cout << "Using selection: DRAWING" << std::endl;
868 key = SELECTION_DRAWING;
869 break;
870 }
871 case SELECTION_PAGE:
872 bbox = NR::Rect(NR::Point(0.0, 0.0),
873 NR::Point(sp_document_width(doc), sp_document_height(doc))
874 );
876 // std::cout << "Using selection: PAGE" << std::endl;
877 key = SELECTION_PAGE;
878 break;
879 case SELECTION_CUSTOM:
880 default:
881 break;
882 } // switch
884 // remember area setting
885 prefs_set_string_attribute ( "dialogs.export.exportarea",
886 "value", selection_names[key]);
888 if ( key != SELECTION_CUSTOM && bbox ) {
889 sp_export_set_area (base, bbox->min()[NR::X],
890 bbox->min()[NR::Y],
891 bbox->max()[NR::X],
892 bbox->max()[NR::Y]);
893 }
895 } // end of if ( SP_ACTIVE_DESKTOP )
898 if (SP_ACTIVE_DESKTOP && !gtk_object_get_data(GTK_OBJECT(base), "filename-modified")) {
899 GtkWidget * file_entry;
900 const gchar * filename = NULL;
901 float xdpi = 0.0, ydpi = 0.0;
903 file_entry = (GtkWidget *)gtk_object_get_data (base, "filename");
905 switch (key) {
906 case SELECTION_PAGE:
907 case SELECTION_DRAWING: {
908 SPDocument * doc = SP_ACTIVE_DOCUMENT;
909 sp_document_get_export_hints (doc, &filename, &xdpi, &ydpi);
911 if (filename == NULL) {
912 if (doc_export_name != NULL) {
913 filename = g_strdup(doc_export_name);
914 } else {
915 filename = g_strdup("");
916 }
917 }
918 break;
919 }
920 case SELECTION_SELECTION:
921 if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) {
923 sp_selection_get_export_hints (sp_desktop_selection(SP_ACTIVE_DESKTOP), &filename, &xdpi, &ydpi);
925 /* If we still don't have a filename -- let's build
926 one that's nice */
927 if (filename == NULL) {
928 const gchar * id = NULL;
929 const GSList * reprlst = sp_desktop_selection(SP_ACTIVE_DESKTOP)->reprList();
930 for(; reprlst != NULL; reprlst = reprlst->next) {
931 Inkscape::XML::Node * repr = (Inkscape::XML::Node *)reprlst->data;
932 if (repr->attribute("id")) {
933 id = repr->attribute("id");
934 break;
935 }
936 }
938 filename = create_filepath_from_id (id, gtk_entry_get_text(GTK_ENTRY(file_entry)));
939 }
940 }
941 break;
942 case SELECTION_CUSTOM:
943 default:
944 break;
945 }
947 if (filename != NULL) {
948 g_free(original_name);
949 original_name = g_strdup(filename);
950 gtk_entry_set_text(GTK_ENTRY(file_entry), filename);
951 }
953 if (xdpi != 0.0) {
954 sp_export_value_set(base, "xdpi", xdpi);
955 }
957 /* These can't be separate, and setting x sets y, so for
958 now setting this is disabled. Hopefully it won't be in
959 the future */
960 if (FALSE && ydpi != 0.0) {
961 sp_export_value_set(base, "ydpi", ydpi);
962 }
963 }
965 return;
966 } // end of sp_export_area_toggled()
968 /// Called when dialog is deleted
969 static gint
970 sp_export_progress_delete ( GtkWidget *widget, GdkEvent *event, GObject *base )
971 {
972 g_object_set_data (base, "cancel", (gpointer) 1);
973 return TRUE;
974 } // end of sp_export_progress_delete()
976 /// Called when progress is cancelled
977 static void
978 sp_export_progress_cancel ( GtkWidget *widget, GObject *base )
979 {
980 g_object_set_data (base, "cancel", (gpointer) 1);
981 } // end of sp_export_progress_cancel()
983 /// Called for every progress iteration
984 static unsigned int
985 sp_export_progress_callback (float value, void *data)
986 {
987 GtkWidget *prg;
988 int evtcount;
990 if (g_object_get_data ((GObject *) data, "cancel"))
991 return FALSE;
993 prg = (GtkWidget *) g_object_get_data ((GObject *) data, "progress");
994 gtk_progress_bar_set_fraction ((GtkProgressBar *) prg, value);
996 evtcount = 0;
997 while ((evtcount < 16) && gdk_events_pending ()) {
998 gtk_main_iteration_do (FALSE);
999 evtcount += 1;
1000 }
1002 gtk_main_iteration_do (FALSE);
1004 return TRUE;
1006 } // end of sp_export_progress_callback()
1008 GtkWidget *
1009 create_progress_dialog (GtkObject *base, gchar *progress_text) {
1010 GtkWidget *dlg, *prg, *btn; /* progressbar-stuff */
1012 dlg = gtk_dialog_new ();
1013 gtk_window_set_title (GTK_WINDOW (dlg), _("Export in progress"));
1014 prg = gtk_progress_bar_new ();
1015 sp_transientize (dlg);
1016 gtk_window_set_resizable (GTK_WINDOW (dlg), FALSE);
1017 g_object_set_data ((GObject *) base, "progress", prg);
1019 gtk_progress_bar_set_text ((GtkProgressBar *) prg, progress_text);
1021 gtk_progress_bar_set_orientation ( (GtkProgressBar *) prg,
1022 GTK_PROGRESS_LEFT_TO_RIGHT);
1023 gtk_box_pack_start ((GtkBox *) ((GtkDialog *) dlg)->vbox,
1024 prg, FALSE, FALSE, 4 );
1025 btn = gtk_dialog_add_button ( GTK_DIALOG (dlg),
1026 GTK_STOCK_CANCEL,
1027 GTK_RESPONSE_CANCEL );
1029 g_signal_connect ( (GObject *) dlg, "delete_event",
1030 (GCallback) sp_export_progress_delete, base);
1031 g_signal_connect ( (GObject *) btn, "clicked",
1032 (GCallback) sp_export_progress_cancel, base);
1033 gtk_window_set_modal ((GtkWindow *) dlg, TRUE);
1034 gtk_widget_show_all (dlg);
1036 return dlg;
1037 }
1039 // FIXME: Some lib function should be available to do this ...
1040 static gchar *
1041 filename_add_extension (const gchar *filename, const gchar *extension)
1042 {
1043 gchar *dot;
1045 dot = strrchr (filename, '.');
1046 if ( !dot )
1047 return g_strconcat (filename, ".", extension, NULL);
1048 {
1049 if (dot[1] == '\0')
1050 return g_strconcat (filename, extension, NULL);
1051 else
1052 {
1053 if (g_strcasecmp (dot + 1, extension) == 0)
1054 return g_strdup (filename);
1055 else
1056 {
1057 return g_strconcat (filename, ".", extension, NULL);
1058 }
1059 }
1060 }
1061 }
1063 /// Called when export button is clicked
1064 static void
1065 sp_export_export_clicked (GtkButton *button, GtkObject *base)
1066 {
1067 if (!SP_ACTIVE_DESKTOP) return;
1069 SPNamedView *nv = sp_desktop_namedview(SP_ACTIVE_DESKTOP);
1071 GtkWidget *be = (GtkWidget *)gtk_object_get_data(base, "batch_checkbox");
1072 GtkWidget *he = (GtkWidget *)gtk_object_get_data(base, "hide_checkbox");
1073 bool hide = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (he));
1074 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (be))) {
1075 // Batch export of selected objects
1077 gint num = g_slist_length((GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
1078 gint n = 0;
1080 if (num < 1)
1081 return;
1083 gchar *progress_text = g_strdup_printf (_("Exporting %d files"), num);
1084 GtkWidget *prog_dlg = create_progress_dialog (base, progress_text);
1085 g_free (progress_text);
1087 for (GSList *i = (GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList();
1088 i != NULL;
1089 i = i->next) {
1090 SPItem *item = (SPItem *) i->data;
1091 // retrieve export filename hint
1092 const gchar *fn = SP_OBJECT_REPR(item)->attribute("inkscape:export-filename");
1093 if (!fn) {
1094 fn = create_filepath_from_id (SP_OBJECT_ID(item), NULL);
1095 }
1097 // retrieve export dpi hints
1098 const gchar *dpi_hint = SP_OBJECT_REPR(item)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
1099 gdouble dpi = 0.0;
1100 if (dpi_hint) {
1101 dpi = atof(dpi_hint);
1102 }
1103 if (dpi == 0.0) {
1104 dpi = DPI_BASE;
1105 }
1107 NRRect area;
1108 sp_item_invoke_bbox(item, &area, sp_item_i2r_affine((SPItem *) item), TRUE);
1110 gint width = (gint) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1111 gint height = (gint) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1113 if (width > 1 && height > 1) {
1114 /* Do export */
1115 if (!sp_export_png_file (sp_desktop_document (SP_ACTIVE_DESKTOP), fn,
1116 area.x0, area.y0, area.x1, area.y1, width, height, dpi, dpi,
1117 nv->pagecolor,
1118 NULL, NULL, TRUE, // overwrite without asking
1119 hide ? (GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList() : NULL
1120 )) {
1121 gchar * error;
1122 gchar * safeFile = Inkscape::IO::sanitizeString(fn);
1123 error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile);
1124 sp_ui_error_dialog(error);
1125 g_free(safeFile);
1126 g_free(error);
1127 }
1128 }
1129 n++;
1130 sp_export_progress_callback((float)n/num, base);
1131 }
1133 gtk_widget_destroy (prog_dlg);
1134 g_object_set_data (G_OBJECT (base), "cancel", (gpointer) 0);
1136 } else {
1138 GtkWidget *fe = (GtkWidget *)gtk_object_get_data(base, "filename");
1139 gchar const *filename = gtk_entry_get_text(GTK_ENTRY(fe));
1141 float const x0 = sp_export_value_get_px(base, "x0");
1142 float const y0 = sp_export_value_get_px(base, "y0");
1143 float const x1 = sp_export_value_get_px(base, "x1");
1144 float const y1 = sp_export_value_get_px(base, "y1");
1145 float const xdpi = sp_export_value_get(base, "xdpi");
1146 float const ydpi = sp_export_value_get(base, "ydpi");
1147 int const width = int(sp_export_value_get(base, "bmwidth") + 0.5);
1148 int const height = int(sp_export_value_get(base, "bmheight") + 0.5);
1150 if (filename == NULL || *filename == '\0') {
1151 sp_ui_error_dialog(_("You have to enter a filename"));
1152 return;
1153 }
1155 if (!((x1 > x0) && (y1 > y0) && (width > 0) && (height > 0))) {
1156 sp_ui_error_dialog (_("The chosen area to be exported is invalid"));
1157 return;
1158 }
1160 gchar *dirname = g_path_get_dirname(filename);
1161 if ( dirname == NULL
1162 || !Inkscape::IO::file_test(dirname, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) )
1163 {
1164 gchar *safeDir = Inkscape::IO::sanitizeString(dirname);
1165 gchar *error = g_strdup_printf(_("Directory %s does not exist or is not a directory.\n"),
1166 safeDir);
1167 sp_ui_error_dialog(error);
1168 g_free(safeDir);
1169 g_free(error);
1170 g_free(dirname);
1171 return;
1172 }
1173 g_free(dirname);
1175 // make sure that .png is the extension of the file:
1176 gchar * filename_ext = filename_add_extension(filename, "png");
1177 gtk_entry_set_text(GTK_ENTRY(fe), filename_ext);
1179 gchar *fn = g_path_get_basename (filename_ext);
1181 gchar *progress_text = g_strdup_printf (_("Exporting %s (%d x %d)"), fn, width, height);
1182 g_free (fn);
1183 GtkWidget *prog_dlg = create_progress_dialog (base, progress_text);
1184 g_free (progress_text);
1186 /* Do export */
1187 if (!sp_export_png_file (sp_desktop_document (SP_ACTIVE_DESKTOP), filename_ext,
1188 x0, y0, x1, y1, width, height, xdpi, ydpi,
1189 nv->pagecolor,
1190 sp_export_progress_callback, base, FALSE,
1191 hide ? (GSList *) sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList() : NULL
1192 )) {
1193 gchar * error;
1194 gchar * safeFile = Inkscape::IO::sanitizeString(filename);
1195 error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile);
1196 sp_ui_error_dialog(error);
1197 g_free(safeFile);
1198 g_free(error);
1199 }
1201 /* Reset the filename so that it can be changed again by changing
1202 selections and all that */
1203 g_free(original_name);
1204 original_name = g_strdup(filename_ext);
1205 gtk_object_set_data (GTK_OBJECT (base), "filename-modified", (gpointer)FALSE);
1207 gtk_widget_destroy (prog_dlg);
1208 g_object_set_data (G_OBJECT (base), "cancel", (gpointer) 0);
1210 /* Setup the values in the document */
1211 switch ((selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")))) {
1212 case SELECTION_PAGE:
1213 case SELECTION_DRAWING: {
1214 SPDocument * doc = SP_ACTIVE_DOCUMENT;
1215 Inkscape::XML::Node * repr = sp_document_repr_root(doc);
1216 bool modified = false;
1217 const gchar * temp_string;
1219 bool saved = sp_document_get_undo_sensitive(doc);
1220 sp_document_set_undo_sensitive(doc, false);
1222 temp_string = repr->attribute("inkscape:export-filename");
1223 if (temp_string == NULL || strcmp(temp_string, filename_ext)) {
1224 repr->setAttribute("inkscape:export-filename", filename_ext);
1225 modified = true;
1226 }
1227 temp_string = repr->attribute("inkscape:export-xdpi");
1228 if (temp_string == NULL || xdpi != atof(temp_string)) {
1229 sp_repr_set_svg_double(repr, "inkscape:export-xdpi", xdpi);
1230 modified = true;
1231 }
1232 temp_string = repr->attribute("inkscape:export-ydpi");
1233 if (temp_string == NULL || xdpi != atof(temp_string)) {
1234 sp_repr_set_svg_double(repr, "inkscape:export-ydpi", ydpi);
1235 modified = true;
1236 }
1238 if (modified)
1239 repr->setAttribute("sodipodi:modified", "TRUE");
1240 sp_document_set_undo_sensitive(doc, saved);
1241 break;
1242 }
1243 case SELECTION_SELECTION: {
1244 const GSList * reprlst;
1245 SPDocument * doc = SP_ACTIVE_DOCUMENT;
1246 bool modified = false;
1248 bool saved = sp_document_get_undo_sensitive(doc);
1249 sp_document_set_undo_sensitive(doc, false);
1250 reprlst = sp_desktop_selection(SP_ACTIVE_DESKTOP)->reprList();
1252 for(; reprlst != NULL; reprlst = reprlst->next) {
1253 Inkscape::XML::Node * repr = (Inkscape::XML::Node *)reprlst->data;
1254 const gchar * temp_string;
1256 if (repr->attribute("id") == NULL ||
1257 !(g_strrstr(filename_ext, repr->attribute("id")) != NULL &&
1258 (!SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT) ||
1259 strcmp(g_dirname(filename), g_dirname(SP_DOCUMENT_URI(SP_ACTIVE_DOCUMENT))) == 0))) {
1260 temp_string = repr->attribute("inkscape:export-filename");
1261 if (temp_string == NULL || strcmp(temp_string, filename_ext)) {
1262 repr->setAttribute("inkscape:export-filename", filename_ext);
1263 modified = true;
1264 }
1265 }
1266 temp_string = repr->attribute("inkscape:export-xdpi");
1267 if (temp_string == NULL || xdpi != atof(temp_string)) {
1268 sp_repr_set_svg_double(repr, "inkscape:export-xdpi", xdpi);
1269 modified = true;
1270 }
1271 temp_string = repr->attribute("inkscape:export-ydpi");
1272 if (temp_string == NULL || xdpi != atof(temp_string)) {
1273 sp_repr_set_svg_double(repr, "inkscape:export-ydpi", ydpi);
1274 modified = true;
1275 }
1276 }
1278 if (modified) {
1279 Inkscape::XML::Node * repr = sp_document_repr_root(doc);
1280 repr->setAttribute("sodipodi:modified", "TRUE");
1281 }
1283 sp_document_set_undo_sensitive(doc, saved);
1284 break;
1285 }
1286 default:
1287 break;
1288 }
1290 g_free (filename_ext);
1292 }
1294 } // end of sp_export_export_clicked()
1296 /// Called when Browse button is clicked
1297 static void
1298 sp_export_browse_clicked (GtkButton *button, gpointer userdata)
1299 {
1300 GtkWidget *fs, *fe;
1301 const gchar *filename;
1303 fs = gtk_file_chooser_dialog_new (_("Select a filename for exporting"),
1304 NULL,
1305 GTK_FILE_CHOOSER_ACTION_SAVE,
1306 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1307 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1308 NULL );
1310 #ifdef WITH_GNOME_VFS
1311 if (gnome_vfs_initialized()) {
1312 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(fs), false);
1313 }
1314 #endif
1316 fe = (GtkWidget *)g_object_get_data (G_OBJECT (dlg), "filename");
1318 sp_transientize (fs);
1320 gtk_window_set_modal(GTK_WINDOW (fs), true);
1322 filename = gtk_entry_get_text (GTK_ENTRY (fe));
1324 if (*filename == '\0') {
1325 filename = homedir_path(NULL);
1326 }
1328 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (fs), filename);
1330 if (gtk_dialog_run (GTK_DIALOG (fs)) == GTK_RESPONSE_ACCEPT)
1331 {
1332 gchar *file;
1334 file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (fs));
1336 gchar * utf8file = g_filename_to_utf8( file, -1, NULL, NULL, NULL );
1337 gtk_entry_set_text (GTK_ENTRY (fe), utf8file);
1339 g_object_set_data (G_OBJECT (dlg), "filename", fe);
1341 g_free(utf8file);
1342 g_free(file);
1343 }
1345 gtk_widget_destroy (fs);
1347 return;
1348 } // end of sp_export_browse_clicked()
1350 // TODO: Move this to nr-rect-fns.h.
1351 static bool
1352 sp_export_bbox_equal(NR::Rect const &one, NR::Rect const &two)
1353 {
1354 double const epsilon = pow(10.0, -EXPORT_COORD_PRECISION);
1355 return (
1356 (fabs(one.min()[NR::X] - two.min()[NR::X]) < epsilon) &&
1357 (fabs(one.min()[NR::Y] - two.min()[NR::Y]) < epsilon) &&
1358 (fabs(one.max()[NR::X] - two.max()[NR::X]) < epsilon) &&
1359 (fabs(one.max()[NR::Y] - two.max()[NR::Y]) < epsilon)
1360 );
1361 }
1363 /**
1364 \brief This function is used to detect the current selection setting
1365 based on the values in the x0, y0, x1 and y0 fields.
1366 \param base The export dialog itself
1368 One of the most confusing parts of this function is why the array
1369 is built at the beginning. What needs to happen here is that we
1370 should always check the current selection to see if it is the valid
1371 one. While this is a performance improvement it is also a usability
1372 one during the cases where things like selections and drawings match
1373 size. This way buttons change less 'randomly' (atleast in the eyes
1374 of the user). To do this an array is built where the current selection
1375 type is placed first, and then the others in an order from smallest
1376 to largest (this can be configured by reshuffling \c test_order).
1378 All of the values in this function are rounded to two decimal places
1379 because that is what is shown to the user. While everything is kept
1380 more accurate than that, the user can't control more acurrate than
1381 that, so for this to work for them - it needs to check on that level
1382 of accuracy.
1384 \todo finish writing this up
1385 */
1386 static void
1387 sp_export_detect_size(GtkObject * base) {
1388 static const selection_type test_order[SELECTION_NUMBER_OF] = {SELECTION_SELECTION, SELECTION_DRAWING, SELECTION_PAGE, SELECTION_CUSTOM};
1389 selection_type this_test[SELECTION_NUMBER_OF + 1];
1390 selection_type key = SELECTION_NUMBER_OF;
1392 NR::Point x(sp_export_value_get_px (base, "x0"),
1393 sp_export_value_get_px (base, "y0"));
1394 NR::Point y(sp_export_value_get_px (base, "x1"),
1395 sp_export_value_get_px (base, "y1"));
1396 NR::Rect current_bbox(x, y);
1397 //std::cout << "Current " << current_bbox;
1399 this_test[0] = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
1400 for (int i = 0; i < SELECTION_NUMBER_OF; i++) {
1401 this_test[i + 1] = test_order[i];
1402 }
1404 for (int i = 0;
1405 i < SELECTION_NUMBER_OF + 1 &&
1406 key == SELECTION_NUMBER_OF &&
1407 SP_ACTIVE_DESKTOP != NULL;
1408 i++) {
1409 // std::cout << "Looking at: " << selection_names[this_test[i]] << std::endl;
1410 switch (this_test[i]) {
1411 case SELECTION_SELECTION:
1412 if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) {
1413 NR::Maybe<NR::Rect> bbox = (sp_desktop_selection (SP_ACTIVE_DESKTOP))->bounds();
1415 //std::cout << "Selection " << bbox;
1416 if ( bbox && sp_export_bbox_equal(*bbox,current_bbox)) {
1417 key = SELECTION_SELECTION;
1418 }
1419 }
1420 break;
1421 case SELECTION_DRAWING: {
1422 SPDocument *doc = sp_desktop_document (SP_ACTIVE_DESKTOP);
1424 NR::Maybe<NR::Rect> bbox = sp_item_bbox_desktop (SP_ITEM (SP_DOCUMENT_ROOT (doc)));
1426 // std::cout << "Drawing " << bbox2;
1427 if ( bbox && sp_export_bbox_equal(*bbox,current_bbox) ) {
1428 key = SELECTION_DRAWING;
1429 }
1430 break;
1431 }
1433 case SELECTION_PAGE: {
1434 SPDocument *doc;
1436 doc = sp_desktop_document (SP_ACTIVE_DESKTOP);
1438 NR::Point x(0.0, 0.0);
1439 NR::Point y(sp_document_width(doc),
1440 sp_document_height(doc));
1441 NR::Rect bbox(x, y);
1443 // std::cout << "Page " << bbox;
1444 if (sp_export_bbox_equal(bbox,current_bbox)) {
1445 key = SELECTION_PAGE;
1446 }
1448 break;
1449 }
1450 default:
1451 break;
1452 }
1453 }
1454 // std::cout << std::endl;
1456 if (key == SELECTION_NUMBER_OF) {
1457 key = SELECTION_CUSTOM;
1458 }
1460 /* We're now using a custom size, not a fixed one */
1461 /* printf("Detecting state: %s\n", selection_names[key]); */
1462 selection_type old = (selection_type)(GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(base), "selection-type")));
1463 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gtk_object_get_data(base, selection_names[old])), FALSE);
1464 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(gtk_object_get_data(base, selection_names[key])), TRUE);
1465 gtk_object_set_data(GTK_OBJECT(base), "selection-type", (gpointer)key);
1467 return;
1468 } /* sp_export_detect_size */
1470 /// Called when area x0 value is changed
1471 static void
1472 sp_export_area_x_value_changed (GtkAdjustment *adj, GtkObject *base)
1473 {
1474 float x0, x1, xdpi, width;
1476 if (gtk_object_get_data (base, "update"))
1477 return;
1479 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1480 (base, "units")))
1481 {
1482 return;
1483 }
1485 gtk_object_set_data ( base, "update", GUINT_TO_POINTER (TRUE) );
1487 x0 = sp_export_value_get_px (base, "x0");
1488 x1 = sp_export_value_get_px (base, "x1");
1489 xdpi = sp_export_value_get (base, "xdpi");
1491 width = floor ((x1 - x0) * xdpi / DPI_BASE + 0.5);
1493 if (width < SP_EXPORT_MIN_SIZE) {
1494 const gchar *key;
1495 width = SP_EXPORT_MIN_SIZE;
1496 key = (const gchar *)gtk_object_get_data (GTK_OBJECT (adj), "key");
1498 if (!strcmp (key, "x0")) {
1499 x1 = x0 + width * DPI_BASE / xdpi;
1500 sp_export_value_set_px (base, "x1", x1);
1501 } else {
1502 x0 = x1 - width * DPI_BASE / xdpi;
1503 sp_export_value_set_px (base, "x0", x0);
1504 }
1505 }
1507 sp_export_value_set_px (base, "width", x1 - x0);
1508 sp_export_value_set (base, "bmwidth", width);
1510 sp_export_detect_size(base);
1512 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1514 return;
1515 } // end of sp_export_area_x_value_changed()
1517 /// Called when area y0 value is changed.
1518 static void
1519 sp_export_area_y_value_changed (GtkAdjustment *adj, GtkObject *base)
1520 {
1521 float y0, y1, ydpi, height;
1523 if (gtk_object_get_data (base, "update"))
1524 return;
1526 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1527 (base, "units")))
1528 {
1529 return;
1530 }
1532 gtk_object_set_data (base, "update", GUINT_TO_POINTER (TRUE));
1534 y0 = sp_export_value_get_px (base, "y0");
1535 y1 = sp_export_value_get_px (base, "y1");
1536 ydpi = sp_export_value_get (base, "ydpi");
1538 height = floor ((y1 - y0) * ydpi / DPI_BASE + 0.5);
1540 if (height < SP_EXPORT_MIN_SIZE) {
1541 const gchar *key;
1542 height = SP_EXPORT_MIN_SIZE;
1543 key = (const gchar *)gtk_object_get_data (GTK_OBJECT (adj), "key");
1544 if (!strcmp (key, "y0")) {
1545 y1 = y0 + height * DPI_BASE / ydpi;
1546 sp_export_value_set_px (base, "y1", y1);
1547 } else {
1548 y0 = y1 - height * DPI_BASE / ydpi;
1549 sp_export_value_set_px (base, "y0", y0);
1550 }
1551 }
1553 sp_export_value_set_px (base, "height", y1 - y0);
1554 sp_export_value_set (base, "bmheight", height);
1556 sp_export_detect_size(base);
1558 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1560 return;
1561 } // end of sp_export_area_y_value_changed()
1563 /// Called when x1-x0 or area width is changed
1564 static void
1565 sp_export_area_width_value_changed (GtkAdjustment *adj, GtkObject *base)
1566 {
1567 float x0, x1, xdpi, width, bmwidth;
1569 if (gtk_object_get_data (base, "update"))
1570 return;
1572 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1573 (base, "units"))) {
1574 return;
1575 }
1577 gtk_object_set_data (base, "update", GUINT_TO_POINTER (TRUE));
1579 x0 = sp_export_value_get_px (base, "x0");
1580 x1 = sp_export_value_get_px (base, "x1");
1581 xdpi = sp_export_value_get (base, "xdpi");
1582 width = sp_export_value_get_px (base, "width");
1583 bmwidth = floor (width * xdpi / DPI_BASE + 0.5);
1585 if (bmwidth < SP_EXPORT_MIN_SIZE) {
1587 bmwidth = SP_EXPORT_MIN_SIZE;
1588 width = bmwidth * DPI_BASE / xdpi;
1589 sp_export_value_set_px (base, "width", width);
1590 }
1592 sp_export_value_set_px (base, "x1", x0 + width);
1593 sp_export_value_set (base, "bmwidth", bmwidth);
1595 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1597 return;
1598 } // end of sp_export_area_width_value_changed()
1600 /// Called when y1-y0 or area height is changed.
1601 static void
1602 sp_export_area_height_value_changed (GtkAdjustment *adj, GtkObject *base)
1603 {
1605 float y0, y1, ydpi, height, bmheight;
1607 if (gtk_object_get_data (base, "update"))
1608 return;
1610 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1611 (base, "units"))) {
1612 return;
1613 }
1615 gtk_object_set_data (base, "update", GUINT_TO_POINTER (TRUE));
1617 y0 = sp_export_value_get_px (base, "y0");
1618 y1 = sp_export_value_get_px (base, "y1");
1619 ydpi = sp_export_value_get (base, "ydpi");
1620 height = sp_export_value_get_px (base, "height");
1621 bmheight = floor (height * ydpi / DPI_BASE + 0.5);
1623 if (bmheight < SP_EXPORT_MIN_SIZE) {
1624 bmheight = SP_EXPORT_MIN_SIZE;
1625 height = bmheight * DPI_BASE / ydpi;
1626 sp_export_value_set_px (base, "height", height);
1627 }
1629 sp_export_value_set_px (base, "y1", y0 + height);
1630 sp_export_value_set (base, "bmheight", bmheight);
1632 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1634 return;
1635 } // end of sp_export_area_height_value_changed()
1637 /**
1638 \brief A function to set the ydpi
1639 \param base The export dialog
1641 This function grabs all of the y values and then figures out the
1642 new bitmap size based on the changing dpi value. The dpi value is
1643 gotten from the xdpi setting as these can not currently be independent.
1644 */
1645 static void
1646 sp_export_set_image_y (GtkObject *base)
1647 {
1648 float y0, y1, xdpi;
1650 y0 = sp_export_value_get_px (base, "y0");
1651 y1 = sp_export_value_get_px (base, "y1");
1652 xdpi = sp_export_value_get (base, "xdpi");
1654 sp_export_value_set (base, "ydpi", xdpi);
1655 sp_export_value_set (base, "bmheight", (y1 - y0) * xdpi / DPI_BASE);
1657 return;
1658 } // end of sp_export_set_image_y()
1660 /**
1661 \brief A function to set the xdpi
1662 \param base The export dialog
1664 This function grabs all of the x values and then figures out the
1665 new bitmap size based on the changing dpi value. The dpi value is
1666 gotten from the xdpi setting as these can not currently be independent.
1667 */
1668 static void
1669 sp_export_set_image_x (GtkObject *base)
1670 {
1671 float x0, x1, xdpi;
1673 x0 = sp_export_value_get_px (base, "x0");
1674 x1 = sp_export_value_get_px (base, "x1");
1675 xdpi = sp_export_value_get (base, "xdpi");
1677 sp_export_value_set (base, "ydpi", xdpi);
1678 sp_export_value_set (base, "bmwidth", (x1 - x0) * xdpi / DPI_BASE);
1680 return;
1681 } // end of sp_export_set_image_x()
1683 /// Called when pixel width is changed
1684 static void
1685 sp_export_bitmap_width_value_changed (GtkAdjustment *adj, GtkObject *base)
1686 {
1687 float x0, x1, bmwidth, xdpi;
1689 if (gtk_object_get_data (base, "update"))
1690 return;
1692 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1693 (base, "units"))) {
1694 return;
1695 }
1697 gtk_object_set_data (base, "update", GUINT_TO_POINTER (TRUE));
1699 x0 = sp_export_value_get_px (base, "x0");
1700 x1 = sp_export_value_get_px (base, "x1");
1701 bmwidth = sp_export_value_get (base, "bmwidth");
1703 if (bmwidth < SP_EXPORT_MIN_SIZE) {
1704 bmwidth = SP_EXPORT_MIN_SIZE;
1705 sp_export_value_set (base, "bmwidth", bmwidth);
1706 }
1708 xdpi = bmwidth * DPI_BASE / (x1 - x0);
1709 sp_export_value_set (base, "xdpi", xdpi);
1711 sp_export_set_image_y (base);
1713 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1715 return;
1716 } // end of sp_export_bitmap_width_value_changed()
1718 /// Called when pixel height is changed
1719 static void
1720 sp_export_bitmap_height_value_changed (GtkAdjustment *adj, GtkObject *base)
1721 {
1722 float y0, y1, bmheight, xdpi;
1724 if (gtk_object_get_data (base, "update"))
1725 return;
1727 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1728 (base, "units"))) {
1729 return;
1730 }
1732 gtk_object_set_data (base, "update", GUINT_TO_POINTER (TRUE));
1734 y0 = sp_export_value_get_px (base, "y0");
1735 y1 = sp_export_value_get_px (base, "y1");
1736 bmheight = sp_export_value_get (base, "bmheight");
1738 if (bmheight < SP_EXPORT_MIN_SIZE) {
1739 bmheight = SP_EXPORT_MIN_SIZE;
1740 sp_export_value_set (base, "bmheight", bmheight);
1741 }
1743 xdpi = bmheight * DPI_BASE / (y1 - y0);
1744 sp_export_value_set (base, "xdpi", xdpi);
1746 sp_export_set_image_x (base);
1748 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1750 return;
1751 } // end of sp_export_bitmap_width_value_changed()
1753 /**
1754 \brief A function to adjust the bitmap width when the xdpi value changes
1755 \param adj The adjustment that was changed
1756 \param base The export dialog itself
1758 The first thing this function checks is to see if we are doing an
1759 update. If we are, this function just returns because there is another
1760 instance of it that will handle everything for us. If there is a
1761 units change, we also assume that everyone is being updated appropriately
1762 and there is nothing for us to do.
1764 If we're the highest level function, we set the update flag, and
1765 continue on our way.
1767 All of the values are grabbed using the \c sp_export_value_get functions
1768 (call to the _pt ones for x0 and x1 but just standard for xdpi). The
1769 xdpi value is saved in the preferences for the next time the dialog
1770 is opened. (does the selection dpi need to be set here?)
1772 A check is done to to ensure that we aren't outputing an invalid width,
1773 this is set by SP_EXPORT_MIN_SIZE. If that is the case the dpi is
1774 changed to make it valid.
1776 After all of this the bitmap width is changed.
1778 We also change the ydpi. This is a temporary hack as these can not
1779 currently be independent. This is likely to change in the future.
1780 */
1781 void
1782 sp_export_xdpi_value_changed (GtkAdjustment *adj, GtkObject *base)
1783 {
1784 float x0, x1, xdpi, bmwidth;
1786 if (gtk_object_get_data (base, "update"))
1787 return;
1789 if (sp_unit_selector_update_test ((SPUnitSelector *)gtk_object_get_data
1790 (base, "units"))) {
1791 return;
1792 }
1794 gtk_object_set_data (base, "update", GUINT_TO_POINTER (TRUE));
1796 x0 = sp_export_value_get_px (base, "x0");
1797 x1 = sp_export_value_get_px (base, "x1");
1798 xdpi = sp_export_value_get (base, "xdpi");
1800 // remember xdpi setting
1801 prefs_set_double_attribute ("dialogs.export.defaultxdpi", "value", xdpi);
1803 bmwidth = (x1 - x0) * xdpi / DPI_BASE;
1805 if (bmwidth < SP_EXPORT_MIN_SIZE) {
1806 bmwidth = SP_EXPORT_MIN_SIZE;
1807 if (x1 != x0)
1808 xdpi = bmwidth * DPI_BASE / (x1 - x0);
1809 else
1810 xdpi = DPI_BASE;
1811 sp_export_value_set (base, "xdpi", xdpi);
1812 }
1814 sp_export_value_set (base, "bmwidth", bmwidth);
1816 sp_export_set_image_y (base);
1818 gtk_object_set_data (base, "update", GUINT_TO_POINTER (FALSE));
1820 return;
1821 } // end of sp_export_xdpi_value_changed()
1824 /**
1825 \brief A function to change the area that is used for the exported
1826 bitmap.
1827 \param base This is the export dialog
1828 \param x0 Horizontal upper left hand corner of the picture in points
1829 \param y0 Vertical upper left hand corner of the picture in points
1830 \param x1 Horizontal lower right hand corner of the picture in points
1831 \param y1 Vertical lower right hand corner of the picture in points
1833 This function just calls \c sp_export_value_set_px for each of the
1834 parameters that is passed in. This allows for setting them all in
1835 one convient area.
1837 Update is set to suspend all of the other test running while all the
1838 values are being set up. This allows for a performance increase, but
1839 it also means that the wrong type won't be detected with only some of
1840 the values set. After all the values are set everyone is told that
1841 there has been an update.
1842 */
1843 static void
1844 sp_export_set_area ( GtkObject *base, double x0, double y0, double x1, double y1 )
1845 {
1846 gtk_object_set_data ( base, "update", GUINT_TO_POINTER (TRUE) );
1847 sp_export_value_set_px (base, "x1", x1);
1848 sp_export_value_set_px (base, "y1", y1);
1849 sp_export_value_set_px (base, "x0", x0);
1850 sp_export_value_set_px (base, "y0", y0);
1851 gtk_object_set_data ( base, "update", GUINT_TO_POINTER (FALSE) );
1853 sp_export_area_x_value_changed ((GtkAdjustment *)gtk_object_get_data (base, "x1"), base);
1854 sp_export_area_y_value_changed ((GtkAdjustment *)gtk_object_get_data (base, "y1"), base);
1856 return;
1857 }
1859 /**
1860 \brief Sets the value of an adjustment
1861 \param base The export dialog
1862 \param key Which adjustment to set
1863 \param val What value to set it to
1865 This function finds the adjustment using the data stored in the
1866 export dialog. After finding the adjustment it then sets
1867 the value of it.
1868 */
1869 static void
1870 sp_export_value_set ( GtkObject *base, const gchar *key, double val )
1871 {
1872 GtkAdjustment *adj;
1874 adj = (GtkAdjustment *)gtk_object_get_data (base, key);
1876 gtk_adjustment_set_value (adj, val);
1877 }
1879 /**
1880 \brief A function to set a value using the units points
1881 \param base The export dialog
1882 \param key Which value should be set
1883 \param val What the value should be in points
1885 This function first gets the adjustment for the key that is passed
1886 in. It then figures out what units are currently being used in the
1887 dialog. After doing all of that, it then converts the incoming
1888 value and sets the adjustment.
1889 */
1890 static void
1891 sp_export_value_set_px (GtkObject *base, const gchar *key, double val)
1892 {
1893 const SPUnit *unit = sp_unit_selector_get_unit ((SPUnitSelector *)gtk_object_get_data (base, "units") );
1895 sp_export_value_set (base, key, sp_pixels_get_units (val, *unit));
1897 return;
1898 }
1900 /**
1901 \brief Get the value of an adjustment in the export dialog
1902 \param base The export dialog
1903 \param key Which adjustment is being looked for
1904 \return The value in the specified adjustment
1906 This function gets the adjustment from the data field in the export
1907 dialog. It then grabs the value from the adjustment.
1908 */
1909 static float
1910 sp_export_value_get ( GtkObject *base, const gchar *key )
1911 {
1912 GtkAdjustment *adj;
1914 adj = (GtkAdjustment *)gtk_object_get_data (base, key);
1916 return adj->value;
1917 }
1919 /**
1920 \brief Grabs a value in the export dialog and converts the unit
1921 to points
1922 \param base The export dialog
1923 \param key Which value should be returned
1924 \return The value in the adjustment in points
1926 This function, at its most basic, is a call to \c sp_export_value_get
1927 to get the value of the adjustment. It then finds the units that
1928 are being used by looking at the "units" attribute of the export
1929 dialog. Using that it converts the returned value into points.
1930 */
1931 static float
1932 sp_export_value_get_px ( GtkObject *base, const gchar *key )
1933 {
1934 float value = sp_export_value_get(base, key);
1935 const SPUnit *unit = sp_unit_selector_get_unit ((SPUnitSelector *)gtk_object_get_data (base, "units"));
1937 return sp_units_get_pixels (value, *unit);
1938 } // end of sp_export_value_get_px()
1940 /**
1941 \brief This function is called when the filename is changed by
1942 anyone. It resets the virgin bit.
1943 \param object Text entry box
1944 \param data The export dialog
1945 \return None
1947 This function gets called when the text area is modified. It is
1948 looking for the case where the text area is modified from its
1949 original value. In that case it sets the "filename-modified" bit
1950 to TRUE. If the text dialog returns back to the original text, the
1951 bit gets reset. This should stop simple mistakes.
1952 */
1953 static void
1954 sp_export_filename_modified (GtkObject * object, gpointer data)
1955 {
1956 GtkWidget * text_entry = (GtkWidget *)object;
1957 GtkWidget * export_dialog = (GtkWidget *)data;
1959 if (!strcmp(original_name, gtk_entry_get_text(GTK_ENTRY(text_entry)))) {
1960 gtk_object_set_data (GTK_OBJECT (export_dialog), "filename-modified", (gpointer)FALSE);
1961 // printf("Modified: FALSE\n");
1962 } else {
1963 gtk_object_set_data (GTK_OBJECT (export_dialog), "filename-modified", (gpointer)TRUE);
1964 // printf("Modified: TRUE\n");
1965 }
1967 return;
1968 } // end sp_export_filename_modified
1970 /*
1971 Local Variables:
1972 mode:c++
1973 c-file-style:"stroustrup"
1974 c-file-offsets:((innamespace . 0)(inline-open . 0))
1975 indent-tabs-mode:nil
1976 fill-column:99
1977 End:
1978 */
1979 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :