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/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 254f3976c..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. @@ -357,6 +373,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 +1206,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..647a70ae4 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 */ @@ -574,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; 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; };