Code

Mnemonics in "Export bitmap", and "Rows and Columns" dialogs (Bug 170765)
[inkscape.git] / src / ui / dialog / tile.cpp
1 /*
2  * A simple dialog for creating grid type arrangements of selected objects
3  *
4  * Authors:
5  *   Bob Jamison ( based off trace dialog)
6  *   John Cliff
7  *   Other dudes from The Inkscape Organization
8  *   Abhishek Sharma
9  *
10  * Copyright (C) 2004 Bob Jamison
11  * Copyright (C) 2004 John Cliff
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  */
15 //#define DEBUG_GRID_ARRANGE 1
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
21 #include <gtk/gtkdialog.h> //for GTK_RESPONSE* types
22 #include <gtk/gtksizegroup.h>
23 #include <glibmm/i18n.h>
24 #include <gtkmm/stock.h>
26 #include "verbs.h"
27 #include "preferences.h"
28 #include "inkscape.h"
29 #include "desktop-handles.h"
30 #include "selection.h"
31 #include "document.h"
32 #include "sp-item.h"
33 #include "widgets/icon.h"
34 #include "tile.h"
35 #include "desktop.h"
37 /*
38  *    Sort items by their x co-ordinates, taking account of y (keeps rows intact)
39  *
40  *    <0 *elem1 goes before *elem2
41  *    0  *elem1 == *elem2
42  *    >0  *elem1 goes after *elem2
43  */
44 int
45 sp_compare_x_position(SPItem *first, SPItem *second)
46 {
47     using Geom::X;
48     using Geom::Y;
50     Geom::OptRect a = first->getBounds(first->i2doc_affine());
51     Geom::OptRect b = second->getBounds(second->i2doc_affine());
53     if ( !a || !b ) {
54         // FIXME?
55         return 0;
56     }
58     double const a_height = a->dimensions()[Y];
59     double const b_height = b->dimensions()[Y];
61     bool a_in_b_vert = false;
62     if ((a->min()[Y] < b->min()[Y] + 0.1) && (a->min()[Y] > b->min()[Y] - b_height)) {
63         a_in_b_vert = true;
64     } else if ((b->min()[Y] < a->min()[Y] + 0.1) && (b->min()[Y] > a->min()[Y] - a_height)) {
65         a_in_b_vert = true;
66     } else if (b->min()[Y] == a->min()[Y]) {
67         a_in_b_vert = true;
68     } else {
69         a_in_b_vert = false;
70     }
72     if (!a_in_b_vert) {
73         return -1;
74     }
75     if (a_in_b_vert && a->min()[X] > b->min()[X]) {
76         return 1;
77     }
78     if (a_in_b_vert && a->min()[X] < b->min()[X]) {
79         return -1;
80     }
81     return 0;
82 }
84 /*
85  *    Sort items by their y co-ordinates.
86  */
87 int
88 sp_compare_y_position(SPItem *first, SPItem *second)
89 {
90     Geom::OptRect a = first->getBounds(first->i2doc_affine());
91     Geom::OptRect b = second->getBounds(second->i2doc_affine());
93     if ( !a || !b ) {
94         // FIXME?
95         return 0;
96     }
98     if (a->min()[Geom::Y] > b->min()[Geom::Y]) {
99         return 1;
100     }
101     if (a->min()[Geom::Y] < b->min()[Geom::Y]) {
102         return -1;
103     }
105     return 0;
108 namespace Inkscape {
109 namespace UI {
110 namespace Dialog {
113 //#########################################################################
114 //## E V E N T S
115 //#########################################################################
117 /*
118  *
119  * This arranges the selection in a grid pattern.
120  *
121  */
123 void TileDialog::Grid_Arrange ()
126     int cnt,row_cnt,col_cnt,a,row,col;
127     double grid_left,grid_top,col_width,row_height,paddingx,paddingy,width, height, new_x, new_y,cx,cy;
128     double total_col_width,total_row_height;
129     col_width = 0;
130     row_height = 0;
131     total_col_width=0;
132     total_row_height=0;
134     // check for correct numbers in the row- and col-spinners
135     on_col_spinbutton_changed();
136     on_row_spinbutton_changed();
138     // set padding to manual values
139     paddingx = XPadSpinner.get_value();
140     paddingy = YPadSpinner.get_value();
142     std::vector<double> row_heights;
143     std::vector<double> col_widths;
144     std::vector<double> row_ys;
145     std::vector<double> col_xs;
147     int NoOfCols = NoOfColsSpinner.get_value_as_int();
148     int NoOfRows = NoOfRowsSpinner.get_value_as_int();
150     width = 0;
151     for (a=0;a<NoOfCols; a++){
152         col_widths.push_back(width);
153     }
155     height = 0;
156     for (a=0;a<NoOfRows; a++){
157         row_heights.push_back(height);
158     }
159     grid_left = 99999;
160     grid_top = 99999;
162     SPDesktop *desktop = getDesktop();
163     sp_desktop_document(desktop)->ensureUpToDate();
165     Inkscape::Selection *selection = sp_desktop_selection (desktop);
166     const GSList *items = selection ? selection->itemList() : 0;
167     cnt=0;
168     for (; items != NULL; items = items->next) {
169         SPItem *item = SP_ITEM(items->data);
170         Geom::OptRect b = item->getBounds(item->i2doc_affine());
171         if (!b) {
172             continue;
173         }
175         width = b->dimensions()[Geom::X];
176         height = b->dimensions()[Geom::Y];
178         cx = b->midpoint()[Geom::X];
179         cy = b->midpoint()[Geom::Y];
181         if (b->min()[Geom::X] < grid_left) {
182             grid_left = b->min()[Geom::X];
183         }
184         if (b->min()[Geom::Y] < grid_top) {
185             grid_top = b->min()[Geom::Y];
186         }
187         if (width > col_width) {
188             col_width = width;
189         }
190         if (height > row_height) {
191             row_height = height;
192         }
193     }
196     // require the sorting done before we can calculate row heights etc.
198     g_return_if_fail(selection);
199     const GSList *items2 = selection->itemList();
200     GSList *rev = g_slist_copy((GSList *) items2);
201     GSList *sorted = NULL;
202     rev = g_slist_sort(rev, (GCompareFunc) sp_compare_y_position);
203     sorted = g_slist_sort(rev, (GCompareFunc) sp_compare_x_position);
206     // Calculate individual Row and Column sizes if necessary
209         cnt=0;
210         const GSList *sizes = sorted;
211         for (; sizes != NULL; sizes = sizes->next) {
212             SPItem *item = SP_ITEM(sizes->data);
213             Geom::OptRect b = item->getBounds(item->i2doc_affine());
214             if (b) {
215                 width = b->dimensions()[Geom::X];
216                 height = b->dimensions()[Geom::Y];
217                 if (width > col_widths[(cnt % NoOfCols)]) {
218                     col_widths[(cnt % NoOfCols)] = width;
219                 }
220                 if (height > row_heights[(cnt / NoOfCols)]) {
221                     row_heights[(cnt / NoOfCols)] = height;
222                 }
223             }
225             cnt++;
226         }
229     /// Make sure the top and left of the grid dont move by compensating for align values.
230     if (RowHeightButton.get_active()){
231         grid_top = grid_top - (((row_height - row_heights[0]) / 2)*(VertAlign));
232     }
233     if (ColumnWidthButton.get_active()){
234         grid_left = grid_left - (((col_width - col_widths[0]) /2)*(HorizAlign));
235     }
237     #ifdef DEBUG_GRID_ARRANGE
238      g_print("\n cx = %f cy= %f gridleft=%f",cx,cy,grid_left);
239     #endif
241     // Calculate total widths and heights, allowing for columns and rows non uniformly sized.
243     if (ColumnWidthButton.get_active()){
244         total_col_width = col_width * NoOfCols;
245         col_widths.clear();
246         for (a=0;a<NoOfCols; a++){
247             col_widths.push_back(col_width);
248         }
249     } else {
250         for (a = 0; a < (int)col_widths.size(); a++)
251         {
252           total_col_width += col_widths[a] ;
253         }
254     }
256     if (RowHeightButton.get_active()){
257         total_row_height = row_height * NoOfRows;
258         row_heights.clear();
259         for (a=0;a<NoOfRows; a++){
260             row_heights.push_back(row_height);
261         }
262     } else {
263         for (a = 0; a < (int)row_heights.size(); a++)
264         {
265           total_row_height += row_heights[a] ;
266         }
267     }
270     Geom::OptRect sel_bbox = selection->bounds();
271     // Fit to bbox, calculate padding between rows accordingly.
272     if ( sel_bbox && !SpaceManualRadioButton.get_active() ){
273 #ifdef DEBUG_GRID_ARRANGE
274 g_print("\n row = %f     col = %f selection x= %f selection y = %f", total_row_height,total_col_width, b.extent(Geom::X), b.extent(Geom::Y));
275 #endif
276         paddingx = (sel_bbox->width() - total_col_width) / (NoOfCols -1);
277         paddingy = (sel_bbox->height() - total_row_height) / (NoOfRows -1);
278     }
280 /*
281     Horizontal align  - Left    = 0
282                         Centre  = 1
283                         Right   = 2
285     Vertical align    - Top     = 0
286                         Middle  = 1
287                         Bottom  = 2
289     X position is calculated by taking the grids left co-ord, adding the distance to the column,
290    then adding 1/2 the spacing multiplied by the align variable above,
291    Y position likewise, takes the top of the grid, adds the y to the current row then adds the padding in to align it.
293 */
295     // Calculate row and column x and y coords required to allow for columns and rows which are non uniformly sized.
297     for (a=0;a<NoOfCols; a++){
298         if (a<1) col_xs.push_back(0);
299         else col_xs.push_back(col_widths[a-1]+paddingx+col_xs[a-1]);
300     }
303     for (a=0;a<NoOfRows; a++){
304         if (a<1) row_ys.push_back(0);
305         else row_ys.push_back(row_heights[a-1]+paddingy+row_ys[a-1]);
306     }
308     cnt=0;
309   for (row_cnt=0; ((sorted != NULL) && (row_cnt<NoOfRows)); row_cnt++) {
311              GSList *current_row = NULL;
312              for (col_cnt = 0; ((sorted != NULL) && (col_cnt<NoOfCols)); col_cnt++) {
313                  current_row = g_slist_append (current_row, sorted->data);
314                  sorted = sorted->next;
315              }
317              for (; current_row != NULL; current_row = current_row->next) {
318                  SPItem *item=SP_ITEM(current_row->data);
319                  Inkscape::XML::Node *repr = SP_OBJECT_REPR(item);
320                  Geom::OptRect b = item->getBounds(item->i2doc_affine());
321                  Geom::Point min;
322                  if (b) {
323                      width = b->dimensions()[Geom::X];
324                      height = b->dimensions()[Geom::Y];
325                      min = b->min();
326                  } else {
327                      width = height = 0;
328                      min = Geom::Point(0, 0);
329                  }
331                  row = cnt / NoOfCols;
332                  col = cnt % NoOfCols;
334                  new_x = grid_left + (((col_widths[col] - width)/2)*HorizAlign) + col_xs[col];
335                  new_y = grid_top + (((row_heights[row] - height)/2)*VertAlign) + row_ys[row];
337                  // signs are inverted between x and y due to y inversion
338                  Geom::Point move = Geom::Point(new_x - min[Geom::X], min[Geom::Y] - new_y);
339                  Geom::Matrix const affine = Geom::Matrix(Geom::Translate(move));
340                  item->set_i2d_affine(item->i2d_affine() * affine);
341                  item->doWriteTransform(repr, item->transform,  NULL);
342                  SP_OBJECT (current_row->data)->updateRepr();
343                  cnt +=1;
344              }
345              g_slist_free (current_row);
346     }
348     DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_SELECTION_GRIDTILE,
349                        _("Arrange in a grid"));
354 //#########################################################################
355 //## E V E N T S
356 //#########################################################################
359 void TileDialog::_apply()
361     Grid_Arrange();
365 /**
366  * changed value in # of columns spinbox.
367  */
368 void TileDialog::on_row_spinbutton_changed()
370     // quit if run by the attr_changed listener
371     if (updating) {
372             return;
373         }
375     // in turn, prevent listener from responding
376     updating = true;
377     SPDesktop *desktop = getDesktop();
379     Inkscape::Selection *selection = desktop ? desktop->selection : 0;
380     g_return_if_fail( selection );
382     GSList const *items = selection->itemList();
383     int selcount = g_slist_length((GSList *)items);
385     double PerCol = ceil(selcount / NoOfColsSpinner.get_value());
386     NoOfRowsSpinner.set_value(PerCol);
387     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
388     prefs->setDouble("/dialogs/gridtiler/NoOfCols", NoOfColsSpinner.get_value());
389     updating=false;
392 /**
393  * changed value in # of rows spinbox.
394  */
395 void TileDialog::on_col_spinbutton_changed()
397     // quit if run by the attr_changed listener
398     if (updating) {
399             return;
400         }
402     // in turn, prevent listener from responding
403     updating = true;
404     SPDesktop *desktop = getDesktop();
405     Inkscape::Selection *selection = desktop ? desktop->selection : 0;
406     g_return_if_fail(selection);
408     GSList const *items = selection->itemList();
409     int selcount = g_slist_length((GSList *)items);
411     double PerRow = ceil(selcount / NoOfRowsSpinner.get_value());
412     NoOfColsSpinner.set_value(PerRow);
413     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
414     prefs->setDouble("/dialogs/gridtiler/NoOfCols", PerRow);
416     updating=false;
419 /**
420  * changed value in x padding spinbox.
421  */
422 void TileDialog::on_xpad_spinbutton_changed()
424     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
425     prefs->setDouble("/dialogs/gridtiler/XPad", XPadSpinner.get_value());
429 /**
430  * changed value in y padding spinbox.
431  */
432 void TileDialog::on_ypad_spinbutton_changed()
434     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
435     prefs->setDouble("/dialogs/gridtiler/YPad", YPadSpinner.get_value());
439 /**
440  * checked/unchecked autosize Rows button.
441  */
442 void TileDialog::on_RowSize_checkbutton_changed()
444     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
445     if (RowHeightButton.get_active()) {
446         prefs->setDouble("/dialogs/gridtiler/AutoRowSize", 20);
447     } else {
448         prefs->setDouble("/dialogs/gridtiler/AutoRowSize", -20);
449     }
450     RowHeightBox.set_sensitive ( !RowHeightButton.get_active());
453 /**
454  * checked/unchecked autosize Rows button.
455  */
456 void TileDialog::on_ColSize_checkbutton_changed()
458     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
459     if (ColumnWidthButton.get_active()) {
460         prefs->setDouble("/dialogs/gridtiler/AutoColSize", 20);
461     } else {
462         prefs->setDouble("/dialogs/gridtiler/AutoColSize", -20);
463     }
464     ColumnWidthBox.set_sensitive ( !ColumnWidthButton.get_active());
467 /**
468  * changed value in columns spinbox.
469  */
470 void TileDialog::on_rowSize_spinbutton_changed()
472     // quit if run by the attr_changed listener
473     if (updating) {
474             return;
475         }
477     // in turn, prevent listener from responding
478     updating = true;
479     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
480     prefs->setDouble("/dialogs/gridtiler/RowHeight", RowHeightSpinner.get_value());
481     updating=false;
485 /**
486  * changed value in rows spinbox.
487  */
488 void TileDialog::on_colSize_spinbutton_changed()
490     // quit if run by the attr_changed listener
491     if (updating) {
492             return;
493         }
495     // in turn, prevent listener from responding
496     updating = true;
497     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
498     prefs->setDouble("/dialogs/gridtiler/ColWidth", ColumnWidthSpinner.get_value());
499     updating=false;
503 /**
504  * changed Radio button in Spacing group.
505  */
506 void TileDialog::Spacing_button_changed()
508     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
509     if (SpaceManualRadioButton.get_active()) {
510         prefs->setDouble("/dialogs/gridtiler/SpacingType", 20);
511     } else {
512         prefs->setDouble("/dialogs/gridtiler/SpacingType", -20);
513     }
515     SizesHBox.set_sensitive ( SpaceManualRadioButton.get_active());
518 /**
519  * changed Radio button in Vertical Align group.
520  */
521 void TileDialog::VertAlign_changed()
523     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
524     if (VertTopRadioButton.get_active()) {
525         VertAlign = 0;
526         prefs->setInt("/dialogs/gridtiler/VertAlign", 0);
527     } else if (VertCentreRadioButton.get_active()){
528         VertAlign = 1;
529         prefs->setInt("/dialogs/gridtiler/VertAlign", 1);
530     } else if (VertBotRadioButton.get_active()){
531         VertAlign = 2;
532         prefs->setInt("/dialogs/gridtiler/VertAlign", 2);
533     }
536 /**
537  * changed Radio button in Vertical Align group.
538  */
539 void TileDialog::HorizAlign_changed()
541     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
542     if (HorizLeftRadioButton.get_active()) {
543         HorizAlign = 0;
544         prefs->setInt("/dialogs/gridtiler/HorizAlign", 0);
545     } else if (HorizCentreRadioButton.get_active()){
546         HorizAlign = 1;
547         prefs->setInt("/dialogs/gridtiler/HorizAlign", 1);
548     } else if (HorizRightRadioButton.get_active()){
549         HorizAlign = 2;
550         prefs->setInt("/dialogs/gridtiler/HorizAlign", 2);
551     }
554 /**
555  * Desktop selection changed
556  */
557 void TileDialog::updateSelection()
559     // quit if run by the attr_changed listener
560     if (updating) {
561         return;
562     }
564     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
565     // in turn, prevent listener from responding
566     updating = true;
567     SPDesktop *desktop = getDesktop();
568     Inkscape::Selection *selection = desktop ? desktop->selection : 0;
569     GSList const *items = selection ? selection->itemList() : 0;
571     if (items) {
572         int selcount = g_slist_length((GSList *)items);
574         if (NoOfColsSpinner.get_value() > 1 && NoOfRowsSpinner.get_value() > 1){
575             // Update the number of rows assuming number of columns wanted remains same.
576             double NoOfRows = ceil(selcount / NoOfColsSpinner.get_value());
577             NoOfRowsSpinner.set_value(NoOfRows);
579             // if the selection has less than the number set for one row, reduce it appropriately
580             if (selcount < NoOfColsSpinner.get_value()) {
581                 double NoOfCols = ceil(selcount / NoOfRowsSpinner.get_value());
582                 NoOfColsSpinner.set_value(NoOfCols);
583                 prefs->setInt("/dialogs/gridtiler/NoOfCols", NoOfCols);
584             }
585         } else {
586             double PerRow = ceil(sqrt(selcount));
587             double PerCol = ceil(sqrt(selcount));
588             NoOfRowsSpinner.set_value(PerRow);
589             NoOfColsSpinner.set_value(PerCol);
590             prefs->setInt("/dialogs/gridtiler/NoOfCols", static_cast<int>(PerCol));
591         }
592     }
594     updating = false;
599 /*##########################
600 ## Experimental
601 ##########################*/
603 static void updateSelectionCallback(Inkscape::Application */*inkscape*/, Inkscape::Selection */*selection*/, TileDialog *dlg)
605     TileDialog *tledlg = (TileDialog *) dlg;
606     tledlg->updateSelection();
610 //#########################################################################
611 //## C O N S T R U C T O R    /    D E S T R U C T O R
612 //#########################################################################
613 /**
614  * Constructor
615  */
616 TileDialog::TileDialog()
617     : UI::Widget::Panel("", "/dialogs/gridtiler", SP_VERB_SELECTION_GRIDTILE)
619      // bool used by spin button callbacks to stop loops where they change each other.
620     updating = false;
621     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
623     // could not do this in gtkmm - there's no Gtk::SizeGroup public constructor (!)
624     GtkSizeGroup *_col1 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
625     GtkSizeGroup *_col2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
626     GtkSizeGroup *_col3 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
628     {
629         // Selection Change signal
630         g_signal_connect ( G_OBJECT (INKSCAPE), "change_selection", G_CALLBACK (updateSelectionCallback), this);
631     }
633     Gtk::Box *contents = _getContents();
635 #define MARGIN 2
637     //##Set up the panel
639     SPDesktop *desktop = getDesktop();
641     Inkscape::Selection *selection = desktop ? desktop->selection : 0;
642     g_return_if_fail( selection );
643     int selcount = 1;
644     if (!selection->isEmpty()) {
645         GSList const *items = selection->itemList();
646         selcount = g_slist_length((GSList *)items);
647     }
650     /*#### Number of Rows ####*/
652     double PerRow = ceil(sqrt(selcount));
653     double PerCol = ceil(sqrt(selcount));
655     #ifdef DEBUG_GRID_ARRANGE
656         g_print("/n PerRox = %f PerCol = %f selcount = %d",PerRow,PerCol,selcount);
657     #endif
659     NoOfRowsLabel.set_text_with_mnemonic(_("_Rows:"));
660     NoOfRowsLabel.set_mnemonic_widget(NoOfRowsSpinner);
661     NoOfRowsBox.pack_start(NoOfRowsLabel, false, false, MARGIN);
663     NoOfRowsSpinner.set_digits(0);
664     NoOfRowsSpinner.set_increments(1, 0);
665     NoOfRowsSpinner.set_range(1.0, 100.0);
666     NoOfRowsSpinner.set_value(PerCol);
667     NoOfRowsSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_col_spinbutton_changed));
668     tips.set_tip(NoOfRowsSpinner, _("Number of rows"));
669     NoOfRowsBox.pack_start(NoOfRowsSpinner, false, false, MARGIN);
670     gtk_size_group_add_widget(_col1, (GtkWidget *) NoOfRowsBox.gobj());
672     RowHeightButton.set_label(_("Equal _height"));
673     RowHeightButton.set_use_underline(true);
674     double AutoRow = prefs->getDouble("/dialogs/gridtiler/AutoRowSize", 15);
675     if (AutoRow>0)
676          AutoRowSize=true;
677     else
678          AutoRowSize=false;
679     RowHeightButton.set_active(AutoRowSize);
681     NoOfRowsBox.pack_start(RowHeightButton, false, false, MARGIN);
683     tips.set_tip(RowHeightButton, _("If not set, each row has the height of the tallest object in it"));
684     RowHeightButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::on_RowSize_checkbutton_changed));
686  {
687         /*#### Radio buttons to control vertical alignment ####*/
689         VertAlignLabel.set_label(_("Align:"));
690         VertAlignHBox.pack_start(VertAlignLabel, false, false, MARGIN);
692         VertTopRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed));
693         VertAlignGroup = VertTopRadioButton.get_group();
694         VertAlignVBox.pack_start(VertTopRadioButton, false, false, 0);
696         VertCentreRadioButton.set_group(VertAlignGroup);
697         VertCentreRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed));
698         VertAlignVBox.pack_start(VertCentreRadioButton, false, false, 0);
700         VertBotRadioButton.set_group(VertAlignGroup);
701         VertBotRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed));
702         VertAlignVBox.pack_start(VertBotRadioButton, false, false, 0);
704         VertAlign = prefs->getInt("/dialogs/gridtiler/VertAlign", 1);
705         if (VertAlign == 0) {
706             VertTopRadioButton.set_active(TRUE);
707         }
708         else if (VertAlign == 1) {
709             VertCentreRadioButton.set_active(TRUE);
710         }
711         else if (VertAlign == 2){
712             VertBotRadioButton.set_active(TRUE);
713         }
714         VertAlignHBox.pack_start(VertAlignVBox, false, false, MARGIN);
715         NoOfRowsBox.pack_start(VertAlignHBox, false, false, MARGIN);
716     }
718     SpinsHBox.pack_start(NoOfRowsBox, false, false, MARGIN);
721     /*#### Label for X ####*/
722     padXByYLabel.set_label(" ");
723     XByYLabelVBox.pack_start(padXByYLabel, false, false, MARGIN);
724     XByYLabel.set_markup(" &#215; ");
725     XByYLabelVBox.pack_start(XByYLabel, false, false, MARGIN);
726     SpinsHBox.pack_start(XByYLabelVBox, false, false, MARGIN);
727     gtk_size_group_add_widget(_col2, (GtkWidget *) XByYLabelVBox.gobj());
729     /*#### Number of columns ####*/
731     NoOfColsLabel.set_text_with_mnemonic(_("_Columns:"));
732     NoOfColsLabel.set_mnemonic_widget(NoOfColsSpinner);
733     NoOfColsBox.pack_start(NoOfColsLabel, false, false, MARGIN);
735     NoOfColsSpinner.set_digits(0);
736     NoOfColsSpinner.set_increments(1, 0);
737     NoOfColsSpinner.set_range(1.0, 100.0);
738     NoOfColsSpinner.set_value(PerRow);
739     NoOfColsSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_row_spinbutton_changed));
740     tips.set_tip(NoOfColsSpinner, _("Number of columns"));
741     NoOfColsBox.pack_start(NoOfColsSpinner, false, false, MARGIN);
742     gtk_size_group_add_widget(_col3, (GtkWidget *) NoOfColsBox.gobj());
744     ColumnWidthButton.set_label(_("Equal _width"));
745     ColumnWidthButton.set_use_underline(true);
746     double AutoCol = prefs->getDouble("/dialogs/gridtiler/AutoColSize", 15);
747     if (AutoCol>0)
748          AutoColSize=true;
749     else
750          AutoColSize=false;
751     ColumnWidthButton.set_active(AutoColSize);
752     NoOfColsBox.pack_start(ColumnWidthButton, false, false, MARGIN);
754     tips.set_tip(ColumnWidthButton, _("If not set, each column has the width of the widest object in it"));
755     ColumnWidthButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::on_ColSize_checkbutton_changed));
758     {
759         /*#### Radio buttons to control horizontal alignment ####*/
761         HorizAlignLabel.set_label(_("Align:"));
762         HorizAlignVBox.pack_start(HorizAlignLabel, false, false, MARGIN);
764         HorizAlignHBox.pack_start(*(new Gtk::HBox()), true, true, 0); // centering strut
766         HorizLeftRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed));
767         HorizAlignGroup = HorizLeftRadioButton.get_group();
768         HorizAlignHBox.pack_start(HorizLeftRadioButton, false, false, 0);
770         HorizCentreRadioButton.set_group(HorizAlignGroup);
771         HorizCentreRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed));
772         HorizAlignHBox.pack_start(HorizCentreRadioButton, false, false, 0);
774         HorizRightRadioButton.set_group(HorizAlignGroup);
775         HorizRightRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed));
776         HorizAlignHBox.pack_start(HorizRightRadioButton, false, false, 0);
778         HorizAlignHBox.pack_start(*(new Gtk::HBox()), true, true, 0); // centering strut
780         HorizAlign = prefs->getInt("/dialogs/gridtiler/HorizAlign", 1);
781         if (HorizAlign == 0) {
782             HorizLeftRadioButton.set_active(TRUE);
783         }
784         else if (HorizAlign == 1) {
785             HorizCentreRadioButton.set_active(TRUE);
786         }
787         else if (HorizAlign == 2) {
788             HorizRightRadioButton.set_active(TRUE);
789         }
790         HorizAlignVBox.pack_start(HorizAlignHBox, false, false, MARGIN);
791         NoOfColsBox.pack_start(HorizAlignVBox, false, false, MARGIN);
792     }
794     SpinsHBox.pack_start(NoOfColsBox, false, false, MARGIN);
796     TileBox.pack_start(SpinsHBox, false, false, MARGIN);
798     {
799         /*#### Radio buttons to control spacing manually or to fit selection bbox ####*/
800         SpaceByBBoxRadioButton.set_label(_("_Fit into selection box"));
801         SpaceByBBoxRadioButton.set_use_underline (true);
802         SpaceByBBoxRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed));
803         SpacingGroup = SpaceByBBoxRadioButton.get_group();
805         SpacingVBox.pack_start(SpaceByBBoxRadioButton, false, false, MARGIN);
807         SpaceManualRadioButton.set_label(_("_Set spacing:"));
808         SpaceManualRadioButton.set_use_underline (true);
809         SpaceManualRadioButton.set_group(SpacingGroup);
810         SpaceManualRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed));
811         SpacingVBox.pack_start(SpaceManualRadioButton, false, false, MARGIN);
813         TileBox.pack_start(SpacingVBox, false, false, MARGIN);
814     }
816     {
817         /*#### Y Padding ####*/
819         GtkWidget *i = sp_icon_new (Inkscape::ICON_SIZE_MENU, "object-rows");
820         YPadBox.pack_start (*(Glib::wrap(i)), false, false, MARGIN);
822         YPadSpinner.set_digits(1);
823         YPadSpinner.set_increments(0.2, 0);
824         YPadSpinner.set_range(-10000, 10000);
825         double YPad = prefs->getDouble("/dialogs/gridtiler/YPad", 15);
826         YPadSpinner.set_value(YPad);
827         YPadBox.pack_start(YPadSpinner, true, true, MARGIN);
828         tips.set_tip(YPadSpinner, _("Vertical spacing between rows (px units)"));
829         YPadSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_ypad_spinbutton_changed));
830         gtk_size_group_add_widget(_col1, (GtkWidget *) YPadBox.gobj());
832         SizesHBox.pack_start(YPadBox, false, false, MARGIN);
833     }
835     {
836     Gtk::HBox *spacer = new Gtk::HBox;
837     SizesHBox.pack_start(*spacer, false, false, 0);
838     gtk_size_group_add_widget(_col2, (GtkWidget *) spacer->gobj());
839     }
841     {
842         /*#### X padding ####*/
844         GtkWidget *i = sp_icon_new (Inkscape::ICON_SIZE_MENU, "object-columns");
845         XPadBox.pack_start (*(Glib::wrap(i)), false, false, MARGIN);
847         XPadSpinner.set_digits(1);
848         XPadSpinner.set_increments(0.2, 0);
849         XPadSpinner.set_range(-10000, 10000);
850         double XPad = prefs->getDouble("/dialogs/gridtiler/XPad", 15);
851         XPadSpinner.set_value(XPad);
852         XPadBox.pack_start(XPadSpinner, true, true, MARGIN);
853         tips.set_tip(XPadSpinner, _("Horizontal spacing between columns (px units)"));
854         XPadSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_xpad_spinbutton_changed));
855         gtk_size_group_add_widget(_col3, (GtkWidget *) XPadBox.gobj());
857         SizesHBox.pack_start(XPadBox, false, false, MARGIN);
858     }
861     TileBox.pack_start(SizesHBox, false, false, MARGIN);
863     contents->pack_start(TileBox);
865     double SpacingType = prefs->getDouble("/dialogs/gridtiler/SpacingType", 15);
866     if (SpacingType>0) {
867         ManualSpacing=true;
868     } else {
869         ManualSpacing=false;
870     }
871     SpaceManualRadioButton.set_active(ManualSpacing);
872     SpaceByBBoxRadioButton.set_active(!ManualSpacing);
873     SizesHBox.set_sensitive (ManualSpacing);
875     //## The OK button
876     TileOkButton = addResponseButton(C_("Rows and columns dialog","_Arrange"), GTK_RESPONSE_APPLY);
877     TileOkButton->set_use_underline(true);
878     tips.set_tip((*TileOkButton), _("Arrange selected objects"));
880     show_all_children();
883 } //namespace Dialog
884 } //namespace UI
885 } //namespace Inkscape
887 /*
888   Local Variables:
889   mode:c++
890   c-file-style:"stroustrup"
891   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
892   indent-tabs-mode:nil
893   fill-column:99
894   End:
895 */
896 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :