27#include <glibmm/i18n.h>
28#include <gtkmm/grid.h>
29#include <gtkmm/sizegroup.h>
30#include <sigc++/functors/mem_fun.h>
55 std::vector<SPItem *> results;
60 double last_height = 0.0;
61 double target = box_top;
65 if (item_box->height() > last_height) {
66 last_height = item_box->height();
67 target = item_box->midpoint()[
Geom::Y];
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;
81 if (max > target && min < target) {
83 results.push_back(
item);
92 std::sort(results.begin(), results.end(), [](
SPItem *a,
SPItem *b) {
94 return (a->desktopVisualBounds()->min()[Geom::X] < b->desktopVisualBounds()->min()[Geom::X]);
97 if (results.size() == 0) {
98 g_warning(
"Bad grid detection when sorting items!");
102 results.reserve(
items->size());
103 results.insert(results.end(), sorted_rest.begin(), sorted_rest.end());
130 if (!selection || selection->
isEmpty())
return;
133 if (sel_box.empty())
return;
134 double grid_left = sel_box->min()[
Geom::X];
135 double grid_top = sel_box->min()[
Geom::Y];
140 if (NoOfRows * NoOfCols < sorted.size()) {
141 NoOfRows = (sorted.size() + NoOfCols - 1) / NoOfCols;
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++) {
154 if (
width > col_widths[(i % NoOfCols)]) {
155 col_widths[(i % NoOfCols)] =
width;
157 if (
height > row_heights[(i / NoOfCols)]) {
158 row_heights[(i / NoOfCols)] =
height;
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));
168 grid_top = grid_top - (((row_height - row_heights[0]) / 2)*(
VertAlign));
171 grid_left = grid_left - (((col_width - col_widths[0]) /2)*(
HorizAlign));
175 double last_col_padding = 0.0;
176 double total_col_width = 0.0;
178 total_col_width = col_width * NoOfCols;
180 last_col_padding = (col_width - col_widths[NoOfCols-1]) / 2;
181 std::fill(col_widths.begin(), col_widths.end(), col_width);
183 total_col_width = std::accumulate(col_widths.begin(), col_widths.end(), 0);
186 double last_row_padding = 0.0;
187 double total_row_height = 0.0;
189 total_row_height = row_height * NoOfRows;
191 last_row_padding = (row_height - row_heights[NoOfRows-1]) / 2;
192 std::fill(row_heights.begin(), row_heights.end(), row_height);
194 total_row_height = std::accumulate(row_heights.begin(), row_heights.end(), 0);
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);
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];
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];
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;
233 for(;it!=sorted.end()&&col_cnt<NoOfCols;++it) {
234 current_row.push_back(*it);
238 for (
auto item:current_row) {
247 int row = cnt / NoOfCols;
248 int col = cnt % NoOfCols;
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];
276 if (!selection)
return;
278 int selcount = (int) boost::distance(selection->
items());
297 if (!selection)
return;
299 int selcount = (int) boost::distance(selection->
items());
337 prefs->
setDouble(
"/dialogs/gridtiler/AutoRowSize", 20);
339 prefs->
setDouble(
"/dialogs/gridtiler/AutoRowSize", -20);
351 prefs->
setDouble(
"/dialogs/gridtiler/AutoColSize", 20);
353 prefs->
setDouble(
"/dialogs/gridtiler/AutoColSize", -20);
401 prefs->
setDouble(
"/dialogs/gridtiler/SpacingType", 20);
403 prefs->
setDouble(
"/dialogs/gridtiler/SpacingType", -20);
436 std::vector<SPItem*>
items;
441 if (!
items.empty()) {
455 double PerRow = ceil(sqrt(selcount));
456 double PerCol = ceil(sqrt(selcount));
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>())
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);
497 Gtk::Box *contents =
this;
498 set_valign(Gtk::Align::START);
506 NoOfRowsBox.set_orientation(Gtk::Orientation::VERTICAL);
520 double AutoRow = prefs->
getDouble(
"/dialogs/gridtiler/AutoRowSize", 15);
529 RowHeightButton.set_tooltip_text(_(
"If not set, each row has the height of the tallest object in it"));
535 XByYLabel.set_markup(
"<span size='larger'> × </span>");
536 XByYLabel.set_valign(Gtk::Align::CENTER);
544 NoOfColsBox.set_orientation(Gtk::Orientation::VERTICAL);
558 double AutoCol = prefs->
getDouble(
"/dialogs/gridtiler/AutoColSize", 15);
566 ColumnWidthButton.set_tooltip_text(_(
"If not set, each column has the width of the widest object in it"));
571 TileBox.set_orientation(Gtk::Orientation::VERTICAL);
578 AlignLabel.set_markup(_(
"<b>Alignment:</b>"));
614 double yPad = prefs->
getDouble(
"/dialogs/gridtiler/YPad", 15);
621 double xPad = prefs->
getDouble(
"/dialogs/gridtiler/XPad", 15);
636 contents->set_margin(8);
639 double SpacingType = prefs->
getDouble(
"/dialogs/gridtiler/SpacingType", 15);
3x3 matrix representing an affine transformation.
Axis-aligned rectangle that can be empty.
Two-dimensional point that doubles as a vector.
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.
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.
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.
SPDesktop * getDesktop() const
sigc::connection _cols_changed_connection
void arrange() override
Do the actual work.
Inkscape::UI::Widget::SpinButton NoOfColsSpinner
void on_colSize_spinbutton_changed()
changed value in rows spinbox.
Gtk::CheckButton SpaceByBBoxRadioButton
Gtk::CheckButton RowHeightButton
Inkscape::UI::Widget::SpinButton NoOfRowsSpinner
void updateSelection()
Respond to selection change.
Gtk::CheckButton SpaceManualRadioButton
sigc::connection _rows_changed_connection
void Spacing_button_changed()
changed Radio button in Spacing group.
Inkscape::UI::Widget::UnitMenu PaddingUnitMenu
Inkscape::UI::Widget::ScalarUnit YPadding
sigc::connection _selection_changed_connection
~GridArrangeTab() override
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 setDesktop(SPDesktop *)
void on_row_spinbutton_changed()
changed value in # of rows spinbox.
void Align_changed()
changed Anchor selection widget.
Gtk::CheckButton ColumnWidthButton
To do: update description of desktop.
SPDocument * getDocument() const
Inkscape::Selection * getSelection() const
const Geom::Affine & doc2dt() const
Document to desktop coordinate transformation.
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.
void set_i2d_affine(Geom::Affine const &transform)
Geom::OptRect documentVisualBounds() const
Get item's visual bbox in document coordinate system.
Geom::OptRect desktopVisualBounds() const
Get item's visual bbox in desktop coordinate system.
Geom::Affine i2doc_affine() const
Returns the accumulated transformation of the item and all its ancestors, including root's viewport.
void doWriteTransform(Geom::Affine const &transform, Geom::Affine const *adv=nullptr, bool compensate=true)
Set a new transform on an object.
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
TODO: insert short description here.
static std::vector< SPItem * > grid_item_sort(Inkscape::ObjectSet *items)
Sort ObjectSet by an existing grid arrangement.
Macro for icon names used in Inkscape.
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
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.
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
Singleton class to access the preferences file in a convenient way.
Dialog for creating grid type arrangements of selected objects.