mirror of https://github.com/KLayout/klayout.git
586 lines
16 KiB
C++
586 lines
16 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2017 Matthias Koefferlein
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
#ifndef HDR_layEditable
|
|
#define HDR_layEditable
|
|
|
|
#include "laybasicCommon.h"
|
|
|
|
#include "tlObjectCollection.h"
|
|
#include "laySnap.h"
|
|
#include "dbTrans.h"
|
|
#include "dbPoint.h"
|
|
#include "dbBox.h"
|
|
#include "dbObject.h"
|
|
|
|
#include <set>
|
|
#include <limits>
|
|
|
|
class QWidget;
|
|
|
|
namespace lay
|
|
{
|
|
|
|
class Editables;
|
|
class PropertiesPage;
|
|
class PropertiesDialog;
|
|
|
|
/**
|
|
* @brief The "editable" interface
|
|
*
|
|
* An "editable" object is providing an interface with the
|
|
* common editing operations like "delete", "copy", "select" etc.
|
|
* The "editable" objects are maintained in an lay::Editables collection.
|
|
*/
|
|
class LAYBASIC_PUBLIC Editable
|
|
: virtual public tl::Object
|
|
{
|
|
public:
|
|
enum SelectionMode { Replace = 0, Reset, Add, Invert };
|
|
enum MoveMode { Any = 0, Selected, Partial };
|
|
|
|
/**
|
|
* @brief The constructor
|
|
*
|
|
* @param editables The collection in which to insert the
|
|
* object. Can be 0 for not inserting it somewhere.
|
|
*/
|
|
Editable (Editables *editables = 0);
|
|
|
|
/**
|
|
* @brief The constructor
|
|
*/
|
|
virtual ~Editable ();
|
|
|
|
/**
|
|
* @brief "delete" operation
|
|
*/
|
|
virtual void del ()
|
|
{
|
|
// .. by default, nothing is implemented ..
|
|
}
|
|
|
|
/**
|
|
* @brief "cut" operation
|
|
*/
|
|
virtual void cut ()
|
|
{
|
|
// .. by default, nothing is implemented ..
|
|
}
|
|
|
|
/**
|
|
* @brief "copy" operation
|
|
*/
|
|
virtual void copy ()
|
|
{
|
|
// .. by default, nothing is implemented ..
|
|
}
|
|
|
|
/**
|
|
* @brief Deliver the bbox of the selection
|
|
*
|
|
* This bounding box is used to compute the center of the
|
|
* selection for transformation by an angle (it is better
|
|
* to do this around der center of the selection bbox).
|
|
* The bbox must either be empty (if no selection is present)
|
|
* or must be given in micron units.
|
|
*/
|
|
virtual db::DBox selection_bbox ()
|
|
{
|
|
return db::DBox ();
|
|
}
|
|
|
|
/**
|
|
* @brief transform the selection
|
|
*
|
|
* The transformation is given in micron units.
|
|
*/
|
|
virtual void transform (const db::DCplxTrans & /*tr*/)
|
|
{
|
|
// .. by default, nothing is implemented ..
|
|
}
|
|
|
|
/**
|
|
* @brief "paste" operation
|
|
*/
|
|
virtual void paste ()
|
|
{
|
|
// .. by default, nothing is implemented ..
|
|
}
|
|
|
|
/**
|
|
* @brief "point selection proximity" predicate
|
|
*
|
|
* The point selection proximity is a method to determine which
|
|
* object should be selected by point selection. The point selection
|
|
* proximity is a typical distance value of the point to the closest
|
|
* object in micron. The plugin with the least point selection proximity
|
|
* is selected first for the actual "select" operation.
|
|
* If a plugin definitly wants to get the selection, it should return
|
|
* a negative value. If the plugin is only weakly interested in a selection,
|
|
* it should return the value provided by the default implementation.
|
|
* The click_proximity method can be used to implement cycling through
|
|
* several objects on the same location by delivering the proximity for
|
|
* "new" objects only by remembering the objects already selected.
|
|
* If the client of the plugin finds no plugin that has anything to select,
|
|
* it will try to reset the selected and do a new scan over all plugins.
|
|
*
|
|
* @param pos The point at which to select in micron space.
|
|
* @param mode The mode of the selection for which the closest object is looked for.
|
|
* @return The distance in micron
|
|
*/
|
|
virtual double click_proximity (const db::DPoint & /*pos*/, SelectionMode /*mode*/)
|
|
{
|
|
return std::numeric_limits<double>::max ();
|
|
}
|
|
|
|
/**
|
|
* @brief transient selection
|
|
*
|
|
* The transient selection is triggered when the mouse does not move for
|
|
* some time interval ("hover mode").
|
|
* This method is supposed to create a transient selection on a single object
|
|
* at the given point.
|
|
*
|
|
* @param point The point at which to select in micron space.
|
|
* @return Should return true if anything was selected
|
|
*/
|
|
virtual bool transient_select (const db::DPoint & /*pos*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief Clear the transient selection
|
|
*
|
|
* This method is supposed to reset any transient selection
|
|
*/
|
|
virtual void clear_transient_selection ()
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
/**
|
|
* @brief Clears the previous selection state
|
|
*
|
|
* This method is used by the single-point selection cycling protocol to clear the
|
|
* plugin's single-point selection state. The cycling protocol is used when a certain
|
|
* point is clicked at multiple times. A plugin is supposed to remember such selections and
|
|
* exlcude them from futher checks. If all objects in question are selected, no further
|
|
* object would be selected. clear_previous_selection is called in that case to indicate that
|
|
* the previous selection should be cleared and a new cycle is about to begin
|
|
*/
|
|
virtual void clear_previous_selection ()
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
/**
|
|
* @brief "select" operation
|
|
*
|
|
* This is geometrical selection of objects. Selection can be
|
|
* either by a box or by a point. In the latter case, a degenerated
|
|
* box must be provided which is a single-point box.
|
|
* An empty box equals "all".
|
|
* The return value is basically used by the point selection mode
|
|
* to determine the first editable that gets the selection.
|
|
*
|
|
* @param box The box within which to select in micron space.
|
|
* @param mode The selection mode
|
|
* @return Should return true if anything was selected, in particular in point mode
|
|
*/
|
|
virtual bool select (const db::DBox & /*box*/, SelectionMode /*mode*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief Start a "move" operation
|
|
*
|
|
* The move operation can be requested in three modes: In "Any" mode, the plugin
|
|
* can decide whether it wants to catch a move request and return true.
|
|
* In "Selected" mode, the plugin is supposed to move all selected objects.
|
|
* In "Partial" mode, the plugin is supposed to pick an object from the selected
|
|
* ones and perform a move that modifies that object. In "Any" or "Selected" mode,
|
|
* the plugin must return true to catch the selection. Only one plugin will receive
|
|
* the selection.
|
|
*
|
|
* All move operations start from point p.
|
|
*
|
|
* A move operation is continued by "move" events and terminated
|
|
* by either a "cancel" or a "end_move" event.
|
|
*
|
|
* The basic algorithm used for the move implementation is this:
|
|
* 1.) if anything is selected, call begin_move on every Editable with sel=Partial.
|
|
* If a plugin returns true, the method returns.
|
|
* 2.) else if anything is selected, call begin_move on every Editable with sel=Selected.
|
|
* 3.) if nothing is selected, call begin_move on every Editable with sel=Any. Stop if one of
|
|
* these returns true.
|
|
* 4.) if none returned true, select pointwise around "p" and proceed as in 2.)
|
|
*
|
|
* @param sel See above.
|
|
* @param p The point at which the mouse was clicked
|
|
* @param ac The angle constraint imposed (lay::AC_Global if no specific is requested)
|
|
* @return See above.
|
|
*/
|
|
virtual bool begin_move (MoveMode /*sel*/, const db::DPoint & /*p*/, lay::angle_constraint_type /*ac*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief Continue a "move" operation
|
|
*
|
|
* These events are sent whenever the mouse is moved.
|
|
*
|
|
* @param p The current mouse location
|
|
* @param ac The angle constraint imposed (lay::AC_Global if no specific is requested)
|
|
*/
|
|
virtual void move (const db::DPoint & /*p*/, lay::angle_constraint_type /*ac*/)
|
|
{
|
|
// .. by default, nothing is implemented ..
|
|
}
|
|
|
|
/**
|
|
* @brief Transform the moved object/set while in a move operation
|
|
*
|
|
* These events are sent whenever the right mouse button is clicked in order to request a
|
|
* rotation of the content currently moved.
|
|
*
|
|
* @param p The current point
|
|
* @param tr The transformation to apply
|
|
* @param ac The angle constraint imposed (lay::AC_Global if no specific is requested)
|
|
*/
|
|
virtual void move_transform (const db::DPoint & /*p*/, db::DFTrans /*tr*/, lay::angle_constraint_type /*ac*/)
|
|
{
|
|
// .. by default, nothing is implemented ..
|
|
}
|
|
|
|
/**
|
|
* @brief Terminate a "move" operation
|
|
*
|
|
* @param p The last mouse location
|
|
* @param ac The angle constraint imposed (lay::AC_Global if no specific is requested)
|
|
*/
|
|
virtual void end_move (const db::DPoint & /*p*/, lay::angle_constraint_type /*ac*/)
|
|
{
|
|
// .. by default, nothing is implemented ..
|
|
}
|
|
|
|
/**
|
|
* @brief Cancel any pending operations
|
|
*
|
|
* This event is sent whenever a pending operation such as
|
|
* a move operation should be canceled.
|
|
*/
|
|
virtual void edit_cancel ()
|
|
{
|
|
// .. by default, nothing is implemented ..
|
|
}
|
|
|
|
/**
|
|
* @brief Tell how many objects are selected
|
|
*
|
|
* This method is used to determine if anything is selected - i.e.
|
|
* anything can be copied.
|
|
*/
|
|
virtual size_t selection_size ()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Create a "properties page" object
|
|
*
|
|
* A "properties page" object is first a Qt widget (a QFrame)
|
|
* that is acting as a proxy to a certain selected editable object.
|
|
* It acts as the communication link between the Editable object and
|
|
* the properties dialog by displaying and applying properties.
|
|
* The object returned by this method is newed and must be deleted
|
|
* by the caller. The return value is 0 if the Editable object does
|
|
* not support a properties page.
|
|
*/
|
|
virtual lay::PropertiesPage *properties_page (QWidget * /*parent*/)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Destruction callback by the properties page
|
|
*
|
|
* The properties page object calls this method if it is destroyed
|
|
* on the Editable object that it was issued from.
|
|
*/
|
|
virtual void properties_page_deleted ()
|
|
{
|
|
// .. nothing yet.
|
|
}
|
|
|
|
protected:
|
|
Editables *editables ()
|
|
{
|
|
return mp_editables;
|
|
}
|
|
|
|
private:
|
|
Editables *mp_editables;
|
|
};
|
|
|
|
/**
|
|
* @brief The "editable" collection
|
|
*
|
|
* This class provides a common interface to a collection of "editables".
|
|
* If a pointer to this object is passed to the constructor of the
|
|
* editable object, the latter is automatically inserted into this
|
|
* collection.
|
|
* In addition to managing the editable objects, a selection mechanism
|
|
* is provided: by enabling or disabling certain editable objects, the
|
|
* "select" requests are forwarded to a subset of the editable objects.
|
|
*/
|
|
class LAYBASIC_PUBLIC Editables
|
|
: public db::Object
|
|
{
|
|
public:
|
|
typedef tl::shared_collection<lay::Editable>::iterator iterator;
|
|
|
|
/**
|
|
* @brief The constructor
|
|
*/
|
|
Editables (db::Manager *manager = 0);
|
|
|
|
/**
|
|
* @brief The destructor
|
|
*/
|
|
virtual ~Editables ();
|
|
|
|
/**
|
|
* @brief The delete operation
|
|
*/
|
|
void del ();
|
|
|
|
/**
|
|
* @brief "cut" operation
|
|
*/
|
|
void cut ();
|
|
|
|
/**
|
|
* @brief "copy" operation
|
|
*/
|
|
void copy ();
|
|
|
|
/**
|
|
* @brief "paste" operation
|
|
*/
|
|
void paste ();
|
|
|
|
/**
|
|
* @brief Deliver the bbox of the selection
|
|
*
|
|
* This bounding box is used to compute the center of the
|
|
* selection for transformation by an angle (it is better
|
|
* to do this around der center of the selection bbox).
|
|
* The bbox must either be empty (if no selection is present)
|
|
* or must be given in micron units.
|
|
*/
|
|
db::DBox selection_bbox ();
|
|
|
|
/**
|
|
* @brief transform the selection
|
|
*
|
|
* The transformation is given in micron units.
|
|
*/
|
|
void transform (const db::DCplxTrans &tr);
|
|
|
|
/**
|
|
* @brief Enable or disable a certain editable
|
|
*/
|
|
void enable (lay::Editable *, bool en);
|
|
|
|
/**
|
|
* @brief Clear a selection
|
|
*
|
|
* The selection is cleared irregardless of whether the editable
|
|
* is enabled or not.
|
|
*/
|
|
void clear_selection ();
|
|
|
|
/**
|
|
* @brief Establish a transient selection
|
|
*
|
|
* The transient selection is supposed to highlight the object which would be scope of the next
|
|
* select or move operation. Since move is usually defined to move the current selection, the
|
|
* transient selection should not be done if the view is in move mode and something is selected.
|
|
* Exceptions are: highlighting an object within the current selection.
|
|
*/
|
|
void transient_select (const db::DPoint &pt);
|
|
|
|
/**
|
|
* @brief Clear the transient selection
|
|
*/
|
|
void clear_transient_selection ();
|
|
|
|
/**
|
|
* @brief Clear the previous selection
|
|
*
|
|
* The previous selection is used to implement the cycling protocol for single-point
|
|
* selections.
|
|
*/
|
|
void clear_previous_selection ();
|
|
|
|
/**
|
|
* @brief Select "all"
|
|
*/
|
|
void select ();
|
|
|
|
/**
|
|
* @brief Select geometrically by a rectangle
|
|
*/
|
|
void select (const db::DBox &box, Editable::SelectionMode mode);
|
|
|
|
/**
|
|
* @brief Select geometrically by a point
|
|
*/
|
|
void select (const db::DPoint &pt, Editable::SelectionMode mode);
|
|
|
|
/**
|
|
* @brief Start "move" operation
|
|
*
|
|
* @param sel Should be true if the selection is to be dragged.
|
|
* @param ac The angle constraint imposed (lay::AC_Global if no specific is requested)
|
|
* @return true, if anything is dragged
|
|
*/
|
|
bool begin_move (const db::DPoint &p, lay::angle_constraint_type ac);
|
|
|
|
/**
|
|
* @brief Continue "move" operation
|
|
*/
|
|
void move (const db::DPoint &p, lay::angle_constraint_type ac);
|
|
|
|
/**
|
|
* @brief Transform during a move operation
|
|
*/
|
|
void move_transform (const db::DPoint &p, db::DFTrans tr, lay::angle_constraint_type ac);
|
|
|
|
/**
|
|
* @brief End "move" operation
|
|
*/
|
|
void end_move (const db::DPoint &p, lay::angle_constraint_type ac);
|
|
|
|
/**
|
|
* @brief Tell how many objects are selected.
|
|
*
|
|
* This method will return the number of selected objects.
|
|
*/
|
|
size_t selection_size ();
|
|
|
|
/**
|
|
* @brief Cancel any pending operations
|
|
*/
|
|
void edit_cancel ();
|
|
|
|
/**
|
|
* @brief Editable iterator: begin
|
|
*/
|
|
iterator begin ()
|
|
{
|
|
return m_editables.begin ();
|
|
}
|
|
|
|
/**
|
|
* @brief Editable iterator: end
|
|
*/
|
|
iterator end ()
|
|
{
|
|
return m_editables.end ();
|
|
}
|
|
|
|
/**
|
|
* @brief The "show properties" operation
|
|
*/
|
|
void show_properties (QWidget *parent);
|
|
|
|
/**
|
|
* @brief An event triggered if the selection changed
|
|
* After the selection changed, this event is fired.
|
|
*/
|
|
tl::Event selection_changed_event;
|
|
|
|
/**
|
|
* @brief Send a selection changed signal to all observers
|
|
*/
|
|
virtual void signal_selection_changed ()
|
|
{
|
|
selection_changed_event ();
|
|
}
|
|
|
|
/**
|
|
* @brief An event indicating that the transient selection has changed
|
|
*/
|
|
tl::Event transient_selection_changed_event;
|
|
|
|
/**
|
|
* @brief Send a transient selection changed signal to all observers
|
|
*/
|
|
virtual void signal_transient_selection_changed ()
|
|
{
|
|
transient_selection_changed_event ();
|
|
}
|
|
|
|
/**
|
|
* @brief Enable or disable edit operations
|
|
*
|
|
* This method is called when the client code wishes to (temporarily) enable to disable
|
|
* user functions that may cause an edit operation. This method can be reimplemented to
|
|
* disable menu entries etc.
|
|
*/
|
|
virtual void enable_edits (bool /*enable*/)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
protected:
|
|
/**
|
|
* @brief Cancel all edit operations
|
|
*
|
|
* This method can be overridden in order to implement special behaviour on cancel
|
|
* of edits (i.e. release the mouse).
|
|
* Make sure, the base implementation is called as well.
|
|
*/
|
|
virtual void cancel_edits ();
|
|
|
|
private:
|
|
friend class Editable;
|
|
|
|
tl::shared_collection<lay::Editable> m_editables;
|
|
std::set<lay::Editable *> m_enabled;
|
|
lay::PropertiesDialog *mp_properties_dialog;
|
|
bool m_move_selection;
|
|
bool m_any_move_operation;
|
|
db::DBox m_last_selected_point;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|
|
|