X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fui%2Fdialog%2Falign-and-distribute.cpp;h=024d4b2f12dff91a762342732b72c57d1f586bde;hb=5ef6cb9428f2e6f5457e890a1c3b37f53730c07a;hp=2767a32d198c30d765ca41b16bce655edbf99036;hpb=871fccc39b870543073d7015a9d8c701252b68f9;p=inkscape.git diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index 2767a32d1..024d4b2f1 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -1,7 +1,7 @@ -/** - * \brief Align and Distribute dialog - * - * Authors: +/** @file + * @brief Align and Distribute dialog - implementation + */ +/* Authors: * Bryce W. Harrington * Aubanel MONNIER * Frank Felfe @@ -18,38 +18,29 @@ # include #endif -#include "verbs.h" - -#include "dialogs/unclump.h" -#include "removeoverlap/removeoverlap.h" -#include "graphlayout/graphlayout.h" - #include - - - -#include "util/glib-list-iterators.h" - -#include "widgets/icon.h" - -#include "inkscape.h" -#include "document.h" -#include "selection.h" #include "desktop-handles.h" +#include "unclump.h" +#include "document.h" +#include "enums.h" +#include "graphlayout/graphlayout.h" +#include "inkscape.h" #include "macros.h" +#include "node-context.h" //For access to ShapeEditor +#include "preferences.h" +#include "removeoverlap/removeoverlap.h" +#include "selection.h" +#include "shape-editor.h" //For node align/distribute methods +#include "sp-flowtext.h" #include "sp-item-transform.h" -#include "prefs-utils.h" -#include "enums.h" - #include "sp-text.h" -#include "sp-flowtext.h" #include "text-editing.h" - -#include "node-context.h" //For access to ShapeEditor -#include "shape-editor.h" //For node align/distribute methods - #include "tools-switch.h" +#include "ui/icon-names.h" +#include "util/glib-list-iterators.h" +#include "verbs.h" +#include "widgets/icon.h" #include "align-and-distribute.h" @@ -122,12 +113,15 @@ private : Inkscape::Selection *selection = sp_desktop_selection(desktop); if (!selection) return; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool sel_as_group = prefs->getBool("/dialogs/align/sel-as-groups"); + using Inkscape::Util::GSListConstIterator; std::list selected; selected.insert >(selected.end(), selection->itemList(), NULL); if (selected.empty()) return; - NR::Point mp; //Anchor point + Geom::Point mp; //Anchor point AlignAndDistribute::AlignTarget target = _dialog.getAlignTarget(); const Coeffs &a= _allCoeffs[_index]; switch (target) @@ -151,12 +145,17 @@ private : ); //remove the master from the selection SPItem * thing = *master; - selected.erase(master); + // TODO: either uncomment or remove the following commented lines, depending on which + // behaviour of moving objects makes most sense; also cf. discussion at + // https://bugs.launchpad.net/inkscape/+bug/255933 + /*if (!sel_as_group) { */ + selected.erase(master); + /*}*/ //Compute the anchor point - NR::Maybe b = sp_item_bbox_desktop (thing); + Geom::OptRect b = sp_item_bbox_desktop (thing); if (b) { - mp = NR::Point(a.mx0 * b->min()[NR::X] + a.mx1 * b->max()[NR::X], - a.my0 * b->min()[NR::Y] + a.my1 * b->max()[NR::Y]); + mp = Geom::Point(a.mx0 * b->min()[Geom::X] + a.mx1 * b->max()[Geom::X], + a.my0 * b->min()[Geom::Y] + a.my1 * b->max()[Geom::Y]); } else { return; } @@ -164,17 +163,17 @@ private : } case AlignAndDistribute::PAGE: - mp = NR::Point(a.mx1 * sp_document_width(sp_desktop_document(desktop)), + mp = Geom::Point(a.mx1 * sp_document_width(sp_desktop_document(desktop)), a.my1 * sp_document_height(sp_desktop_document(desktop))); break; case AlignAndDistribute::DRAWING: { - NR::Maybe b = sp_item_bbox_desktop + Geom::OptRect b = sp_item_bbox_desktop ( (SPItem *) sp_document_root (sp_desktop_document (desktop)) ); if (b) { - mp = NR::Point(a.mx0 * b->min()[NR::X] + a.mx1 * b->max()[NR::X], - a.my0 * b->min()[NR::Y] + a.my1 * b->max()[NR::Y]); + mp = Geom::Point(a.mx0 * b->min()[Geom::X] + a.mx1 * b->max()[Geom::X], + a.my0 * b->min()[Geom::Y] + a.my1 * b->max()[Geom::Y]); } else { return; } @@ -183,10 +182,10 @@ private : case AlignAndDistribute::SELECTION: { - NR::Maybe b = selection->bounds(); + Geom::OptRect b = selection->bounds(); if (b) { - mp = NR::Point(a.mx0 * b->min()[NR::X] + a.mx1 * b->max()[NR::X], - a.my0 * b->min()[NR::Y] + a.my1 * b->max()[NR::Y]); + mp = Geom::Point(a.mx0 * b->min()[Geom::X] + a.mx1 * b->max()[Geom::X], + a.my0 * b->min()[Geom::Y] + a.my1 * b->max()[Geom::Y]); } else { return; } @@ -204,30 +203,35 @@ private : // a selected original, they will be unmoved too, possibly contrary to user's // expecation. However this is a minor point compared to making align/distribute always // work as expected, and "unmoved" is the default option anyway. - int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); - prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); + int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); + prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); bool changed = false; - //Move each item in the selected list + Geom::OptRect b; + if (sel_as_group) + b = selection->bounds(); + + //Move each item in the selected list separately for (std::list::iterator it(selected.begin()); it != selected.end(); it++) { sp_document_ensure_up_to_date(sp_desktop_document (desktop)); - NR::Maybe b = sp_item_bbox_desktop (*it); + if (!sel_as_group) + b = sp_item_bbox_desktop (*it); if (b) { - NR::Point const sp(a.sx0 * b->min()[NR::X] + a.sx1 * b->max()[NR::X], - a.sy0 * b->min()[NR::Y] + a.sy1 * b->max()[NR::Y]); - NR::Point const mp_rel( mp - sp ); + Geom::Point const sp(a.sx0 * b->min()[Geom::X] + a.sx1 * b->max()[Geom::X], + a.sy0 * b->min()[Geom::Y] + a.sy1 * b->max()[Geom::Y]); + Geom::Point const mp_rel( mp - sp ); if (LInfty(mp_rel) > 1e-9) { - sp_item_move_rel(*it, NR::translate(mp_rel)); + sp_item_move_rel(*it, Geom::Translate(mp_rel)); changed = true; } } } // restore compensation setting - prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation); + prefs->setInt("/options/clonecompensation/value", saved_compensation); if (changed) { sp_document_done ( sp_desktop_document (desktop) , SP_VERB_DIALOG_ALIGN_DISTRIBUTE, @@ -255,24 +259,20 @@ ActionAlign::Coeffs const ActionAlign::_allCoeffs[10] = { {0., 0., 1., 0., 0., 0., 0., 1.} }; -struct BBoxSort -{ - SPItem *item; - float anchor; - NR::Rect bbox; - BBoxSort(SPItem *pItem, NR::Rect bounds, NR::Dim2 orientation, double kBegin, double kEnd) : +BBoxSort::BBoxSort(SPItem *pItem, Geom::Rect bounds, Geom::Dim2 orientation, double kBegin, double kEnd) : item(pItem), bbox (bounds) - { +{ anchor = kBegin * bbox.min()[orientation] + kEnd * bbox.max()[orientation]; - } - BBoxSort(const BBoxSort &rhs): +} +BBoxSort::BBoxSort(const BBoxSort &rhs) : //NOTE : this copy ctor is called O(sort) when sorting the vector //this is bad. The vector should be a vector of pointers. //But I'll wait the bohem GC before doing that - item(rhs.item), anchor(rhs.anchor), bbox(rhs.bbox) { - } -}; + item(rhs.item), anchor(rhs.anchor), bbox(rhs.bbox) +{ +} + bool operator< (const BBoxSort &a, const BBoxSort &b) { return (a.anchor < b.anchor); @@ -285,7 +285,7 @@ public : guint row, guint column, AlignAndDistribute &dialog, bool onInterSpace, - NR::Dim2 orientation, + Geom::Dim2 orientation, double kBegin, double kEnd ): Action(id, tiptext, row, column, @@ -322,7 +322,7 @@ private : it != selected.end(); ++it) { - NR::Maybe bbox = sp_item_bbox_desktop(*it); + Geom::OptRect bbox = sp_item_bbox_desktop(*it); if (bbox) { sorted.push_back(BBoxSort(*it, *bbox, _orientation, _kBegin, _kEnd)); } @@ -331,8 +331,9 @@ private : std::sort(sorted.begin(), sorted.end()); // see comment in ActionAlign above - int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); - prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); + prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); unsigned int len = sorted.size(); bool changed = false; @@ -345,7 +346,7 @@ private : float span = 0; for (unsigned int i = 0; i < len; i++) { - span += sorted[i].bbox.extent(_orientation); + span += sorted[i].bbox[_orientation].extent(); } //new distance between each bbox float step = (dist - span) / (len - 1); @@ -355,12 +356,12 @@ private : it ++ ) { if (!NR_DF_TEST_CLOSE (pos, it->bbox.min()[_orientation], 1e-6)) { - NR::Point t(0.0, 0.0); + Geom::Point t(0.0, 0.0); t[_orientation] = pos - it->bbox.min()[_orientation]; - sp_item_move_rel(it->item, NR::translate(t)); + sp_item_move_rel(it->item, Geom::Translate(t)); changed = true; } - pos += it->bbox.extent(_orientation); + pos += it->bbox[_orientation].extent(); pos += step; } } @@ -379,17 +380,17 @@ private : //Don't move if we are really close if (!NR_DF_TEST_CLOSE (pos, it.anchor, 1e-6)) { //Compute translation - NR::Point t(0.0, 0.0); + Geom::Point t(0.0, 0.0); t[_orientation] = pos - it.anchor; //translate - sp_item_move_rel(it.item, NR::translate(t)); + sp_item_move_rel(it.item, Geom::Translate(t)); changed = true; } } } // restore compensation setting - prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation); + prefs->setInt("/options/clonecompensation/value", saved_compensation); if (changed) { sp_document_done ( sp_desktop_document (desktop), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, @@ -399,7 +400,7 @@ private : guint _index; AlignAndDistribute &_dialog; bool _onInterSpace; - NR::Dim2 _orientation; + Geom::Dim2 _orientation; double _kBegin; double _kEnd; @@ -413,7 +414,7 @@ public : const Glib::ustring &tiptext, guint column, AlignAndDistribute &dialog, - NR::Dim2 orientation, bool distribute): + Geom::Dim2 orientation, bool distribute): Action(id, tiptext, 0, column, dialog.nodes_table(), dialog.tooltips(), dialog), _orientation(orientation), @@ -421,7 +422,7 @@ public : {} private : - NR::Dim2 _orientation; + Geom::Dim2 _orientation; bool _distribute; virtual void on_button_click() { @@ -431,9 +432,9 @@ private : if (!SP_IS_NODE_CONTEXT (event_context)) return ; if (_distribute) - SP_NODE_CONTEXT (event_context)->shape_editor->distribute(_orientation); + event_context->shape_editor->distribute((Geom::Dim2)_orientation); else - SP_NODE_CONTEXT (event_context)->shape_editor->align(_orientation); + event_context->shape_editor->align((Geom::Dim2)_orientation); } }; @@ -458,17 +459,19 @@ public: removeOverlapXGap.set_digits(1); removeOverlapXGap.set_size_request(60, -1); - removeOverlapXGap.set_increments(1.0, 5.0); + removeOverlapXGap.set_increments(1.0, 0); removeOverlapXGap.set_range(-1000.0, 1000.0); removeOverlapXGap.set_value(0); dialog.tooltips().set_tip(removeOverlapXGap, _("Minimum horizontal gap (in px units) between bounding boxes")); - /* TRANSLATORS: Horizontal gap */ - removeOverlapXGapLabel.set_label(_("H:")); + //TRANSLATORS: only translate "string" in "context|string". + // For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS + // "H:" stands for horizontal gap + removeOverlapXGapLabel.set_label(Q_("gap|H:")); removeOverlapYGap.set_digits(1); removeOverlapYGap.set_size_request(60, -1); - removeOverlapYGap.set_increments(1.0, 5.0); + removeOverlapYGap.set_increments(1.0, 0); removeOverlapYGap.set_range(-1000.0, 1000.0); removeOverlapYGap.set_value(0); dialog.tooltips().set_tip(removeOverlapYGap, @@ -489,8 +492,9 @@ private : if (!_dialog.getDesktop()) return; // see comment in ActionAlign above - int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); - prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); + prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); // xGap and yGap are the minimum space required between bounding rectangles. double const xGap = removeOverlapXGap.get_value(); @@ -499,7 +503,7 @@ private : xGap, yGap); // restore compensation setting - prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation); + prefs->setInt("/options/clonecompensation/value", saved_compensation); sp_document_done(sp_desktop_document(_dialog.getDesktop()), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Remove overlaps")); @@ -523,13 +527,14 @@ private : if (!_dialog.getDesktop()) return; // see comment in ActionAlign above - int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); - prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); + prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); graphlayout(sp_desktop_selection(_dialog.getDesktop())->itemList()); // restore compensation setting - prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation); + prefs->setInt("/options/clonecompensation/value", saved_compensation); sp_document_done(sp_desktop_document(_dialog.getDesktop()), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network")); @@ -553,13 +558,14 @@ private : if (!_dialog.getDesktop()) return; // see comment in ActionAlign above - int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); - prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); + prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); unclump ((GSList *) sp_desktop_selection(_dialog.getDesktop())->itemList()); // restore compensation setting - prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation); + prefs->setInt("/options/clonecompensation/value", saved_compensation); sp_document_done (sp_desktop_document (_dialog.getDesktop()), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Unclump")); @@ -594,7 +600,7 @@ private : //Check 2 or more selected objects if (selected.size() < 2) return; - NR::Maybe sel_bbox = selection->bounds(); + Geom::OptRect sel_bbox = selection->bounds(); if (!sel_bbox) { return; } @@ -607,29 +613,30 @@ private : } // see comment in ActionAlign above - int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); - prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); + prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); for (std::list::iterator it(selected.begin()); it != selected.end(); ++it) { sp_document_ensure_up_to_date(sp_desktop_document (desktop)); - NR::Maybe item_box = sp_item_bbox_desktop (*it); + Geom::OptRect item_box = sp_item_bbox_desktop (*it); if (item_box) { // find new center, staying within bbox - double x = _dialog.randomize_bbox->min()[NR::X] + item_box->extent(NR::X)/2 + - g_random_double_range (0, _dialog.randomize_bbox->extent(NR::X) - item_box->extent(NR::X)); - double y = _dialog.randomize_bbox->min()[NR::Y] + item_box->extent(NR::Y)/2 + - g_random_double_range (0, _dialog.randomize_bbox->extent(NR::Y) - item_box->extent(NR::Y)); + double x = _dialog.randomize_bbox->min()[Geom::X] + (*item_box)[Geom::X].extent() /2 + + g_random_double_range (0, (*_dialog.randomize_bbox)[Geom::X].extent() - (*item_box)[Geom::X].extent()); + double y = _dialog.randomize_bbox->min()[Geom::Y] + (*item_box)[Geom::Y].extent()/2 + + g_random_double_range (0, (*_dialog.randomize_bbox)[Geom::Y].extent() - (*item_box)[Geom::Y].extent()); // displacement is the new center minus old: - NR::Point t = NR::Point (x, y) - 0.5*(item_box->max() + item_box->min()); - sp_item_move_rel(*it, NR::translate(t)); + Geom::Point t = Geom::Point (x, y) - 0.5*(item_box->max() + item_box->min()); + sp_item_move_rel(*it, Geom::Translate(t)); } } // restore compensation setting - prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation); + prefs->setInt("/options/clonecompensation/value", saved_compensation); sp_document_done (sp_desktop_document (desktop), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Randomize positions")); @@ -639,9 +646,9 @@ private : struct Baselines { SPItem *_item; - NR::Point _base; - NR::Dim2 _orientation; - Baselines(SPItem *item, NR::Point base, NR::Dim2 orientation) : + Geom::Point _base; + Geom::Dim2 _orientation; + Baselines(SPItem *item, Geom::Point base, Geom::Dim2 orientation) : _item (item), _base (base), _orientation (orientation) @@ -661,7 +668,7 @@ public : guint column, AlignAndDistribute &dialog, Gtk::Table &table, - NR::Dim2 orientation, bool distribute): + Geom::Dim2 orientation, bool distribute): Action(id, tiptext, row, column, table, dialog.tooltips(), dialog), _orientation(orientation), @@ -669,7 +676,7 @@ public : {} private : - NR::Dim2 _orientation; + Geom::Dim2 _orientation; bool _distribute; virtual void on_button_click() { @@ -687,8 +694,8 @@ private : //Check 2 or more selected objects if (selected.size() < 2) return; - NR::Point b_min = NR::Point (HUGE_VAL, HUGE_VAL); - NR::Point b_max = NR::Point (-HUGE_VAL, -HUGE_VAL); + Geom::Point b_min = Geom::Point (HUGE_VAL, HUGE_VAL); + Geom::Point b_max = Geom::Point (-HUGE_VAL, -HUGE_VAL); std::vector sorted; @@ -698,11 +705,11 @@ private : { if (SP_IS_TEXT (*it) || SP_IS_FLOWTEXT (*it)) { Inkscape::Text::Layout const *layout = te_get_layout(*it); - NR::Point base = layout->characterAnchorPoint(layout->begin()) * sp_item_i2d_affine(*it); - if (base[NR::X] < b_min[NR::X]) b_min[NR::X] = base[NR::X]; - if (base[NR::Y] < b_min[NR::Y]) b_min[NR::Y] = base[NR::Y]; - if (base[NR::X] > b_max[NR::X]) b_max[NR::X] = base[NR::X]; - if (base[NR::Y] > b_max[NR::Y]) b_max[NR::Y] = base[NR::Y]; + Geom::Point base = layout->characterAnchorPoint(layout->begin()) * sp_item_i2d_affine(*it); + if (base[Geom::X] < b_min[Geom::X]) b_min[Geom::X] = base[Geom::X]; + if (base[Geom::Y] < b_min[Geom::Y]) b_min[Geom::Y] = base[Geom::Y]; + if (base[Geom::X] > b_max[Geom::X]) b_max[Geom::X] = base[Geom::X]; + if (base[Geom::Y] > b_max[Geom::Y]) b_max[Geom::Y] = base[Geom::Y]; Baselines b (*it, base, _orientation); sorted.push_back(b); @@ -720,10 +727,10 @@ private : double step = (b_max[_orientation] - b_min[_orientation])/(sorted.size() - 1); for (unsigned int i = 0; i < sorted.size(); i++) { SPItem *item = sorted[i]._item; - NR::Point base = sorted[i]._base; - NR::Point t(0.0, 0.0); + Geom::Point base = sorted[i]._base; + Geom::Point t(0.0, 0.0); t[_orientation] = b_min[_orientation] + step * i - base[_orientation]; - sp_item_move_rel(item, NR::translate(t)); + sp_item_move_rel(item, Geom::Translate(t)); changed = true; } @@ -739,10 +746,10 @@ private : { if (SP_IS_TEXT (*it) || SP_IS_FLOWTEXT (*it)) { Inkscape::Text::Layout const *layout = te_get_layout(*it); - NR::Point base = layout->characterAnchorPoint(layout->begin()) * sp_item_i2d_affine(*it); - NR::Point t(0.0, 0.0); + Geom::Point base = layout->characterAnchorPoint(layout->begin()) * sp_item_i2d_affine(*it); + Geom::Point t(0.0, 0.0); t[_orientation] = b_min[_orientation] - base[_orientation]; - sp_item_move_rel(*it, NR::translate(t)); + sp_item_move_rel(*it, Geom::Translate(t)); changed = true; } } @@ -766,7 +773,7 @@ void on_tool_changed(Inkscape::Application */*inkscape*/, SPEventContext */*cont void on_selection_changed(Inkscape::Application */*inkscape*/, Inkscape::Selection */*selection*/, AlignAndDistribute *daad) { - daad->randomize_bbox = NR::Nothing(); + daad->randomize_bbox = Geom::OptRect(); } ///////////////////////////////////////////////////////// @@ -775,8 +782,8 @@ void on_selection_changed(Inkscape::Application */*inkscape*/, Inkscape::Selecti AlignAndDistribute::AlignAndDistribute() - : UI::Widget::Panel ("", "dialogs.align", SP_VERB_DIALOG_ALIGN_DISTRIBUTE), - randomize_bbox(NR::Nothing()), + : UI::Widget::Panel ("", "/dialogs/align", SP_VERB_DIALOG_ALIGN_DISTRIBUTE), + randomize_bbox(), _alignFrame(_("Align")), _distributeFrame(_("Distribute")), _removeOverlapFrame(_("Remove overlaps")), @@ -787,134 +794,145 @@ AlignAndDistribute::AlignAndDistribute() _removeOverlapTable(1, 5, false), _graphLayoutTable(1, 5, false), _nodesTable(1, 4, true), - _anchorLabel(_("Relative to: ")) + _anchorLabel(_("Relative to: ")), + _selgrpLabel(_("Treat selection as group: ")) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); //Instanciate the align buttons - addAlignButton("al_left_out", - _("Align right sides of objects to left side of anchor"), + addAlignButton(INKSCAPE_ICON_ALIGN_HORIZONTAL_RIGHT_TO_ANCHOR, + _("Align right edges of objects to the left edge of the anchor"), 0, 0); - addAlignButton("al_left_in", - _("Align left sides"), + addAlignButton(INKSCAPE_ICON_ALIGN_HORIZONTAL_LEFT, + _("Align left edges"), 0, 1); - addAlignButton("al_center_hor", + addAlignButton(INKSCAPE_ICON_ALIGN_HORIZONTAL_CENTER, _("Center on vertical axis"), 0, 2); - addAlignButton("al_right_in", + addAlignButton(INKSCAPE_ICON_ALIGN_HORIZONTAL_RIGHT, _("Align right sides"), 0, 3); - addAlignButton("al_right_out", - _("Align left sides of objects to right side of anchor"), + addAlignButton(INKSCAPE_ICON_ALIGN_HORIZONTAL_LEFT_TO_ANCHOR, + _("Align left edges of objects to the right edge of the anchor"), 0, 4); - addAlignButton("al_top_out", - _("Align bottoms of objects to top of anchor"), + addAlignButton(INKSCAPE_ICON_ALIGN_VERTICAL_BOTTOM_TO_ANCHOR, + _("Align bottom edges of objects to the top edge of the anchor"), 1, 0); - addAlignButton("al_top_in", - _("Align tops"), + addAlignButton(INKSCAPE_ICON_ALIGN_VERTICAL_TOP, + _("Align top edges"), 1, 1); - addAlignButton("al_center_ver", + addAlignButton(INKSCAPE_ICON_ALIGN_VERTICAL_CENTER, _("Center on horizontal axis"), 1, 2); - addAlignButton("al_bottom_in", - _("Align bottoms"), + addAlignButton(INKSCAPE_ICON_ALIGN_VERTICAL_BOTTOM, + _("Align bottom edges"), 1, 3); - addAlignButton("al_bottom_out", - _("Align tops of objects to bottom of anchor"), + addAlignButton(INKSCAPE_ICON_ALIGN_VERTICAL_TOP_TO_ANCHOR, + _("Align top edges of objects to the bottom edge of the anchor"), 1, 4); //Baseline aligns - addBaselineButton("al_baselines_vert", - _("Align baseline anchors of texts vertically"), - 0, 5, this->align_table(), NR::X, false); - addBaselineButton("al_baselines_hor", + addBaselineButton(INKSCAPE_ICON_ALIGN_HORIZONTAL_BASELINE, _("Align baseline anchors of texts horizontally"), - 1, 5, this->align_table(), NR::Y, false); + 0, 5, this->align_table(), Geom::X, false); + addBaselineButton(INKSCAPE_ICON_ALIGN_VERTICAL_BASELINE, + _("Align baselines of texts"), + 1, 5, this->align_table(), Geom::Y, false); //The distribute buttons - addDistributeButton("distribute_hdist", + addDistributeButton(INKSCAPE_ICON_DISTRIBUTE_HORIZONTAL_GAPS, _("Make horizontal gaps between objects equal"), - 0, 4, true, NR::X, .5, .5); + 0, 4, true, Geom::X, .5, .5); - addDistributeButton("distribute_left", - _("Distribute left sides equidistantly"), - 0, 1, false, NR::X, 1., 0.); - addDistributeButton("distribute_hcentre", + addDistributeButton(INKSCAPE_ICON_DISTRIBUTE_HORIZONTAL_LEFT, + _("Distribute left edges equidistantly"), + 0, 1, false, Geom::X, 1., 0.); + addDistributeButton(INKSCAPE_ICON_DISTRIBUTE_HORIZONTAL_CENTER, _("Distribute centers equidistantly horizontally"), - 0, 2, false, NR::X, .5, .5); - addDistributeButton("distribute_right", - _("Distribute right sides equidistantly"), - 0, 3, false, NR::X, 0., 1.); + 0, 2, false, Geom::X, .5, .5); + addDistributeButton(INKSCAPE_ICON_DISTRIBUTE_HORIZONTAL_RIGHT, + _("Distribute right edges equidistantly"), + 0, 3, false, Geom::X, 0., 1.); - addDistributeButton("distribute_vdist", + addDistributeButton(INKSCAPE_ICON_DISTRIBUTE_VERTICAL_GAPS, _("Make vertical gaps between objects equal"), - 1, 4, true, NR::Y, .5, .5); + 1, 4, true, Geom::Y, .5, .5); - addDistributeButton("distribute_top", - _("Distribute tops equidistantly"), - 1, 1, false, NR::Y, 0, 1); - addDistributeButton("distribute_vcentre", + addDistributeButton(INKSCAPE_ICON_DISTRIBUTE_VERTICAL_TOP, + _("Distribute top edges equidistantly"), + 1, 1, false, Geom::Y, 0, 1); + addDistributeButton(INKSCAPE_ICON_DISTRIBUTE_VERTICAL_CENTER, _("Distribute centers equidistantly vertically"), - 1, 2, false, NR::Y, .5, .5); - addDistributeButton("distribute_bottom", - _("Distribute bottoms equidistantly"), - 1, 3, false, NR::Y, 1., 0.); + 1, 2, false, Geom::Y, .5, .5); + addDistributeButton(INKSCAPE_ICON_DISTRIBUTE_VERTICAL_BOTTOM, + _("Distribute bottom edges equidistantly"), + 1, 3, false, Geom::Y, 1., 0.); //Baseline distribs - addBaselineButton("distribute_baselines_hor", + addBaselineButton(INKSCAPE_ICON_DISTRIBUTE_HORIZONTAL_BASELINE, _("Distribute baseline anchors of texts horizontally"), - 0, 5, this->distribute_table(), NR::X, true); - addBaselineButton("distribute_baselines_vert", - _("Distribute baseline anchors of texts vertically"), - 1, 5, this->distribute_table(), NR::Y, true); + 0, 5, this->distribute_table(), Geom::X, true); + addBaselineButton(INKSCAPE_ICON_DISTRIBUTE_VERTICAL_BASELINE, + _("Distribute baselines of texts vertically"), + 1, 5, this->distribute_table(), Geom::Y, true); //Randomize & Unclump - addRandomizeButton("distribute_randomize", + addRandomizeButton(INKSCAPE_ICON_DISTRIBUTE_RANDOMIZE, _("Randomize centers in both dimensions"), 2, 2); - addUnclumpButton("unclump", + addUnclumpButton(INKSCAPE_ICON_DISTRIBUTE_UNCLUMP, _("Unclump objects: try to equalize edge-to-edge distances"), 2, 4); //Remove overlaps - addRemoveOverlapsButton("remove_overlaps", + addRemoveOverlapsButton(INKSCAPE_ICON_DISTRIBUTE_REMOVE_OVERLAPS, _("Move objects as little as possible so that their bounding boxes do not overlap"), 0, 0); //Graph Layout - addGraphLayoutButton("graph_layout", + addGraphLayoutButton(INKSCAPE_ICON_DISTRIBUTE_GRAPH, _("Nicely arrange selected connector network"), 0, 0); //Node Mode buttons - addNodeButton("node_halign", - _("Align selected nodes horizontally"), - 0, NR::X, false); - addNodeButton("node_valign", - _("Align selected nodes vertically"), - 1, NR::Y, false); - addNodeButton("node_hdistribute", + // NOTE: "align nodes vertically" means "move nodes vertically until they align on a common + // _horizontal_ line". This is analogous to what the "align-vertical-center" icon means. + // There is no doubt some ambiguity. For this reason the descriptions are different. + addNodeButton(INKSCAPE_ICON_ALIGN_VERTICAL_NODES, + _("Align selected nodes to a common horizontal line"), + 0, Geom::X, false); + addNodeButton(INKSCAPE_ICON_ALIGN_HORIZONTAL_NODES, + _("Align selected nodes to a common vertical line"), + 1, Geom::Y, false); + addNodeButton(INKSCAPE_ICON_DISTRIBUTE_HORIZONTAL_NODE, _("Distribute selected nodes horizontally"), - 2, NR::X, true); - addNodeButton("node_vdistribute", + 2, Geom::X, true); + addNodeButton(INKSCAPE_ICON_DISTRIBUTE_VERTICAL_NODE, _("Distribute selected nodes vertically"), - 3, NR::Y, true); + 3, Geom::Y, true); //Rest of the widgetry _combo.append_text(_("Last selected")); _combo.append_text(_("First selected")); - _combo.append_text(_("Biggest item")); - _combo.append_text(_("Smallest item")); + _combo.append_text(_("Biggest object")); + _combo.append_text(_("Smallest object")); _combo.append_text(_("Page")); _combo.append_text(_("Drawing")); _combo.append_text(_("Selection")); - _combo.set_active(prefs_get_int_attribute("dialogs.align", "align-to", 6)); + _combo.set_active(prefs->getInt("/dialogs/align/align-to", 6)); _combo.signal_changed().connect(sigc::mem_fun(*this, &AlignAndDistribute::on_ref_change)); _anchorBox.pack_start(_anchorLabel); _anchorBox.pack_start(_combo); + _selgrpBox.pack_start(_selgrpLabel); + _selgrpBox.pack_start(_selgrp); + _selgrp.set_active(prefs->getBool("/dialogs/align/sel-as-groups")); + _selgrp.signal_toggled().connect(sigc::mem_fun(*this, &AlignAndDistribute::on_selgrp_toggled)); + _alignBox.pack_start(_anchorBox); + _alignBox.pack_start(_selgrpBox); _alignBox.pack_start(_alignTable); _alignFrame.add(_alignBox); @@ -939,7 +957,7 @@ AlignAndDistribute::AlignAndDistribute() // Connect to the global selection change, to invalidate cached randomize_bbox g_signal_connect (G_OBJECT (INKSCAPE), "change_selection", G_CALLBACK (on_selection_changed), this); - randomize_bbox = NR::Nothing(); + randomize_bbox = Geom::OptRect(); show_all_children(); @@ -957,8 +975,15 @@ AlignAndDistribute::~AlignAndDistribute() } void AlignAndDistribute::on_ref_change(){ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt("/dialogs/align/align-to", _combo.get_active_row_number()); + + //Make blink the master +} - prefs_set_int_attribute("dialogs.align", "align-to", _combo.get_active_row_number()); +void AlignAndDistribute::on_selgrp_toggled(){ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt("/dialogs/align/sel-as-groups", _selgrp.get_active()); //Make blink the master } @@ -994,7 +1019,7 @@ void AlignAndDistribute::addAlignButton(const Glib::ustring &id, const Glib::ust } void AlignAndDistribute::addDistributeButton(const Glib::ustring &id, const Glib::ustring tiptext, guint row, guint col, bool onInterSpace, - NR::Dim2 orientation, float kBegin, float kEnd) + Geom::Dim2 orientation, float kBegin, float kEnd) { _actionList.push_back( new ActionDistribute( @@ -1006,7 +1031,7 @@ void AlignAndDistribute::addDistributeButton(const Glib::ustring &id, const Glib } void AlignAndDistribute::addNodeButton(const Glib::ustring &id, const Glib::ustring tiptext, - guint col, NR::Dim2 orientation, bool distribute) + guint col, Geom::Dim2 orientation, bool distribute) { _actionList.push_back( new ActionNode( @@ -1051,7 +1076,7 @@ void AlignAndDistribute::addRandomizeButton(const Glib::ustring &id, const Glib: } void AlignAndDistribute::addBaselineButton(const Glib::ustring &id, const Glib::ustring tiptext, - guint row, guint col, Gtk::Table &table, NR::Dim2 orientation, bool distribute) + guint row, guint col, Gtk::Table &table, Geom::Dim2 orientation, bool distribute) { _actionList.push_back( new ActionBaseline( @@ -1077,9 +1102,9 @@ std::list::iterator AlignAndDistribute::find_master( std::list::iterator it = list.begin(); it != list.end(); it++) { - NR::Maybe b = sp_item_bbox_desktop (*it); + Geom::OptRect b = sp_item_bbox_desktop (*it); if (b) { - gdouble dim = b->extent(horizontal ? NR::X : NR::Y); + gdouble dim = (*b)[horizontal ? Geom::X : Geom::Y].extent(); if (dim > max) { max = dim; master = it; @@ -1094,9 +1119,9 @@ std::list::iterator AlignAndDistribute::find_master( std::list::iterator it = list.begin(); it != list.end(); it++) { - NR::Maybe b = sp_item_bbox_desktop (*it); + Geom::OptRect b = sp_item_bbox_desktop (*it); if (b) { - gdouble dim = b->extent(horizontal ? NR::X : NR::Y); + gdouble dim = (*b)[horizontal ? Geom::X : Geom::Y].extent(); if (dim < max) { max = dim; master = it;