Code

Ctrl+click in pen/pencil tool: Created dots are now selected; Alt is used for randomn...
[inkscape.git] / src / ui / dialog / align-and-distribute.cpp
index 4acbbbb43a1a7547baede2f6dbd194f95c3473d9..4846158a712fa7faea9706d9e20214060971ab9d 100644 (file)
@@ -46,7 +46,8 @@
 #include "sp-flowtext.h"
 #include "text-editing.h"
 
-#include "node-context.h" //For node align/distribute function
+#include "node-context.h"  //For access to ShapeEditor
+#include "shape-editor.h" //For node align/distribute methods
 
 #include "tools-switch.h"
 
@@ -70,7 +71,7 @@ public :
         _id(id),
         _parent(parent)
     {
-        Gtk::Widget*  pIcon = Gtk::manage( sp_icon_get_icon( _id, GTK_ICON_SIZE_LARGE_TOOLBAR) );
+        Gtk::Widget*  pIcon = Gtk::manage( sp_icon_get_icon( _id, Inkscape::ICON_SIZE_LARGE_TOOLBAR) );
         Gtk::Button * pButton = Gtk::manage(new Gtk::Button());
         pButton->set_relief(Gtk::RELIEF_NONE);
         pIcon->show();
@@ -115,10 +116,10 @@ private :
 
     virtual void on_button_click() {
         //Retreive selected objects
-        SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+        SPDesktop *desktop = _dialog.getDesktop();
         if (!desktop) return;
 
-        Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
+        Inkscape::Selection *selection = sp_desktop_selection(desktop);
         if (!selection) return;
 
         using Inkscape::Util::GSListConstIterator;
@@ -152,31 +153,43 @@ private :
             SPItem * thing = *master;
             selected.erase(master);
             //Compute the anchor point
-            NR::Rect b = sp_item_bbox_desktop (thing);
-            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]);
+            NR::Maybe<NR::Rect> 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]);
+            } else {
+                return;
+            }
             break;
         }
 
         case AlignAndDistribute::PAGE:
-            mp = NR::Point(a.mx1 * sp_document_width(SP_DT_DOCUMENT(desktop)),
-                           a.my1 * sp_document_height(SP_DT_DOCUMENT(desktop)));
+            mp = NR::Point(a.mx1 * sp_document_width(sp_desktop_document(desktop)),
+                           a.my1 * sp_document_height(sp_desktop_document(desktop)));
             break;
 
         case AlignAndDistribute::DRAWING:
         {
-            NR::Rect b = sp_item_bbox_desktop
-                ( (SPItem *) sp_document_root (SP_DT_DOCUMENT (desktop)) );
-            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]);
+            NR::Maybe<NR::Rect> 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]);
+            } else {
+                return;
+            }
             break;
         }
 
         case AlignAndDistribute::SELECTION:
         {
-            NR::Rect b =  selection->bounds();
-            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]);
+            NR::Maybe<NR::Rect> 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]);
+            } else {
+                return;
+            }
             break;
         }
 
@@ -200,14 +213,16 @@ private :
              it != selected.end();
              it++)
         {
-            sp_document_ensure_up_to_date(SP_DT_DOCUMENT (desktop));
-            NR::Rect b = sp_item_bbox_desktop (*it);
-            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 );
-            if (LInfty(mp_rel) > 1e-9) {
-                sp_item_move_rel(*it, NR::translate(mp_rel));
-                changed = true;
+            sp_document_ensure_up_to_date(sp_desktop_document (desktop));
+            NR::Maybe<NR::Rect> 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 );
+                if (LInfty(mp_rel) > 1e-9) {
+                    sp_item_move_rel(*it, NR::translate(mp_rel));
+                    changed = true;
+                }
             }
         }
 
@@ -215,7 +230,8 @@ private :
         prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
 
         if (changed) {
-            sp_document_done ( SP_DT_DOCUMENT (desktop) );
+            sp_document_done ( sp_desktop_document (desktop) , SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
+                               _("Align"));
         }
 
 
@@ -244,9 +260,9 @@ struct BBoxSort
     SPItem *item;
     float anchor;
     NR::Rect bbox;
-    BBoxSort(SPItem *pItem, NR::Dim2 orientation, double kBegin, double kEnd) :
+    BBoxSort(SPItem *pItem, NR::Rect bounds, NR::Dim2 orientation, double kBegin, double kEnd) :
         item(pItem),
-        bbox (sp_item_bbox_desktop (pItem))
+        bbox (bounds)
     {
         anchor = kBegin * bbox.min()[orientation] + kEnd * bbox.max()[orientation];
     }
@@ -284,10 +300,10 @@ public :
 private :
     virtual void on_button_click() {
         //Retreive selected objects
-        SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+        SPDesktop *desktop = _dialog.getDesktop();
         if (!desktop) return;
 
-        Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
+        Inkscape::Selection *selection = sp_desktop_selection(desktop);
         if (!selection) return;
 
         using Inkscape::Util::GSListConstIterator;
@@ -306,8 +322,10 @@ private :
             it != selected.end();
             ++it)
         {
-            BBoxSort b (*it, _orientation, _kBegin, _kEnd);
-            sorted.push_back(b);
+            NR::Maybe<NR::Rect> bbox = sp_item_bbox_desktop(*it);
+            if (bbox) {
+                sorted.push_back(BBoxSort(*it, *bbox, _orientation, _kBegin, _kEnd));
+            }
         }
         //sort bbox by anchors
         std::sort(sorted.begin(), sorted.end());
@@ -374,7 +392,8 @@ private :
         prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
 
         if (changed) {
-            sp_document_done ( SP_DT_DOCUMENT (desktop) );
+            sp_document_done ( sp_desktop_document (desktop), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, 
+                               _("Distribute"));
         }
     }
     guint _index;
@@ -407,16 +426,14 @@ private :
     virtual void on_button_click()
     {
 
-        if (!SP_ACTIVE_DESKTOP) return;
-       SPEventContext *event_context = SP_DT_EVENTCONTEXT(SP_ACTIVE_DESKTOP);
+        if (!_dialog.getDesktop()) return;
+       SPEventContext *event_context = sp_desktop_event_context(_dialog.getDesktop());
        if (!SP_IS_NODE_CONTEXT (event_context)) return ;
 
-        Inkscape::NodePath::Path *nodepath = SP_NODE_CONTEXT (event_context)->nodepath;
-        if (!nodepath) return;
         if (_distribute)
-            sp_nodepath_selected_distribute(nodepath, _orientation);
+            SP_NODE_CONTEXT (event_context)->shape_editor->distribute(_orientation);
         else
-            sp_nodepath_selected_align(nodepath, _orientation);
+            SP_NODE_CONTEXT (event_context)->shape_editor->align(_orientation);
 
     }
 };
@@ -469,7 +486,7 @@ public:
 private :
     virtual void on_button_click()
     {
-        if (!SP_ACTIVE_DESKTOP) return;
+        if (!_dialog.getDesktop()) return;
 
         // see comment in ActionAlign above
         int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
@@ -478,13 +495,14 @@ private :
         // xGap and yGap are the minimum space required between bounding rectangles.
         double const xGap = removeOverlapXGap.get_value();
         double const yGap = removeOverlapYGap.get_value();
-        removeoverlap(SP_DT_SELECTION(SP_ACTIVE_DESKTOP)->itemList(),
+        removeoverlap(sp_desktop_selection(_dialog.getDesktop())->itemList(),
                       xGap, yGap);
 
         // restore compensation setting
         prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
 
-        sp_document_done(SP_DT_DOCUMENT(SP_ACTIVE_DESKTOP));
+        sp_document_done(sp_desktop_document(_dialog.getDesktop()), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, 
+                         _("Remove overlaps"));
     }
 };
 
@@ -502,18 +520,19 @@ public:
 private :
     virtual void on_button_click()
     {
-        if (!SP_ACTIVE_DESKTOP) return;
+        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);
 
-        graphlayout(SP_DT_SELECTION(SP_ACTIVE_DESKTOP)->itemList());
+        graphlayout(sp_desktop_selection(_dialog.getDesktop())->itemList());
 
         // restore compensation setting
         prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
 
-        sp_document_done(SP_DT_DOCUMENT(SP_ACTIVE_DESKTOP));
+        sp_document_done(sp_desktop_document(_dialog.getDesktop()), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, 
+                         _("Arrange connector network"));
     }
 };
 
@@ -531,18 +550,19 @@ public :
 private :
     virtual void on_button_click()
     {
-        if (!SP_ACTIVE_DESKTOP) return;
+        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);
 
-        unclump ((GSList *) SP_DT_SELECTION(SP_ACTIVE_DESKTOP)->itemList());
+        unclump ((GSList *) sp_desktop_selection(_dialog.getDesktop())->itemList());
 
         // restore compensation setting
         prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
 
-        sp_document_done (SP_DT_DOCUMENT (SP_ACTIVE_DESKTOP));
+        sp_document_done (sp_desktop_document (_dialog.getDesktop()), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, 
+                          _("Unclump"));
     }
 };
 
@@ -560,10 +580,10 @@ public :
 private :
     virtual void on_button_click()
     {
-        SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+        SPDesktop *desktop = _dialog.getDesktop();
         if (!desktop) return;
 
-        Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
+        Inkscape::Selection *selection = sp_desktop_selection(desktop);
         if (!selection) return;
 
         using Inkscape::Util::GSListConstIterator;
@@ -574,12 +594,16 @@ private :
         //Check 2 or more selected objects
         if (selected.size() < 2) return;
 
+        NR::Maybe<NR::Rect> sel_bbox = selection->bounds();
+        if (!sel_bbox) {
+            return;
+        }
+
         // This bbox is cached between calls to randomize, so that there's no growth nor shrink
         // nor drift on sequential randomizations. Discard cache on global (or better active
         // desktop's) selection_change signal.
-        if (!_dialog.randomize_bbox_set) {
-            _dialog.randomize_bbox = selection->bounds();
-            _dialog.randomize_bbox_set = true;
+        if (!_dialog.randomize_bbox) {
+            _dialog.randomize_bbox = *sel_bbox;
         }
 
         // see comment in ActionAlign above
@@ -590,22 +614,25 @@ private :
             it != selected.end();
             ++it)
         {
-            sp_document_ensure_up_to_date(SP_DT_DOCUMENT (desktop));
-            NR::Rect item_box = sp_item_bbox_desktop (*it);
-            // 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));
-            // 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));
+            sp_document_ensure_up_to_date(sp_desktop_document (desktop));
+            NR::Maybe<NR::Rect> 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));
+                // 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));
+            }
         }
 
         // restore compensation setting
         prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
 
-        sp_document_done (SP_DT_DOCUMENT (SP_ACTIVE_DESKTOP));
+        sp_document_done (sp_desktop_document (desktop), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, 
+                          _("Randomize positions"));
     }
 };
 
@@ -646,10 +673,10 @@ private :
     bool _distribute;
     virtual void on_button_click()
     {
-        SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+        SPDesktop *desktop = _dialog.getDesktop();
         if (!desktop) return;
 
-        Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
+        Inkscape::Selection *selection = sp_desktop_selection(desktop);
         if (!selection) return;
 
         using Inkscape::Util::GSListConstIterator;
@@ -700,6 +727,11 @@ private :
                 changed = true;
             }
 
+            if (changed) {
+                sp_document_done (sp_desktop_document (desktop), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, 
+                                  _("Distribute text baselines"));
+            }
+
         } else {
             for (std::list<SPItem *>::iterator it(selected.begin());
                  it != selected.end();
@@ -714,10 +746,11 @@ private :
                     changed = true;
                 }
             }
-        }
 
-        if (changed) {
-            sp_document_done (SP_DT_DOCUMENT (SP_ACTIVE_DESKTOP));
+            if (changed) {
+                sp_document_done (sp_desktop_document (desktop), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, 
+                                  _("Align text baselines"));
+            }
         }
     }
 };
@@ -727,13 +760,13 @@ private :
 void on_tool_changed(Inkscape::Application *inkscape, SPEventContext *context, AlignAndDistribute *daad)
 {
     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
-    if (desktop && SP_DT_EVENTCONTEXT(desktop))
+    if (desktop && sp_desktop_event_context(desktop))
         daad->setMode(tools_active(desktop) == TOOLS_NODES);
 }
 
 void on_selection_changed(Inkscape::Application *inkscape, Inkscape::Selection *selection, AlignAndDistribute *daad)
 {
-    daad->randomize_bbox_set = false;
+    daad->randomize_bbox = NR::Nothing();
 }
 
 /////////////////////////////////////////////////////////
@@ -742,8 +775,8 @@ void on_selection_changed(Inkscape::Application *inkscape, Inkscape::Selection *
 
 
 AlignAndDistribute::AlignAndDistribute() 
-    : Dialog ("dialogs.align", SP_VERB_DIALOG_ALIGN_DISTRIBUTE),
-      randomize_bbox (NR::Point (0, 0), NR::Point (0, 0)),
+    : UI::Widget::Panel ("", "dialogs.align", SP_VERB_DIALOG_ALIGN_DISTRIBUTE),
+      randomize_bbox(NR::Nothing()),
       _alignFrame(_("Align")),
       _distributeFrame(_("Distribute")),
       _removeOverlapFrame(_("Remove overlaps")),
@@ -875,7 +908,7 @@ AlignAndDistribute::AlignAndDistribute()
     _combo.append_text(_("Drawing"));
     _combo.append_text(_("Selection"));
 
-    _combo.set_active(6);
+    _combo.set_active(prefs_get_int_attribute("dialogs.align", "align-to", 6));
     _combo.signal_changed().connect(sigc::mem_fun(*this, &AlignAndDistribute::on_ref_change));
 
     _anchorBox.pack_start(_anchorLabel);
@@ -890,25 +923,23 @@ AlignAndDistribute::AlignAndDistribute()
     _graphLayoutFrame.add(_graphLayoutTable);
     _nodesFrame.add(_nodesTable);
 
-    // Top level vbox
-    Gtk::VBox *vbox = get_vbox();
-    vbox->set_spacing(4);
+    Gtk::Box *contents = _getContents();
+    contents->set_spacing(4);
 
     // Notebook for individual transformations
 
-    vbox->pack_start(_alignFrame, true, true);
-    vbox->pack_start(_distributeFrame, true, true);
-    vbox->pack_start(_removeOverlapFrame, true, true);
-    vbox->pack_start(_graphLayoutFrame, true, true);
-    vbox->pack_start(_nodesFrame, true, true);
+    contents->pack_start(_alignFrame, true, true);
+    contents->pack_start(_distributeFrame, true, true);
+    contents->pack_start(_removeOverlapFrame, true, true);
+    contents->pack_start(_graphLayoutFrame, true, true);
+    contents->pack_start(_nodesFrame, true, true);
 
     //Connect to the global tool change signal
     g_signal_connect (G_OBJECT (INKSCAPE), "set_eventcontext", G_CALLBACK (on_tool_changed), this);
 
     // 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::Rect (NR::Point (0, 0), NR::Point (0, 0));
-    randomize_bbox_set = false;
+    randomize_bbox = NR::Nothing();
 
     show_all_children();
 
@@ -926,7 +957,10 @@ AlignAndDistribute::~AlignAndDistribute()
 }
 
 void AlignAndDistribute::on_ref_change(){
-//Make blink the master
+
+    prefs_set_int_attribute("dialogs.align", "align-to", _combo.get_active_row_number());
+
+    //Make blink the master
 }
 
 
@@ -1043,11 +1077,13 @@ std::list<SPItem *>::iterator AlignAndDistribute::find_master( std::list<SPItem
     {
         gdouble max = -1e18;
         for (std::list<SPItem *>::iterator it = list.begin(); it != list.end(); it++) {
-            NR::Rect b = sp_item_bbox_desktop (*it);
-            gdouble dim = b.extent(horizontal ? NR::X : NR::Y);
-            if (dim > max) {
-                max = dim;
-                master = it;
+            NR::Maybe<NR::Rect> b = sp_item_bbox_desktop (*it);
+            if (b) {
+                gdouble dim = b->extent(horizontal ? NR::X : NR::Y);
+                if (dim > max) {
+                    max = dim;
+                    master = it;
+                }
             }
         }
         return master;
@@ -1058,11 +1094,13 @@ std::list<SPItem *>::iterator AlignAndDistribute::find_master( std::list<SPItem
     {
         gdouble max = 1e18;
         for (std::list<SPItem *>::iterator it = list.begin(); it != list.end(); it++) {
-            NR::Rect b = sp_item_bbox_desktop (*it);
-            gdouble dim = b.extent(horizontal ? NR::X : NR::Y);
-            if (dim < max) {
-                max = dim;
-                master = it;
+            NR::Maybe<NR::Rect> b = sp_item_bbox_desktop (*it);
+            if (b) {
+                gdouble dim = b->extent(horizontal ? NR::X : NR::Y);
+                if (dim < max) {
+                    max = dim;
+                    master = it;
+                }
             }
         }
         return master;