b506109383cc8d2f7080ea9b0c94a9c8fca76da6
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(sp_item_i2doc_affine(first));
50 Geom::OptRect b = second->getBounds(sp_item_i2doc_affine(second));
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(sp_item_i2doc_affine(first));
90 Geom::OptRect b = second->getBounds(sp_item_i2doc_affine(second));
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;
105 }
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 ()
123 {
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_document_ensure_up_to_date(sp_desktop_document(desktop));
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(sp_item_i2doc_affine(item));
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(sp_item_i2doc_affine(item));
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(sp_item_i2doc_affine(item));
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 sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * affine);
340 sp_item_write_transform(item, repr, item->transform, NULL);
341 SP_OBJECT (current_row->data)->updateRepr();
342 cnt +=1;
343 }
344 g_slist_free (current_row);
345 }
347 sp_document_done (sp_desktop_document (desktop), SP_VERB_SELECTION_GRIDTILE,
348 _("Arrange in a grid"));
350 }
353 //#########################################################################
354 //## E V E N T S
355 //#########################################################################
358 void TileDialog::_apply()
359 {
360 Grid_Arrange();
361 }
364 /**
365 * changed value in # of columns spinbox.
366 */
367 void TileDialog::on_row_spinbutton_changed()
368 {
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;
389 }
391 /**
392 * changed value in # of rows spinbox.
393 */
394 void TileDialog::on_col_spinbutton_changed()
395 {
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;
416 }
418 /**
419 * changed value in x padding spinbox.
420 */
421 void TileDialog::on_xpad_spinbutton_changed()
422 {
423 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
424 prefs->setDouble("/dialogs/gridtiler/XPad", XPadSpinner.get_value());
426 }
428 /**
429 * changed value in y padding spinbox.
430 */
431 void TileDialog::on_ypad_spinbutton_changed()
432 {
433 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
434 prefs->setDouble("/dialogs/gridtiler/YPad", YPadSpinner.get_value());
435 }
438 /**
439 * checked/unchecked autosize Rows button.
440 */
441 void TileDialog::on_RowSize_checkbutton_changed()
442 {
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());
450 }
452 /**
453 * checked/unchecked autosize Rows button.
454 */
455 void TileDialog::on_ColSize_checkbutton_changed()
456 {
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());
464 }
466 /**
467 * changed value in columns spinbox.
468 */
469 void TileDialog::on_rowSize_spinbutton_changed()
470 {
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;
482 }
484 /**
485 * changed value in rows spinbox.
486 */
487 void TileDialog::on_colSize_spinbutton_changed()
488 {
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;
500 }
502 /**
503 * changed Radio button in Spacing group.
504 */
505 void TileDialog::Spacing_button_changed()
506 {
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());
515 }
517 /**
518 * changed Radio button in Vertical Align group.
519 */
520 void TileDialog::VertAlign_changed()
521 {
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 }
533 }
535 /**
536 * changed Radio button in Vertical Align group.
537 */
538 void TileDialog::HorizAlign_changed()
539 {
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 }
551 }
553 /**
554 * Desktop selection changed
555 */
556 void TileDialog::updateSelection()
557 {
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;
594 }
598 /*##########################
599 ## Experimental
600 ##########################*/
602 static void updateSelectionCallback(Inkscape::Application */*inkscape*/, Inkscape::Selection */*selection*/, TileDialog *dlg)
603 {
604 TileDialog *tledlg = (TileDialog *) dlg;
605 tledlg->updateSelection();
606 }
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)
617 {
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(" × ");
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();
873 }
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:fileencoding=utf-8:textwidth=99 :