mirror of https://github.com/KLayout/klayout.git
WIP: undo, backspace implementation, bug fixes
This commit is contained in:
parent
57cd512bf9
commit
d3d2eda54a
|
|
@ -122,7 +122,9 @@ Manager::transaction (const std::string &description, transaction_id_t join_with
|
|||
tl_assert (! m_replay);
|
||||
|
||||
if (! m_transactions.empty () && reinterpret_cast<transaction_id_t> (& m_transactions.back ()) == join_with) {
|
||||
m_transactions.back ().second = description;
|
||||
if (! description.empty ()) {
|
||||
m_transactions.back ().second = description;
|
||||
}
|
||||
} else {
|
||||
// delete all following transactions and add a new one
|
||||
erase_transactions (m_current, m_transactions.end ());
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ namespace edt
|
|||
|
||||
ShapeEditService::ShapeEditService (db::Manager *manager, lay::LayoutViewBase *view, db::ShapeIterator::flags_type shape_types)
|
||||
: edt::Service (manager, view, shape_types),
|
||||
m_layer (0), m_cv_index (0), mp_cell (0), mp_layout (0), m_combine_mode (CM_Add)
|
||||
m_layer (0), m_cv_index (0), mp_cell (0), mp_layout (0), m_combine_mode (CM_Add), m_update_edit_layer_enabled (true)
|
||||
{
|
||||
view->current_layer_changed_event.add (this, &ShapeEditService::update_edit_layer);
|
||||
}
|
||||
|
|
@ -151,7 +151,7 @@ ShapeEditService::get_edit_layer ()
|
|||
|
||||
// fetches the last configuration for the given layer
|
||||
view ()->set_active_cellview_index (cv_index);
|
||||
edt::config_recent_for_layer (view (), cv->layout ().get_properties ((unsigned int) layer), cv_index);
|
||||
edt::config_recent_for_layer (view (), dispatcher (), cv->layout ().get_properties ((unsigned int) layer), cv_index);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -171,12 +171,41 @@ ShapeEditService::change_edit_layer (const db::LayerProperties &lp)
|
|||
|
||||
// fetches the last configuration for the given layer
|
||||
view ()->set_active_cellview_index (m_cv_index);
|
||||
edt::config_recent_for_layer (view (), lp, m_cv_index);
|
||||
edt::config_recent_for_layer (view (), dispatcher (), lp, m_cv_index);
|
||||
}
|
||||
|
||||
void
|
||||
ShapeEditService::set_layer (const db::LayerProperties &lp, unsigned int cv_index)
|
||||
{
|
||||
if (! mp_layout) {
|
||||
return;
|
||||
}
|
||||
|
||||
int layer = mp_layout->get_layer_maybe (lp);
|
||||
if (layer < 0) {
|
||||
layer = mp_layout->insert_layer (lp);
|
||||
}
|
||||
|
||||
m_layer = (unsigned int) layer;
|
||||
m_cv_index = cv_index;
|
||||
|
||||
m_update_edit_layer_enabled = false;
|
||||
try {
|
||||
view ()->set_current_layer (cv_index, lp);
|
||||
m_update_edit_layer_enabled = true;
|
||||
} catch (...) {
|
||||
m_update_edit_layer_enabled = true;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ShapeEditService::update_edit_layer (const lay::LayerPropertiesConstIterator &cl)
|
||||
{
|
||||
if (! m_update_edit_layer_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! editing ()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -238,7 +267,7 @@ ShapeEditService::update_edit_layer (const lay::LayerPropertiesConstIterator &cl
|
|||
|
||||
// fetches the last configuration for the given layer
|
||||
view ()->set_active_cellview_index (cv_index);
|
||||
edt::config_recent_for_layer (view (), cv->layout ().get_properties ((unsigned int) layer), cv_index);
|
||||
edt::config_recent_for_layer (view (), dispatcher (), cv->layout ().get_properties ((unsigned int) layer), cv_index);
|
||||
|
||||
current_layer_changed ();
|
||||
}
|
||||
|
|
@ -1360,7 +1389,12 @@ PathService::do_delete ()
|
|||
update_marker ();
|
||||
update_via ();
|
||||
|
||||
} else if (! m_previous_segments.empty ()) {
|
||||
|
||||
pop_segment ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1459,6 +1493,10 @@ PathService::via (int dir)
|
|||
tl_assert (false); // see TODO
|
||||
#endif
|
||||
|
||||
if (! editing ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// not enough points to form a path
|
||||
if (m_points.size () < 2) {
|
||||
return;
|
||||
|
|
@ -1512,15 +1550,11 @@ PathService::via (int dir)
|
|||
|
||||
}
|
||||
|
||||
commit_recent (view ());
|
||||
|
||||
// produce the path up to the current point
|
||||
db::DPoint via_pos = m_points.back ();
|
||||
|
||||
db::Shape path_shape;
|
||||
{
|
||||
db::Transaction transaction (manager (), tl::to_string (tr ("Create path")));
|
||||
path_shape = cell ().shapes (layer ()).insert (get_path ());
|
||||
}
|
||||
|
||||
bool is_bottom = via_def.via_type.bottom.log_equal (lp);
|
||||
db::LayerProperties lp_new = is_bottom ? via_def.via_type.top : via_def.via_type.bottom;
|
||||
|
||||
|
|
@ -1545,7 +1579,9 @@ PathService::via (int dir)
|
|||
params.insert (std::make_pair ("h_top", tl::Variant (h_top)));
|
||||
|
||||
{
|
||||
db::Transaction transaction (manager (), tl::to_string (tr ("Create via")));
|
||||
db::Transaction transaction (manager (), tl::to_string (tr ("Create path segment")));
|
||||
|
||||
db::Shape path_shape = cell ().shapes (layer ()).insert (get_path ());
|
||||
|
||||
auto via_lib_cell = via_def.lib->layout ().get_pcell_variant_dict (via_def.pcell, params);
|
||||
auto via_cell = layout ().get_lib_proxy (via_def.lib, via_lib_cell);
|
||||
|
|
@ -1558,15 +1594,15 @@ PathService::via (int dir)
|
|||
}
|
||||
|
||||
change_edit_layer (lp_new);
|
||||
|
||||
m_points.clear ();
|
||||
m_points.push_back (via_pos);
|
||||
m_points.push_back (via_pos);
|
||||
m_last = m_points.back ();
|
||||
|
||||
update_marker ();
|
||||
update_via ();
|
||||
}
|
||||
|
||||
m_points.clear ();
|
||||
m_points.push_back (via_pos);
|
||||
m_points.push_back (via_pos);
|
||||
m_last = m_points.back ();
|
||||
|
||||
update_marker ();
|
||||
update_via ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1615,35 +1651,37 @@ PathService::update_via ()
|
|||
// change the via PCell
|
||||
|
||||
{
|
||||
db::Transaction transaction (manager (), tl::to_string (tr ("Create via")), ps.via_transaction_id);
|
||||
db::Transaction transaction (manager () && ! manager ()->transacting () ? manager () : 0, std::string (), ps.transaction_id);
|
||||
ps.via_instance = via_parent_cell->change_pcell_parameters (ps.via_instance, params);
|
||||
|
||||
layout ().cleanup ();
|
||||
}
|
||||
}
|
||||
|
||||
static std::string path_config_keys [] = {
|
||||
cfg_edit_path_width,
|
||||
cfg_edit_path_ext_var_begin,
|
||||
cfg_edit_path_ext_var_end,
|
||||
cfg_edit_path_ext_type
|
||||
};
|
||||
|
||||
void
|
||||
PathService::push_segment (const db::Shape &shape, const db::Instance &instance, const db::ViaType &via_type, db::Manager::transaction_id_t via_transaction_id)
|
||||
PathService::push_segment (const db::Shape &shape, const db::Instance &instance, const db::ViaType &via_type, db::Manager::transaction_id_t transaction_id)
|
||||
{
|
||||
m_previous_segments.push_back (PathSegment ());
|
||||
|
||||
PathSegment &ps = m_previous_segments.back ();
|
||||
ps.points = m_points;
|
||||
ps.last_point = m_last;
|
||||
ps.path_shape = shape;
|
||||
ps.via_instance = instance;
|
||||
ps.via_transaction_id = via_transaction_id;
|
||||
ps.via_type = via_type;
|
||||
ps.layer = layer ();
|
||||
ps.layer = layout ().get_properties (layer ());
|
||||
ps.cv_index = cv_index ();
|
||||
ps.transaction_id = transaction_id;
|
||||
|
||||
std::string cfg [] = {
|
||||
cfg_edit_path_width,
|
||||
cfg_edit_path_ext_var_begin,
|
||||
cfg_edit_path_ext_var_end,
|
||||
cfg_edit_path_ext_type
|
||||
};
|
||||
|
||||
for (unsigned int i = 0; i < sizeof (cfg) / sizeof (cfg[0]); ++i) {
|
||||
ps.config.push_back (std::make_pair (cfg [i], std::string ()));
|
||||
for (unsigned int i = 0; i < sizeof (path_config_keys) / sizeof (path_config_keys[0]); ++i) {
|
||||
ps.config.push_back (std::make_pair (path_config_keys [i], std::string ()));
|
||||
view ()->config_get (ps.config.back ().first, ps.config.back ().second);
|
||||
}
|
||||
}
|
||||
|
|
@ -1651,7 +1689,48 @@ PathService::push_segment (const db::Shape &shape, const db::Instance &instance,
|
|||
void
|
||||
PathService::pop_segment ()
|
||||
{
|
||||
// @@@
|
||||
PathSegment ps = m_previous_segments.back ();
|
||||
m_previous_segments.pop_back ();
|
||||
|
||||
if (manager () && manager ()->transaction_id_for_undo () == ps.transaction_id) {
|
||||
|
||||
// should remove shape and via instance
|
||||
manager ()->undo ();
|
||||
|
||||
// empties the undo queue, so we don't keep objects there and spoil subsequent "update_via" actions
|
||||
// TODO: is there a better way to do this?
|
||||
manager ()->transaction (std::string ());
|
||||
manager ()->cancel ();
|
||||
|
||||
} else {
|
||||
|
||||
// fallback without using undo
|
||||
db::Transaction transaction (manager (), tl::to_string (tr ("Undo path segment")));
|
||||
|
||||
if (! ps.path_shape.is_null () && ps.path_shape.shapes ()) {
|
||||
ps.path_shape.shapes ()->erase_shape (ps.path_shape);
|
||||
}
|
||||
|
||||
if (! ps.via_instance.is_null () && ps.via_instance.instances ()) {
|
||||
ps.via_instance.instances ()->erase (ps.via_instance);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
set_layer (ps.layer, ps.cv_index);
|
||||
|
||||
m_points = ps.points;
|
||||
m_last = ps.last_point;
|
||||
|
||||
for (auto i = ps.config.begin (); i != ps.config.end (); ++i) {
|
||||
dispatcher ()->config_set (i->first, i->second);
|
||||
}
|
||||
|
||||
// avoids update_via() which might spoil the via we just recovered
|
||||
m_needs_update = false;
|
||||
dispatcher ()->config_end ();
|
||||
|
||||
update_marker ();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ protected:
|
|||
void deliver_shape (const db::Path &path);
|
||||
void deliver_shape (const db::Box &box);
|
||||
void deliver_shape (const db::Point &point);
|
||||
void set_layer (const db::LayerProperties &lp, unsigned int cv_index);
|
||||
void open_editor_hooks ();
|
||||
template <class Shape>
|
||||
void deliver_shape_to_hooks (const Shape &shape);
|
||||
|
|
@ -92,6 +93,7 @@ private:
|
|||
db::Layout *mp_layout;
|
||||
combine_mode_type m_combine_mode;
|
||||
tl::weak_collection<edt::EditorHooks> m_editor_hooks;
|
||||
bool m_update_edit_layer_enabled;
|
||||
|
||||
void update_edit_layer (const lay::LayerPropertiesConstIterator &iter);
|
||||
};
|
||||
|
|
@ -248,18 +250,20 @@ protected:
|
|||
private:
|
||||
struct PathSegment
|
||||
{
|
||||
PathSegment () : layer (0), cv_index (0), via_transaction_id (0) { }
|
||||
PathSegment () : cv_index (0), transaction_id (0) { }
|
||||
|
||||
unsigned int layer;
|
||||
db::LayerProperties layer;
|
||||
int cv_index;
|
||||
std::list<std::pair<std::string, std::string> > config;
|
||||
std::vector<db::DPoint> points;
|
||||
db::DPoint last_point;
|
||||
db::Shape path_shape;
|
||||
db::Instance via_instance;
|
||||
db::Manager::transaction_id_t via_transaction_id;
|
||||
db::ViaType via_type;
|
||||
db::Manager::transaction_id_t transaction_id;
|
||||
};
|
||||
|
||||
std::vector <db::DPoint> m_points;
|
||||
std::vector<db::DPoint> m_points;
|
||||
double m_width, m_bgnext, m_endext;
|
||||
enum { Flush = 0, Square, Variable, Round } m_type;
|
||||
bool m_needs_update;
|
||||
|
|
@ -270,7 +274,7 @@ private:
|
|||
db::Path get_path () const;
|
||||
void set_last_point (const db::DPoint &p);
|
||||
void update_via ();
|
||||
void push_segment (const db::Shape &shape, const db::Instance &instance, const db::ViaType &via_type, db::Manager::transaction_id_t via_transaction_id);
|
||||
void push_segment (const db::Shape &shape, const db::Instance &instance, const db::ViaType &via_type, db::Manager::transaction_id_t transaction_id);
|
||||
void pop_segment ();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ commit_recent (lay::LayoutViewBase *view)
|
|||
}
|
||||
|
||||
void
|
||||
config_recent_for_layer (lay::LayoutViewBase *view, const db::LayerProperties &lp, int cv_index)
|
||||
config_recent_for_layer (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher, const db::LayerProperties &lp, int cv_index)
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
lay::EditorOptionsPages *eo_pages = view->editor_options_pages ();
|
||||
|
|
@ -107,7 +107,7 @@ config_recent_for_layer (lay::LayoutViewBase *view, const db::LayerProperties &l
|
|||
|
||||
for (std::vector<lay::EditorOptionsPage *>::const_iterator op = eo_pages->pages ().begin (); op != eo_pages->pages ().end (); ++op) {
|
||||
if ((*op)->active ()) {
|
||||
(*op)->config_recent_for_layer (view, lp, cv_index);
|
||||
(*op)->config_recent_for_layer (dispatcher, lp, cv_index);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -116,7 +116,6 @@ config_recent_for_layer (lay::LayoutViewBase *view, const db::LayerProperties &l
|
|||
bool
|
||||
set_or_request_current_layer (lay::LayoutViewBase *view, const db::LayerProperties &lp, unsigned int cv_index, bool make_current)
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
// try to find an existing layer
|
||||
if (make_current) {
|
||||
if (view->set_current_layer (cv_index, lp)) {
|
||||
|
|
@ -128,39 +127,26 @@ set_or_request_current_layer (lay::LayoutViewBase *view, const db::LayerProperti
|
|||
}
|
||||
}
|
||||
|
||||
if (! view->control_panel ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const lay::CellView &cv = view->cellview (cv_index);
|
||||
if (! cv.is_valid ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (QMessageBox::question (view->widget (), tr ("Create Layer"), tr ("Layer %1 does not exist yet. Create it now?").arg (tl::to_qstring (lp.to_string ()))) == QMessageBox::Yes) {
|
||||
lay::LayerPropertiesNode lpn;
|
||||
lpn.set_source (lay::ParsedLayerSource (lp, cv_index));
|
||||
view->init_layer_properties (lpn);
|
||||
|
||||
lay::LayerPropertiesNode lpn;
|
||||
lpn.set_source (lay::ParsedLayerSource (lp, cv_index));
|
||||
view->init_layer_properties (lpn);
|
||||
{
|
||||
db::Transaction transaction (! view->manager ()->transacting () ? view->manager () : 0, tl::to_string (QObject::tr ("Create new layer")));
|
||||
|
||||
{
|
||||
db::Transaction transaction (! view->manager ()->transacting () ? view->manager () : 0, tl::to_string (QObject::tr ("Create new layer")));
|
||||
|
||||
lay::LayerPropertiesConstIterator lpi = lay::LayerPropertiesConstIterator (& view->insert_layer (view->end_layers (), lpn));
|
||||
if (make_current) {
|
||||
view->set_current_layer (lpi);
|
||||
}
|
||||
lpi->realize_source ();
|
||||
lay::LayerPropertiesConstIterator lpi = lay::LayerPropertiesConstIterator (& view->insert_layer (view->end_layers (), lpn));
|
||||
if (make_current) {
|
||||
view->set_current_layer (lpi);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
lpi->realize_source ();
|
||||
}
|
||||
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
namespace lay
|
||||
{
|
||||
class LayoutViewBase;
|
||||
class Dispatcher;
|
||||
}
|
||||
|
||||
namespace edt {
|
||||
|
|
@ -77,7 +78,7 @@ commit_recent (lay::LayoutViewBase *view);
|
|||
* @brief Configure attributes for the most-recent entry with the given layer
|
||||
*/
|
||||
void
|
||||
config_recent_for_layer (lay::LayoutViewBase *view, const db::LayerProperties &lp, int cv_index);
|
||||
config_recent_for_layer (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher, const db::LayerProperties &lp, int cv_index);
|
||||
|
||||
/**
|
||||
* @brief Request to make the given layer the current one (asks whether to create the layer if needed)
|
||||
|
|
|
|||
Loading…
Reference in New Issue