From 717470a389427f940063e2fda9165b0c523b45e3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 5 Dec 2019 00:36:46 +0100 Subject: [PATCH 1/7] Enhancement of the "interactive" (infix) modes 1.) Copy & Cut will now take the selection from the transient selection if no real selection is present 2.) Hence, Copy & Cut are always enabled 3.) The same if true for duplicate 4.) Move interactive will also act immediately on the transient selection. --- src/ant/ant/antService.cc | 26 ++++++++-- src/ant/ant/antService.h | 7 ++- src/edt/edt/edtService.cc | 12 +++++ src/edt/edt/edtService.h | 15 ++++-- src/img/img/imgService.cc | 9 ++++ src/img/img/imgService.h | 5 ++ src/lay/lay/layMainWindow.cc | 21 ++------ src/laybasic/laybasic/gsiDeclLayLayoutView.cc | 48 ++++++++++------- src/laybasic/laybasic/layEditable.cc | 16 ++++++ src/laybasic/laybasic/layEditable.h | 15 +++++- src/laybasic/laybasic/layLayoutView.cc | 16 +++++- src/laybasic/laybasic/layMove.cc | 51 ++++++++++++++++--- src/laybasic/laybasic/layMove.h | 6 ++- 13 files changed, 189 insertions(+), 58 deletions(-) diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc index 24a2397bf..c84694978 100644 --- a/src/ant/ant/antService.cc +++ b/src/ant/ant/antService.cc @@ -901,11 +901,6 @@ Service::drag_cancel () delete mp_active_ruler; mp_active_ruler = 0; } - - if (mp_transient_ruler) { - delete mp_transient_ruler; - mp_transient_ruler = 0; - } } int @@ -1030,6 +1025,8 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang // cancel any pending move or drag operations, reset mp_active_ruler widget ()->drag_cancel (); // KLUDGE: every service does this to the same service manager + clear_transient_selection (); + // choose move mode if (mode == lay::Editable::Selected) { @@ -1486,6 +1483,7 @@ Service::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio // stop dragging drag_cancel (); + clear_transient_selection (); // end the transaction manager ()->commit (); @@ -1535,6 +1533,7 @@ void Service::deactivated () { drag_cancel (); + clear_transient_selection (); } std::pair @@ -1576,6 +1575,8 @@ struct RulerIdComp void Service::reduce_rulers (int num) { + clear_transient_selection (); + lay::AnnotationShapes::iterator rfrom = mp_view->annotation_shapes ().begin (); lay::AnnotationShapes::iterator rto = mp_view->annotation_shapes ().end (); @@ -1921,6 +1922,21 @@ Service::clear_transient_selection () } } +void +Service::transient_to_selection () +{ + if (mp_transient_ruler) { + for (lay::AnnotationShapes::iterator r = mp_view->annotation_shapes ().begin (); r != mp_view->annotation_shapes ().end (); ++r) { + const ant::Object *robj = dynamic_cast (r->ptr ()); + if (robj == mp_transient_ruler->ruler ()) { + m_selected.insert (std::make_pair (r, 0)); + selection_to_view (); + return; + } + } + } +} + void Service::clear_previous_selection () { diff --git a/src/ant/ant/antService.h b/src/ant/ant/antService.h index f8e6faaaf..91eb807ea 100644 --- a/src/ant/ant/antService.h +++ b/src/ant/ant/antService.h @@ -284,6 +284,11 @@ public: */ virtual void clear_previous_selection (); + /** + * @brief Turns the transient selection to the selection + */ + virtual void transient_to_selection (); + /** * @brief Establish a transient selection */ @@ -548,7 +553,7 @@ private: bool select (obj_iterator obj, lay::Editable::SelectionMode mode); /** - * @brief Clear the selection + * @brief Clears the selection */ void clear_selection (); diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc index 254f3976c..7d5914bde 100644 --- a/src/edt/edt/edtService.cc +++ b/src/edt/edt/edtService.cc @@ -357,6 +357,9 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang { if (view ()->is_editable () && mode == lay::Editable::Selected) { + // flush any pending updates of the markers + dm_selection_to_view.execute (); + m_move_start = p; m_move_trans = db::DTrans (); m_move_sel = true; // TODO: there is no "false". Remove this. @@ -1187,6 +1190,15 @@ Service::selection_applies (const lay::ObjectInstPath & /*sel*/) const return false; } +void +Service::transient_to_selection () +{ + if (! m_transient_selection.empty ()) { + m_selection.insert (m_transient_selection.begin (), m_transient_selection.end ()); + selection_to_view (); + } +} + void Service::clear_previous_selection () { diff --git a/src/edt/edt/edtService.h b/src/edt/edt/edtService.h index 0ac8246b8..2f0fee85d 100644 --- a/src/edt/edt/edtService.h +++ b/src/edt/edt/edtService.h @@ -184,11 +184,6 @@ public: */ virtual bool select (const db::DBox &box, lay::Editable::SelectionMode mode); - /** - * @brief Clears the previous selection - */ - virtual void clear_previous_selection (); - /** * @brief Returns true, if the given selected object is handled by this service */ @@ -269,11 +264,21 @@ public: */ bool select (const lay::ObjectInstPath &obj, lay::Editable::SelectionMode mode); + /** + * @brief Clears the previous selection + */ + void clear_previous_selection (); + /** * @brief Establish a transient selection */ bool transient_select (const db::DPoint &pos); + /** + * @brief Turns the transient selection to the selection + */ + virtual void transient_to_selection (); + /** * @brief Clear the transient selection */ diff --git a/src/img/img/imgService.cc b/src/img/img/imgService.cc index 3b4987c14..15402a987 100644 --- a/src/img/img/imgService.cc +++ b/src/img/img/imgService.cc @@ -1063,6 +1063,15 @@ Service::clear_previous_selection () m_previous_selection.clear (); } +void +Service::transient_to_selection () +{ + if (mp_transient_view) { + m_selected.insert (std::make_pair (mp_transient_view->image_ref (), 0)); + selection_to_view (); + } +} + bool Service::select (obj_iterator obj, lay::Editable::SelectionMode mode) { diff --git a/src/img/img/imgService.h b/src/img/img/imgService.h index 6d8c070ad..e32af8552 100644 --- a/src/img/img/imgService.h +++ b/src/img/img/imgService.h @@ -304,6 +304,11 @@ public: */ virtual bool transient_select (const db::DPoint &pos); + /** + * @brief Turns the transient selection to the selection + */ + virtual void transient_to_selection (); + /** * @brief Clear the transient selection */ diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index 33fcf8237..0a3924964 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -2275,7 +2275,7 @@ MainWindow::do_cm_duplicate (bool interactive) { BEGIN_PROTECTED - if (current_view () && current_view ()->has_selection ()) { + if (current_view ()) { // Do duplicate simply by concatenating copy & paste currently. // Save the clipboard state before in order to preserve the current content @@ -2327,7 +2327,7 @@ MainWindow::cm_copy () { BEGIN_PROTECTED - if (current_view () && current_view ()->has_selection ()) { + if (current_view ()) { current_view ()->copy (); current_view ()->clear_selection (); } @@ -2370,7 +2370,7 @@ MainWindow::cm_cut () { BEGIN_PROTECTED - if (current_view () && current_view ()->has_selection ()) { + if (current_view ()) { current_view ()->cut (); current_view ()->cancel (); // see del() for reason why cancel is after cut current_view ()->clear_selection (); @@ -2766,21 +2766,6 @@ MainWindow::update_action_states () } - if (mp_menu->is_valid ("edit_menu.copy")) { - Action copy_action = mp_menu->action ("edit_menu.copy"); - copy_action.set_enabled (current_view () && current_view ()->has_selection () && edits_enabled ()); - } - - if (mp_menu->is_valid ("edit_menu.duplicate")) { - Action copy_action = mp_menu->action ("edit_menu.duplicate"); - copy_action.set_enabled (current_view () && current_view ()->has_selection () && edits_enabled ()); - } - - if (mp_menu->is_valid ("edit_menu.cut")) { - Action cut_action = mp_menu->action ("edit_menu.cut"); - cut_action.set_enabled (current_view () && current_view ()->has_selection () && edits_enabled ()); - } - if (mp_menu->is_valid ("edit_menu.paste")) { Action paste_action = mp_menu->action ("edit_menu.paste"); paste_action.set_enabled (! db::Clipboard::instance ().empty () && edits_enabled ()); diff --git a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc index 2e0b3d44c..9eb7715b1 100644 --- a/src/laybasic/laybasic/gsiDeclLayLayoutView.cc +++ b/src/laybasic/laybasic/gsiDeclLayLayoutView.cc @@ -821,6 +821,29 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou "selection. Calling this method is useful to ensure there are no potential interactions with the script's " "functionality.\n" ) + + gsi::method ("clear_selection", &lay::LayoutView::clear_selection, + "@brief Clears the selection of all objects (shapes, annotations, images ...)\n" + "\n" + "This method has been introduced in version 0.26.2\n" + ) + + gsi::method ("clear_transient_selection", &lay::LayoutView::clear_transient_selection, + "@brief Clears the transient selection (mouse-over hightlights) of all objects (shapes, annotations, images ...)\n" + "\n" + "This method has been introduced in version 0.26.2\n" + ) + + gsi::method ("transient_to_selection", &lay::LayoutView::transient_to_selection, + "@brief Turns the transient selection into the actual selection\n" + "\n" + "The current selection is cleared before. All highlighted objects under the mouse will become selected. " + "This applies to all types of objects (rulers, shapes, images ...).\n" + "\n" + "This method has been introduced in version 0.26.2\n" + ) + + gsi::method ("selection_bbox", &lay::LayoutView::selection_bbox, + "@brief Returns the bounding box of the current selection\n" + "\n" + "This method has been introduced in version 0.26.2\n" + ) + gsi::method ("stop", &lay::LayoutView::stop, "@brief Stops redraw thread and close any browsers\n" "This method usually does not need to be called explicitly. The redraw thread is stopped automatically." @@ -1077,7 +1100,6 @@ Class decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou ) + gsi::method_ext ("delete_layers", &delete_layers1, gsi::arg ("iterators"), "@brief Deletes the layer properties nodes specified by the iterator\n" - "@args iterators\n" "\n" "This method deletes the nodes specifies by the iterators. This method is the most convenient way to " "delete multiple entries.\n" @@ -1837,9 +1859,8 @@ static void cv_show_all_cells (lay::CellViewRef *cv) } Class decl_CellView ("lay", "CellView", - method ("==", static_cast (&lay::CellViewRef::operator==), + method ("==", static_cast (&lay::CellViewRef::operator==), gsi::arg ("other"), "@brief Equality: indicates whether the cellviews refer to the same one\n" - "@args other\n" "In version 0.25, the definition of the equality operator has been changed to reflect identity of the " "cellview. Before that version, identity of the cell shown was implied." ) + @@ -1868,32 +1889,28 @@ Class decl_CellView ("lay", "CellView", "@brief Returns true, if the cellview is valid\n" "A cellview may become invalid if the corresponding tab is closed for example." ) + - method ("path=|set_path", &lay::CellViewRef::set_unspecific_path, + method ("path=|set_path", &lay::CellViewRef::set_unspecific_path, gsi::arg ("path"), "@brief Sets the unspecific part of the path explicitly\n" - "@args path\n" "\n" "Setting the unspecific part of the path will clear the context path component and\n" "update the context and target cell.\n" ) + - method ("context_path=|set_context_path", &lay::CellViewRef::set_specific_path, + method ("context_path=|set_context_path", &lay::CellViewRef::set_specific_path, gsi::arg ("path"), "@brief Sets the context path explicitly\n" - "@args path\n" "\n" "This method assumes that the unspecific part of the path \n" "is established already and that the context path starts\n" "from the context cell.\n" ) + - method ("cell_index=|set_cell", (void (lay::CellViewRef::*) (lay::CellViewRef::cell_index_type)) &lay::CellViewRef::set_cell, + method ("cell_index=|set_cell", (void (lay::CellViewRef::*) (lay::CellViewRef::cell_index_type)) &lay::CellViewRef::set_cell, gsi::arg ("cell_index"), "@brief Sets the path to the given cell\n" - "@args cell_index\n" "\n" "This method will construct any path to this cell, not a \n" "particular one. It will clear the context path\n" "and update the context and target cell. Note that the cell is specified by it's index.\n" ) + - method ("cell_name=|set_cell_name", (void (lay::CellViewRef::*) (const std::string &)) &lay::CellViewRef::set_cell, + method ("cell_name=|set_cell_name", (void (lay::CellViewRef::*) (const std::string &)) &lay::CellViewRef::set_cell, gsi::arg ("cell_name"), "@brief Sets the cell by name\n" - "@args cell_name\n" "\n" "If the name is not a valid one, the cellview will become\n" "invalid.\n" @@ -1901,9 +1918,8 @@ Class decl_CellView ("lay", "CellView", "particular one. It will clear the context path\n" "and update the context and target cell.\n" ) + - method_ext ("cell=", set_cell, + method_ext ("cell=", set_cell, gsi::arg ("cell"), "@brief Sets the cell by reference to a Cell object\n" - "@args cell\n" "Setting the cell reference to nil invalidates the cellview. " "This method will construct any path to this cell, not a \n" "particular one. It will clear the context path\n" @@ -1961,9 +1977,8 @@ Class decl_CellView ("lay", "CellView", "@brief Returns the technology name for the layout behind the given cell view\n" "This method has been added in version 0.23.\n" ) + - method_ext ("technology=", &apply_technology, + method_ext ("technology=", &apply_technology, gsi::arg ("tech_name"), "@brief Sets the technology for the layout behind the given cell view\n" - "@args tech_name\n" "According to the specification of the technology, new layer properties may be loaded " "or the net tracer may be reconfigured. If the layout is shown in multiple views, the " "technology is updated for all views.\n" @@ -1972,9 +1987,8 @@ Class decl_CellView ("lay", "CellView", method_ext ("layout", &get_layout, "@brief Gets the reference to the layout object addressed by this view\n" ) + - method_ext ("descend", &cv_descend, + method_ext ("descend", &cv_descend, gsi::arg ("path"), "@brief Descends further into the hierarchy.\n" - "@args path\n" "Adds the given path (given as an array of InstElement objects) to the specific path of the " "cellview with the given index. In effect, the cell addressed by the terminal of the new path " "components can be shown in the context of the upper cells, if the minimum hierarchy level is " diff --git a/src/laybasic/laybasic/layEditable.cc b/src/laybasic/laybasic/layEditable.cc index e85c67087..1f9db6a6f 100644 --- a/src/laybasic/laybasic/layEditable.cc +++ b/src/laybasic/laybasic/layEditable.cc @@ -301,6 +301,22 @@ Editables::clear_transient_selection () signal_transient_selection_changed (); } +void +Editables::transient_to_selection () +{ + cancel_edits (); + for (iterator e = begin (); e != end (); ++e) { + e->select (db::DBox (), lay::Editable::Reset); // clear selection + e->clear_previous_selection (); + e->transient_to_selection (); + e->clear_transient_selection (); + } + + // send a signal to the observers + signal_transient_selection_changed (); + signal_selection_changed (); +} + void Editables::clear_selection () { diff --git a/src/laybasic/laybasic/layEditable.h b/src/laybasic/laybasic/layEditable.h index 6fd58531c..2007bacff 100644 --- a/src/laybasic/laybasic/layEditable.h +++ b/src/laybasic/laybasic/layEditable.h @@ -182,6 +182,14 @@ public: return false; } + /** + * @brief Turns the transient selection to the selection + */ + virtual void transient_to_selection () + { + // .. nothing yet .. + } + /** * @brief Clear the transient selection * @@ -418,7 +426,7 @@ public: * or must be given in micron units. */ db::DBox selection_bbox (); - + /** * @brief transform the selection * @@ -457,6 +465,11 @@ public: */ void clear_transient_selection (); + /** + * @brief Turns the transient selection to the selection + */ + void transient_to_selection (); + /** * @brief Clear the previous selection * diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index d669f4da0..f437fd510 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -5154,7 +5154,7 @@ LayoutView::paste_interactive () // operations. trans->close (); - if (mp_move_service->begin_move (trans.release ())) { + if (mp_move_service->begin_move (trans.release (), false)) { switch_mode (-1); // move mode } } @@ -5167,7 +5167,14 @@ LayoutView::copy () } else if (mp_control_panel && mp_control_panel->has_focus ()) { mp_control_panel->copy (); } else { + + if (lay::Editables::selection_size () == 0) { + // try to use the transient selection for the real one + lay::Editables::transient_to_selection (); + } + lay::Editables::copy (); + } } @@ -5182,8 +5189,15 @@ LayoutView::cut () db::Transaction trans (manager (), tl::to_string (QObject::tr ("Cut Layers"))); mp_control_panel->cut (); } else { + + if (lay::Editables::selection_size () == 0) { + // try to use the transient selection for the real one + lay::Editables::transient_to_selection (); + } + db::Transaction trans (manager (), tl::to_string (QObject::tr ("Cut"))); lay::Editables::cut (); + } } diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc index 8e366293c..7245ded29 100644 --- a/src/laybasic/laybasic/layMove.cc +++ b/src/laybasic/laybasic/layMove.cc @@ -38,6 +38,7 @@ MoveService::MoveService (lay::LayoutView *view) : QObject (), lay::ViewService (view->view_object_widget ()), m_dragging (false), + m_dragging_transient (false), mp_editables (view), mp_view (view), m_global_grid (0.001) @@ -148,6 +149,9 @@ MoveService::mouse_move_event (const db::DPoint &p, unsigned int buttons, bool p } + // track mouse position for the infix move initiation + m_mouse_pos = p; + return ret; // not taken to allow the mouse tracker to receive events as well } @@ -163,7 +167,7 @@ MoveService::mouse_click_event (const db::DPoint &p, unsigned int buttons, bool return true; } if (prio && (buttons & lay::LeftButton) != 0) { - if (handle_dragging (p, buttons, 0)) { + if (handle_dragging (p, buttons, false, 0)) { return true; } } @@ -216,7 +220,7 @@ bool MoveService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio) { if (prio && (buttons & lay::LeftButton) != 0) { - if (handle_dragging (p, buttons, 0)) { + if (handle_dragging (p, buttons, false, 0)) { return true; } } @@ -230,26 +234,50 @@ MoveService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool } bool -MoveService::begin_move (db::Transaction *transaction) +MoveService::begin_move (db::Transaction *transaction, bool selected_after_move) { + if (m_dragging) { + return false; + } + std::auto_ptr trans_holder (transaction); - drag_cancel (); + bool drag_transient = ! selected_after_move; + if (mp_editables->selection_size () == 0) { + // try to use the transient selection for the real one + mp_editables->transient_to_selection (); + drag_transient = true; + } + + if (mp_editables->selection_size () == 0) { + // still nothing selected + return false; + } db::DBox bbox = mp_editables->selection_bbox (); if (bbox.empty ()) { - // nothing selected + // nothing (useful) selected return false; } set_cursor (lay::Cursor::size_all); - // emulate a "begin move" at the center of the selection bbox - this will become the reference point - return handle_dragging (bbox.center (), 0, trans_holder.release ()); + // emulate a "begin move" at the current mouse position if inside the box or the closest point + // of the box. + + db::DPoint pstart = m_mouse_pos; + if (! bbox.contains (pstart)) { + pstart.set_x (std::max (pstart.x (), bbox.p1 ().x ())); + pstart.set_x (std::min (pstart.x (), bbox.p2 ().x ())); + pstart.set_y (std::max (pstart.y (), bbox.p1 ().y ())); + pstart.set_y (std::min (pstart.y (), bbox.p2 ().y ())); + } + + return handle_dragging (pstart, 0, drag_transient, trans_holder.release ()); } bool -MoveService::handle_dragging (const db::DPoint &p, unsigned int buttons, db::Transaction *transaction) +MoveService::handle_dragging (const db::DPoint &p, unsigned int buttons, bool drag_transient, db::Transaction *transaction) { std::auto_ptr trans_holder (transaction); @@ -267,6 +295,7 @@ MoveService::handle_dragging (const db::DPoint &p, unsigned int buttons, db::Tra mp_view->clear_transient_selection (); m_dragging = true; + m_dragging_transient = drag_transient; widget ()->grab_mouse (this, false); m_shift = db::DPoint (); @@ -278,8 +307,14 @@ MoveService::handle_dragging (const db::DPoint &p, unsigned int buttons, db::Tra } else { m_dragging = false; + widget ()->ungrab_mouse (this); mp_editables->end_move (p, ac_from_buttons (buttons), mp_transaction.release ()); + + if (m_dragging_transient) { + mp_editables->clear_selection (); + } + return true; } diff --git a/src/laybasic/laybasic/layMove.h b/src/laybasic/laybasic/layMove.h index b3bf39b2e..45608a125 100644 --- a/src/laybasic/laybasic/layMove.h +++ b/src/laybasic/laybasic/layMove.h @@ -49,7 +49,7 @@ public: ~MoveService (); virtual bool configure (const std::string &name, const std::string &value); - bool begin_move (db::Transaction *transaction = 0); + bool begin_move (db::Transaction *transaction = 0, bool selected_after_move = true); private: virtual bool mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio); @@ -62,13 +62,15 @@ private: virtual void drag_cancel (); virtual void deactivated (); - bool handle_dragging (const db::DPoint &p, unsigned int buttons, db::Transaction *transaction); + bool handle_dragging (const db::DPoint &p, unsigned int buttons, bool drag_transient, db::Transaction *transaction); bool m_dragging; + bool m_dragging_transient; lay::Editables *mp_editables; lay::LayoutView *mp_view; double m_global_grid; db::DPoint m_shift; + db::DPoint m_mouse_pos; std::auto_ptr mp_transaction; }; From 2402adc45d661b937c52725c1e9da012feed0428 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 5 Dec 2019 01:09:48 +0100 Subject: [PATCH 2/7] Open to silence instance copy mode dialog By using "don't ask again" the instance copy mode dialog won't come up again. The mode can be reverted back to "ask" in the editor options. --- src/edt/edt/CopyModeDialog.ui | 86 +++++--- src/edt/edt/EditorOptionsGeneric.ui | 298 +++++++++++++++++---------- src/edt/edt/edtConfig.cc | 1 + src/edt/edt/edtConfig.h | 1 + src/edt/edt/edtDialogs.cc | 3 +- src/edt/edt/edtDialogs.h | 2 +- src/edt/edt/edtEditorOptionsPages.cc | 6 + src/edt/edt/edtPlugin.cc | 1 + src/edt/edt/edtService.cc | 30 ++- src/edt/edt/edtService.h | 3 + 10 files changed, 287 insertions(+), 144 deletions(-) diff --git a/src/edt/edt/CopyModeDialog.ui b/src/edt/edt/CopyModeDialog.ui index 8add36f07..563c8580c 100644 --- a/src/edt/edt/CopyModeDialog.ui +++ b/src/edt/edt/CopyModeDialog.ui @@ -1,7 +1,8 @@ - + + CopyModeDialog - - + + 0 0 @@ -9,38 +10,56 @@ 164 - + Copy Options - - - 9 - - + + 6 + + 9 + + + 9 + + + 9 + + + 9 + - - + + Copy Mode - - - 9 - - + + 6 + + 9 + + + 9 + + + 9 + + + 9 + - - + + Shallow copy (instances only) - - + + Deep copy (instances plus cell) @@ -48,12 +67,19 @@ + + + + Don't ask again (you can always reset this in the editor options) + + + - + Qt::Vertical - + 20 40 @@ -62,12 +88,12 @@ - - + + Qt::Horizontal - - QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok @@ -81,11 +107,11 @@ CopyModeDialog accept() - + 248 254 - + 157 274 @@ -97,11 +123,11 @@ CopyModeDialog reject() - + 316 260 - + 286 274 diff --git a/src/edt/edt/EditorOptionsGeneric.ui b/src/edt/edt/EditorOptionsGeneric.ui index 022fc069c..36c1aadd0 100644 --- a/src/edt/edt/EditorOptionsGeneric.ui +++ b/src/edt/edt/EditorOptionsGeneric.ui @@ -1,7 +1,8 @@ - + + EditorOptionsGeneric - - + + 0 0 @@ -9,34 +10,52 @@ 417 - + Form - - - 9 - - + + 6 + + 9 + + + 9 + + + 9 + + + 9 + - - + + Snapping - - + + 9 - + + 9 + + + 9 + + + 9 + + 6 - + - + Qt::Horizontal - + 148 16 @@ -44,15 +63,15 @@ - + - + Qt::Horizontal - + QSizePolicy::Fixed - + 16 20 @@ -60,57 +79,55 @@ - - - - - 0 - 0 + + + + 0 0 - - Enter the grid in micron. Can be anisotropic ("gx,gy") + + Enter the grid in micron. Can be anisotropic ("gx,gy") - - - + + + Grid - - - + + + Objects - - + + - + No grid - + Global grid - + Other grid ... - - - + + + Snap to other objects @@ -119,75 +136,84 @@ - - + + Angle Constraints - - + + 9 - + + 9 + + + 9 + + + 9 + + 6 - - - + + + Movements - - - + + + Connections - - + + - + Any Angle - + Diagonal - + Manhattan - - + + - + Any Direction - + Diagonal - + Manhattan - + - + Qt::Horizontal - + 257 41 @@ -199,36 +225,91 @@ - - - Selection Mode + + + Hierarchical Features - - + + 9 - + + 9 + + + 9 + + + 9 + + 6 - - - - - 7 - 0 + + + + Copy mode + + + + + + + Shallow select + + + + + + + 0 0 - - Select top level objects only + + QComboBox::AdjustToContentsOnFirstShow + + + Shallow mode (instance only) + + + + + Deep mode (instance and cell) + + + + + Ask + + - - - - Hierarchy + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Select top level objects only @@ -236,30 +317,37 @@ - - + + Instance Display - - - 9 - - + + 6 + + 9 + + + 9 + + + 9 + + + 9 + - - + + Show shapes when moving (max. - - - - 5 - 0 + + + 0 0 @@ -267,18 +355,18 @@ - - + + shapes) - + Qt::Horizontal - + 20 20 @@ -291,10 +379,10 @@ - + Qt::Vertical - + 121 51 diff --git a/src/edt/edt/edtConfig.cc b/src/edt/edt/edtConfig.cc index 2c62dac78..ef531eaa8 100644 --- a/src/edt/edt/edtConfig.cc +++ b/src/edt/edt/edtConfig.cc @@ -57,6 +57,7 @@ std::string cfg_edit_inst_column_x ("edit-inst-column_x"); std::string cfg_edit_inst_column_y ("edit-inst-column_y"); std::string cfg_edit_inst_place_origin ("edit-inst-place-origin"); std::string cfg_edit_top_level_selection ("edit-top-level-selection"); +std::string cfg_edit_hier_copy_mode ("edit-hier-copy-mode"); std::string cfg_edit_show_shapes_of_instances ("edit-show-shapes-of-instances"); std::string cfg_edit_max_shapes_of_instances ("edit-max-shapes-of-instances"); std::string cfg_edit_global_grid ("grid-micron"); diff --git a/src/edt/edt/edtConfig.h b/src/edt/edt/edtConfig.h index b727ea4a7..1c9795678 100644 --- a/src/edt/edt/edtConfig.h +++ b/src/edt/edt/edtConfig.h @@ -68,6 +68,7 @@ extern EDT_PUBLIC std::string cfg_edit_inst_column_x; extern EDT_PUBLIC std::string cfg_edit_inst_column_y; extern EDT_PUBLIC std::string cfg_edit_inst_place_origin; extern EDT_PUBLIC std::string cfg_edit_top_level_selection; +extern EDT_PUBLIC std::string cfg_edit_hier_copy_mode; extern EDT_PUBLIC std::string cfg_edit_combine_mode; // ------------------------------------------------------------ diff --git a/src/edt/edt/edtDialogs.cc b/src/edt/edt/edtDialogs.cc index cf596fd37..7234ec51b 100644 --- a/src/edt/edt/edtDialogs.cc +++ b/src/edt/edt/edtDialogs.cc @@ -196,7 +196,7 @@ CopyModeDialog::~CopyModeDialog () } bool -CopyModeDialog::exec_dialog (unsigned int &mode) +CopyModeDialog::exec_dialog (unsigned int &mode, bool &dont_ask) { if (mode == 0) { shallow_rb->setChecked (true); @@ -207,6 +207,7 @@ CopyModeDialog::exec_dialog (unsigned int &mode) } else { mode = 1; } + dont_ask = dont_ask_cbx->isChecked (); return true; } else { return false; diff --git a/src/edt/edt/edtDialogs.h b/src/edt/edt/edtDialogs.h index e7d8d6258..cbb137edb 100644 --- a/src/edt/edt/edtDialogs.h +++ b/src/edt/edt/edtDialogs.h @@ -64,7 +64,7 @@ public: CopyModeDialog (QWidget *parent); virtual ~CopyModeDialog (); - bool exec_dialog (unsigned int &mode); + bool exec_dialog (unsigned int &mode, bool &dont_ask); }; /** diff --git a/src/edt/edt/edtEditorOptionsPages.cc b/src/edt/edt/edtEditorOptionsPages.cc index b47af42b7..b1b8585f4 100644 --- a/src/edt/edt/edtEditorOptionsPages.cc +++ b/src/edt/edt/edtEditorOptionsPages.cc @@ -265,6 +265,8 @@ EditorOptionsGeneric::apply (lay::Plugin *root) root->config_set (cfg_edit_connect_angle_mode, acc.to_string (lay::angle_constraint_type (mp_ui->conn_angle_cb->currentIndex ()))); root->config_set (cfg_edit_top_level_selection, tl::to_string (mp_ui->hier_sel_cbx->isChecked ())); + int cpm = mp_ui->hier_copy_mode_cbx->currentIndex (); + root->config_set (cfg_edit_hier_copy_mode, tl::to_string ((cpm < 0 || cpm > 1) ? -1 : cpm)); root->config_set (cfg_edit_snap_to_objects, tl::to_string (mp_ui->snap_objects_cbx->isChecked ())); unsigned int max_shapes = 1000; @@ -321,6 +323,10 @@ EditorOptionsGeneric::setup (lay::Plugin *root) root->config_get (cfg_edit_top_level_selection, top_level_sel); mp_ui->hier_sel_cbx->setChecked (top_level_sel); + int cpm = -1; + root->config_get (cfg_edit_hier_copy_mode, cpm); + mp_ui->hier_copy_mode_cbx->setCurrentIndex ((cpm < 0 || cpm > 1) ? 2 : cpm); + bool snap_to_objects = false; root->config_get (cfg_edit_snap_to_objects, snap_to_objects); mp_ui->snap_objects_cbx->setChecked (snap_to_objects); diff --git a/src/edt/edt/edtPlugin.cc b/src/edt/edt/edtPlugin.cc index d97395acf..478121156 100644 --- a/src/edt/edt/edtPlugin.cc +++ b/src/edt/edt/edtPlugin.cc @@ -198,6 +198,7 @@ public: virtual void get_options (std::vector < std::pair > &options) const { options.push_back (std::pair (cfg_edit_top_level_selection, "false")); + options.push_back (std::pair (cfg_edit_hier_copy_mode, "-1")); options.push_back (std::pair (cfg_edit_grid, "")); options.push_back (std::pair (cfg_edit_snap_to_objects, "false")); options.push_back (std::pair (cfg_edit_move_angle_mode, "any")); diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc index 7d5914bde..5573329d5 100644 --- a/src/edt/edt/edtService.cc +++ b/src/edt/edt/edtService.cc @@ -113,6 +113,7 @@ Service::Service (db::Manager *manager, lay::LayoutView *view, db::ShapeIterator m_connect_ac (lay::AC_Any), m_move_ac (lay::AC_Any), m_alt_ac (lay::AC_Global), m_snap_to_objects (false), m_top_level_sel (false), m_show_shapes_of_instances (true), m_max_shapes_of_instances (1000), + m_hier_copy_mode (-1), m_indicate_secondary_selection (false), m_seq (0), dm_selection_to_view (this, &edt::Service::do_selection_to_view) @@ -134,6 +135,7 @@ Service::Service (db::Manager *manager, lay::LayoutView *view) m_connect_ac (lay::AC_Any), m_move_ac (lay::AC_Any), m_alt_ac (lay::AC_Global), m_snap_to_objects (true), m_top_level_sel (false), m_show_shapes_of_instances (true), m_max_shapes_of_instances (1000), + m_hier_copy_mode (-1), m_indicate_secondary_selection (false), m_seq (0), dm_selection_to_view (this, &edt::Service::do_selection_to_view) @@ -255,6 +257,8 @@ Service::configure (const std::string &name, const std::string &value) return true; // taken } else if (name == cfg_edit_top_level_selection) { tl::from_string (value, m_top_level_sel); + } else if (name == cfg_edit_hier_copy_mode) { + tl::from_string (value, m_hier_copy_mode); } return false; // not taken @@ -309,18 +313,30 @@ Service::copy_selected () edt::CopyModeDialog mode_dialog (view ()); bool need_to_ask_for_copy_mode = false; - for (objects::const_iterator r = m_selection.begin (); r != m_selection.end () && ! need_to_ask_for_copy_mode; ++r) { - if (r->is_cell_inst ()) { - const db::Cell &cell = view ()->cellview (r->cv_index ())->layout ().cell (r->back ().inst_ptr.cell_index ()); - if (! cell.is_proxy ()) { - need_to_ask_for_copy_mode = true; + unsigned int inst_mode = 0; + + if (m_hier_copy_mode < 0) { + for (objects::const_iterator r = m_selection.begin (); r != m_selection.end () && ! need_to_ask_for_copy_mode; ++r) { + if (r->is_cell_inst ()) { + const db::Cell &cell = view ()->cellview (r->cv_index ())->layout ().cell (r->back ().inst_ptr.cell_index ()); + if (! cell.is_proxy ()) { + need_to_ask_for_copy_mode = true; + } } } + } else { + inst_mode = (unsigned int) m_hier_copy_mode; } - unsigned int inst_mode = 0; + bool dont_ask_again = false; - if (! need_to_ask_for_copy_mode || mode_dialog.exec_dialog (inst_mode)) { + if (! need_to_ask_for_copy_mode || mode_dialog.exec_dialog (inst_mode, dont_ask_again)) { + + // store the given value "forever" + if (dont_ask_again) { + plugin_root ()->config_set (cfg_edit_hier_copy_mode, tl::to_string (inst_mode)); + plugin_root ()->config_end (); + } // create one ClipboardData object per cv_index because, this one assumes that there is // only one source layout object. diff --git a/src/edt/edt/edtService.h b/src/edt/edt/edtService.h index 2f0fee85d..647a70ae4 100644 --- a/src/edt/edt/edtService.h +++ b/src/edt/edt/edtService.h @@ -579,6 +579,9 @@ private: bool m_show_shapes_of_instances; unsigned int m_max_shapes_of_instances; + // Hierarchical copy mode (-1: ask, 0: shallow, 1: deep) + int m_hier_copy_mode; + // Sequence number of selection bool m_indicate_secondary_selection; unsigned long m_seq; From a430b4df831a80db813626ac5b564c83afdb8547 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 7 Dec 2019 19:08:35 +0100 Subject: [PATCH 3/7] Supply 'read_all' capability of text stream with CRLF replacement. --- src/tl/tl/tlStream.cc | 68 +++++++++++++++++++++--------- src/tl/tl/tlStream.h | 14 +++++- src/tl/unit_tests/tlStreamTests.cc | 38 +++++++++++++++++ 3 files changed, 98 insertions(+), 22 deletions(-) diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc index 7b1724bf8..d12002dde 100644 --- a/src/tl/tl/tlStream.cc +++ b/src/tl/tl/tlStream.cc @@ -422,6 +422,30 @@ TextInputStream::TextInputStream (InputStream &stream) } } +std::string +TextInputStream::read_all () +{ + return read_all (std::numeric_limits::max ()); +} + +std::string +TextInputStream::read_all (size_t max_count) +{ + std::string text; + + while (! at_end () && max_count > 0) { + char c = get_char (); + if (c == 0) { + break; + } else { + --max_count; + text += c; + } + } + + return text; +} + const std::string & TextInputStream::get_line () { @@ -430,9 +454,7 @@ TextInputStream::get_line () while (! at_end ()) { char c = get_char (); - if (c == '\r') { - // simply skip CR - } else if (c == '\n' || c == 0) { + if (c == '\n' || c == 0) { break; } else { m_line_buffer += c; @@ -445,31 +467,35 @@ TextInputStream::get_line () char TextInputStream::get_char () { - m_line = m_next_line; - const char *c = m_stream.get (1); - if (c == 0) { - m_at_end = true; - return 0; - } else { - if (*c == '\n') { - ++m_next_line; + while (true) { + m_line = m_next_line; + const char *c = m_stream.get (1); + if (c == 0) { + m_at_end = true; + return 0; + } else if (*c != '\r' && *c) { + if (*c == '\n') { + ++m_next_line; + } + return *c; } - return *c; } } char TextInputStream::peek_char () { - m_line = m_next_line; - const char *c = m_stream.get (1); - if (c == 0) { - m_at_end = true; - return 0; - } else { - char cc = *c; - m_stream.unget (1); - return cc; + while (true) { + m_line = m_next_line; + const char *c = m_stream.get (1); + if (c == 0) { + m_at_end = true; + return 0; + } else if (*c != '\r' && *c) { + char cc = *c; + m_stream.unget (1); + return cc; + } } } diff --git a/src/tl/tl/tlStream.h b/src/tl/tl/tlStream.h index c300c551d..6752b03c4 100644 --- a/src/tl/tl/tlStream.h +++ b/src/tl/tl/tlStream.h @@ -564,7 +564,7 @@ private: // --------------------------------------------------------------------------------- /** - * @brief An ASCII input stream + * @brief A text input stream (UTF8 encoded) * * This class is put in front of a InputStream to format the input as text input stream. */ @@ -591,6 +591,18 @@ public: */ const std::string &get_line (); + /** + * @brief Reads all remaining bytes into the string + */ + std::string read_all (); + + /** + * @brief Reads all remaining bytes into the string + * + * This function reads all remaining of max_count bytes. + */ + std::string read_all (size_t max_count); + /** * @brief Get a single character */ diff --git a/src/tl/unit_tests/tlStreamTests.cc b/src/tl/unit_tests/tlStreamTests.cc index 4c398e206..01a6c6b71 100644 --- a/src/tl/unit_tests/tlStreamTests.cc +++ b/src/tl/unit_tests/tlStreamTests.cc @@ -107,3 +107,41 @@ TEST(TextOutputStream) throw; } } + +TEST(TextInputStream) +{ + std::string fn = tmp_file ("test.txt"); + + { + tl::OutputStream os (fn, tl::OutputStream::OM_Auto, false); + os << "Hello, world!\nWith another line\n\r\r\nseparated by a LFCR and CRLF."; + } + + { + tl::InputStream is (fn); + tl::TextInputStream tis (is); + EXPECT_EQ (tis.get_line (), "Hello, world!"); + EXPECT_EQ (tis.line_number (), 1); + EXPECT_EQ (tis.get_line (), "With another line"); + EXPECT_EQ (tis.line_number (), 2); + EXPECT_EQ (tis.peek_char (), '\n'); + EXPECT_EQ (tis.get_line (), ""); + EXPECT_EQ (tis.line_number (), 3); + EXPECT_EQ (tis.peek_char (), 's'); + EXPECT_EQ (tis.get_line (), "separated by a LFCR and CRLF."); + EXPECT_EQ (tis.line_number (), 4); + EXPECT_EQ (tis.at_end (), true); + } + + { + tl::InputStream is (fn); + tl::TextInputStream tis (is); + EXPECT_EQ (tis.read_all (5), "Hello"); + } + + { + tl::InputStream is (fn); + tl::TextInputStream tis (is); + EXPECT_EQ (tis.read_all (), "Hello, world!\nWith another line\n\nseparated by a LFCR and CRLF."); + } +} From 9ef90aa13549034b72af13cbb7b91b8c2f098d3f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 7 Dec 2019 19:14:21 +0100 Subject: [PATCH 4/7] Fixed #439 (CRLF issue with plain-text macros) --- src/lym/lym/lymMacro.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lym/lym/lymMacro.cc b/src/lym/lym/lymMacro.cc index c8a94b594..b82ce7b5a 100644 --- a/src/lym/lym/lymMacro.cc +++ b/src/lym/lym/lymMacro.cc @@ -240,7 +240,8 @@ void Macro::load_from (const std::string &fn) } else if (m_format == PlainTextFormat || m_format == PlainTextWithHashAnnotationsFormat) { tl::InputStream stream (path); - m_text = stream.read_all (); + tl::TextInputStream text_stream (stream); + m_text = text_stream.read_all (); sync_properties_with_text (); } From c2140216184999eeb26663a4176dd4805e410e70 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 7 Dec 2019 21:51:10 +0100 Subject: [PATCH 5/7] Fixed #440 (issue with LayoutView#each_annotation_selected) --- src/ant/ant/gsiDeclAnt.cc | 4 ++-- testdata/ruby/antTest.rb | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/ant/ant/gsiDeclAnt.cc b/src/ant/ant/gsiDeclAnt.cc index 68cb6f6c1..367183222 100644 --- a/src/ant/ant/gsiDeclAnt.cc +++ b/src/ant/ant/gsiDeclAnt.cc @@ -1063,7 +1063,7 @@ public: typedef AnnotationRef value_type; typedef std::map::const_iterator iterator_type; typedef void pointer; - typedef const value_type &reference; + typedef value_type reference; typedef std::forward_iterator_tag iterator_category; typedef void difference_type; @@ -1088,7 +1088,7 @@ public: return *this; } - value_type operator* () const + reference operator* () const { return value_type (*(static_cast (m_iter->first->ptr ())), m_services[m_service]->view ()); } diff --git a/testdata/ruby/antTest.rb b/testdata/ruby/antTest.rb index 9b7eaa6d7..27e2a34f1 100644 --- a/testdata/ruby/antTest.rb +++ b/testdata/ruby/antTest.rb @@ -530,6 +530,40 @@ class Ant_TestClass < TestBase end + # each_annotation_selected + def test_4 + + if !RBA.constants.member?(:Application) + return + end + + mw = RBA::Application::instance.main_window + mw.close_all + mw.create_layout( 0 ) + lv = mw.current_view + + a = annot_obj( RBA::DPoint::new( 1.0, 2.0 ), RBA::DPoint::new( 3.0, 4.0 ), "a", "b", "c", 1, 2, false, 3 ) + assert_equal( a.is_valid?, false ) + lv.insert_annotation( a ) + + mw.cm_select_all + + arr = [] + lv.each_annotation_selected { |a| arr.push(a) } + assert_equal(arr.size, 1) + assert_equal(arr[0].to_s, "p1=1,2, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal") + + arr[0].p1 = RBA::DPoint::new(11, 12) + + arr = [] + lv.each_annotation_selected { |a| arr.push(a) } + assert_equal(arr.size, 1) + assert_equal(arr[0].to_s, "p1=11,12, p2=3,4, fmt=a, fmt_x=b, fmt_y=c, style=arrow_end, outline=diag_xy, snap=false, ac=horizontal") + + mw.close_all + + end + end load("test_epilogue.rb") From 3b9beb0d49c3d9e4a742feb42288519655428c05 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 7 Dec 2019 23:39:39 +0100 Subject: [PATCH 6/7] Fixed #438 (error on redefinition of subcircuit in SPICE) --- src/db/db/dbNetlistSpiceReader.cc | 8 +++++++- src/db/db/dbNetlistSpiceReader.h | 3 +++ src/db/unit_tests/dbNetlistReaderTests.cc | 18 ++++++++++++++++++ testdata/algo/nreader11.cir | 22 ++++++++++++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 testdata/algo/nreader11.cir diff --git a/src/db/db/dbNetlistSpiceReader.cc b/src/db/db/dbNetlistSpiceReader.cc index c54a7e352..dff5050cc 100644 --- a/src/db/db/dbNetlistSpiceReader.cc +++ b/src/db/db/dbNetlistSpiceReader.cc @@ -254,6 +254,7 @@ void NetlistSpiceReader::read (tl::InputStream &stream, db::Netlist &netlist) mp_circuit = 0; mp_nets_by_name.reset (0); m_global_nets.clear (); + m_circuits_read.clear (); try { @@ -891,11 +892,16 @@ void NetlistSpiceReader::read_circuit (tl::Extractor &ex, const std::string &nc) } else { if (cc->pin_count () != nn.size () + m_global_nets.size ()) { - error (tl::sprintf (tl::to_string (tr ("Pin count mismatch between implicit (through call) and explicit circuit definition: %d expected, got %d")), int (cc->pin_count ()), int (nn.size ()))); + error (tl::sprintf (tl::to_string (tr ("Pin count mismatch between implicit (through call) and explicit circuit definition: %d expected, got %d in circuit %s")), int (cc->pin_count ()), int (nn.size ()), nc)); } } + if (m_circuits_read.find (cc) != m_circuits_read.end ()) { + error (tl::sprintf (tl::to_string (tr ("Redefinition of circuit %s")), nc)); + } + m_circuits_read.insert (cc); + std::auto_ptr > n2n (mp_nets_by_name.release ()); mp_nets_by_name.reset (0); diff --git a/src/db/db/dbNetlistSpiceReader.h b/src/db/db/dbNetlistSpiceReader.h index 95eca62e2..ddf5eecea 100644 --- a/src/db/db/dbNetlistSpiceReader.h +++ b/src/db/db/dbNetlistSpiceReader.h @@ -28,6 +28,8 @@ #include "tlStream.h" #include +#include +#include #include namespace db @@ -129,6 +131,7 @@ private: std::string m_stored_line; std::map m_captured; std::vector m_global_nets; + std::set m_circuits_read; void push_stream (const std::string &path); void pop_stream (); diff --git a/src/db/unit_tests/dbNetlistReaderTests.cc b/src/db/unit_tests/dbNetlistReaderTests.cc index 98a6b3491..dc4d40d41 100644 --- a/src/db/unit_tests/dbNetlistReaderTests.cc +++ b/src/db/unit_tests/dbNetlistReaderTests.cc @@ -384,3 +384,21 @@ TEST(10_SubcircuitsNoPins) ); } +TEST(11_ErrorOnCircuitRedefinition) +{ + db::Netlist nl; + + std::string path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "nreader11.cir"); + + std::string msg; + try { + db::NetlistSpiceReader reader; + tl::InputStream is (path); + reader.read (is, nl); + } catch (tl::Exception &ex) { + msg = ex.msg (); + } + + EXPECT_EQ (tl::replaced (msg, path, "?"), "Redefinition of circuit SUBCKT in ?, line 20"); +} + diff --git a/testdata/algo/nreader11.cir b/testdata/algo/nreader11.cir new file mode 100644 index 000000000..2b334a8d2 --- /dev/null +++ b/testdata/algo/nreader11.cir @@ -0,0 +1,22 @@ +* written by unit test + +* cell SUBCKT +* pin +* pin A +* pin V42 +* pin Z +* pin gnd +* pin gnd +.SUBCKT SUBCKT \$1 A[5]<1> V42\x28\x25\x29 Z gnd gnd$1 +XD_$1 V42\x28\x25\x29 \$3 Z \$1 HVPMOS PARAMS: L=0.2 W=1 AS=0.18 AD=0.18 ++ PS=2.16 PD=2.16 +* device instance $2 r0 *1 0,0 HVPMOS +XD_$2 V42\x28\x25\x29 A[5]<1> \$3 \$1 HVPMOS PARAMS: L=0.2 W=1 AS=0.18 AD=0.18 ++ PS=2.16 PD=2.16 +XD_$3 gnd \$3 gnd gnd$1 HVNMOS PARAMS: L=1.13 W=2.12 PS=6 PD=6 AS=0 AD=0 +XD_$4 gnd \$3 Z gnd$1 HVNMOS PARAMS: L=0.4 W=0.4 PS=1.16 PD=1.16 AS=0.19 AD=0.19 +XD_$5 gnd A[5]<1> \$3 gnd$1 HVNMOS PARAMS: L=0.4 W=0.4 PS=1.76 PD=1.76 AS=0.19 AD=0.19 +.ENDS SUBCKT +.SUBCKT SUBCKT \$1 A[5]<1> V42\x28\x25\x29 Z gnd gnd$1 +XD_$13 gnd \$3 gnd gnd$1 HVNMOS PARAMS: L=1.13 W=2.12 PS=6 PD=6 AS=0 AD=0 +.ENDS SUBCKT From 63cc73b5696e374112ab0c08954ed6655490fcc9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 8 Dec 2019 08:43:08 +0100 Subject: [PATCH 7/7] Fixed #445 (cryptic message when instances are selected and 'merge shapes' is used) --- src/edt/edt/edtMainService.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edt/edt/edtMainService.cc b/src/edt/edt/edtMainService.cc index 67d3fd24d..78c1f0329 100644 --- a/src/edt/edt/edtMainService.cc +++ b/src/edt/edt/edtMainService.cc @@ -1641,7 +1641,7 @@ MainService::boolean_op (int mode) for (std::vector::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) { for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) { - if (int (s->layer ()) == layer_index && ! s->is_cell_inst () && (s->shape ().is_polygon () || s->shape ().is_path () || s->shape ().is_box ())) { + if (! s->is_cell_inst () && int (s->layer ()) == layer_index && (s->shape ().is_polygon () || s->shape ().is_path () || s->shape ().is_box ())) { db::Cell &cell = view ()->cellview (s->cv_index ())->layout ().cell (s->cell_index ()); if (cell.shapes (s->layer ()).is_valid (s->shape ())) { cell.shapes (s->layer ()).erase_shape (s->shape ());