diff --git a/src/lay/lay/layMainConfigPages.cc b/src/lay/lay/layMainConfigPages.cc index 5b95b0229..ceb7aabc0 100644 --- a/src/lay/lay/layMainConfigPages.cc +++ b/src/lay/lay/layMainConfigPages.cc @@ -434,9 +434,10 @@ CustomizeMenuConfigPage::apply (const std::vector top_level_menus; top_level_menus.insert (std::make_pair (std::string (), tl::to_string (QObject::tr ("Main Menu")))); + top_level_menus.insert (std::make_pair (std::string ("secrets"), tl::to_string (QObject::tr ("Key Binding Targets")))); top_level_menus.insert (std::make_pair (std::string ("lcp_context_menu"), tl::to_string (QObject::tr ("Layer Panel Context Menu")))); top_level_menus.insert (std::make_pair (std::string ("hcp_context_menu"), tl::to_string (QObject::tr ("Cell List Context Menu")))); - + // fill the bindings list mp_ui->bindings_list->clear (); diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index 3ae39ec3d..71a1da23d 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -742,6 +742,13 @@ MainWindow::init_menu () { // default menu layout + MenuLayoutEntry secret_menu [] = { + MenuLayoutEntry ("paste_interactive:edit", tl::to_string (QObject::tr ("Paste Interactive")), SLOT (cm_paste_interactive ())), + MenuLayoutEntry ("duplicate_interactive:edit", tl::to_string (QObject::tr ("Duplicate Interactive")), SLOT (cm_duplicate_interactive ())), + MenuLayoutEntry ("sel_move_interactive", tl::to_string (QObject::tr ("Move Interactive")), SLOT (cm_sel_move_interactive ())), + MenuLayoutEntry::last () + }; + MenuLayoutEntry empty_menu [] = { MenuLayoutEntry::last () }; @@ -995,6 +1002,7 @@ MainWindow::init_menu () MenuLayoutEntry ("macros_menu", tl::to_string (QObject::tr ("&Macros")), macros_menu), MenuLayoutEntry::separator ("help_group"), MenuLayoutEntry ("help_menu", tl::to_string (QObject::tr ("&Help")), help_menu), + MenuLayoutEntry ("@secrets", tl::to_string (QObject::tr ("Secret Features")), secret_menu), MenuLayoutEntry ("@toolbar", "", toolbar_entries), MenuLayoutEntry::last () }; @@ -2233,7 +2241,7 @@ MainWindow::cm_cell_copy () } void -MainWindow::cm_duplicate () +MainWindow::do_cm_duplicate (bool interactive) { BEGIN_PROTECTED @@ -2248,7 +2256,11 @@ MainWindow::cm_duplicate () current_view ()->copy (); current_view ()->clear_selection (); current_view ()->cancel (); - current_view ()->paste (); + if (interactive) { + current_view ()->paste_interactive (); + } else { + current_view ()->paste (); + } db::Clipboard::instance ().swap (saved_clipboard); } catch (...) { db::Clipboard::instance ().swap (saved_clipboard); @@ -2260,6 +2272,26 @@ MainWindow::cm_duplicate () END_PROTECTED } +void +MainWindow::cm_duplicate () +{ + BEGIN_PROTECTED + + do_cm_duplicate (false); + + END_PROTECTED +} + +void +MainWindow::cm_duplicate_interactive () +{ + BEGIN_PROTECTED + + do_cm_duplicate (true); + + END_PROTECTED +} + void MainWindow::cm_copy () { @@ -2274,19 +2306,35 @@ MainWindow::cm_copy () } void -MainWindow::cm_paste () +MainWindow::do_cm_paste (bool interactive) { BEGIN_PROTECTED if (current_view () && ! db::Clipboard::instance ().empty ()) { current_view ()->cancel (); current_view ()->clear_selection (); - current_view ()->paste (); + if (interactive) { + current_view ()->paste_interactive (); + } else { + current_view ()->paste (); + } } END_PROTECTED } +void +MainWindow::cm_paste () +{ + do_cm_paste (false); +} + +void +MainWindow::cm_paste_interactive () +{ + do_cm_paste (true); +} + void MainWindow::cm_cut () { @@ -3568,6 +3616,12 @@ MainWindow::cm_sel_move_to () call_on_current_view (&lay::LayoutView::cm_sel_move_to, tl::to_string (QObject::tr ("move selection to position"))); } +void +MainWindow::cm_sel_move_interactive () +{ + call_on_current_view (&lay::LayoutView::cm_sel_move_interactive, tl::to_string (QObject::tr ("move selection interactively"))); +} + void MainWindow::cm_sel_scale () { @@ -3685,19 +3739,7 @@ MainWindow::clone_current_view () // create a new view view = new lay::LayoutView (current_view (), &m_manager, lay::ApplicationBase::instance ()->is_editable (), plugin_root (), mp_view_stack); - connect (view, SIGNAL (title_changed ()), this, SLOT (view_title_changed ())); - connect (view, SIGNAL (dirty_changed ()), this, SLOT (view_title_changed ())); - connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ())); - connect (view, SIGNAL (menu_needs_update ()), this, SLOT (menu_needs_update ())); - connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int))); - connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool))); - connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ())); - mp_views.push_back (view); - - // we must resize the widget here to set the geometry properly. - // This is required to make zoom_fit work. - view->setGeometry (0, 0, mp_view_stack->width (), mp_view_stack->height ()); - view->show (); + add_view (view); // set initial attributes view->set_hier_levels (curr->get_hier_levels ()); @@ -4291,12 +4333,9 @@ MainWindow::create_layout (const std::string &technology, int mode) return create_or_load_layout (0, 0, technology, mode); } -int -MainWindow::do_create_view () +void +MainWindow::add_view (lay::LayoutView *view) { - // create a new view - lay::LayoutView *view = new lay::LayoutView (&m_manager, lay::ApplicationBase::instance ()->is_editable (), plugin_root (), mp_view_stack); - connect (view, SIGNAL (title_changed ()), this, SLOT (view_title_changed ())); connect (view, SIGNAL (dirty_changed ()), this, SLOT (view_title_changed ())); connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ())); @@ -4304,6 +4343,7 @@ MainWindow::do_create_view () connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int))); connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool))); connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ())); + connect (view, SIGNAL (mode_change (int)), this, SLOT (select_mode (int))); mp_views.push_back (view); @@ -4311,6 +4351,14 @@ MainWindow::do_create_view () // This is required to make zoom_fit work. view->setGeometry (0, 0, mp_view_stack->width (), mp_view_stack->height ()); view->show (); +} + +int +MainWindow::do_create_view () +{ + // create a new view + lay::LayoutView *view = new lay::LayoutView (&m_manager, lay::ApplicationBase::instance ()->is_editable (), plugin_root (), mp_view_stack); + add_view (view); // set initial attributes view->set_synchronous (synchronous ()); diff --git a/src/lay/lay/layMainWindow.h b/src/lay/lay/layMainWindow.h index de4ef64ec..dc79128c4 100644 --- a/src/lay/lay/layMainWindow.h +++ b/src/lay/lay/layMainWindow.h @@ -504,13 +504,6 @@ public: */ void select_view (int index); - /** - * @brief Select the given mode - * - * @param The index of the mode to select - */ - void select_mode (int m); - /** * @brief Get the instance of the assistant */ @@ -645,17 +638,17 @@ signals: public slots: /** - * @brief Display the current position + * @brief Displays the current position */ void current_pos (double x, double y, bool dbu_units); /** - * @brief Clear the current position + * @brief Clears the current position */ void clear_current_pos (); /** - * @brief Display a status message next to the coordinates + * @brief Displays a status message next to the coordinates */ void message (const std::string &s, int ms); @@ -664,6 +657,13 @@ public slots: */ void clear_message (); + /** + * @brief Selects the given mode + * + * @param The index of the mode to select + */ + void select_mode (int m); + /** * @brief Called when one of the built-in modes (i.e. select, move) is selected */ @@ -691,7 +691,9 @@ public slots: void cm_show_properties (); void cm_copy (); void cm_paste (); + void cm_paste_interactive (); void cm_duplicate (); + void cm_duplicate_interactive (); void cm_cut (); void cm_zoom_fit_sel (); void cm_zoom_fit (); @@ -772,6 +774,7 @@ public slots: void cm_sel_scale (); void cm_sel_move (); void cm_sel_move_to (); + void cm_sel_move_interactive (); void cm_show_assistant (); // forwarded to the current view: layer list context menu @@ -946,6 +949,9 @@ private: void closeEvent (QCloseEvent *event); void resizeEvent (QResizeEvent *event); + void do_cm_paste (bool interactive); + void do_cm_duplicate (bool interactive); + void format_message (); int dirty_files (std::string &dirty_files); @@ -956,6 +962,7 @@ private: void current_view_changed (); void update_window_title (); void update_tab_title (int i); + void add_view (LayoutView *view); bool can_close (); lay::CellViewRef create_or_load_layout (const std::string *filename, const db::LoadLayoutOptions *options, const std::string &tech, const int mode); diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index 531a604ca..3f0c2ce78 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -5085,6 +5085,29 @@ LayoutView::paste () } } +void +LayoutView::paste_interactive () +{ + clear_selection (); + + { + db::Transaction trans (manager (), tl::to_string (QObject::tr ("Paste"))); + + // let the receivers sort out who is pasting what .. + if (mp_hierarchy_panel) { + mp_hierarchy_panel->paste (); + } + if (mp_control_panel) { + mp_control_panel->paste (); + } + lay::Editables::paste (); + } + + if (mp_move_service->begin_move ()) { + switch_mode (-1); // move mode + } +} + void LayoutView::copy () { @@ -6763,6 +6786,23 @@ LayoutView::cm_sel_scale () } } +void +LayoutView::cm_sel_move_interactive () +{ + if (mp_move_service->begin_move ()) { + switch_mode (-1); // move mode + } +} + +void +LayoutView::switch_mode (int m) +{ + if (m_mode != m) { + mode (m); + emit mode_change (m); + } +} + void LayoutView::cm_sel_move_to () { diff --git a/src/laybasic/laybasic/layLayoutView.h b/src/laybasic/laybasic/layLayoutView.h index d562d74ca..6d9da0bde 100644 --- a/src/laybasic/laybasic/layLayoutView.h +++ b/src/laybasic/laybasic/layLayoutView.h @@ -254,6 +254,11 @@ public: */ void paste (); + /** + * @brief Pastes from clipboard and initiates a move + */ + void paste_interactive (); + /** * @brief Copies to clipboard * @@ -1617,6 +1622,14 @@ public: */ void mode (int m); + /** + * @brief Switches the application's mode + * + * Switches the mode on application level. Use this method to initiate + * a mode switch from the view. + */ + void switch_mode (int m); + /** * @brief Test, if the view is currently in move mode. */ @@ -2582,6 +2595,7 @@ public slots: void cm_sel_scale (); void cm_sel_move (); void cm_sel_move_to (); + void cm_sel_move_interactive (); // forwarded to the layer control panel void cm_new_tab (); @@ -2698,6 +2712,11 @@ signals: */ void menu_needs_update (); + /** + * @brief The view initiated a mode change + */ + void mode_change (int m); + protected: /** * @brief Establish the view operations diff --git a/src/laybasic/laybasic/layMove.cc b/src/laybasic/laybasic/layMove.cc index deb9d5e56..7a6a5e708 100644 --- a/src/laybasic/laybasic/layMove.cc +++ b/src/laybasic/laybasic/layMove.cc @@ -229,6 +229,22 @@ MoveService::mouse_press_event (const db::DPoint &p, unsigned int buttons, bool return false; } +bool +MoveService::begin_move () +{ + drag_cancel (); + + db::DBox bbox = mp_editables->selection_bbox (); + if (bbox.empty ()) { + // nothing 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); +} bool MoveService::handle_dragging (const db::DPoint &p, unsigned int buttons) diff --git a/src/laybasic/laybasic/layMove.h b/src/laybasic/laybasic/layMove.h index 84ff6c7dd..0c12efaf2 100644 --- a/src/laybasic/laybasic/layMove.h +++ b/src/laybasic/laybasic/layMove.h @@ -46,6 +46,7 @@ public: ~MoveService (); virtual bool configure (const std::string &name, const std::string &value); + bool begin_move (); private: virtual bool mouse_press_event (const db::DPoint &p, unsigned int buttons, bool prio);