summaryrefslogtreecommitdiffstats
path: root/src/ui/dialog/grid-arrange-tab.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:24:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:24:48 +0000
commitcca66b9ec4e494c1d919bff0f71a820d8afab1fa (patch)
tree146f39ded1c938019e1ed42d30923c2ac9e86789 /src/ui/dialog/grid-arrange-tab.cpp
parentInitial commit. (diff)
downloadinkscape-upstream/1.2.2.tar.xz
inkscape-upstream/1.2.2.zip
Adding upstream version 1.2.2.upstream/1.2.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/ui/dialog/grid-arrange-tab.cpp659
1 files changed, 659 insertions, 0 deletions
diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp
new file mode 100644
index 0000000..a0508bc
--- /dev/null
+++ b/src/ui/dialog/grid-arrange-tab.cpp
@@ -0,0 +1,659 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * A simple dialog for creating grid type arrangements of selected objects
+ *
+ * Authors:
+ * Bob Jamison ( based off trace dialog)
+ * John Cliff
+ * Other dudes from The Inkscape Organization
+ * Abhishek Sharma
+ * Declara Denis
+ *
+ * Copyright (C) 2004 Bob Jamison
+ * Copyright (C) 2004 John Cliff
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+//#define DEBUG_GRID_ARRANGE 1
+
+#include "ui/dialog/grid-arrange-tab.h"
+#include <numeric>
+#include <glibmm/i18n.h>
+
+#include <gtkmm/grid.h>
+#include <gtkmm/sizegroup.h>
+
+#include <2geom/transforms.h>
+
+#include "preferences.h"
+#include "inkscape.h"
+
+#include "document.h"
+#include "document-undo.h"
+#include "desktop.h"
+
+#include "ui/icon-names.h"
+#include "ui/dialog/tile.h" // for Inkscape::UI::Dialog::ArrangeDialog
+
+
+/**
+ * Sort ObjectSet by an existing grid arrangement
+ *
+ * This is based on this paper here: DOI:10.1049/iet-ipr.2015.0126
+ *
+ * @param items - The unsorted object set to sort.
+ * @returns a new grid-sorted std::vector of SPItems.
+ */
+static std::vector<SPItem *> grid_item_sort(Inkscape::ObjectSet *items)
+{
+ std::vector<SPItem *> results;
+ Inkscape::ObjectSet rest;
+
+ // 1. Find middle Y position of the largest top object.
+ double box_top = items->visualBounds()->min()[Geom::Y];
+ double last_height = 0.0;
+ double target = box_top;
+ for (auto item : items->items()) {
+ if (auto item_box = item->desktopVisualBounds()) {
+ if (Geom::are_near(item_box->min()[Geom::Y], box_top, 2.0)) {
+ if (item_box->height() > last_height) {
+ last_height = item_box->height();
+ target = item_box->midpoint()[Geom::Y];
+ }
+ }
+ }
+ }
+
+ // 2. Loop through all remaining items
+ for (auto item : items->items()) {
+ // Items without visual bounds are completely ignored.
+ if (auto item_box = item->desktopVisualBounds()) {
+ auto radius = item_box->height() / 2;
+ auto min = item_box->midpoint()[Geom::Y] - radius;
+ auto max = item_box->midpoint()[Geom::Y] + radius;
+
+ if (max > target && min < target) {
+ // 2a. if the item's radius falls on the Y position above
+ results.push_back(item);
+ } else {
+ // 2b. Save items not in this row for later
+ rest.add(item);
+ }
+ }
+ }
+
+ // 3. Sort this single row according to the X position
+ std::sort(results.begin(), results.end(), [](SPItem *a, SPItem *b) {
+ // These boxes always exist because of the above filtering.
+ return (a->desktopVisualBounds()->min()[Geom::X] < b->desktopVisualBounds()->min()[Geom::X]);
+ });
+
+ if (results.size() == 0) {
+ g_warning("Bad grid detection when sorting items!");
+ } else if (!rest.isEmpty()) {
+ // 4. If there's any remaining, run this function again.
+ auto sorted_rest = grid_item_sort(&rest);
+ results.reserve(items->size());
+ results.insert(results.end(), sorted_rest.begin(), sorted_rest.end());
+ }
+ return results;
+}
+
+ namespace Inkscape {
+ namespace UI {
+ namespace Dialog {
+
+
+ //#########################################################################
+ //## E V E N T S
+ //#########################################################################
+
+ /*
+ *
+ * This arranges the selection in a grid pattern.
+ *
+ */
+
+ void GridArrangeTab::arrange()
+ {
+ // check for correct numbers in the row- and col-spinners
+ on_col_spinbutton_changed();
+ on_row_spinbutton_changed();
+
+ // set padding to manual values
+ double paddingx = XPadding.getValue("px");
+ double paddingy = YPadding.getValue("px");
+ int NoOfCols = NoOfColsSpinner.get_value_as_int();
+ int NoOfRows = NoOfRowsSpinner.get_value_as_int();
+
+ SPDesktop *desktop = Parent->getDesktop();
+ desktop->getDocument()->ensureUpToDate();
+ Inkscape::Selection *selection = desktop->getSelection();
+ if (!selection) return;
+
+ auto sel_box = selection->documentBounds(SPItem::VISUAL_BBOX);
+ double grid_left = sel_box->min()[Geom::X];
+ double grid_top = sel_box->min()[Geom::Y];
+
+ // require the sorting done before we can calculate row heights etc.
+ auto sorted = grid_item_sort(selection);
+
+ // Calculate individual Row and Column sizes if necessary
+ auto row_heights = std::vector<double>(NoOfRows, 0.0);
+ auto col_widths = std::vector<double>(NoOfCols, 0.0);
+ for(int i = 0; i < sorted.size(); i++) {
+ if (Geom::OptRect box = sorted[i]->documentVisualBounds()) {
+ double width = box->dimensions()[Geom::X];
+ double height = box->dimensions()[Geom::Y];
+ if (width > col_widths[(i % NoOfCols)]) {
+ col_widths[(i % NoOfCols)] = width;
+ }
+ if (height > row_heights[(i / NoOfCols)]) {
+ row_heights[(i / NoOfCols)] = height;
+ }
+ }
+ }
+
+ double col_width = *std::max_element(std::begin(col_widths), std::end(col_widths));
+ double row_height = *std::max_element(std::begin(row_heights), std::end(row_heights));
+
+ /// Make sure the top and left of the grid don't move by compensating for align values.
+ if (RowHeightButton.get_active()){
+ grid_top = grid_top - (((row_height - row_heights[0]) / 2)*(VertAlign));
+ }
+ if (ColumnWidthButton.get_active()){
+ grid_left = grid_left - (((col_width - col_widths[0]) /2)*(HorizAlign));
+ }
+
+ // Calculate total widths and heights, allowing for columns and rows non uniformly sized.
+ double last_col_padding = 0.0;
+ double total_col_width = 0.0;
+ if (ColumnWidthButton.get_active()){
+ total_col_width = col_width * NoOfCols;
+ // Remember the amount of padding the box will lose on the right side
+ last_col_padding = (col_width - col_widths[NoOfCols-1]) / 2;
+ std::fill(col_widths.begin(), col_widths.end(), col_width);
+ } else {
+ total_col_width = std::accumulate(col_widths.begin(), col_widths.end(), 0);
+ }
+
+ double last_row_padding = 0.0;
+ double total_row_height = 0.0;
+ if (RowHeightButton.get_active()){
+ total_row_height = row_height * NoOfRows;
+ // Remember the amount of padding the box will lose on the bottom side
+ last_row_padding = (row_height - row_heights[NoOfRows-1]) / 2;
+ std::fill(row_heights.begin(), row_heights.end(), row_height);
+ } else {
+ total_row_height = std::accumulate(row_heights.begin(), row_heights.end(), 0);
+ }
+
+ // Fit to bbox, calculate padding between rows accordingly.
+ if (SpaceByBBoxRadioButton.get_active()) {
+ paddingx = (sel_box->width() - total_col_width + last_col_padding) / (NoOfCols -1);
+ paddingy = (sel_box->height() - total_row_height + last_row_padding) / (NoOfRows -1);
+ }
+
+/*
+ Horizontal align - Left = 0
+ Centre = 1
+ Right = 2
+
+ Vertical align - Top = 0
+ Middle = 1
+ Bottom = 2
+
+ X position is calculated by taking the grids left co-ord, adding the distance to the column,
+ then adding 1/2 the spacing multiplied by the align variable above,
+ Y position likewise, takes the top of the grid, adds the y to the current row then adds the padding in to align it.
+
+*/
+
+ // Calculate row and column x and y coords required to allow for columns and rows which are non uniformly sized.
+ std::vector<double> col_xs = {0.0};
+ for (int col=1; col < NoOfCols; col++) {
+ col_xs.push_back(col_widths[col-1] + paddingx + col_xs[col-1]);
+ }
+
+ std::vector<double> row_ys = {0.0};
+ for (int row=1; row < NoOfRows; row++) {
+ row_ys.push_back(row_heights[row-1] + paddingy + row_ys[row-1]);
+ }
+
+ int cnt = 0;
+ std::vector<SPItem*>::iterator it = sorted.begin();
+ for (int row_cnt=0; ((it != sorted.end()) && (row_cnt<NoOfRows)); ++row_cnt) {
+
+ std::vector<SPItem *> current_row;
+ int col_cnt = 0;
+ for(;it!=sorted.end()&&col_cnt<NoOfCols;++it) {
+ current_row.push_back(*it);
+ col_cnt++;
+ }
+
+ for (auto item:current_row) {
+ auto min = Geom::Point(0, 0);
+ double width, height = 0;
+ if (auto vbox = item->documentVisualBounds()) {
+ width = vbox->dimensions()[Geom::X];
+ height = vbox->dimensions()[Geom::Y];
+ min = vbox->min();
+ }
+
+ int row = cnt / NoOfCols;
+ int col = cnt % NoOfCols;
+
+ double new_x = grid_left + (((col_widths[col] - width)/2)*HorizAlign) + col_xs[col];
+ double new_y = grid_top + (((row_heights[row] - height)/2)*VertAlign) + row_ys[row];
+
+ Geom::Point move = Geom::Point(new_x, new_y) - min;
+ Geom::Affine const affine = Geom::Affine(Geom::Translate(move));
+ item->set_i2d_affine(item->i2doc_affine() * affine * item->document->doc2dt());
+ item->doWriteTransform(item->transform);
+ item->updateRepr();
+ cnt +=1;
+ }
+ }
+
+ DocumentUndo::done(desktop->getDocument(), _("Arrange in a grid"), INKSCAPE_ICON("dialog-align-and-distribute"));
+
+}
+
+
+//#########################################################################
+//## E V E N T S
+//#########################################################################
+
+/**
+ * changed value in # of columns spinbox.
+ */
+void GridArrangeTab::on_row_spinbutton_changed()
+{
+ SPDesktop *desktop = Parent->getDesktop();
+ Inkscape::Selection *selection = desktop ? desktop->selection : nullptr;
+ if (!selection) return;
+
+ int selcount = (int) boost::distance(selection->items());
+
+ double NoOfRows = ceil(selcount / NoOfColsSpinner.get_value());
+ NoOfRowsSpinner.set_value(NoOfRows);
+}
+
+/**
+ * changed value in # of rows spinbox.
+ */
+void GridArrangeTab::on_col_spinbutton_changed()
+{
+ SPDesktop *desktop = Parent->getDesktop();
+ Inkscape::Selection *selection = desktop ? desktop->selection : nullptr;
+ if (!selection) return;
+
+ int selcount = (int) boost::distance(selection->items());
+
+ double NoOfCols = ceil(selcount / NoOfRowsSpinner.get_value());
+ NoOfColsSpinner.set_value(NoOfCols);
+}
+
+/**
+ * changed value in x padding spinbox.
+ */
+void GridArrangeTab::on_xpad_spinbutton_changed()
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble("/dialogs/gridtiler/XPad", XPadding.getValue("px"));
+
+}
+
+/**
+ * changed value in y padding spinbox.
+ */
+void GridArrangeTab::on_ypad_spinbutton_changed()
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble("/dialogs/gridtiler/YPad", YPadding.getValue("px"));
+}
+
+
+/**
+ * checked/unchecked autosize Rows button.
+ */
+void GridArrangeTab::on_RowSize_checkbutton_changed()
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ if (RowHeightButton.get_active()) {
+ prefs->setDouble("/dialogs/gridtiler/AutoRowSize", 20);
+ } else {
+ prefs->setDouble("/dialogs/gridtiler/AutoRowSize", -20);
+ }
+ RowHeightBox.set_sensitive ( !RowHeightButton.get_active());
+}
+
+/**
+ * checked/unchecked autosize Rows button.
+ */
+void GridArrangeTab::on_ColSize_checkbutton_changed()
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ if (ColumnWidthButton.get_active()) {
+ prefs->setDouble("/dialogs/gridtiler/AutoColSize", 20);
+ } else {
+ prefs->setDouble("/dialogs/gridtiler/AutoColSize", -20);
+ }
+ ColumnWidthBox.set_sensitive ( !ColumnWidthButton.get_active());
+}
+
+/**
+ * changed value in columns spinbox.
+ */
+void GridArrangeTab::on_rowSize_spinbutton_changed()
+{
+ // quit if run by the attr_changed listener
+ if (updating) {
+ return;
+ }
+
+ // in turn, prevent listener from responding
+ updating = true;
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble("/dialogs/gridtiler/RowHeight", RowHeightSpinner.get_value());
+ updating=false;
+
+}
+
+/**
+ * changed value in rows spinbox.
+ */
+void GridArrangeTab::on_colSize_spinbutton_changed()
+{
+ // quit if run by the attr_changed listener
+ if (updating) {
+ return;
+ }
+
+ // in turn, prevent listener from responding
+ updating = true;
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble("/dialogs/gridtiler/ColWidth", ColumnWidthSpinner.get_value());
+ updating=false;
+
+}
+
+/**
+ * changed Radio button in Spacing group.
+ */
+void GridArrangeTab::Spacing_button_changed()
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ if (SpaceManualRadioButton.get_active()) {
+ prefs->setDouble("/dialogs/gridtiler/SpacingType", 20);
+ } else {
+ prefs->setDouble("/dialogs/gridtiler/SpacingType", -20);
+ }
+
+ XPadding.set_sensitive ( SpaceManualRadioButton.get_active());
+ YPadding.set_sensitive ( SpaceManualRadioButton.get_active());
+}
+
+/**
+ * changed Anchor selection widget.
+ */
+void GridArrangeTab::Align_changed()
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ VertAlign = AlignmentSelector.getVerticalAlignment();
+ prefs->setInt("/dialogs/gridtiler/VertAlign", VertAlign);
+ HorizAlign = AlignmentSelector.getHorizontalAlignment();
+ prefs->setInt("/dialogs/gridtiler/HorizAlign", HorizAlign);
+}
+
+/**
+ * Desktop selection changed
+ */
+void GridArrangeTab::updateSelection()
+{
+ // quit if run by the attr_changed listener
+ if (updating) {
+ return;
+ }
+
+ // in turn, prevent listener from responding
+ updating = true;
+ SPDesktop *desktop = Parent->getDesktop();
+ Inkscape::Selection *selection = desktop ? desktop->selection : nullptr;
+ std::vector<SPItem*> items;
+ if (selection) {
+ items.insert(items.end(), selection->items().begin(), selection->items().end());
+ }
+
+ if (!items.empty()) {
+ int selcount = items.size();
+
+ if (NoOfColsSpinner.get_value() > 1 && NoOfRowsSpinner.get_value() > 1){
+ // Update the number of rows assuming number of columns wanted remains same.
+ double NoOfRows = ceil(selcount / NoOfColsSpinner.get_value());
+ NoOfRowsSpinner.set_value(NoOfRows);
+
+ // if the selection has less than the number set for one row, reduce it appropriately
+ if (selcount < NoOfColsSpinner.get_value()) {
+ double NoOfCols = ceil(selcount / NoOfRowsSpinner.get_value());
+ NoOfColsSpinner.set_value(NoOfCols);
+ }
+ } else {
+ double PerRow = ceil(sqrt(selcount));
+ double PerCol = ceil(sqrt(selcount));
+ NoOfRowsSpinner.set_value(PerRow);
+ NoOfColsSpinner.set_value(PerCol);
+ }
+ }
+
+ updating = false;
+}
+
+void GridArrangeTab::setDesktop(SPDesktop *desktop)
+{
+ _selection_changed_connection.disconnect();
+
+ if (desktop) {
+ updateSelection();
+
+ _selection_changed_connection = INKSCAPE.signal_selection_changed.connect(
+ sigc::hide<0>(sigc::mem_fun(*this, &GridArrangeTab::updateSelection)));
+ }
+}
+
+
+//#########################################################################
+//## C O N S T R U C T O R / D E S T R U C T O R
+//#########################################################################
+/**
+ * Constructor
+ */
+GridArrangeTab::GridArrangeTab(ArrangeDialog *parent)
+ : Parent(parent),
+ XPadding(_("X:"), _("Horizontal spacing between columns."), UNIT_TYPE_LINEAR, "", "object-columns", &PaddingUnitMenu),
+ YPadding(_("Y:"), _("Vertical spacing between rows."), XPadding, "", "object-rows"),
+ PaddingTable(Gtk::manage(new Gtk::Grid()))
+{
+ // bool used by spin button callbacks to stop loops where they change each other.
+ updating = false;
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ auto _col1 = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL);
+ auto _col2 = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL);
+ auto _col3 = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL);
+
+ Gtk::Box *contents = this;
+ set_valign(Gtk::ALIGN_START);
+
+#define MARGIN 2
+
+ //##Set up the panel
+
+ NoOfRowsLabel.set_text_with_mnemonic(_("_Rows:"));
+ NoOfRowsLabel.set_mnemonic_widget(NoOfRowsSpinner);
+ NoOfRowsBox.set_orientation(Gtk::ORIENTATION_VERTICAL);
+ NoOfRowsBox.pack_start(NoOfRowsLabel, false, false, MARGIN);
+
+ NoOfRowsSpinner.set_digits(0);
+ NoOfRowsSpinner.set_increments(1, 0);
+ NoOfRowsSpinner.set_range(1.0, 10000.0);
+ NoOfRowsSpinner.signal_changed().connect(sigc::mem_fun(*this, &GridArrangeTab::on_col_spinbutton_changed));
+ NoOfRowsSpinner.set_tooltip_text(_("Number of rows"));
+ NoOfRowsBox.pack_start(NoOfRowsSpinner, false, false, MARGIN);
+ _col1->add_widget(NoOfRowsBox);
+
+ RowHeightButton.set_label(_("Equal _height"));
+ RowHeightButton.set_use_underline(true);
+ double AutoRow = prefs->getDouble("/dialogs/gridtiler/AutoRowSize", 15);
+ if (AutoRow>0)
+ AutoRowSize=true;
+ else
+ AutoRowSize=false;
+ RowHeightButton.set_active(AutoRowSize);
+
+ NoOfRowsBox.pack_start(RowHeightButton, false, false, MARGIN);
+
+ RowHeightButton.set_tooltip_text(_("If not set, each row has the height of the tallest object in it"));
+ RowHeightButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::on_RowSize_checkbutton_changed));
+
+ SpinsHBox.pack_start(NoOfRowsBox, false, false, MARGIN);
+
+
+ /*#### Label for X ####*/
+ padXByYLabel.set_label(" ");
+ XByYLabelVBox.set_orientation(Gtk::ORIENTATION_VERTICAL);
+ XByYLabelVBox.pack_start(padXByYLabel, false, false, MARGIN);
+ XByYLabel.set_markup(" &#215; ");
+ XByYLabelVBox.pack_start(XByYLabel, false, false, MARGIN);
+ SpinsHBox.pack_start(XByYLabelVBox, false, false, MARGIN);
+ _col2->add_widget(XByYLabelVBox);
+
+ /*#### Number of columns ####*/
+
+ NoOfColsLabel.set_text_with_mnemonic(_("_Columns:"));
+ NoOfColsLabel.set_mnemonic_widget(NoOfColsSpinner);
+ NoOfColsBox.set_orientation(Gtk::ORIENTATION_VERTICAL);
+ NoOfColsBox.pack_start(NoOfColsLabel, false, false, MARGIN);
+
+ NoOfColsSpinner.set_digits(0);
+ NoOfColsSpinner.set_increments(1, 0);
+ NoOfColsSpinner.set_range(1.0, 10000.0);
+ NoOfColsSpinner.signal_changed().connect(sigc::mem_fun(*this, &GridArrangeTab::on_row_spinbutton_changed));
+ NoOfColsSpinner.set_tooltip_text(_("Number of columns"));
+ NoOfColsBox.pack_start(NoOfColsSpinner, false, false, MARGIN);
+ _col3->add_widget(NoOfColsBox);
+
+ ColumnWidthButton.set_label(_("Equal _width"));
+ ColumnWidthButton.set_use_underline(true);
+ double AutoCol = prefs->getDouble("/dialogs/gridtiler/AutoColSize", 15);
+ if (AutoCol>0)
+ AutoColSize=true;
+ else
+ AutoColSize=false;
+ ColumnWidthButton.set_active(AutoColSize);
+ NoOfColsBox.pack_start(ColumnWidthButton, false, false, MARGIN);
+
+ ColumnWidthButton.set_tooltip_text(_("If not set, each column has the width of the widest object in it"));
+ ColumnWidthButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::on_ColSize_checkbutton_changed));
+
+ SpinsHBox.pack_start(NoOfColsBox, false, false, MARGIN);
+
+ TileBox.set_orientation(Gtk::ORIENTATION_VERTICAL);
+ TileBox.pack_start(SpinsHBox, false, false, MARGIN);
+
+ VertAlign = prefs->getInt("/dialogs/gridtiler/VertAlign", 1);
+ HorizAlign = prefs->getInt("/dialogs/gridtiler/HorizAlign", 1);
+
+ // Anchor selection widget
+ AlignLabel.set_label(_("Alignment:"));
+ AlignLabel.set_halign(Gtk::ALIGN_START);
+ AlignLabel.set_valign(Gtk::ALIGN_CENTER);
+ AlignmentSelector.setAlignment(HorizAlign, VertAlign);
+ AlignmentSelector.on_selectionChanged().connect(sigc::mem_fun(*this, &GridArrangeTab::Align_changed));
+ TileBox.pack_start(AlignLabel, false, false, MARGIN);
+ TileBox.pack_start(AlignmentSelector, true, false, MARGIN);
+
+ {
+ /*#### Radio buttons to control spacing manually or to fit selection bbox ####*/
+ SpaceByBBoxRadioButton.set_label(_("_Fit into selection box"));
+ SpaceByBBoxRadioButton.set_use_underline (true);
+ SpaceByBBoxRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::Spacing_button_changed));
+ SpacingGroup = SpaceByBBoxRadioButton.get_group();
+
+ SpacingVBox.pack_start(SpaceByBBoxRadioButton, false, false, MARGIN);
+
+ SpaceManualRadioButton.set_label(_("_Set spacing:"));
+ SpaceManualRadioButton.set_use_underline (true);
+ SpaceManualRadioButton.set_group(SpacingGroup);
+ SpaceManualRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &GridArrangeTab::Spacing_button_changed));
+ SpacingVBox.pack_start(SpaceManualRadioButton, false, false, MARGIN);
+
+ TileBox.pack_start(SpacingVBox, false, false, MARGIN);
+ }
+
+ {
+ /*#### Padding ####*/
+ PaddingUnitMenu.setUnitType(UNIT_TYPE_LINEAR);
+ PaddingUnitMenu.setUnit("px");
+
+ YPadding.setDigits(5);
+ YPadding.setIncrements(0.2, 0);
+ YPadding.setRange(-10000, 10000);
+ double yPad = prefs->getDouble("/dialogs/gridtiler/YPad", 15);
+ YPadding.setValue(yPad, "px");
+ YPadding.signal_value_changed().connect(sigc::mem_fun(*this, &GridArrangeTab::on_ypad_spinbutton_changed));
+
+ XPadding.setDigits(5);
+ XPadding.setIncrements(0.2, 0);
+ XPadding.setRange(-10000, 10000);
+ double xPad = prefs->getDouble("/dialogs/gridtiler/XPad", 15);
+ XPadding.setValue(xPad, "px");
+
+ XPadding.signal_value_changed().connect(sigc::mem_fun(*this, &GridArrangeTab::on_xpad_spinbutton_changed));
+ }
+
+ PaddingTable->set_border_width(MARGIN);
+ PaddingTable->set_row_spacing(MARGIN);
+ PaddingTable->set_column_spacing(MARGIN);
+ PaddingTable->attach(XPadding, 0, 0, 1, 1);
+ PaddingTable->attach(PaddingUnitMenu, 1, 0, 1, 1);
+ PaddingTable->attach(YPadding, 0, 1, 1, 1);
+
+ TileBox.pack_start(*PaddingTable, false, false, MARGIN);
+
+ contents->set_border_width(4);
+ contents->pack_start(TileBox);
+
+ double SpacingType = prefs->getDouble("/dialogs/gridtiler/SpacingType", 15);
+ if (SpacingType>0) {
+ ManualSpacing=true;
+ } else {
+ ManualSpacing=false;
+ }
+ SpaceManualRadioButton.set_active(ManualSpacing);
+ SpaceByBBoxRadioButton.set_active(!ManualSpacing);
+ XPadding.set_sensitive (ManualSpacing);
+ YPadding.set_sensitive (ManualSpacing);
+
+ show_all_children();
+}
+
+
+GridArrangeTab::~GridArrangeTab() {
+ setDesktop(nullptr);
+}
+
+} //namespace Dialog
+} //namespace UI
+} //namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :