selection.h revision 1f6daa293cacc62d85a023412c70534a12f6e99a
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop#ifndef SEEN_INKSCAPE_SELECTION_H
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop#define SEEN_INKSCAPE_SELECTION_H
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop/*
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop * Authors:
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop * Lauris Kaplinski <lauris@kaplinski.com>
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop * MenTaLguY <mental@rydia.net>
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop * bulia byak <buliabyak@users.sf.net>
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop *
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop * Copyright (C) 2004-2005 MenTaLguY
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop * Copyright (C) 1999-2002 Lauris Kaplinski
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop * Copyright (C) 2001-2002 Ximian, Inc.
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop *
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop * Released under GNU GPL, read the file 'COPYING' for more information
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop */
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop#include <vector>
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop#include <map>
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop#include <list>
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop#include <set>
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop#include <stddef.h>
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop#include <sigc++/sigc++.h>
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lierop#include "gc-managed.h"
45d2569e428fc3733725b5e64e313e48c2a9d989Diederik van Lierop#include "gc-finalized.h"
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop#include "gc-anchored.h"
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop#include "gc-soft-ptr.h"
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop#include "sp-item.h"
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lierop
ae73b82cf10057153a43afdcb1f3a22deac18ea2Diederik van Lieropclass SPDesktop;
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lieropclass SPItem;
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lieropclass SPBox3D;
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lieropclass Persp3D;
45d2569e428fc3733725b5e64e313e48c2a9d989Diederik van Lierop
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lieroptypedef std::list<SPObject*> SelContainer;
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop
e0762361898748e8a6943d30ef1b5b070d4498a1Diederik van Lieropnamespace Inkscape {
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lieropclass LayerModel;
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lieropnamespace XML {
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lieropclass Node;
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lierop}
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lierop}
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lierop
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lierop/*template<typename T>
45d2569e428fc3733725b5e64e313e48c2a9d989Diederik van Lieropconst GSList* std_list_to_GS_list(const std::list<T *> list) const
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop{
c60180049420944fe78f7d8b2ca1df28cba163fdDiederik van Lierop gpointer l=NULL;
45d2569e428fc3733725b5e64e313e48c2a9d989Diederik van Lierop for(auto x:list){
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop
c60180049420944fe78f7d8b2ca1df28cba163fdDiederik van Lierop }
195e5fada891025f6d2f260e915ac209e0c0a5d0Diederik van Lierop}*/
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lieropnamespace Inkscape {
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop/**
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop * The set of selected SPObjects for a given document and layer model.
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lierop *
45d2569e428fc3733725b5e64e313e48c2a9d989Diederik van Lierop * This class represents the set of selected SPItems for a given
45d2569e428fc3733725b5e64e313e48c2a9d989Diederik van Lierop * document (referenced in LayerModel).
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop *
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop * An SPObject and its parent cannot be simultaneously selected;
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop * selecting an SPObjects has the side-effect of unselecting any of
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop * its children which might have been selected.
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop *
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lierop * This is a per-desktop object that keeps the list of selected objects
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop * at the given desktop. Both SPItem and SPRepr lists can be retrieved
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop * from the selection. Many actions operate on the selection, so it is
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop * widely used throughout the code.
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop * It also implements its own asynchronous notification signals that
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop * UI elements can listen to.
45d2569e428fc3733725b5e64e313e48c2a9d989Diederik van Lierop */
45d2569e428fc3733725b5e64e313e48c2a9d989Diederik van Lieropclass Selection : public Inkscape::GC::Managed<>,
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop public Inkscape::GC::Finalized,
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lierop public Inkscape::GC::Anchored
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop{
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lieroppublic:
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop enum CompareSize { HORIZONTAL, VERTICAL, AREA };
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop /**
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop * Constructs an selection object, bound to a particular
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop * layer model
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lierop *
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lierop * @param layers the layer model (for the SPDesktop, if GUI)
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lierop * @param desktop the desktop associated with the layer model, or NULL if in console mode
727eeb2592befe925906eb7605e9ed770697162bDiederik van Lierop */
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop Selection(LayerModel *layers, SPDesktop *desktop);
45d2569e428fc3733725b5e64e313e48c2a9d989Diederik van Lierop ~Selection();
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop /**
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop * Returns the layer model the selection is bound to (works in console or GUI mode)
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop *
45d2569e428fc3733725b5e64e313e48c2a9d989Diederik van Lierop * @return the layer model the selection is bound to, which is the same as the desktop
45d2569e428fc3733725b5e64e313e48c2a9d989Diederik van Lierop * layer model for GUI mode
45d2569e428fc3733725b5e64e313e48c2a9d989Diederik van Lierop */
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop LayerModel *layers() { return _layers; }
72cd517ebd6730a0b8b1b71bdb267ffe9f1d94ffDiederik van Lierop
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop /**
f200d31b8a03050faa7243929bbd5698db488399Diederik van Lierop * Returns the desktop the selection is bound to
*
* @return the desktop the selection is bound to, or NULL if in console mode
*/
SPDesktop *desktop() { return _desktop; }
/**
* Returns active layer for selection (currentLayer or its parent).
*
* @return layer item the selection is bound to
*/
SPObject *activeContext();
/**
* Add an SPObject to the set of selected objects.
*
* @param obj the SPObject to add
*/
void add(SPObject *obj, bool persist_selection_context = false);
/**
* Add an XML node's SPObject to the set of selected objects.
*
* @param the xml node of the item to add
*/
void add(XML::Node *repr) { add(_objectForXMLNode(repr)); }
/**
* Set the selection to a single specific object.
*
* @param obj the object to select
*/
void set(SPObject *obj, bool persist_selection_context = false);
/**
* Set the selection to an XML node's SPObject.
*
* @param repr the xml node of the item to select
*/
void set(XML::Node *repr) { set(_objectForXMLNode(repr)); }
/**
* Removes an item from the set of selected objects.
*
* It is ok to call this method for an unselected item.
*
* @param item the item to unselect
*/
void remove(SPObject *obj);
/**
* Removes an item if selected, adds otherwise.
*
* @param item the item to unselect
*/
void toggle(SPObject *obj);
/**
* Removes an item from the set of selected objects.
*
* It is ok to call this method for an unselected item.
*
* @param repr the xml node of the item to remove
*/
void remove(XML::Node *repr) { remove(_objectForXMLNode(repr)); }
/**
* Selects exactly the specified objects.
*
* @param objs the objects to select
*/
void setList(std::vector<SPItem*> const &objs);
/**
* Adds the specified objects to selection, without deselecting first.
*
* @param objs the objects to select
*/
void addList(std::vector<SPItem*> const &objs);
/**
* Clears the selection and selects the specified objects.
*
* @param repr a list of xml nodes for the items to select
*/
void setReprList(std::vector<XML::Node*> const &reprs);
/** Add items from an STL iterator range to the selection.
* \param from the begin iterator
* \param to the end iterator
*/
template <typename InputIterator>
void add(InputIterator from, InputIterator to) {
_invalidateCachedLists();
while ( from != to ) {
_add(*from);
++from;
}
_emitChanged();
}
/**
* Unselects all selected objects..
*/
void clear();
/**
* Returns true if no items are selected.
*/
bool isEmpty() const { return _objs.empty(); }
/**
* Returns true if the given object is selected.
*/
bool includes(SPObject *obj) const;
/**
* Returns true if the given item is selected.
*/
bool includes(XML::Node *repr) const {
return includes(_objectForXMLNode(repr));
}
/**
* Returns a single selected object.
*
* @return NULL unless exactly one object is selected
*/
SPObject *single();
/**
* Returns a single selected item.
*
* @return NULL unless exactly one object is selected
*/
SPItem *singleItem();
/**
* Returns the smallest item from this selection.
*/
SPItem *smallestItem(CompareSize compare);
/**
* Returns the largest item from this selection.
*/
SPItem *largestItem(CompareSize compare);
/**
* Returns a single selected object's xml node.
*
* @return NULL unless exactly one object is selected
*/
XML::Node *singleRepr();
/** Returns the list of selected objects. */
std::vector<SPObject*> const &list();
/** Returns the list of selected SPItems. */
std::vector<SPItem*> const &itemList();
/** Returns a list of the xml nodes of all selected objects. */
/// \todo only returns reprs of SPItems currently; need a separate
/// method for that
std::vector<XML::Node*> const &reprList();
/** Returns a list of all perspectives which have a 3D box in the current selection.
(these may also be nested in groups) */
std::list<Persp3D *> const perspList();
/**
* Returns a list of all 3D boxes in the current selection which are associated to @c
* persp. If @c pers is @c NULL, return all selected boxes.
*/
std::list<SPBox3D *> const box3DList(Persp3D *persp = NULL);
/** Returns the number of layers in which there are selected objects. */
unsigned int numberOfLayers();
/** Returns the number of parents to which the selected objects belong. */
unsigned int numberOfParents();
/** Returns the bounding rectangle of the selection. */
Geom::OptRect bounds(SPItem::BBoxType type) const;
Geom::OptRect visualBounds() const;
Geom::OptRect geometricBounds() const;
/**
* Returns either the visual or geometric bounding rectangle of the selection, based on the
* preferences specified for the selector tool
*/
Geom::OptRect preferredBounds() const;
/// Returns the bounding rectangle of the selectionin document coordinates.
Geom::OptRect documentBounds(SPItem::BBoxType type) const;
/**
* Returns the rotation/skew center of the selection.
*/
boost::optional<Geom::Point> center() const;
/**
* Compute the list of points in the selection that are to be considered for snapping from.
*
* @return Selection's snap points
*/
std::vector<Inkscape::SnapCandidatePoint> getSnapPoints(SnapPreferences const *snapprefs) const;
/**
* Connects a slot to be notified of selection changes.
*
* This method connects the given slot such that it will
* be called upon any change in the set of selected objects.
*
* @param slot the slot to connect
*
* @return the resulting connection
*/
sigc::connection connectChanged(sigc::slot<void, Selection *> const &slot) {
return _changed_signal.connect(slot);
}
sigc::connection connectChangedFirst(sigc::slot<void, Selection *> const &slot)
{
return _changed_signal.slots().insert(_changed_signal.slots().begin(), slot);
}
/**
* Connects a slot to be notified of selected object modifications.
*
* This method connects the given slot such that it will
* receive notifications whenever any selected item is
* modified.
*
* @param slot the slot to connect
*
* @return the resulting connection
*
*/
sigc::connection connectModified(sigc::slot<void, Selection *, unsigned int> const &slot)
{
return _modified_signal.connect(slot);
}
sigc::connection connectModifiedFirst(sigc::slot<void, Selection *, unsigned int> const &slot)
{
return _modified_signal.slots().insert(_modified_signal.slots().begin(), slot);
}
private:
/** no copy. */
Selection(Selection const &);
/** no assign. */
void operator=(Selection const &);
/** Issues modification notification signals. */
static int _emit_modified(Selection *selection);
/** Schedules an item modification signal to be sent. */
void _schedule_modified(SPObject *obj, unsigned int flags);
/** Issues modified selection signal. */
void _emitModified(unsigned int flags);
/** Issues changed selection signal. */
void _emitChanged(bool persist_selection_context = false);
void _invalidateCachedLists();
/** unselect all descendants of the given item. */
void _removeObjectDescendants(SPObject *obj);
/** unselect all ancestors of the given item. */
void _removeObjectAncestors(SPObject *obj);
/** clears the selection (without issuing a notification). */
void _clear();
/** adds an object (without issuing a notification). */
void _add(SPObject *obj);
/** removes an object (without issuing a notification). */
void _remove(SPObject *obj);
/** returns the SPObject corresponding to an xml node (if any). */
SPObject *_objectForXMLNode(XML::Node *repr) const;
/** Releases an active layer object that is being removed. */
void _releaseContext(SPObject *obj);
mutable std::list<SPObject*> _objs; //to more efficiently remove arbitrary elements
mutable std::vector<SPObject*> _objs_vector; // to be returned by list();
mutable std::set<SPObject*> _objs_set; //to efficiently test if object is selected
mutable std::vector<XML::Node*> _reprs;
mutable std::vector<SPItem*> _items;
void add_box_perspective(SPBox3D *box);
void add_3D_boxes_recursively(SPObject *obj);
void remove_box_perspective(SPBox3D *box);
void remove_3D_boxes_recursively(SPObject *obj);
SPItem *_sizeistItem(bool sml, CompareSize compare);
std::list<SPBox3D *> _3dboxes;
LayerModel *_layers;
GC::soft_ptr<SPDesktop> _desktop;
SPObject* _selection_context;
unsigned int _flags;
unsigned int _idle;
std::map<SPObject *, sigc::connection> _modified_connections;
std::map<SPObject *, sigc::connection> _release_connections;
sigc::connection _context_release_connection;
sigc::signal<void, Selection *> _changed_signal;
sigc::signal<void, Selection *, unsigned int> _modified_signal;
};
}
#endif
/*
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 :