Code

A simple layout document as to what, why and how is cppification.
[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"
34 #include "desktop.h"
36 /*
37  *    Sort items by their x co-ordinates, taking account of y (keeps rows intact)
38  *
39  *    <0 *elem1 goes before *elem2
40  *    0  *elem1 == *elem2
41  *    >0  *elem1 goes after *elem2
42  */
43 int
44 sp_compare_x_position(SPItem *first, SPItem *second)
45 {
46     using Geom::X;
47     using Geom::Y;
49     Geom::OptRect a = first->getBounds(first->i2doc_affine());
50     Geom::OptRect b = second->getBounds(second->i2doc_affine());
52     if ( !a || !b ) {
53         // FIXME?
54         return 0;
55     }
57     double const a_height = a->dimensions()[Y];
58     double const b_height = b->dimensions()[Y];
60     bool a_in_b_vert = false;
61     if ((a->min()[Y] < b->min()[Y] + 0.1) && (a->min()[Y] > b->min()[Y] - b_height)) {
62         a_in_b_vert = true;
63     } else if ((b->min()[Y] < a->min()[Y] + 0.1) && (b->min()[Y] > a->min()[Y] - a_height)) {
64         a_in_b_vert = true;
65     } else if (b->min()[Y] == a->min()[Y]) {
66         a_in_b_vert = true;
67     } else {
68         a_in_b_vert = false;
69     }
71     if (!a_in_b_vert) {
72         return -1;
73     }
74     if (a_in_b_vert && a->min()[X] > b->min()[X]) {
75         return 1;
76     }
77     if (a_in_b_vert && a->min()[X] < b->min()[X]) {
78         return -1;
79     }
80     return 0;
81 }
83 /*
84  *    Sort items by their y co-ordinates.
85  */
86 int
87 sp_compare_y_position(SPItem *first, SPItem *second)
88 {
89     Geom::OptRect a = first->getBounds(first->i2doc_affine());
90     Geom::OptRect b = second->getBounds(second->i2doc_affine());
92     if ( !a || !b ) {
93         // FIXME?
94         return 0;
95     }
97     if (a->min()[Geom::Y] > b->min()[Geom::Y]) {
98         return 1;
99     }
100     if (a->min()[Geom::Y] < b->min()[Geom::Y]) {
101         return -1;
102     }
104     return 0;
107 namespace Inkscape {
108 namespace UI {
109 namespace Dialog {
112 //#########################################################################
113 //## E V E N T S
114 //#########################################################################
116 /*
117  *
118  * This arranges the selection in a grid pattern.
119  *
120  */
122 void TileDialog::Grid_Arrange ()
125     int cnt,row_cnt,col_cnt,a,row,col;
126     double grid_left,grid_top,col_width,row_height,paddingx,paddingy,width, height, new_x, new_y,cx,cy;
127     double total_col_width,total_row_height;
128     col_width = 0;
129     row_height = 0;
130     total_col_width=0;
131     total_row_height=0;
133     // check for correct numbers in the row- and col-spinners
134     on_col_spinbutton_changed();
135     on_row_spinbutton_changed();
137     // set padding to manual values
138     paddingx = XPadSpinner.get_value();
139     paddingy = YPadSpinner.get_value();
141     std::vector<double> row_heights;
142     std::vector<double> col_widths;
143     std::vector<double> row_ys;
144     std::vector<double> col_xs;
146     int NoOfCols = NoOfColsSpinner.get_value_as_int();
147     int NoOfRows = NoOfRowsSpinner.get_value_as_int();
149     width = 0;
150     for (a=0;a<NoOfCols; a++){
151         col_widths.push_back(width);
152     }
154     height = 0;
155     for (a=0;a<NoOfRows; a++){
156         row_heights.push_back(height);
157     }
158     grid_left = 99999;
159     grid_top = 99999;
161     SPDesktop *desktop = getDesktop();
162     sp_desktop_document(desktop)->ensure_up_to_date();
164     Inkscape::Selection *selection = sp_desktop_selection (desktop);
165     const GSList *items = selection ? selection->itemList() : 0;
166     cnt=0;
167     for (; items != NULL; items = items->next) {
168         SPItem *item = SP_ITEM(items->data);
169         Geom::OptRect b = item->getBounds(item->i2doc_affine());
170         if (!b) {
171             continue;
172         }
174         width = b->dimensions()[Geom::X];
175         height = b->dimensions()[Geom::Y];
177         cx = b->midpoint()[Geom::X];
178         cy = b->midpoint()[Geom::Y];
180         if (b->min()[Geom::X] < grid_left) {
181             grid_left = b->min()[Geom::X];
182         }
183         if (b->min()[Geom::Y] < grid_top) {
184             grid_top = b->min()[Geom::Y];
185         }
186         if (width > col_width) {
187             col_width = width;
188         }
189         if (height > row_height) {
190             row_height = height;
191         }
192     }
195     // require the sorting done before we can calculate row heights etc.
197     g_return_if_fail(selection);
198     const GSList *items2 = selection->itemList();
199     GSList *rev = g_slist_copy((GSList *) items2);
200     GSList *sorted = NULL;
201     rev = g_slist_sort(rev, (GCompareFunc) sp_compare_y_position);
202     sorted = g_slist_sort(rev, (GCompareFunc) sp_compare_x_position);
205     // Calculate individual Row and Column sizes if necessary
208         cnt=0;
209         const GSList *sizes = sorted;
210         for (; sizes != NULL; sizes = sizes->next) {
211             SPItem *item = SP_ITEM(sizes->data);
212             Geom::OptRect b = item->getBounds(item->i2doc_affine());
213             if (b) {
214                 width = b->dimensions()[Geom::X];
215                 height = b->dimensions()[Geom::Y];
216                 if (width > col_widths[(cnt % NoOfCols)]) {
217                     col_widths[(cnt % NoOfCols)] = width;
218                 }
219                 if (height > row_heights[(cnt / NoOfCols)]) {
220                     row_heights[(cnt / NoOfCols)] = height;
221                 }
222             }
224             cnt++;
225         }
228     /// Make sure the top and left of the grid dont move by compensating for align values.
229     if (RowHeightButton.get_active()){
230         grid_top = grid_top - (((row_height - row_heights[0]) / 2)*(VertAlign));
231     }
232     if (ColumnWidthButton.get_active()){
233         grid_left = grid_left - (((col_width - col_widths[0]) /2)*(HorizAlign));
234     }
236     #ifdef DEBUG_GRID_ARRANGE
237      g_print("\n cx = %f cy= %f gridleft=%f",cx,cy,grid_left);
238     #endif
240     // Calculate total widths and heights, allowing for columns and rows non uniformly sized.
242     if (ColumnWidthButton.get_active()){
243         total_col_width = col_width * NoOfCols;
244         col_widths.clear();
245         for (a=0;a<NoOfCols; a++){
246             col_widths.push_back(col_width);
247         }
248     } else {
249         for (a = 0; a < (int)col_widths.size(); a++)
250         {
251           total_col_width += col_widths[a] ;
252         }
253     }
255     if (RowHeightButton.get_active()){
256         total_row_height = row_height * NoOfRows;
257         row_heights.clear();
258         for (a=0;a<NoOfRows; a++){
259             row_heights.push_back(row_height);
260         }
261     } else {
262         for (a = 0; a < (int)row_heights.size(); a++)
263         {
264           total_row_height += row_heights[a] ;
265         }
266     }
269     Geom::OptRect sel_bbox = selection->bounds();
270     // Fit to bbox, calculate padding between rows accordingly.
271     if ( sel_bbox && !SpaceManualRadioButton.get_active() ){
272 #ifdef DEBUG_GRID_ARRANGE
273 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));
274 #endif
275         paddingx = (sel_bbox->width() - total_col_width) / (NoOfCols -1);
276         paddingy = (sel_bbox->height() - total_row_height) / (NoOfRows -1);
277     }
279 /*
280     Horizontal align  - Left    = 0
281                         Centre  = 1
282                         Right   = 2
284     Vertical align    - Top     = 0
285                         Middle  = 1
286                         Bottom  = 2
288     X position is calculated by taking the grids left co-ord, adding the distance to the column,
289    then adding 1/2 the spacing multiplied by the align variable above,
290    Y position likewise, takes the top of the grid, adds the y to the current row then adds the padding in to align it.
292 */
294     // Calculate row and column x and y coords required to allow for columns and rows which are non uniformly sized.
296     for (a=0;a<NoOfCols; a++){
297         if (a<1) col_xs.push_back(0);
298         else col_xs.push_back(col_widths[a-1]+paddingx+col_xs[a-1]);
299     }
302     for (a=0;a<NoOfRows; a++){
303         if (a<1) row_ys.push_back(0);
304         else row_ys.push_back(row_heights[a-1]+paddingy+row_ys[a-1]);
305     }
307     cnt=0;
308   for (row_cnt=0; ((sorted != NULL) && (row_cnt<NoOfRows)); row_cnt++) {
310              GSList *current_row = NULL;
311              for (col_cnt = 0; ((sorted != NULL) && (col_cnt<NoOfCols)); col_cnt++) {
312                  current_row = g_slist_append (current_row, sorted->data);
313                  sorted = sorted->next;
314              }
316              for (; current_row != NULL; current_row = current_row->next) {
317                  SPItem *item=SP_ITEM(current_row->data);
318                  Inkscape::XML::Node *repr = SP_OBJECT_REPR(item);
319                  Geom::OptRect b = item->getBounds(item->i2doc_affine());
320                  Geom::Point min;
321                  if (b) {
322                      width = b->dimensions()[Geom::X];
323                      height = b->dimensions()[Geom::Y];
324                      min = b->min();
325                  } else {
326                      width = height = 0;
327                      min = Geom::Point(0, 0);
328                  }
330                  row = cnt / NoOfCols;
331                  col = cnt % NoOfCols;
333                  new_x = grid_left + (((col_widths[col] - width)/2)*HorizAlign) + col_xs[col];
334                  new_y = grid_top + (((row_heights[row] - height)/2)*VertAlign) + row_ys[row];
336                  // signs are inverted between x and y due to y inversion
337                  Geom::Point move = Geom::Point(new_x - min[Geom::X], min[Geom::Y] - new_y);
338                  Geom::Matrix const affine = Geom::Matrix(Geom::Translate(move));
339                  item->set_i2d_affine(item->i2d_affine() * affine);
340                  item->doWriteTransform(repr, item->transform,  NULL);
341                  SP_OBJECT (current_row->data)->updateRepr();
342                  cnt +=1;
343              }
344              g_slist_free (current_row);
345     }
347     SPDocumentUndo::done (sp_desktop_document (desktop), SP_VERB_SELECTION_GRIDTILE,
348                       _("Arrange in a grid"));
353 //#########################################################################
354 //## E V E N T S
355 //#########################################################################
358 void TileDialog::_apply()
360     Grid_Arrange();
364 /**
365  * changed value in # of columns spinbox.
366  */
367 void TileDialog::on_row_spinbutton_changed()
369     // quit if run by the attr_changed listener
370     if (updating) {
371             return;
372         }
374     // in turn, prevent listener from responding
375     updating = true;
376     SPDesktop *desktop = getDesktop();
378     Inkscape::Selection *selection = desktop ? desktop->selection : 0;
379     g_return_if_fail( selection );
381     GSList const *items = selection->itemList();
382     int selcount = g_slist_length((GSList *)items);
384     double PerCol = ceil(selcount / NoOfColsSpinner.get_value());
385     NoOfRowsSpinner.set_value(PerCol);
386     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
387     prefs->setDouble("/dialogs/gridtiler/NoOfCols", NoOfColsSpinner.get_value());
388     updating=false;
391 /**
392  * changed value in # of rows spinbox.
393  */
394 void TileDialog::on_col_spinbutton_changed()
396     // quit if run by the attr_changed listener
397     if (updating) {
398             return;
399         }
401     // in turn, prevent listener from responding
402     updating = true;
403     SPDesktop *desktop = getDesktop();
404     Inkscape::Selection *selection = desktop ? desktop->selection : 0;
405     g_return_if_fail(selection);
407     GSList const *items = selection->itemList();
408     int selcount = g_slist_length((GSList *)items);
410     double PerRow = ceil(selcount / NoOfRowsSpinner.get_value());
411     NoOfColsSpinner.set_value(PerRow);
412     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
413     prefs->setDouble("/dialogs/gridtiler/NoOfCols", PerRow);
415     updating=false;
418 /**
419  * changed value in x padding spinbox.
420  */
421 void TileDialog::on_xpad_spinbutton_changed()
423     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
424     prefs->setDouble("/dialogs/gridtiler/XPad", XPadSpinner.get_value());
428 /**
429  * changed value in y padding spinbox.
430  */
431 void TileDialog::on_ypad_spinbutton_changed()
433     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
434     prefs->setDouble("/dialogs/gridtiler/YPad", YPadSpinner.get_value());
438 /**
439  * checked/unchecked autosize Rows button.
440  */
441 void TileDialog::on_RowSize_checkbutton_changed()
443     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
444     if (RowHeightButton.get_active()) {
445         prefs->setDouble("/dialogs/gridtiler/AutoRowSize", 20);
446     } else {
447         prefs->setDouble("/dialogs/gridtiler/AutoRowSize", -20);
448     }
449     RowHeightBox.set_sensitive ( !RowHeightButton.get_active());
452 /**
453  * checked/unchecked autosize Rows button.
454  */
455 void TileDialog::on_ColSize_checkbutton_changed()
457     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
458     if (ColumnWidthButton.get_active()) {
459         prefs->setDouble("/dialogs/gridtiler/AutoColSize", 20);
460     } else {
461         prefs->setDouble("/dialogs/gridtiler/AutoColSize", -20);
462     }
463     ColumnWidthBox.set_sensitive ( !ColumnWidthButton.get_active());
466 /**
467  * changed value in columns spinbox.
468  */
469 void TileDialog::on_rowSize_spinbutton_changed()
471     // quit if run by the attr_changed listener
472     if (updating) {
473             return;
474         }
476     // in turn, prevent listener from responding
477     updating = true;
478     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
479     prefs->setDouble("/dialogs/gridtiler/RowHeight", RowHeightSpinner.get_value());
480     updating=false;
484 /**
485  * changed value in rows spinbox.
486  */
487 void TileDialog::on_colSize_spinbutton_changed()
489     // quit if run by the attr_changed listener
490     if (updating) {
491             return;
492         }
494     // in turn, prevent listener from responding
495     updating = true;
496     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
497     prefs->setDouble("/dialogs/gridtiler/ColWidth", ColumnWidthSpinner.get_value());
498     updating=false;
502 /**
503  * changed Radio button in Spacing group.
504  */
505 void TileDialog::Spacing_button_changed()
507     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
508     if (SpaceManualRadioButton.get_active()) {
509         prefs->setDouble("/dialogs/gridtiler/SpacingType", 20);
510     } else {
511         prefs->setDouble("/dialogs/gridtiler/SpacingType", -20);
512     }
514     SizesHBox.set_sensitive ( SpaceManualRadioButton.get_active());
517 /**
518  * changed Radio button in Vertical Align group.
519  */
520 void TileDialog::VertAlign_changed()
522     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
523     if (VertTopRadioButton.get_active()) {
524         VertAlign = 0;
525         prefs->setInt("/dialogs/gridtiler/VertAlign", 0);
526     } else if (VertCentreRadioButton.get_active()){
527         VertAlign = 1;
528         prefs->setInt("/dialogs/gridtiler/VertAlign", 1);
529     } else if (VertBotRadioButton.get_active()){
530         VertAlign = 2;
531         prefs->setInt("/dialogs/gridtiler/VertAlign", 2);
532     }
535 /**
536  * changed Radio button in Vertical Align group.
537  */
538 void TileDialog::HorizAlign_changed()
540     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
541     if (HorizLeftRadioButton.get_active()) {
542         HorizAlign = 0;
543         prefs->setInt("/dialogs/gridtiler/HorizAlign", 0);
544     } else if (HorizCentreRadioButton.get_active()){
545         HorizAlign = 1;
546         prefs->setInt("/dialogs/gridtiler/HorizAlign", 1);
547     } else if (HorizRightRadioButton.get_active()){
548         HorizAlign = 2;
549         prefs->setInt("/dialogs/gridtiler/HorizAlign", 2);
550     }
553 /**
554  * Desktop selection changed
555  */
556 void TileDialog::updateSelection()
558     // quit if run by the attr_changed listener
559     if (updating) {
560         return;
561     }
563     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
564     // in turn, prevent listener from responding
565     updating = true;
566     SPDesktop *desktop = getDesktop();
567     Inkscape::Selection *selection = desktop ? desktop->selection : 0;
568     GSList const *items = selection ? selection->itemList() : 0;
570     if (items) {
571         int selcount = g_slist_length((GSList *)items);
573         if (NoOfColsSpinner.get_value() > 1 && NoOfRowsSpinner.get_value() > 1){
574             // Update the number of rows assuming number of columns wanted remains same.
575             double NoOfRows = ceil(selcount / NoOfColsSpinner.get_value());
576             NoOfRowsSpinner.set_value(NoOfRows);
578             // if the selection has less than the number set for one row, reduce it appropriately
579             if (selcount < NoOfColsSpinner.get_value()) {
580                 double NoOfCols = ceil(selcount / NoOfRowsSpinner.get_value());
581                 NoOfColsSpinner.set_value(NoOfCols);
582                 prefs->setInt("/dialogs/gridtiler/NoOfCols", NoOfCols);
583             }
584         } else {
585             double PerRow = ceil(sqrt(selcount));
586             double PerCol = ceil(sqrt(selcount));
587             NoOfRowsSpinner.set_value(PerRow);
588             NoOfColsSpinner.set_value(PerCol);
589             prefs->setInt("/dialogs/gridtiler/NoOfCols", static_cast<int>(PerCol));
590         }
591     }
593     updating = false;
598 /*##########################
599 ## Experimental
600 ##########################*/
602 static void updateSelectionCallback(Inkscape::Application */*inkscape*/, Inkscape::Selection */*selection*/, TileDialog *dlg)
604     TileDialog *tledlg = (TileDialog *) dlg;
605     tledlg->updateSelection();
609 //#########################################################################
610 //## C O N S T R U C T O R    /    D E S T R U C T O R
611 //#########################################################################
612 /**
613  * Constructor
614  */
615 TileDialog::TileDialog()
616     : UI::Widget::Panel("", "/dialogs/gridtiler", SP_VERB_SELECTION_GRIDTILE)
618      // bool used by spin button callbacks to stop loops where they change each other.
619     updating = false;
620     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
622     // could not do this in gtkmm - there's no Gtk::SizeGroup public constructor (!)
623     GtkSizeGroup *_col1 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
624     GtkSizeGroup *_col2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
625     GtkSizeGroup *_col3 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
627     {
628         // Selection Change signal
629         g_signal_connect ( G_OBJECT (INKSCAPE), "change_selection", G_CALLBACK (updateSelectionCallback), this);
630     }
632     Gtk::Box *contents = _getContents();
634 #define MARGIN 2
636     //##Set up the panel
638     SPDesktop *desktop = getDesktop();
640     Inkscape::Selection *selection = desktop ? desktop->selection : 0;
641     g_return_if_fail( selection );
642     int selcount = 1;
643     if (!selection->isEmpty()) {
644         GSList const *items = selection->itemList();
645         selcount = g_slist_length((GSList *)items);
646     }
649     /*#### Number of Rows ####*/
651     double PerRow = ceil(sqrt(selcount));
652     double PerCol = ceil(sqrt(selcount));
654     #ifdef DEBUG_GRID_ARRANGE
655         g_print("/n PerRox = %f PerCol = %f selcount = %d",PerRow,PerCol,selcount);
656     #endif
658     NoOfRowsLabel.set_label(_("Rows:"));
659     NoOfRowsBox.pack_start(NoOfRowsLabel, false, false, MARGIN);
661     NoOfRowsSpinner.set_digits(0);
662     NoOfRowsSpinner.set_increments(1, 0);
663     NoOfRowsSpinner.set_range(1.0, 100.0);
664     NoOfRowsSpinner.set_value(PerCol);
665     NoOfRowsSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_col_spinbutton_changed));
666     tips.set_tip(NoOfRowsSpinner, _("Number of rows"));
667     NoOfRowsBox.pack_start(NoOfRowsSpinner, false, false, MARGIN);
668     gtk_size_group_add_widget(_col1, (GtkWidget *) NoOfRowsBox.gobj());
670     RowHeightButton.set_label(_("Equal height"));
671     double AutoRow = prefs->getDouble("/dialogs/gridtiler/AutoRowSize", 15);
672     if (AutoRow>0)
673          AutoRowSize=true;
674     else
675          AutoRowSize=false;
676     RowHeightButton.set_active(AutoRowSize);
678     NoOfRowsBox.pack_start(RowHeightButton, false, false, MARGIN);
680     tips.set_tip(RowHeightButton, _("If not set, each row has the height of the tallest object in it"));
681     RowHeightButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::on_RowSize_checkbutton_changed));
683  {
684         /*#### Radio buttons to control vertical alignment ####*/
686         VertAlignLabel.set_label(_("Align:"));
687         VertAlignHBox.pack_start(VertAlignLabel, false, false, MARGIN);
689         VertTopRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed));
690         VertAlignGroup = VertTopRadioButton.get_group();
691         VertAlignVBox.pack_start(VertTopRadioButton, false, false, 0);
693         VertCentreRadioButton.set_group(VertAlignGroup);
694         VertCentreRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed));
695         VertAlignVBox.pack_start(VertCentreRadioButton, false, false, 0);
697         VertBotRadioButton.set_group(VertAlignGroup);
698         VertBotRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed));
699         VertAlignVBox.pack_start(VertBotRadioButton, false, false, 0);
701         VertAlign = prefs->getInt("/dialogs/gridtiler/VertAlign", 1);
702         if (VertAlign == 0) {
703             VertTopRadioButton.set_active(TRUE);
704         }
705         else if (VertAlign == 1) {
706             VertCentreRadioButton.set_active(TRUE);
707         }
708         else if (VertAlign == 2){
709             VertBotRadioButton.set_active(TRUE);
710         }
711         VertAlignHBox.pack_start(VertAlignVBox, false, false, MARGIN);
712         NoOfRowsBox.pack_start(VertAlignHBox, false, false, MARGIN);
713     }
715     SpinsHBox.pack_start(NoOfRowsBox, false, false, MARGIN);
718     /*#### Label for X ####*/
719     padXByYLabel.set_label(" ");
720     XByYLabelVBox.pack_start(padXByYLabel, false, false, MARGIN);
721     XByYLabel.set_markup(" &#215; ");
722     XByYLabelVBox.pack_start(XByYLabel, false, false, MARGIN);
723     SpinsHBox.pack_start(XByYLabelVBox, false, false, MARGIN);
724     gtk_size_group_add_widget(_col2, (GtkWidget *) XByYLabelVBox.gobj());
726     /*#### Number of columns ####*/
728     NoOfColsLabel.set_label(_("Columns:"));
729     NoOfColsBox.pack_start(NoOfColsLabel, false, false, MARGIN);
731     NoOfColsSpinner.set_digits(0);
732     NoOfColsSpinner.set_increments(1, 0);
733     NoOfColsSpinner.set_range(1.0, 100.0);
734     NoOfColsSpinner.set_value(PerRow);
735     NoOfColsSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_row_spinbutton_changed));
736     tips.set_tip(NoOfColsSpinner, _("Number of columns"));
737     NoOfColsBox.pack_start(NoOfColsSpinner, false, false, MARGIN);
738     gtk_size_group_add_widget(_col3, (GtkWidget *) NoOfColsBox.gobj());
740     ColumnWidthButton.set_label(_("Equal width"));
741     double AutoCol = prefs->getDouble("/dialogs/gridtiler/AutoColSize", 15);
742     if (AutoCol>0)
743          AutoColSize=true;
744     else
745          AutoColSize=false;
746     ColumnWidthButton.set_active(AutoColSize);
747     NoOfColsBox.pack_start(ColumnWidthButton, false, false, MARGIN);
749     tips.set_tip(ColumnWidthButton, _("If not set, each column has the width of the widest object in it"));
750     ColumnWidthButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::on_ColSize_checkbutton_changed));
753     {
754         /*#### Radio buttons to control horizontal alignment ####*/
756         HorizAlignLabel.set_label(_("Align:"));
757         HorizAlignVBox.pack_start(HorizAlignLabel, false, false, MARGIN);
759         HorizAlignHBox.pack_start(*(new Gtk::HBox()), true, true, 0); // centering strut
761         HorizLeftRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed));
762         HorizAlignGroup = HorizLeftRadioButton.get_group();
763         HorizAlignHBox.pack_start(HorizLeftRadioButton, false, false, 0);
765         HorizCentreRadioButton.set_group(HorizAlignGroup);
766         HorizCentreRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed));
767         HorizAlignHBox.pack_start(HorizCentreRadioButton, false, false, 0);
769         HorizRightRadioButton.set_group(HorizAlignGroup);
770         HorizRightRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed));
771         HorizAlignHBox.pack_start(HorizRightRadioButton, false, false, 0);
773         HorizAlignHBox.pack_start(*(new Gtk::HBox()), true, true, 0); // centering strut
775         HorizAlign = prefs->getInt("/dialogs/gridtiler/HorizAlign", 1);
776         if (HorizAlign == 0) {
777             HorizLeftRadioButton.set_active(TRUE);
778         }
779         else if (HorizAlign == 1) {
780             HorizCentreRadioButton.set_active(TRUE);
781         }
782         else if (HorizAlign == 2) {
783             HorizRightRadioButton.set_active(TRUE);
784         }
785         HorizAlignVBox.pack_start(HorizAlignHBox, false, false, MARGIN);
786         NoOfColsBox.pack_start(HorizAlignVBox, false, false, MARGIN);
787     }
789     SpinsHBox.pack_start(NoOfColsBox, false, false, MARGIN);
791     TileBox.pack_start(SpinsHBox, false, false, MARGIN);
793     {
794         /*#### Radio buttons to control spacing manually or to fit selection bbox ####*/
795         SpaceByBBoxRadioButton.set_label(_("Fit into selection box"));
796         SpaceByBBoxRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed));
797         SpacingGroup = SpaceByBBoxRadioButton.get_group();
799         SpacingVBox.pack_start(SpaceByBBoxRadioButton, false, false, MARGIN);
801         SpaceManualRadioButton.set_label(_("Set spacing:"));
802         SpaceManualRadioButton.set_group(SpacingGroup);
803         SpaceManualRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed));
804         SpacingVBox.pack_start(SpaceManualRadioButton, false, false, MARGIN);
806         TileBox.pack_start(SpacingVBox, false, false, MARGIN);
807     }
809     {
810         /*#### Y Padding ####*/
812         GtkWidget *i = sp_icon_new (Inkscape::ICON_SIZE_MENU, "object-rows");
813         YPadBox.pack_start (*(Glib::wrap(i)), false, false, MARGIN);
815         YPadSpinner.set_digits(1);
816         YPadSpinner.set_increments(0.2, 0);
817         YPadSpinner.set_range(-10000, 10000);
818         double YPad = prefs->getDouble("/dialogs/gridtiler/YPad", 15);
819         YPadSpinner.set_value(YPad);
820         YPadBox.pack_start(YPadSpinner, true, true, MARGIN);
821         tips.set_tip(YPadSpinner, _("Vertical spacing between rows (px units)"));
822         YPadSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_ypad_spinbutton_changed));
823         gtk_size_group_add_widget(_col1, (GtkWidget *) YPadBox.gobj());
825         SizesHBox.pack_start(YPadBox, false, false, MARGIN);
826     }
828     {
829     Gtk::HBox *spacer = new Gtk::HBox;
830     SizesHBox.pack_start(*spacer, false, false, 0);
831     gtk_size_group_add_widget(_col2, (GtkWidget *) spacer->gobj());
832     }
834     {
835         /*#### X padding ####*/
837         GtkWidget *i = sp_icon_new (Inkscape::ICON_SIZE_MENU, "object-columns");
838         XPadBox.pack_start (*(Glib::wrap(i)), false, false, MARGIN);
840         XPadSpinner.set_digits(1);
841         XPadSpinner.set_increments(0.2, 0);
842         XPadSpinner.set_range(-10000, 10000);
843         double XPad = prefs->getDouble("/dialogs/gridtiler/XPad", 15);
844         XPadSpinner.set_value(XPad);
845         XPadBox.pack_start(XPadSpinner, true, true, MARGIN);
846         tips.set_tip(XPadSpinner, _("Horizontal spacing between columns (px units)"));
847         XPadSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_xpad_spinbutton_changed));
848         gtk_size_group_add_widget(_col3, (GtkWidget *) XPadBox.gobj());
850         SizesHBox.pack_start(XPadBox, false, false, MARGIN);
851     }
854     TileBox.pack_start(SizesHBox, false, false, MARGIN);
856     contents->pack_start(TileBox);
858     double SpacingType = prefs->getDouble("/dialogs/gridtiler/SpacingType", 15);
859     if (SpacingType>0) {
860         ManualSpacing=true;
861     } else {
862         ManualSpacing=false;
863     }
864     SpaceManualRadioButton.set_active(ManualSpacing);
865     SpaceByBBoxRadioButton.set_active(!ManualSpacing);
866     SizesHBox.set_sensitive (ManualSpacing);
868     //## The OK button
869     TileOkButton = addResponseButton(Q_("tileClonesDialog|Arrange"), GTK_RESPONSE_APPLY);
870     tips.set_tip((*TileOkButton), _("Arrange selected objects"));
872     show_all_children();
875 } //namespace Dialog
876 } //namespace UI
877 } //namespace Inkscape
879 /*
880   Local Variables:
881   mode:c++
882   c-file-style:"stroustrup"
883   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
884   indent-tabs-mode:nil
885   fill-column:99
886   End:
887 */
888 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 ::