Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
grid-arrange-tab.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * A simple dialog for creating grid type arrangements of selected objects
4 *
5 * Authors:
6 * Bob Jamison ( based off trace dialog)
7 * John Cliff
8 * Other dudes from The Inkscape Organization
9 * Abhishek Sharma
10 * Declara Denis
11 *
12 * Copyright (C) 2004 Bob Jamison
13 * Copyright (C) 2004 John Cliff
14 *
15 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
16 */
17
18//#define DEBUG_GRID_ARRANGE 1
19
20#include "grid-arrange-tab.h"
21
22#include <algorithm>
23#include <iterator>
24#include <numeric>
25#include <vector>
26
27#include <glibmm/i18n.h>
28#include <gtkmm/grid.h>
29#include <gtkmm/sizegroup.h>
30#include <sigc++/functors/mem_fun.h>
31
32#include <2geom/transforms.h>
33
34#include "desktop.h"
35#include "document-undo.h"
36#include "document.h"
37#include "inkscape.h"
38#include "preferences.h"
39#include "selection.h"
40#include "object/object-set.h"
41#include "ui/icon-names.h"
42#include "ui/pack.h"
43#include "ui/dialog/tile.h" // for Inkscape::UI::Dialog::ArrangeDialog
44
53static std::vector<SPItem *> grid_item_sort(Inkscape::ObjectSet *items)
54{
55 std::vector<SPItem *> results;
57
58 // 1. Find middle Y position of the largest top object.
59 double box_top = items->visualBounds()->min()[Geom::Y];
60 double last_height = 0.0;
61 double target = box_top;
62 for (auto item : items->items()) {
63 if (auto item_box = item->desktopVisualBounds()) {
64 if (Geom::are_near(item_box->min()[Geom::Y], box_top, 2.0)) {
65 if (item_box->height() > last_height) {
66 last_height = item_box->height();
67 target = item_box->midpoint()[Geom::Y];
68 }
69 }
70 }
71 }
72
73 // 2. Loop through all remaining items
74 for (auto item : items->items()) {
75 // Items without visual bounds are completely ignored.
76 if (auto item_box = item->desktopVisualBounds()) {
77 auto radius = item_box->height() / 2;
78 auto min = item_box->midpoint()[Geom::Y] - radius;
79 auto max = item_box->midpoint()[Geom::Y] + radius;
80
81 if (max > target && min < target) {
82 // 2a. if the item's radius falls on the Y position above
83 results.push_back(item);
84 } else {
85 // 2b. Save items not in this row for later
86 rest.add(item);
87 }
88 }
89 }
90
91 // 3. Sort this single row according to the X position
92 std::sort(results.begin(), results.end(), [](SPItem *a, SPItem *b) {
93 // These boxes always exist because of the above filtering.
94 return (a->desktopVisualBounds()->min()[Geom::X] < b->desktopVisualBounds()->min()[Geom::X]);
95 });
96
97 if (results.size() == 0) {
98 g_warning("Bad grid detection when sorting items!");
99 } else if (!rest.isEmpty()) {
100 // 4. If there's any remaining, run this function again.
101 auto sorted_rest = grid_item_sort(&rest);
102 results.reserve(items->size());
103 results.insert(results.end(), sorted_rest.begin(), sorted_rest.end());
104 }
105 return results;
106}
107
108namespace Inkscape::UI::Dialog {
109
110//#########################################################################
111//## E V E N T S
112//#########################################################################
113
114/*
115 *
116 * This arranges the selection in a grid pattern.
117 *
118 */
120{
121 // set padding to manual values
122 double paddingx = XPadding.getValue("px");
123 double paddingy = YPadding.getValue("px");
124 int NoOfCols = NoOfColsSpinner.get_value_as_int();
125 int NoOfRows = NoOfRowsSpinner.get_value_as_int();
126
130 if (!selection || selection->isEmpty()) return;
131
132 auto sel_box = selection->documentBounds(SPItem::VISUAL_BBOX);
133 if (sel_box.empty()) return;
134 double grid_left = sel_box->min()[Geom::X];
135 double grid_top = sel_box->min()[Geom::Y];
136
137 // require the sorting done before we can calculate row heights etc.
138 auto sorted = grid_item_sort(selection);
139
140 if (NoOfRows * NoOfCols < sorted.size()) {
141 NoOfRows = (sorted.size() + NoOfCols - 1) / NoOfCols;
143 NoOfRowsSpinner.set_value(NoOfRows);
144 _rows_changed_connection.unblock();
145 }
146
147 // Calculate individual Row and Column sizes if necessary
148 auto row_heights = std::vector<double>(NoOfRows, 0.0);
149 auto col_widths = std::vector<double>(NoOfCols, 0.0);
150 for(int i = 0; i < sorted.size(); i++) {
151 if (Geom::OptRect box = sorted[i]->documentVisualBounds()) {
152 double width = box->dimensions()[Geom::X];
153 double height = box->dimensions()[Geom::Y];
154 if (width > col_widths[(i % NoOfCols)]) {
155 col_widths[(i % NoOfCols)] = width;
156 }
157 if (height > row_heights[(i / NoOfCols)]) {
158 row_heights[(i / NoOfCols)] = height;
159 }
160 }
161 }
162
163 double col_width = *std::max_element(std::begin(col_widths), std::end(col_widths));
164 double row_height = *std::max_element(std::begin(row_heights), std::end(row_heights));
165
167 if (RowHeightButton.get_active()){
168 grid_top = grid_top - (((row_height - row_heights[0]) / 2)*(VertAlign));
169 }
170 if (ColumnWidthButton.get_active()){
171 grid_left = grid_left - (((col_width - col_widths[0]) /2)*(HorizAlign));
172 }
173
174 // Calculate total widths and heights, allowing for columns and rows non uniformly sized.
175 double last_col_padding = 0.0;
176 double total_col_width = 0.0;
177 if (ColumnWidthButton.get_active()){
178 total_col_width = col_width * NoOfCols;
179 // Remember the amount of padding the box will lose on the right side
180 last_col_padding = (col_width - col_widths[NoOfCols-1]) / 2;
181 std::fill(col_widths.begin(), col_widths.end(), col_width);
182 } else {
183 total_col_width = std::accumulate(col_widths.begin(), col_widths.end(), 0);
184 }
185
186 double last_row_padding = 0.0;
187 double total_row_height = 0.0;
188 if (RowHeightButton.get_active()){
189 total_row_height = row_height * NoOfRows;
190 // Remember the amount of padding the box will lose on the bottom side
191 last_row_padding = (row_height - row_heights[NoOfRows-1]) / 2;
192 std::fill(row_heights.begin(), row_heights.end(), row_height);
193 } else {
194 total_row_height = std::accumulate(row_heights.begin(), row_heights.end(), 0);
195 }
196
197 // Fit to bbox, calculate padding between rows accordingly.
198 if (SpaceByBBoxRadioButton.get_active()) {
199 paddingx = (sel_box->width() - total_col_width + last_col_padding) / (NoOfCols -1);
200 paddingy = (sel_box->height() - total_row_height + last_row_padding) / (NoOfRows -1);
201 }
202
203 /*
204 Horizontal align - Left = 0
205 Centre = 1
206 Right = 2
207
208 Vertical align - Top = 0
209 Middle = 1
210 Bottom = 2
211
212 X position is calculated by taking the grids left co-ord, adding the distance to the column,
213 then adding 1/2 the spacing multiplied by the align variable above,
214 Y position likewise, takes the top of the grid, adds the y to the current row then adds the padding in to align it.
215 */
216
217 // Calculate row and column x and y coords required to allow for columns and rows which are non uniformly sized.
218 std::vector<double> col_xs(NoOfCols);
219 for (int col=1; col < NoOfCols; col++) {
220 col_xs[col] = col_widths[col - 1] + paddingx + col_xs[col - 1];
221 }
222
223 std::vector<double> row_ys(NoOfRows);
224 for (int row=1; row < NoOfRows; row++) {
225 row_ys[row] = row_heights[row - 1] + paddingy + row_ys[row - 1];
226 }
227
228 int cnt = 0;
229 std::vector<SPItem*>::iterator it = sorted.begin();
230 for (int row_cnt=0; ((it != sorted.end()) && (row_cnt<NoOfRows)); ++row_cnt) {
231 std::vector<SPItem *> current_row;
232 int col_cnt = 0;
233 for(;it!=sorted.end()&&col_cnt<NoOfCols;++it) {
234 current_row.push_back(*it);
235 col_cnt++;
236 }
237
238 for (auto item:current_row) {
239 auto min = Geom::Point(0, 0);
240 double width = 0, height = 0;
241 if (auto vbox = item->documentVisualBounds()) {
242 width = vbox->dimensions()[Geom::X];
243 height = vbox->dimensions()[Geom::Y];
244 min = vbox->min();
245 }
246
247 int row = cnt / NoOfCols;
248 int col = cnt % NoOfCols;
249
250 double new_x = grid_left + (((col_widths[col] - width)/2)*HorizAlign) + col_xs[col];
251 double new_y = grid_top + (((row_heights[row] - height)/2)*VertAlign) + row_ys[row];
252
253 Geom::Point move = Geom::Point(new_x, new_y) - min;
254 Geom::Affine const affine = Geom::Affine(Geom::Translate(move));
257 item->updateRepr();
258 cnt +=1;
259 }
260 }
261
262 DocumentUndo::done(desktop->getDocument(), _("Arrange in a grid"), INKSCAPE_ICON("dialog-align-and-distribute"));
263}
264
265//#########################################################################
266//## E V E N T S
267//#########################################################################
268
273{
275 Inkscape::Selection *selection = desktop ? desktop->getSelection() : nullptr;
276 if (!selection) return;
277
278 int selcount = (int) boost::distance(selection->items());
279 if (selcount == 0) {
280 return;
281 }
282
283 double NoOfRows = ceil(selcount / NoOfColsSpinner.get_value());
284
286 NoOfRowsSpinner.set_value(NoOfRows);
287 _rows_changed_connection.unblock();
288}
289
294{
296 Inkscape::Selection *selection = desktop ? desktop->getSelection() : nullptr;
297 if (!selection) return;
298
299 int selcount = (int) boost::distance(selection->items());
300 if (selcount == 0) {
301 return;
302 }
303
304 double NoOfCols = ceil(selcount / NoOfRowsSpinner.get_value());
305
307 NoOfColsSpinner.set_value(NoOfCols);
308 _cols_changed_connection.unblock();
309}
310
315{
317 prefs->setDouble("/dialogs/gridtiler/XPad", XPadding.getValue("px"));
318
319}
320
325{
327 prefs->setDouble("/dialogs/gridtiler/YPad", YPadding.getValue("px"));
328}
329
334{
336 if (RowHeightButton.get_active()) {
337 prefs->setDouble("/dialogs/gridtiler/AutoRowSize", 20);
338 } else {
339 prefs->setDouble("/dialogs/gridtiler/AutoRowSize", -20);
340 }
341 RowHeightBox.set_sensitive ( !RowHeightButton.get_active());
342}
343
348{
350 if (ColumnWidthButton.get_active()) {
351 prefs->setDouble("/dialogs/gridtiler/AutoColSize", 20);
352 } else {
353 prefs->setDouble("/dialogs/gridtiler/AutoColSize", -20);
354 }
355 ColumnWidthBox.set_sensitive ( !ColumnWidthButton.get_active());
356}
357
362{
363 // quit if run by the attr_changed listener
364 if (updating) {
365 return;
366 }
367
368 // in turn, prevent listener from responding
369 updating = true;
371 prefs->setDouble("/dialogs/gridtiler/RowHeight", RowHeightSpinner.get_value());
372 updating=false;
373
374}
375
380{
381 // quit if run by the attr_changed listener
382 if (updating) {
383 return;
384 }
385
386 // in turn, prevent listener from responding
387 updating = true;
389 prefs->setDouble("/dialogs/gridtiler/ColWidth", ColumnWidthSpinner.get_value());
390 updating=false;
391
392}
393
398{
400 if (SpaceManualRadioButton.get_active()) {
401 prefs->setDouble("/dialogs/gridtiler/SpacingType", 20);
402 } else {
403 prefs->setDouble("/dialogs/gridtiler/SpacingType", -20);
404 }
405
406 XPadding.set_sensitive ( SpaceManualRadioButton.get_active());
407 YPadding.set_sensitive ( SpaceManualRadioButton.get_active());
408}
409
414{
416 VertAlign = AlignmentSelector.getVerticalAlignment();
417 prefs->setInt("/dialogs/gridtiler/VertAlign", VertAlign);
418 HorizAlign = AlignmentSelector.getHorizontalAlignment();
419 prefs->setInt("/dialogs/gridtiler/HorizAlign", HorizAlign);
420}
421
426{
427 // quit if run by the attr_changed listener
428 if (updating) {
429 return;
430 }
431
432 // in turn, prevent listener from responding
433 updating = true;
435 Inkscape::Selection *selection = desktop ? desktop->getSelection() : nullptr;
436 std::vector<SPItem*> items;
437 if (selection) {
438 items.insert(items.end(), selection->items().begin(), selection->items().end());
439 }
440
441 if (!items.empty()) {
442 int selcount = items.size();
443
444 if (NoOfColsSpinner.get_value() > 1 && NoOfRowsSpinner.get_value() > 1){
445 // Update the number of rows assuming number of columns wanted remains same.
446 double NoOfRows = ceil(selcount / NoOfColsSpinner.get_value());
447 NoOfRowsSpinner.set_value(NoOfRows);
448
449 // if the selection has less than the number set for one row, reduce it appropriately
450 if (selcount < NoOfColsSpinner.get_value()) {
451 double NoOfCols = ceil(selcount / NoOfRowsSpinner.get_value());
452 NoOfColsSpinner.set_value(NoOfCols);
453 }
454 } else {
455 double PerRow = ceil(sqrt(selcount));
456 double PerCol = ceil(sqrt(selcount));
457 NoOfRowsSpinner.set_value(PerRow);
458 NoOfColsSpinner.set_value(PerCol);
459 }
460 }
461
462 updating = false;
463}
464
466{
468
469 if (desktop) {
471
472 _selection_changed_connection = INKSCAPE.signal_selection_changed.connect(
473 sigc::hide<0>(sigc::mem_fun(*this, &GridArrangeTab::updateSelection)));
474 }
475}
476
477//#########################################################################
478//## C O N S T R U C T O R / D E S T R U C T O R
479//#########################################################################
484 : Parent(parent),
485 XPadding{_("X:"), _("Horizontal spacing between columns"), UNIT_TYPE_LINEAR, "object-columns", &PaddingUnitMenu},
486 YPadding(_("Y:"), _("Vertical spacing between rows"), XPadding, "object-rows"),
487 PaddingTable(Gtk::make_managed<Gtk::Grid>())
488{
489 // bool used by spin button callbacks to stop loops where they change each other.
490 updating = false;
492
493 auto _col1 = Gtk::SizeGroup::create(Gtk::SizeGroup::Mode::HORIZONTAL);
494 auto _col2 = Gtk::SizeGroup::create(Gtk::SizeGroup::Mode::HORIZONTAL);
495 auto _col3 = Gtk::SizeGroup::create(Gtk::SizeGroup::Mode::HORIZONTAL);
496
497 Gtk::Box *contents = this;
498 set_valign(Gtk::Align::START);
499
500#define MARGIN 2
501
502 //##Set up the panel
503
504 NoOfRowsLabel.set_text_with_mnemonic(_("_Rows:"));
505 NoOfRowsLabel.set_mnemonic_widget(NoOfRowsSpinner);
506 NoOfRowsBox.set_orientation(Gtk::Orientation::VERTICAL);
507 UI::pack_start(NoOfRowsBox, NoOfRowsLabel, false, false, MARGIN);
508
509 NoOfRowsSpinner.set_digits(0);
510 NoOfRowsSpinner.set_increments(1, 0);
511 NoOfRowsSpinner.set_range(1.0, 10000.0);
512 _rows_changed_connection = NoOfRowsSpinner.signal_value_changed().connect(
513 sigc::mem_fun(*this, &GridArrangeTab::on_row_spinbutton_changed));
514 NoOfRowsSpinner.set_tooltip_text(_("Number of rows"));
515 UI::pack_start(NoOfRowsBox, NoOfRowsSpinner, false, false, MARGIN);
516 _col1->add_widget(NoOfRowsBox);
517
518 RowHeightButton.set_label(_("Equal _height"));
519 RowHeightButton.set_use_underline(true);
520 double AutoRow = prefs->getDouble("/dialogs/gridtiler/AutoRowSize", 15);
521 if (AutoRow>0)
522 AutoRowSize=true;
523 else
524 AutoRowSize=false;
525 RowHeightButton.set_active(AutoRowSize);
526
527 UI::pack_start(NoOfRowsBox, RowHeightButton, false, false, MARGIN);
528
529 RowHeightButton.set_tooltip_text(_("If not set, each row has the height of the tallest object in it"));
530 RowHeightButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::on_RowSize_checkbutton_changed));
531
532 UI::pack_start(SpinsHBox, NoOfRowsBox, false, false, MARGIN);
533
534 /*#### Label for X ####*/
535 XByYLabel.set_markup("<span size='larger'> &#215; </span>");
536 XByYLabel.set_valign(Gtk::Align::CENTER);
537 UI::pack_start(SpinsHBox, XByYLabel, false, false, MARGIN);
538 _col2->add_widget(XByYLabel);
539
540 /*#### Number of columns ####*/
541
542 NoOfColsLabel.set_text_with_mnemonic(_("_Columns:"));
543 NoOfColsLabel.set_mnemonic_widget(NoOfColsSpinner);
544 NoOfColsBox.set_orientation(Gtk::Orientation::VERTICAL);
545 UI::pack_start(NoOfColsBox, NoOfColsLabel, false, false, MARGIN);
546
547 NoOfColsSpinner.set_digits(0);
548 NoOfColsSpinner.set_increments(1, 0);
549 NoOfColsSpinner.set_range(1.0, 10000.0);
550 _cols_changed_connection = NoOfColsSpinner.signal_value_changed().connect(
551 sigc::mem_fun(*this, &GridArrangeTab::on_col_spinbutton_changed));
552 NoOfColsSpinner.set_tooltip_text(_("Number of columns"));
553 UI::pack_start(NoOfColsBox, NoOfColsSpinner, false, false, MARGIN);
554 _col3->add_widget(NoOfColsBox);
555
556 ColumnWidthButton.set_label(_("Equal _width"));
557 ColumnWidthButton.set_use_underline(true);
558 double AutoCol = prefs->getDouble("/dialogs/gridtiler/AutoColSize", 15);
559 if (AutoCol>0)
560 AutoColSize=true;
561 else
562 AutoColSize=false;
563 ColumnWidthButton.set_active(AutoColSize);
564 UI::pack_start(NoOfColsBox, ColumnWidthButton, false, false, MARGIN);
565
566 ColumnWidthButton.set_tooltip_text(_("If not set, each column has the width of the widest object in it"));
567 ColumnWidthButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::on_ColSize_checkbutton_changed));
568
569 UI::pack_start(SpinsHBox, NoOfColsBox, false, false, MARGIN);
570
571 TileBox.set_orientation(Gtk::Orientation::VERTICAL);
572 UI::pack_start(TileBox, SpinsHBox, false, false, MARGIN);
573
574 VertAlign = prefs->getInt("/dialogs/gridtiler/VertAlign", 1);
575 HorizAlign = prefs->getInt("/dialogs/gridtiler/HorizAlign", 1);
576
577 // Anchor selection widget
578 AlignLabel.set_markup(_("<b>Alignment:</b>"));
579 AlignLabel.set_margin_top(8);
580 AlignLabel.set_halign(Gtk::Align::START);
581 AlignLabel.set_valign(Gtk::Align::CENTER);
582 AlignmentSelector.set_margin_start(16);
583 AlignmentSelector.set_halign(Gtk::Align::START);
585 AlignmentSelector.connectSelectionChanged(sigc::mem_fun(*this, &GridArrangeTab::Align_changed));
586 UI::pack_start(TileBox, AlignLabel, false, false, MARGIN);
588
589 {
590 /*#### Radio buttons to control spacing manually or to fit selection bbox ####*/
591 SpaceByBBoxRadioButton.set_label(_("_Fit into selection box"));
592 SpaceByBBoxRadioButton.set_use_underline (true);
593 SpaceByBBoxRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::Spacing_button_changed));
594
595 UI::pack_start(SpacingVBox, SpaceByBBoxRadioButton, false, false, MARGIN);
596
597 SpaceManualRadioButton.set_label(_("_Set spacing:"));
598 SpaceManualRadioButton.set_use_underline (true);
600 SpaceManualRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::Spacing_button_changed));
601 UI::pack_start(SpacingVBox, SpaceManualRadioButton, false, false, MARGIN);
602
603 UI::pack_start(TileBox, SpacingVBox, false, false, MARGIN);
604 }
605
606 {
607 /*#### Padding ####*/
608 PaddingUnitMenu.setUnitType(UNIT_TYPE_LINEAR);
610
612 YPadding.setIncrements(0.2, 0);
613 YPadding.setRange(-10000, 10000);
614 double yPad = prefs->getDouble("/dialogs/gridtiler/YPad", 15);
615 YPadding.setValue(yPad, "px");
617
619 XPadding.setIncrements(0.2, 0);
620 XPadding.setRange(-10000, 10000);
621 double xPad = prefs->getDouble("/dialogs/gridtiler/XPad", 15);
622 XPadding.setValue(xPad, "px");
623
625 }
626
627 PaddingTable->set_margin(MARGIN);
628 PaddingTable->set_row_spacing(MARGIN);
629 PaddingTable->set_column_spacing(MARGIN);
630 PaddingTable->attach(XPadding, 0, 0, 1, 1);
631 PaddingTable->attach(PaddingUnitMenu, 1, 0, 1, 1);
632 PaddingTable->attach(YPadding, 0, 1, 1, 1);
633
634 UI::pack_start(TileBox, *PaddingTable, false, false, MARGIN);
635
636 contents->set_margin(8);
637 UI::pack_start(*contents, TileBox);
638
639 double SpacingType = prefs->getDouble("/dialogs/gridtiler/SpacingType", 15);
640 if (SpacingType>0) {
641 ManualSpacing=true;
642 } else {
643 ManualSpacing=false;
644 }
647 XPadding.set_sensitive (ManualSpacing);
648 YPadding.set_sensitive (ManualSpacing);
649}
650
654
655} // namespace Inkscape::UI::Dialog
656
657/*
658 Local Variables:
659 mode:c++
660 c-file-style:"stroustrup"
661 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
662 indent-tabs-mode:nil
663 fill-column:99
664 End:
665*/
666// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
3x3 matrix representing an affine transformation.
Definition affine.h:70
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Two-dimensional point that doubles as a vector.
Definition point.h:66
Translation by a vector.
Definition transforms.h:115
static void done(SPDocument *document, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
SPItemRange items()
Returns a range of selected SPItems.
Definition object-set.h:255
bool add(SPObject *object, bool nosignal=false)
Add an SPObject to the set of selected objects.
bool isEmpty()
Returns true if no items are selected.
Geom::OptRect documentBounds(SPItem::BBoxType type) const
int size()
Returns size of the selection.
Geom::OptRect visualBounds() const
Preference storage class.
Definition preferences.h:61
double getDouble(Glib::ustring const &pref_path, double def=0.0, Glib::ustring const &unit="")
Retrieve a floating point value.
static Preferences * get()
Access the singleton Preferences object.
int getInt(Glib::ustring const &pref_path, int def=0)
Retrieve an integer.
void setDouble(Glib::ustring const &pref_path, double value)
Set a floating point value.
void setInt(Glib::ustring const &pref_path, int value)
Set an integer value.
The set of selected SPObjects for a given document and layer model.
Definition selection.h:80
SPDesktop * getDesktop() const
Definition dialog-base.h:79
void arrange() override
Do the actual work.
Inkscape::UI::Widget::SpinButton NoOfColsSpinner
void on_colSize_spinbutton_changed()
changed value in rows spinbox.
Inkscape::UI::Widget::SpinButton NoOfRowsSpinner
void updateSelection()
Respond to selection change.
void Spacing_button_changed()
changed Radio button in Spacing group.
Inkscape::UI::Widget::UnitMenu PaddingUnitMenu
Inkscape::UI::Widget::ScalarUnit YPadding
GridArrangeTab(ArrangeDialog *parent)
Constructor.
void on_ypad_spinbutton_changed()
changed value in y padding spinbox.
void on_RowSize_checkbutton_changed()
checked/unchecked autosize Rows button.
void on_xpad_spinbutton_changed()
changed value in x padding spinbox.
void on_col_spinbutton_changed()
changed value in # of columns spinbox.
void on_ColSize_checkbutton_changed()
checked/unchecked autosize Rows button.
Inkscape::UI::Widget::SpinButton RowHeightSpinner
Inkscape::UI::Widget::SpinButton ColumnWidthSpinner
Inkscape::UI::Widget::ScalarUnit XPadding
void on_rowSize_spinbutton_changed()
changed value in columns spinbox.
void on_row_spinbutton_changed()
changed value in # of rows spinbox.
void Align_changed()
changed Anchor selection widget.
void setValue(double number, Glib::ustring const &units)
Sets the number and unit system.
double getValue(Glib::ustring const &units) const
Returns the value in the given unit system.
void setIncrements(double step, double page)
Sets the step and page increments for the spin button.
Definition scalar.cpp:123
Glib::SignalProxy< void()> signal_value_changed()
Signal raised when the spin button's value changes.
Definition scalar.cpp:159
void setDigits(unsigned digits)
Sets the precision to be displayed by the spin button.
Definition scalar.cpp:94
void setRange(double min, double max)
Sets the minimum and maximum range allowed for the spin button.
Definition scalar.cpp:128
bool setUnit(Glib::ustring const &unit)
Sets the dropdown widget to the given unit abbreviation.
Definition unit-menu.cpp:75
bool setUnitType(UnitType unit_type, bool svg_length=false)
Adds the unit type to the widget.
Definition unit-menu.cpp:33
To do: update description of desktop.
Definition desktop.h:149
SPDocument * getDocument() const
Definition desktop.h:189
Inkscape::Selection * getSelection() const
Definition desktop.h:188
const Geom::Affine & doc2dt() const
Document to desktop coordinate transformation.
Definition document.cpp:926
int ensureUpToDate(unsigned int object_modified_tag=0)
Repeatedly works on getting the document updated, since sometimes it takes more than one pass to get ...
Base class for visual SVG elements.
Definition sp-item.h:109
void set_i2d_affine(Geom::Affine const &transform)
Definition sp-item.cpp:1843
Geom::OptRect documentVisualBounds() const
Get item's visual bbox in document coordinate system.
Definition sp-item.cpp:1034
Geom::Affine transform
Definition sp-item.h:138
Geom::OptRect desktopVisualBounds() const
Get item's visual bbox in desktop coordinate system.
Definition sp-item.cpp:1065
@ VISUAL_BBOX
Definition sp-item.h:118
Geom::Affine i2doc_affine() const
Returns the accumulated transformation of the item and all its ancestors, including root's viewport.
Definition sp-item.cpp:1832
void doWriteTransform(Geom::Affine const &transform, Geom::Affine const *adv=nullptr, bool compensate=true)
Set a new transform on an object.
Definition sp-item.cpp:1674
SPDocument * document
Definition sp-object.h:188
Inkscape::XML::Node * updateRepr(unsigned int flags=SP_OBJECT_WRITE_EXT)
Updates the object's repr based on the object's state.
Editable view implementation.
static char const *const parent
Definition dir-util.cpp:70
TODO: insert short description here.
static std::vector< SPItem * > grid_item_sort(Inkscape::ObjectSet *items)
Sort ObjectSet by an existing grid arrangement.
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
Macro for icon names used in Inkscape.
SPItem * item
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
Definition desktop.h:50
Dialog code.
Definition desktop.h:117
static constexpr int height
void pack_start(Gtk::Box &box, Gtk::Widget &child, bool const expand, bool const fill, unsigned const padding)
Adds child to box, packed with reference to the start of box.
Definition pack.cpp:141
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
Singleton class to access the preferences file in a convenient way.
GList * items
SPDesktop * desktop
double width
Affine transformation classes.
Dialog for creating grid type arrangements of selected objects.