Code

Warning and whitespace cleanup.
[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  *
9  * Copyright (C) 2004 Bob Jamison
10  * Copyright (C) 2004 John Cliff
11  *
12  * Released under GNU GPL, read the file 'COPYING' for more information
13  */
14 //#define DEBUG_GRID_ARRANGE 1
16 #ifdef HAVE_CONFIG_H
17 # include <config.h>
18 #endif
20 #include <gtk/gtkdialog.h> //for GTK_RESPONSE* types
21 #include <gtk/gtksizegroup.h>
22 #include <glibmm/i18n.h>
23 #include <gtkmm/stock.h>
25 #include "verbs.h"
26 #include "preferences.h"
27 #include "inkscape.h"
28 #include "desktop-handles.h"
29 #include "selection.h"
30 #include "document.h"
31 #include "sp-item.h"
32 #include "widgets/icon.h"
33 #include "tile.h"
35 /*
36  *    Sort items by their x co-ordinates, taking account of y (keeps rows intact)
37  *
38  *    <0 *elem1 goes before *elem2
39  *    0  *elem1 == *elem2
40  *    >0  *elem1 goes after *elem2
41  */
42 int
43 sp_compare_x_position(SPItem *first, SPItem *second)
44 {
45     using Geom::X;
46     using Geom::Y;
48     Geom::OptRect a = first->getBounds(sp_item_i2doc_affine(first));
49     Geom::OptRect b = second->getBounds(sp_item_i2doc_affine(second));
51     if ( !a || !b ) {
52         // FIXME?
53         return 0;
54     }
56     double const a_height = a->dimensions()[Y];
57     double const b_height = b->dimensions()[Y];
59     bool a_in_b_vert = false;
60     if ((a->min()[Y] < b->min()[Y] + 0.1) && (a->min()[Y] > b->min()[Y] - b_height)) {
61         a_in_b_vert = true;
62     } else if ((b->min()[Y] < a->min()[Y] + 0.1) && (b->min()[Y] > a->min()[Y] - a_height)) {
63         a_in_b_vert = true;
64     } else if (b->min()[Y] == a->min()[Y]) {
65         a_in_b_vert = true;
66     } else {
67         a_in_b_vert = false;
68     }
70     if (!a_in_b_vert) {
71         return -1;
72     }
73     if (a_in_b_vert && a->min()[X] > b->min()[X]) {
74         return 1;
75     }
76     if (a_in_b_vert && a->min()[X] < b->min()[X]) {
77         return -1;
78     }
79     return 0;
80 }
82 /*
83  *    Sort items by their y co-ordinates.
84  */
85 int
86 sp_compare_y_position(SPItem *first, SPItem *second)
87 {
88     Geom::OptRect a = first->getBounds(sp_item_i2doc_affine(first));
89     Geom::OptRect b = second->getBounds(sp_item_i2doc_affine(second));
91     if ( !a || !b ) {
92         // FIXME?
93         return 0;
94     }
96     if (a->min()[Geom::Y] > b->min()[Geom::Y]) {
97         return 1;
98     }
99     if (a->min()[Geom::Y] < b->min()[Geom::Y]) {
100         return -1;
101     }
103     return 0;
106 namespace Inkscape {
107 namespace UI {
108 namespace Dialog {
111 //#########################################################################
112 //## E V E N T S
113 //#########################################################################
115 /*
116  *
117  * This arranges the selection in a grid pattern.
118  *
119  */
121 void TileDialog::Grid_Arrange ()
124     int cnt,row_cnt,col_cnt,a,row,col;
125     double grid_left,grid_top,col_width,row_height,paddingx,paddingy,width, height, new_x, new_y,cx,cy;
126     double total_col_width,total_row_height;
127     col_width = 0;
128     row_height = 0;
129     total_col_width=0;
130     total_row_height=0;
132     // check for correct numbers in the row- and col-spinners
133     on_col_spinbutton_changed();
134     on_row_spinbutton_changed();
136     // set padding to manual values
137     paddingx = XPadSpinner.get_value();
138     paddingy = YPadSpinner.get_value();
140     std::vector<double> row_heights;
141     std::vector<double> col_widths;
142     std::vector<double> row_ys;
143     std::vector<double> col_xs;
145     int NoOfCols = NoOfColsSpinner.get_value_as_int();
146     int NoOfRows = NoOfRowsSpinner.get_value_as_int();
148     width = 0;
149     for (a=0;a<NoOfCols; a++){
150         col_widths.push_back(width);
151     }
153     height = 0;
154     for (a=0;a<NoOfRows; a++){
155         row_heights.push_back(height);
156     }
157     grid_left = 99999;
158     grid_top = 99999;
160     SPDesktop *desktop = getDesktop();
161     sp_document_ensure_up_to_date(sp_desktop_document(desktop));
163     Inkscape::Selection *selection = sp_desktop_selection (desktop);
164     const GSList *items = selection->itemList();
165     cnt=0;
166     for (; items != NULL; items = items->next) {
167         SPItem *item = SP_ITEM(items->data);
168         Geom::OptRect b = item->getBounds(sp_item_i2doc_affine(item));
169         if (!b) {
170             continue;
171         }
173         width = b->dimensions()[Geom::X];
174         height = b->dimensions()[Geom::Y];
176         cx = b->midpoint()[Geom::X];
177         cy = b->midpoint()[Geom::Y];
179         if (b->min()[Geom::X] < grid_left) {
180             grid_left = b->min()[Geom::X];
181         }
182         if (b->min()[Geom::Y] < grid_top) {
183             grid_top = b->min()[Geom::Y];
184         }
185         if (width > col_width) {
186             col_width = width;
187         }
188         if (height > row_height) {
189             row_height = height;
190         }
191     }
194     // require the sorting done before we can calculate row heights etc.
196     const GSList *items2 = selection->itemList();
197     GSList *rev = g_slist_copy((GSList *) items2);
198     GSList *sorted = NULL;
199     rev = g_slist_sort(rev, (GCompareFunc) sp_compare_y_position);
200     sorted = g_slist_sort(rev, (GCompareFunc) sp_compare_x_position);
203     // Calculate individual Row and Column sizes if necessary
206         cnt=0;
207         const GSList *sizes = sorted;
208         for (; sizes != NULL; sizes = sizes->next) {
209             SPItem *item = SP_ITEM(sizes->data);
210             Geom::OptRect b = item->getBounds(sp_item_i2doc_affine(item));
211             if (b) {
212                 width = b->dimensions()[Geom::X];
213                 height = b->dimensions()[Geom::Y];
214                 if (width > col_widths[(cnt % NoOfCols)]) {
215                     col_widths[(cnt % NoOfCols)] = width;
216                 }
217                 if (height > row_heights[(cnt / NoOfCols)]) {
218                     row_heights[(cnt / NoOfCols)] = height;
219                 }
220             }
222             cnt++;
223         }
226     /// Make sure the top and left of the grid dont move by compensating for align values.
227     if (RowHeightButton.get_active()){
228         grid_top = grid_top - (((row_height - row_heights[0]) / 2)*(VertAlign));
229     }
230     if (ColumnWidthButton.get_active()){
231         grid_left = grid_left - (((col_width - col_widths[0]) /2)*(HorizAlign));
232     }
234     #ifdef DEBUG_GRID_ARRANGE
235      g_print("\n cx = %f cy= %f gridleft=%f",cx,cy,grid_left);
236     #endif
238     // Calculate total widths and heights, allowing for columns and rows non uniformly sized.
240     if (ColumnWidthButton.get_active()){
241         total_col_width = col_width * NoOfCols;
242         col_widths.clear();
243         for (a=0;a<NoOfCols; a++){
244             col_widths.push_back(col_width);
245         }
246     } else {
247         for (a = 0; a < (int)col_widths.size(); a++)
248         {
249           total_col_width += col_widths[a] ;
250         }
251     }
253     if (RowHeightButton.get_active()){
254         total_row_height = row_height * NoOfRows;
255         row_heights.clear();
256         for (a=0;a<NoOfRows; a++){
257             row_heights.push_back(row_height);
258         }
259     } else {
260         for (a = 0; a < (int)row_heights.size(); a++)
261         {
262           total_row_height += row_heights[a] ;
263         }
264     }
267     Geom::OptRect sel_bbox = selection->bounds();
268     // Fit to bbox, calculate padding between rows accordingly.
269     if ( sel_bbox && !SpaceManualRadioButton.get_active() ){
270 #ifdef DEBUG_GRID_ARRANGE
271 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));
272 #endif
273         paddingx = (sel_bbox->width() - total_col_width) / (NoOfCols -1);
274         paddingy = (sel_bbox->height() - total_row_height) / (NoOfRows -1);
275     }
277 /*
278     Horizontal align  - Left    = 0
279                         Centre  = 1
280                         Right   = 2
282     Vertical align    - Top     = 0
283                         Middle  = 1
284                         Bottom  = 2
286     X position is calculated by taking the grids left co-ord, adding the distance to the column,
287    then adding 1/2 the spacing multiplied by the align variable above,
288    Y position likewise, takes the top of the grid, adds the y to the current row then adds the padding in to align it.
290 */
292     // Calculate row and column x and y coords required to allow for columns and rows which are non uniformly sized.
294     for (a=0;a<NoOfCols; a++){
295         if (a<1) col_xs.push_back(0);
296         else col_xs.push_back(col_widths[a-1]+paddingx+col_xs[a-1]);
297     }
300     for (a=0;a<NoOfRows; a++){
301         if (a<1) row_ys.push_back(0);
302         else row_ys.push_back(row_heights[a-1]+paddingy+row_ys[a-1]);
303     }
305     cnt=0;
306   for (row_cnt=0; ((sorted != NULL) && (row_cnt<NoOfRows)); row_cnt++) {
308              GSList *current_row = NULL;
309              for (col_cnt = 0; ((sorted != NULL) && (col_cnt<NoOfCols)); col_cnt++) {
310                  current_row = g_slist_append (current_row, sorted->data);
311                  sorted = sorted->next;
312              }
314              for (; current_row != NULL; current_row = current_row->next) {
315                  SPItem *item=SP_ITEM(current_row->data);
316                  Inkscape::XML::Node *repr = SP_OBJECT_REPR(item);
317                  Geom::OptRect b = item->getBounds(sp_item_i2doc_affine(item));
318                  Geom::Point min;
319                  if (b) {
320                      width = b->dimensions()[Geom::X];
321                      height = b->dimensions()[Geom::Y];
322                      min = b->min();
323                  } else {
324                      width = height = 0;
325                      min = Geom::Point(0, 0);
326                  }
328                  row = cnt / NoOfCols;
329                  col = cnt % NoOfCols;
331                  new_x = grid_left + (((col_widths[col] - width)/2)*HorizAlign) + col_xs[col];
332                  new_y = grid_top + (((row_heights[row] - height)/2)*VertAlign) + row_ys[row];
334                  // signs are inverted between x and y due to y inversion
335                  Geom::Point move = Geom::Point(new_x - min[Geom::X], min[Geom::Y] - new_y);
336                  Geom::Matrix const affine = Geom::Matrix(Geom::Translate(move));
337                  sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * affine);
338                  sp_item_write_transform(item, repr, item->transform,  NULL);
339                  SP_OBJECT (current_row->data)->updateRepr();
340                  cnt +=1;
341              }
342              g_slist_free (current_row);
343     }
345     sp_document_done (sp_desktop_document (desktop), SP_VERB_SELECTION_GRIDTILE,
346                       _("Arrange in a grid"));
351 //#########################################################################
352 //## E V E N T S
353 //#########################################################################
356 void TileDialog::_apply()
358     Grid_Arrange();
362 /**
363  * changed value in # of columns spinbox.
364  */
365 void TileDialog::on_row_spinbutton_changed()
367     // quit if run by the attr_changed listener
368     if (updating) {
369             return;
370         }
372     // in turn, prevent listener from responding
373     updating = true;
374     SPDesktop *desktop = getDesktop();
376     Inkscape::Selection *selection = sp_desktop_selection (desktop);
378     GSList const *items = selection->itemList();
379     int selcount = g_slist_length((GSList *)items);
381     double PerCol = ceil(selcount / NoOfColsSpinner.get_value());
382     NoOfRowsSpinner.set_value(PerCol);
383     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
384     prefs->setDouble("/dialogs/gridtiler/NoOfCols", NoOfColsSpinner.get_value());
385     updating=false;
388 /**
389  * changed value in # of rows spinbox.
390  */
391 void TileDialog::on_col_spinbutton_changed()
393     // quit if run by the attr_changed listener
394     if (updating) {
395             return;
396         }
398     // in turn, prevent listener from responding
399     updating = true;
400     SPDesktop *desktop = getDesktop();
401     Inkscape::Selection *selection = sp_desktop_selection (desktop);
403     GSList const *items = selection->itemList();
404     int selcount = g_slist_length((GSList *)items);
406     double PerRow = ceil(selcount / NoOfRowsSpinner.get_value());
407     NoOfColsSpinner.set_value(PerRow);
408     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
409     prefs->setDouble("/dialogs/gridtiler/NoOfCols", PerRow);
411     updating=false;
414 /**
415  * changed value in x padding spinbox.
416  */
417 void TileDialog::on_xpad_spinbutton_changed()
419     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
420     prefs->setDouble("/dialogs/gridtiler/XPad", XPadSpinner.get_value());
424 /**
425  * changed value in y padding spinbox.
426  */
427 void TileDialog::on_ypad_spinbutton_changed()
429     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
430     prefs->setDouble("/dialogs/gridtiler/YPad", YPadSpinner.get_value());
434 /**
435  * checked/unchecked autosize Rows button.
436  */
437 void TileDialog::on_RowSize_checkbutton_changed()
439     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
440     if (RowHeightButton.get_active()) {
441         prefs->setDouble("/dialogs/gridtiler/AutoRowSize", 20);
442     } else {
443         prefs->setDouble("/dialogs/gridtiler/AutoRowSize", -20);
444     }
445     RowHeightBox.set_sensitive ( !RowHeightButton.get_active());
448 /**
449  * checked/unchecked autosize Rows button.
450  */
451 void TileDialog::on_ColSize_checkbutton_changed()
453     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
454     if (ColumnWidthButton.get_active()) {
455         prefs->setDouble("/dialogs/gridtiler/AutoColSize", 20);
456     } else {
457         prefs->setDouble("/dialogs/gridtiler/AutoColSize", -20);
458     }
459     ColumnWidthBox.set_sensitive ( !ColumnWidthButton.get_active());
462 /**
463  * changed value in columns spinbox.
464  */
465 void TileDialog::on_rowSize_spinbutton_changed()
467     // quit if run by the attr_changed listener
468     if (updating) {
469             return;
470         }
472     // in turn, prevent listener from responding
473     updating = true;
474     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
475     prefs->setDouble("/dialogs/gridtiler/RowHeight", RowHeightSpinner.get_value());
476     updating=false;
480 /**
481  * changed value in rows spinbox.
482  */
483 void TileDialog::on_colSize_spinbutton_changed()
485     // quit if run by the attr_changed listener
486     if (updating) {
487             return;
488         }
490     // in turn, prevent listener from responding
491     updating = true;
492     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
493     prefs->setDouble("/dialogs/gridtiler/ColWidth", ColumnWidthSpinner.get_value());
494     updating=false;
498 /**
499  * changed Radio button in Spacing group.
500  */
501 void TileDialog::Spacing_button_changed()
503     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
504     if (SpaceManualRadioButton.get_active()) {
505         prefs->setDouble("/dialogs/gridtiler/SpacingType", 20);
506     } else {
507         prefs->setDouble("/dialogs/gridtiler/SpacingType", -20);
508     }
510     SizesHBox.set_sensitive ( SpaceManualRadioButton.get_active());
513 /**
514  * changed Radio button in Vertical Align group.
515  */
516 void TileDialog::VertAlign_changed()
518     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
519     if (VertTopRadioButton.get_active()) {
520         VertAlign = 0;
521         prefs->setInt("/dialogs/gridtiler/VertAlign", 0);
522     } else if (VertCentreRadioButton.get_active()){
523         VertAlign = 1;
524         prefs->setInt("/dialogs/gridtiler/VertAlign", 1);
525     } else if (VertBotRadioButton.get_active()){
526         VertAlign = 2;
527         prefs->setInt("/dialogs/gridtiler/VertAlign", 2);
528     }
531 /**
532  * changed Radio button in Vertical Align group.
533  */
534 void TileDialog::HorizAlign_changed()
536     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
537     if (HorizLeftRadioButton.get_active()) {
538         HorizAlign = 0;
539         prefs->setInt("/dialogs/gridtiler/HorizAlign", 0);
540     } else if (HorizCentreRadioButton.get_active()){
541         HorizAlign = 1;
542         prefs->setInt("/dialogs/gridtiler/HorizAlign", 1);
543     } else if (HorizRightRadioButton.get_active()){
544         HorizAlign = 2;
545         prefs->setInt("/dialogs/gridtiler/HorizAlign", 2);
546     }
549 /**
550  * Desktop selection changed
551  */
552 void TileDialog::updateSelection()
554     // quit if run by the attr_changed listener
555     if (updating) {
556         return;
557     }
559     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
560     // in turn, prevent listener from responding
561     updating = true;
562     SPDesktop *desktop = getDesktop();
563     Inkscape::Selection *selection = sp_desktop_selection (desktop);
564     const GSList *items = selection->itemList();
565     int selcount = g_slist_length((GSList *)items);
567     if (NoOfColsSpinner.get_value()>1 && NoOfRowsSpinner.get_value()>1){
568         // Update the number of rows assuming number of columns wanted remains same.
569         double NoOfRows = ceil(selcount / NoOfColsSpinner.get_value());
570         NoOfRowsSpinner.set_value(NoOfRows);
572         // if the selection has less than the number set for one row, reduce it appropriately
573         if (selcount<NoOfColsSpinner.get_value()) {
574             double NoOfCols = ceil(selcount / NoOfRowsSpinner.get_value());
575             NoOfColsSpinner.set_value(NoOfCols);
576             prefs->setInt("/dialogs/gridtiler/NoOfCols", NoOfCols);
577         }
578     } else {
579         double PerRow = ceil(sqrt(selcount));
580         double PerCol = ceil(sqrt(selcount));
581         NoOfRowsSpinner.set_value(PerRow);
582         NoOfColsSpinner.set_value(PerCol);
583         prefs->setInt("/dialogs/gridtiler/NoOfCols", static_cast<int>(PerCol));
585     }
587     updating=false;
593 /*##########################
594 ## Experimental
595 ##########################*/
597 static void updateSelectionCallback(Inkscape::Application */*inkscape*/, Inkscape::Selection */*selection*/, TileDialog *dlg)
599     TileDialog *tledlg = (TileDialog *) dlg;
600     tledlg->updateSelection();
604 //#########################################################################
605 //## C O N S T R U C T O R    /    D E S T R U C T O R
606 //#########################################################################
607 /**
608  * Constructor
609  */
610 TileDialog::TileDialog()
611     : UI::Widget::Panel("", "/dialogs/gridtiler", SP_VERB_SELECTION_GRIDTILE)
613      // bool used by spin button callbacks to stop loops where they change each other.
614     updating = false;
615     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
617     // could not do this in gtkmm - there's no Gtk::SizeGroup public constructor (!)
618     GtkSizeGroup *_col1 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
619     GtkSizeGroup *_col2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
620     GtkSizeGroup *_col3 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
622     {
623         // Selection Change signal
624         g_signal_connect ( G_OBJECT (INKSCAPE), "change_selection", G_CALLBACK (updateSelectionCallback), this);
625     }
627     Gtk::Box *contents = _getContents();
629 #define MARGIN 2
631     //##Set up the panel
633     SPDesktop *desktop = getDesktop();
635     Inkscape::Selection *selection = sp_desktop_selection (desktop);
636     int selcount = 1;
637     if (!selection->isEmpty()) {
638         GSList const *items = selection->itemList();
639         selcount = g_slist_length((GSList *)items);
640     }
643     /*#### Number of Rows ####*/
645     double PerRow = ceil(sqrt(selcount));
646     double PerCol = ceil(sqrt(selcount));
648     #ifdef DEBUG_GRID_ARRANGE
649         g_print("/n PerRox = %f PerCol = %f selcount = %d",PerRow,PerCol,selcount);
650     #endif
652     NoOfRowsLabel.set_label(_("Rows:"));
653     NoOfRowsBox.pack_start(NoOfRowsLabel, false, false, MARGIN);
655     NoOfRowsSpinner.set_digits(0);
656     NoOfRowsSpinner.set_increments(1, 5);
657     NoOfRowsSpinner.set_range(1.0, 100.0);
658     NoOfRowsSpinner.set_value(PerCol);
659     NoOfRowsSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_col_spinbutton_changed));
660     tips.set_tip(NoOfRowsSpinner, _("Number of rows"));
661     NoOfRowsBox.pack_start(NoOfRowsSpinner, false, false, MARGIN);
662     gtk_size_group_add_widget(_col1, (GtkWidget *) NoOfRowsBox.gobj());
664     RowHeightButton.set_label(_("Equal height"));
665     double AutoRow = prefs->getDouble("/dialogs/gridtiler/AutoRowSize", 15);
666     if (AutoRow>0)
667          AutoRowSize=true;
668     else
669          AutoRowSize=false;
670     RowHeightButton.set_active(AutoRowSize);
672     NoOfRowsBox.pack_start(RowHeightButton, false, false, MARGIN);
674     tips.set_tip(RowHeightButton, _("If not set, each row has the height of the tallest object in it"));
675     RowHeightButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::on_RowSize_checkbutton_changed));
677  {
678         /*#### Radio buttons to control vertical alignment ####*/
680         VertAlignLabel.set_label(_("Align:"));
681         VertAlignHBox.pack_start(VertAlignLabel, false, false, MARGIN);
683         VertTopRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed));
684         VertAlignGroup = VertTopRadioButton.get_group();
685         VertAlignVBox.pack_start(VertTopRadioButton, false, false, 0);
687         VertCentreRadioButton.set_group(VertAlignGroup);
688         VertCentreRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed));
689         VertAlignVBox.pack_start(VertCentreRadioButton, false, false, 0);
691         VertBotRadioButton.set_group(VertAlignGroup);
692         VertBotRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed));
693         VertAlignVBox.pack_start(VertBotRadioButton, false, false, 0);
695         VertAlign = prefs->getInt("/dialogs/gridtiler/VertAlign", 1);
696         if (VertAlign == 0) {
697             VertTopRadioButton.set_active(TRUE);
698         }
699         else if (VertAlign == 1) {
700             VertCentreRadioButton.set_active(TRUE);
701         }
702         else if (VertAlign == 2){
703             VertBotRadioButton.set_active(TRUE);
704         }
705         VertAlignHBox.pack_start(VertAlignVBox, false, false, MARGIN);
706         NoOfRowsBox.pack_start(VertAlignHBox, false, false, MARGIN);
707     }
709     SpinsHBox.pack_start(NoOfRowsBox, false, false, MARGIN);
712     /*#### Label for X ####*/
713     padXByYLabel.set_label(" ");
714     XByYLabelVBox.pack_start(padXByYLabel, false, false, MARGIN);
715     XByYLabel.set_markup(" &#215; ");
716     XByYLabelVBox.pack_start(XByYLabel, false, false, MARGIN);
717     SpinsHBox.pack_start(XByYLabelVBox, false, false, MARGIN);
718     gtk_size_group_add_widget(_col2, (GtkWidget *) XByYLabelVBox.gobj());
720     /*#### Number of columns ####*/
722     NoOfColsLabel.set_label(_("Columns:"));
723     NoOfColsBox.pack_start(NoOfColsLabel, false, false, MARGIN);
725     NoOfColsSpinner.set_digits(0);
726     NoOfColsSpinner.set_increments(1, 5);
727     NoOfColsSpinner.set_range(1.0, 100.0);
728     NoOfColsSpinner.set_value(PerRow);
729     NoOfColsSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_row_spinbutton_changed));
730     tips.set_tip(NoOfColsSpinner, _("Number of columns"));
731     NoOfColsBox.pack_start(NoOfColsSpinner, false, false, MARGIN);
732     gtk_size_group_add_widget(_col3, (GtkWidget *) NoOfColsBox.gobj());
734     ColumnWidthButton.set_label(_("Equal width"));
735     double AutoCol = prefs->getDouble("/dialogs/gridtiler/AutoColSize", 15);
736     if (AutoCol>0)
737          AutoColSize=true;
738     else
739          AutoColSize=false;
740     ColumnWidthButton.set_active(AutoColSize);
741     NoOfColsBox.pack_start(ColumnWidthButton, false, false, MARGIN);
743     tips.set_tip(ColumnWidthButton, _("If not set, each column has the width of the widest object in it"));
744     ColumnWidthButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::on_ColSize_checkbutton_changed));
747     {
748         /*#### Radio buttons to control horizontal alignment ####*/
750         HorizAlignLabel.set_label(_("Align:"));
751         HorizAlignVBox.pack_start(HorizAlignLabel, false, false, MARGIN);
753         HorizAlignHBox.pack_start(*(new Gtk::HBox()), true, true, 0); // centering strut
755         HorizLeftRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed));
756         HorizAlignGroup = HorizLeftRadioButton.get_group();
757         HorizAlignHBox.pack_start(HorizLeftRadioButton, false, false, 0);
759         HorizCentreRadioButton.set_group(HorizAlignGroup);
760         HorizCentreRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed));
761         HorizAlignHBox.pack_start(HorizCentreRadioButton, false, false, 0);
763         HorizRightRadioButton.set_group(HorizAlignGroup);
764         HorizRightRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed));
765         HorizAlignHBox.pack_start(HorizRightRadioButton, false, false, 0);
767         HorizAlignHBox.pack_start(*(new Gtk::HBox()), true, true, 0); // centering strut
769         HorizAlign = prefs->getInt("/dialogs/gridtiler/HorizAlign", 1);
770         if (HorizAlign == 0) {
771             HorizLeftRadioButton.set_active(TRUE);
772         }
773         else if (HorizAlign == 1) {
774             HorizCentreRadioButton.set_active(TRUE);
775         }
776         else if (HorizAlign == 2) {
777             HorizRightRadioButton.set_active(TRUE);
778         }
779         HorizAlignVBox.pack_start(HorizAlignHBox, false, false, MARGIN);
780         NoOfColsBox.pack_start(HorizAlignVBox, false, false, MARGIN);
781     }
783     SpinsHBox.pack_start(NoOfColsBox, false, false, MARGIN);
785     TileBox.pack_start(SpinsHBox, false, false, MARGIN);
787     {
788         /*#### Radio buttons to control spacing manually or to fit selection bbox ####*/
789         SpaceByBBoxRadioButton.set_label(_("Fit into selection box"));
790         SpaceByBBoxRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed));
791         SpacingGroup = SpaceByBBoxRadioButton.get_group();
793         SpacingVBox.pack_start(SpaceByBBoxRadioButton, false, false, MARGIN);
795         SpaceManualRadioButton.set_label(_("Set spacing:"));
796         SpaceManualRadioButton.set_group(SpacingGroup);
797         SpaceManualRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed));
798         SpacingVBox.pack_start(SpaceManualRadioButton, false, false, MARGIN);
800         TileBox.pack_start(SpacingVBox, false, false, MARGIN);
801     }
803     {
804         /*#### Y Padding ####*/
806         GtkWidget *i = sp_icon_new (Inkscape::ICON_SIZE_MENU, "clonetiler_per_row");
807         YPadBox.pack_start (*(Glib::wrap(i)), false, false, MARGIN);
809         YPadSpinner.set_digits(1);
810         YPadSpinner.set_increments(0.2, 2);
811         YPadSpinner.set_range(-10000, 10000);
812         double YPad = prefs->getDouble("/dialogs/gridtiler/YPad", 15);
813         YPadSpinner.set_value(YPad);
814         YPadBox.pack_start(YPadSpinner, true, true, MARGIN);
815         tips.set_tip(YPadSpinner, _("Vertical spacing between rows (px units)"));
816         YPadSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_ypad_spinbutton_changed));
817         gtk_size_group_add_widget(_col1, (GtkWidget *) YPadBox.gobj());
819         SizesHBox.pack_start(YPadBox, false, false, MARGIN);
820     }
822     {
823     Gtk::HBox *spacer = new Gtk::HBox;
824     SizesHBox.pack_start(*spacer, false, false, 0);
825     gtk_size_group_add_widget(_col2, (GtkWidget *) spacer->gobj());
826     }
828     {
829         /*#### X padding ####*/
831         GtkWidget *i = sp_icon_new (Inkscape::ICON_SIZE_MENU, "clonetiler_per_column");
832         XPadBox.pack_start (*(Glib::wrap(i)), false, false, MARGIN);
834         XPadSpinner.set_digits(1);
835         XPadSpinner.set_increments(0.2, 2);
836         XPadSpinner.set_range(-10000, 10000);
837         double XPad = prefs->getDouble("/dialogs/gridtiler/XPad", 15);
838         XPadSpinner.set_value(XPad);
839         XPadBox.pack_start(XPadSpinner, true, true, MARGIN);
840         tips.set_tip(XPadSpinner, _("Horizontal spacing between columns (px units)"));
841         XPadSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_xpad_spinbutton_changed));
842         gtk_size_group_add_widget(_col3, (GtkWidget *) XPadBox.gobj());
844         SizesHBox.pack_start(XPadBox, false, false, MARGIN);
845     }
848     TileBox.pack_start(SizesHBox, false, false, MARGIN);
850     contents->pack_start(TileBox);
852     double SpacingType = prefs->getDouble("/dialogs/gridtiler/SpacingType", 15);
853     if (SpacingType>0) {
854         ManualSpacing=true;
855     } else {
856         ManualSpacing=false;
857     }
858     SpaceManualRadioButton.set_active(ManualSpacing);
859     SpaceByBBoxRadioButton.set_active(!ManualSpacing);
860     SizesHBox.set_sensitive (ManualSpacing);
862     //## The OK button
863     TileOkButton = addResponseButton(_("Arrange"), GTK_RESPONSE_APPLY);
864     tips.set_tip((*TileOkButton), _("Arrange selected objects"));
866     show_all_children();
869 } //namespace Dialog
870 } //namespace UI
871 } //namespace Inkscape
873 /*
874   Local Variables:
875   mode:c++
876   c-file-style:"stroustrup"
877   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
878   indent-tabs-mode:nil
879   fill-column:99
880   End:
881 */
882 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 ::