diff --git a/src/db/db/dbManager.cc b/src/db/db/dbManager.cc index 345d70857..e94cbc89a 100644 --- a/src/db/db/dbManager.cc +++ b/src/db/db/dbManager.cc @@ -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 (& 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 ()); diff --git a/src/edt/edt/edtServiceImpl.cc b/src/edt/edt/edtServiceImpl.cc index afff27a52..5a0914092 100644 --- a/src/edt/edt/edtServiceImpl.cc +++ b/src/edt/edt/edtServiceImpl.cc @@ -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 diff --git a/src/edt/edt/edtServiceImpl.h b/src/edt/edt/edtServiceImpl.h index 7b002a6df..2c55beb15 100644 --- a/src/edt/edt/edtServiceImpl.h +++ b/src/edt/edt/edtServiceImpl.h @@ -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 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 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 > config; + std::vector 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 m_points; + std::vector 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 (); }; diff --git a/src/edt/edt/edtUtils.cc b/src/edt/edt/edtUtils.cc index 2a7ec7810..13218074d 100644 --- a/src/edt/edt/edtUtils.cc +++ b/src/edt/edt/edtUtils.cc @@ -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::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 } // ------------------------------------------------------------- diff --git a/src/edt/edt/edtUtils.h b/src/edt/edt/edtUtils.h index e4e8b17b3..c9fd7f877 100644 --- a/src/edt/edt/edtUtils.h +++ b/src/edt/edt/edtUtils.h @@ -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)