From 374c8d2c4d6fed3db6e4426056c5246e8bb6c7b8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 2 Aug 2020 17:34:07 +0200 Subject: [PATCH] Some refactoring: pulled out the layout functionality from the layout view and put into a plugin. --- src/laybasic/laybasic/layEditable.cc | 8 + src/laybasic/laybasic/layEditable.h | 7 + src/laybasic/laybasic/layLayoutView.cc | 2198 +--------------- src/laybasic/laybasic/layLayoutView.h | 118 +- .../laybasic/layLayoutViewFunctions.cc | 2249 +++++++++++++++++ .../laybasic/layLayoutViewFunctions.h | 171 ++ src/laybasic/laybasic/laybasic.pro | 6 +- 7 files changed, 2466 insertions(+), 2291 deletions(-) create mode 100644 src/laybasic/laybasic/layLayoutViewFunctions.cc create mode 100644 src/laybasic/laybasic/layLayoutViewFunctions.h diff --git a/src/laybasic/laybasic/layEditable.cc b/src/laybasic/laybasic/layEditable.cc index c2ef0fa38..8b75008f1 100644 --- a/src/laybasic/laybasic/layEditable.cc +++ b/src/laybasic/laybasic/layEditable.cc @@ -444,6 +444,14 @@ Editables::select (const db::DPoint &pt, lay::Editable::SelectionMode mode) signal_selection_changed (); } +void +Editables::repeat_selection (Editable::SelectionMode mode) +{ + if (m_last_selected_point.is_point ()) { + select (m_last_selected_point, mode); + } +} + bool Editables::begin_move (const db::DPoint &p, lay::angle_constraint_type ac) { diff --git a/src/laybasic/laybasic/layEditable.h b/src/laybasic/laybasic/layEditable.h index a5d6831e7..b60ed500a 100644 --- a/src/laybasic/laybasic/layEditable.h +++ b/src/laybasic/laybasic/layEditable.h @@ -493,6 +493,13 @@ public: */ void select (const db::DPoint &pt, Editable::SelectionMode mode); + /** + * @brief Repeat the previous selection + * + * This method will not do anything if there is no previous, click-at selection. + */ + void repeat_selection (Editable::SelectionMode mode); + /** * @brief Start "move" operation * diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index f7ae519f5..62a8566a3 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -46,14 +46,12 @@ #include "layLayoutView.h" #include "layViewOp.h" #include "layViewObject.h" -#include "layLayoutViewConfigPages.h" #include "laybasicConfig.h" #include "layConverters.h" #include "layGridNet.h" #include "layMove.h" #include "layZoomBox.h" #include "layMouseTracker.h" -#include "layTipDialog.h" #include "layEditable.h" #include "layFixedFont.h" #include "laySelector.h" @@ -68,16 +66,10 @@ #include "layBookmarkManagementForm.h" #include "layNetlistBrowserDialog.h" #include "layBookmarksView.h" -#include "laySelectCellViewForm.h" -#include "layCellSelectionForm.h" -#include "layLayoutPropertiesForm.h" -#include "layLayoutStatisticsForm.h" #include "dbClipboard.h" #include "dbLayout.h" #include "dbLayoutUtils.h" -#include "dbRecursiveShapeIterator.h" #include "dbManager.h" -#include "dbEdgeProcessor.h" #include "dbLibrary.h" #include "rdb.h" #include "rdbMarkerBrowserDialog.h" @@ -460,20 +452,10 @@ LayoutView::init (db::Manager *mgr, QWidget * /*parent*/) m_marker_halo = true; m_transient_selection_mode = true; m_sel_inside_pcells = false; - m_move_to_origin_mode_x = 0; - m_move_to_origin_mode_y = 0; - m_del_cell_mode = 0; - m_layer_hier_mode = 0; m_add_other_layers = false; m_always_show_source = false; m_always_show_ld = true; m_always_show_layout_index = false; - m_duplicate_hier_mode = 2; - m_clear_before = true; - m_copy_cva = -1; - m_copy_cvr = -1; - m_copy_layera = -1; - m_copy_layerr = -1; m_search_range = 5; m_layer_properties_lists.push_back (new LayerPropertiesList ()); @@ -616,9 +598,6 @@ LayoutView::init (db::Manager *mgr, QWidget * /*parent*/) create_plugins (); - m_new_layer_props.layer = 1; - m_new_layer_props.datatype = 0; - config_setup (); } @@ -5272,923 +5251,6 @@ LayoutView::cut () } } -void -LayoutView::cm_align_cell_origin () -{ - int cv_index = active_cellview_index (); - if (cv_index >= 0) { - - const db::Cell *cell = cellview (cv_index).cell (); - if (! cell) { - return; - } - if (cell->is_proxy ()) { - throw tl::Exception (tl::to_string (QObject::tr ("Cannot use this function on a PCell or library cell"))); - } - - lay::AlignCellOptionsDialog dialog (this); - if (dialog.exec_dialog (m_align_cell_options)) { - - clear_selection (); - - transaction (tl::to_string (QObject::tr ("Align cell origin"))); - - db::Box bbox; - - if (m_align_cell_options.visible_only) { - for (lay::LayerPropertiesConstIterator l = begin_layers (); !l.at_end (); ++l) { - if (! l->has_children () && l->layer_index () >= 0 && l->cellview_index () == cv_index && l->visible (true /*real*/)) { - bbox += cell->bbox (l->layer_index ()); - } - } - } else { - bbox = cell->bbox (); - } - - db::Coord refx, refy; - switch (m_align_cell_options.mode_x) { - case -1: - refx = bbox.left (); - break; - case 1: - refx = bbox.right (); - break; - default: - refx = bbox.center ().x (); - break; - } - switch (m_align_cell_options.mode_y) { - case -1: - refy = bbox.bottom (); - break; - case 1: - refy = bbox.top (); - break; - default: - refy = bbox.center ().y (); - break; - } - - db::Layout &layout = cellview (cv_index)->layout (); - db::Cell &nc_cell = layout.cell (cell->cell_index ()); - - db::Trans t (db::Vector (-refx + db::coord_traits::rounded (m_align_cell_options.xpos / layout.dbu ()), -refy + db::coord_traits::rounded (m_align_cell_options.ypos / layout.dbu ()))); - - for (unsigned int i = 0; i < layout.layers (); ++i) { - if (layout.is_valid_layer (i)) { - db::Shapes &shapes = nc_cell.shapes (i); - for (db::Shapes::shape_iterator s = shapes.begin (db::ShapeIterator::All); ! s.at_end (); ++s) { - shapes.transform (*s, t); - } - } - } - - for (db::Cell::const_iterator inst = nc_cell.begin (); ! inst.at_end (); ++inst) { - nc_cell.transform (*inst, t); - } - - if (m_align_cell_options.adjust_parents) { - - std::vector > insts_to_modify; - for (db::Cell::parent_inst_iterator pi = nc_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { - insts_to_modify.push_back (std::make_pair (& layout.cell (pi->parent_cell_index ()), pi->child_inst ())); - } - - db::Trans ti (db::Vector (refx, refy)); - for (std::vector >::const_iterator im = insts_to_modify.begin (); im != insts_to_modify.end (); ++im) { - im->first->transform (im->second, db::Trans (db::Vector (im->second.complex_trans ().trans (db::Vector (refx, refy))))); - } - - } - - commit (); - - } - - } -} - -void -LayoutView::cm_cell_user_properties () -{ - if (! mp_hierarchy_panel) { - return; - } - - int cv_index = active_cellview_index (); - cell_path_type path; - mp_hierarchy_panel->current_cell (cv_index, path); - - if (cv_index >= 0 && path.size () > 0) { - - db::Layout &layout = cellview (cv_index)->layout (); - db::Cell &cell = layout.cell (path.back ()); - db::properties_id_type prop_id = cell.prop_id (); - - lay::UserPropertiesForm props_form (this); - if (props_form.show (this, cv_index, prop_id)) { - - transaction (tl::to_string (QObject::tr ("Edit cell's user propertes"))); - cell.prop_id (prop_id); - commit (); - - } - - } -} - -void -LayoutView::cm_cell_replace () -{ - if (! mp_hierarchy_panel) { - return; - } - - int cv_index = active_cellview_index (); - std::vector paths; - mp_hierarchy_panel->selected_cells (cv_index, paths); - - if (cv_index >= 0 && paths.size () > 0) { - - if (paths.size () > 1) { - throw tl::Exception (tl::to_string (QObject::tr ("Replace cell cannot be used when multiple cells are selected"))); - } - - db::Layout &layout = cellview (cv_index)->layout (); - - bool needs_to_ask = false; - for (std::vector::const_iterator p = paths.begin (); p != paths.end () && ! needs_to_ask; ++p) { - if (layout.is_valid_cell_index (p->back ()) && ! layout.cell (p->back ()).is_leaf ()) { - needs_to_ask = true; - } - } - - - lay::ReplaceCellOptionsDialog mode_dialog (this); - - db::cell_index_type with_cell = paths.front ().back (); - int mode = needs_to_ask ? m_del_cell_mode : 0; - - if (mode_dialog.exec_dialog (cellview (cv_index), mode, with_cell)) { - - if (needs_to_ask) { - m_del_cell_mode = mode; - } - - if (with_cell != paths.front ().back ()) { - - // remember the current path - cell_path_type cell_path (cellview (cv_index).combined_unspecific_path ()); - - clear_selection (); - - transaction (tl::to_string (QObject::tr ("Replace cells"))); - - // replace instances of the target cell with the new cell - - db::Cell &target_cell = layout.cell (paths.front ().back ()); - - std::vector > parents; - for (db::Cell::parent_inst_iterator pi = target_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { - parents.push_back (std::make_pair (pi->parent_cell_index (), pi->child_inst ())); - } - - for (std::vector >::const_iterator p = parents.begin (); p != parents.end (); ++p) { - db::CellInstArray ia = p->second.cell_inst (); - ia.object ().cell_index (with_cell); - layout.cell (p->first).replace (p->second, ia); - } - - std::set cells_to_delete; - for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { - if (! p->empty () && layout.is_valid_cell_index (p->back ())) { - cells_to_delete.insert (p->back ()); - if (mode == 2) { - layout.cell (p->back ()).collect_called_cells (cells_to_delete); - } - } - } - - // support a propagation use case: - std::set cells_below_replacement_cell; - cells_below_replacement_cell.insert (with_cell); - layout.cell (with_cell).collect_called_cells (cells_below_replacement_cell); - for (std::set::const_iterator c = cells_below_replacement_cell.begin (); c != cells_below_replacement_cell.end (); ++c) { - cells_to_delete.erase (*c); - } - - if (mode == 0 || mode == 2) { - layout.delete_cells (cells_to_delete); - } else if (mode == 1) { - layout.prune_cells (cells_to_delete); - } - - layout.cleanup (); - - commit (); - - // If one of the cells in the path was deleted, establish a valid path - - bool needs_update = false; - for (size_t i = cell_path.size (); i > 0; ) { - --i; - if (! layout.is_valid_cell_index (cell_path [i])) { - cell_path.erase (cell_path.begin () + i, cell_path.end ()); - needs_update = true; - } - } - - if (needs_update) { - select_cell (cell_path, cv_index); - } - - } - - } - - } -} - -void -LayoutView::cm_lay_convert_to_static () -{ - // end move operations, cancel edit operations - cancel_edits (); - clear_selection (); - - int cv_index = active_cellview_index (); - if (cv_index >= 0) { - - db::Layout &layout = cellview (cv_index)->layout (); - - transaction (tl::to_string (QObject::tr ("Convert all cells to static"))); - - std::vector cells; - for (db::Layout::const_iterator c = layout.begin (); c != layout.end (); ++c) { - cells.push_back (c->cell_index ()); - } - - std::map cell_map; - for (std::vector::const_iterator c = cells.begin (); c != cells.end (); ++c) { - if (layout.is_valid_cell_index (*c)) { - db::cell_index_type new_cell = layout.convert_cell_to_static (*c); - if (new_cell != *c) { - cell_map.insert (std::make_pair (*c, new_cell)); - } - } - } - - // rewrite instances - for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { - for (db::Cell::const_iterator i = c->begin (); ! i.at_end (); ++i) { - std::map::const_iterator cm = cell_map.find (i->cell_index ()); - if (cm != cell_map.end ()) { - db::CellInstArray ci = i->cell_inst (); - ci.object ().cell_index (cm->second); - c->replace (*i, ci); - } - } - } - - layout.cleanup (); - - commit (); - - } -} - -void -LayoutView::cm_cell_convert_to_static () -{ - if (! mp_hierarchy_panel) { - return; - } - - int cv_index = active_cellview_index (); - std::vector paths; - mp_hierarchy_panel->selected_cells (cv_index, paths); - - if (cv_index >= 0 && paths.size () > 0) { - - db::Layout &layout = cellview (cv_index)->layout (); - - // remember the current path - cell_path_type cell_path (cellview (cv_index).combined_unspecific_path ()); - - clear_selection (); - - transaction (tl::to_string (QObject::tr ("Convert cells to static"))); - - std::map cell_map; - - for (std::vector::iterator p = paths.begin (); p != paths.end (); ++p) { - if (! p->empty () && layout.is_valid_cell_index (p->back ())) { - db::cell_index_type new_cell = layout.convert_cell_to_static (p->back ()); - if (new_cell != p->back ()) { - cell_map.insert (std::make_pair (p->back (), new_cell)); - p->back () = new_cell; - } - } - } - - // rewrite instances - for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { - for (db::Cell::const_iterator i = c->begin (); ! i.at_end (); ++i) { - std::map::const_iterator cm = cell_map.find (i->cell_index ()); - if (cm != cell_map.end ()) { - db::CellInstArray ci = i->cell_inst (); - ci.object ().cell_index (cm->second); - c->replace (*i, ci); - } - } - } - - layout.cleanup (); - - commit (); - - // If one of the cells in the path was deleted, establish a valid path - - bool needs_update = false; - for (size_t i = cell_path.size (); i > 0; ) { - --i; - if (! layout.is_valid_cell_index (cell_path [i])) { - cell_path.erase (cell_path.begin () + i, cell_path.end ()); - needs_update = true; - } - } - - if (needs_update) { - select_cell (cell_path, cv_index); - } - - } -} - -static void -collect_cells_to_delete (const db::Layout &layout, const db::Cell &cell, std::set &called) -{ - // don't delete proxies - they are deleted later when the layout is cleaned - for (db::Cell::child_cell_iterator cc = cell.begin_child_cells (); ! cc.at_end (); ++cc) { - if (called.find (*cc) == called.end () && !layout.cell (*cc).is_proxy ()) { - called.insert (*cc); - collect_cells_to_delete (layout, layout.cell (*cc), called); - } - } -} - -void -LayoutView::cm_cell_delete () -{ - if (! mp_hierarchy_panel) { - return; - } - - int cv_index = active_cellview_index (); - std::vector paths; - mp_hierarchy_panel->selected_cells (cv_index, paths); - - if (cv_index >= 0 && paths.size () > 0) { - - db::Layout &layout = cellview (cv_index)->layout (); - - bool needs_to_ask = false; - for (std::vector::const_iterator p = paths.begin (); p != paths.end () && ! needs_to_ask; ++p) { - if (layout.is_valid_cell_index (p->back ()) && ! layout.cell (p->back ()).is_leaf ()) { - needs_to_ask = true; - } - } - - int mode = m_del_cell_mode; - if (! needs_to_ask) { - mode = 0; - } - - lay::DeleteCellModeDialog mode_dialog (this); - if (! needs_to_ask || mode_dialog.exec_dialog (mode)) { - - if (needs_to_ask) { - m_del_cell_mode = mode; - } - - // remember the current path - cell_path_type cell_path (cellview (cv_index).combined_unspecific_path ()); - - clear_selection (); - - std::set cells_to_delete; - for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { - if (! p->empty () && layout.is_valid_cell_index (p->back ())) { - cells_to_delete.insert (p->back ()); - if (mode == 2) { - collect_cells_to_delete (layout, layout.cell (p->back ()), cells_to_delete); - } - } - } - - transaction (tl::to_string (QObject::tr ("Delete cells"))); - - if (mode == 0 || mode == 2) { - layout.delete_cells (cells_to_delete); - } else if (mode == 1) { - layout.prune_cells (cells_to_delete); - } - - layout.cleanup (); - - commit (); - - // If one of the cells in the path was deleted, establish a valid path - - bool needs_update = false; - for (size_t i = cell_path.size (); i > 0; ) { - --i; - if (! layout.is_valid_cell_index (cell_path [i])) { - cell_path.erase (cell_path.begin () + i, cell_path.end ()); - needs_update = true; - } - } - - if (needs_update) { - select_cell (cell_path, cv_index); - } - - } - - } -} - -void -LayoutView::cm_layer_copy () -{ - if (mp_control_panel) { - mp_control_panel->copy (); - } -} - -void -LayoutView::cm_layer_cut () -{ - if (mp_control_panel) { - db::Transaction trans (manager (), tl::to_string (QObject::tr ("Cut Layers"))); - mp_control_panel->cut (); - } -} - -void -LayoutView::cm_layer_paste () -{ - if (mp_control_panel) { - db::Transaction trans (manager (), tl::to_string (QObject::tr ("Paste Layers"))); - mp_control_panel->paste (); - } -} - -void -LayoutView::cm_cell_cut () -{ - if (mp_hierarchy_panel) { - // TODO: currently the hierarchy panel's cut function does it's own transaction handling. - // Otherwise the cut function is not working propertly. - mp_hierarchy_panel->cut (); - } -} - -void -LayoutView::cm_cell_paste () -{ - if (mp_hierarchy_panel) { - db::Transaction trans (manager (), tl::to_string (QObject::tr ("Paste Cells"))); - mp_hierarchy_panel->paste (); - } -} - -void -LayoutView::cm_cell_copy () -{ - if (mp_hierarchy_panel) { - mp_hierarchy_panel->copy (); - } -} - -void -LayoutView::cm_cell_flatten () -{ - if (! mp_hierarchy_panel) { - return; - } - - tl_assert (is_editable ()); - - int cv_index = active_cellview_index (); - if (cv_index >= 0) { - - const lay::CellView &cv = cellview (cv_index); - if (cv.is_valid ()) { - - std::vector paths; - mp_hierarchy_panel->selected_cells (cv_index, paths); - if (paths.empty ()) { - throw tl::Exception (tl::to_string (QObject::tr ("No cells selected for flattening"))); - } - - for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { - if (p->size () > 0 && cv->layout ().cell (p->back ()).is_proxy ()) { - throw tl::Exception (tl::to_string (QObject::tr ("Cannot use this function on a PCell or library cell"))); - } - } - - FlattenInstOptionsDialog options_dialog (this); - - int flatten_insts_levels = -1; - bool prune = true; - if (options_dialog.exec_dialog (flatten_insts_levels, prune) && flatten_insts_levels != 0) { - - bool supports_undo = true; - - if (manager () && manager ()->is_enabled ()) { - - lay::TipDialog td (QApplication::activeWindow (), - tl::to_string (QObject::tr ("Undo buffering for the following operation can be memory and time consuming.\nChoose \"Yes\" to use undo buffering or \"No\" for no undo buffering. Warning: in the latter case, the undo history will be lost.\n\nChoose undo buffering?")), - "flatten-undo-buffering", - lay::TipDialog::yesnocancel_buttons); - - lay::TipDialog::button_type button = lay::TipDialog::null_button; - td.exec_dialog (button); - if (button == lay::TipDialog::cancel_button) { - return; - } - - supports_undo = (button == lay::TipDialog::yes_button); - - } else { - supports_undo = false; - } - - cancel_edits (); - clear_selection (); - - if (manager ()) { - if (! supports_undo) { - manager ()->clear (); - } else { - manager ()->transaction (tl::to_string (QObject::tr ("Flatten cell"))); - } - } - - db::Layout &layout = cv->layout (); - - std::set child_cells; - for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { - if (p->size () > 0) { - layout.cell (p->back ()).collect_called_cells (child_cells); - } - } - - // don't flatten cells which are child cells of the cells to flatten - std::set cells_to_flatten; - for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { - if (p->size () > 0 && child_cells.find (p->back ()) == child_cells.end ()) { - cells_to_flatten.insert (p->back ()); - } - } - - for (std::set::const_iterator c = cells_to_flatten.begin (); c != cells_to_flatten.end (); ++c) { - db::Cell &target_cell = layout.cell (*c); - layout.flatten (target_cell, flatten_insts_levels, prune); - } - - layout.cleanup (); - - if (supports_undo && manager ()) { - manager ()->commit (); - } - - } - - } - - } -} - -void -LayoutView::cm_cell_rename () -{ - if (! mp_hierarchy_panel) { - return; - } - - int cv_index = active_cellview_index (); - cell_path_type path; - mp_hierarchy_panel->current_cell (cv_index, path); - - if (cv_index >= 0 && path.size () > 0) { - - lay::RenameCellDialog name_dialog (this); - - db::Layout &layout = cellview (cv_index)->layout (); - std::string name (layout.cell_name (path.back ())); - if (name_dialog.exec_dialog (layout, name)) { - - transaction (tl::to_string (QObject::tr ("Rename cell"))); - layout.rename_cell (path.back (), name.c_str ()); - commit (); - - } - - } -} - -void -LayoutView::cm_cell_select () -{ - if (mp_hierarchy_panel) { - mp_hierarchy_panel->cm_cell_select (); - } -} - -void -LayoutView::cm_open_current_cell () -{ - set_current_cell_path (active_cellview_index (), cellview (active_cellview_index ()).combined_unspecific_path ()); -} - -void -LayoutView::cm_cell_hide () -{ - if (mp_hierarchy_panel) { - - std::vector paths; - mp_hierarchy_panel->selected_cells (active_cellview_index (), paths); - - transaction (tl::to_string (QObject::tr ("Hide cell"))); - - for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { - if (! p->empty ()) { - hide_cell (p->back (), active_cellview_index ()); - } - } - - commit (); - - } -} - -void -LayoutView::cm_cell_show () -{ - if (mp_hierarchy_panel) { - - std::vector paths; - mp_hierarchy_panel->selected_cells (active_cellview_index (), paths); - - transaction (tl::to_string (QObject::tr ("Show cell"))); - - for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { - if (! p->empty ()) { - show_cell (p->back (), active_cellview_index ()); - } - } - - commit (); - - } -} - -void -LayoutView::cm_cell_show_all () -{ - if (mp_hierarchy_panel) { - transaction (tl::to_string (QObject::tr ("Show all cells"))); - show_all_cells (); - commit (); - } -} - -void -LayoutView::cm_select_all () -{ - if (mp_control_panel) { - mp_control_panel->cm_select_all (); - } -} - -void -LayoutView::cm_new_tab () -{ - if (mp_control_panel) { - mp_control_panel->cm_new_tab (); - } -} - -void -LayoutView::cm_remove_tab () -{ - if (mp_control_panel) { - mp_control_panel->cm_remove_tab (); - } -} - -void -LayoutView::cm_rename_tab () -{ - if (mp_control_panel) { - mp_control_panel->cm_rename_tab (); - } -} - -void -LayoutView::cm_make_invalid () -{ - if (mp_control_panel) { - mp_control_panel->cm_make_invalid (); - } -} - -void -LayoutView::cm_make_valid () -{ - if (mp_control_panel) { - mp_control_panel->cm_make_valid (); - } -} - -void -LayoutView::cm_hide () -{ - if (mp_control_panel) { - mp_control_panel->cm_hide (); - } -} - -void -LayoutView::cm_hide_all () -{ - if (mp_control_panel) { - mp_control_panel->cm_hide_all (); - } -} - -void -LayoutView::cm_show_only () -{ - if (mp_control_panel) { - mp_control_panel->cm_show_only (); - } -} - -void -LayoutView::cm_show_all () -{ - if (mp_control_panel) { - mp_control_panel->cm_show_all (); - } -} - -void -LayoutView::cm_show () -{ - if (mp_control_panel) { - mp_control_panel->cm_show (); - } -} - -void -LayoutView::cm_rename () -{ - if (mp_control_panel) { - mp_control_panel->cm_rename (); - } -} - -void -LayoutView::cm_delete () -{ - if (mp_control_panel) { - mp_control_panel->cm_delete (); - } -} - -void -LayoutView::cm_insert () -{ - if (mp_control_panel) { - mp_control_panel->cm_insert (); - } -} - -void -LayoutView::cm_group () -{ - if (mp_control_panel) { - mp_control_panel->cm_group (); - } -} - -void -LayoutView::cm_ungroup () -{ - if (mp_control_panel) { - mp_control_panel->cm_ungroup (); - } -} - -void -LayoutView::cm_source () -{ - if (mp_control_panel) { - mp_control_panel->cm_source (); - } -} - -void -LayoutView::cm_sort_by_name () -{ - if (mp_control_panel) { - mp_control_panel->cm_sort_by_name (); - } -} - -void -LayoutView::cm_sort_by_ild () -{ - if (mp_control_panel) { - mp_control_panel->cm_sort_by_ild (); - } -} - -void -LayoutView::cm_sort_by_idl () -{ - if (mp_control_panel) { - mp_control_panel->cm_sort_by_idl (); - } -} - -void -LayoutView::cm_sort_by_ldi () -{ - if (mp_control_panel) { - mp_control_panel->cm_sort_by_ldi (); - } -} - -void -LayoutView::cm_sort_by_dli () -{ - if (mp_control_panel) { - mp_control_panel->cm_sort_by_dli (); - } -} - -void -LayoutView::cm_regroup_by_index () -{ - if (mp_control_panel) { - mp_control_panel->cm_regroup_by_index (); - } -} - -void -LayoutView::cm_regroup_by_datatype () -{ - if (mp_control_panel) { - mp_control_panel->cm_regroup_by_datatype (); - } -} - -void -LayoutView::cm_regroup_by_layer () -{ - if (mp_control_panel) { - mp_control_panel->cm_regroup_by_layer (); - } -} - -void -LayoutView::cm_regroup_flatten () -{ - if (mp_control_panel) { - mp_control_panel->cm_regroup_flatten (); - } -} - -void -LayoutView::cm_expand_all () -{ - if (mp_control_panel) { - mp_control_panel->cm_expand_all (); - } -} - -void -LayoutView::cm_add_missing () -{ - if (mp_control_panel) { - mp_control_panel->cm_add_missing (); - } -} - void LayoutView::add_missing_layers () { @@ -6277,12 +5339,6 @@ LayoutView::add_new_layers (const LayerState &state) } } -void -LayoutView::cm_remove_unused () -{ - remove_unused_layers (); -} - void LayoutView::remove_unused_layers () { @@ -6489,138 +5545,6 @@ LayoutView::default_mode () return 0; // TODO: any generic scheme? is select, should be ruler.. } -void -LayoutView::do_cm_duplicate (bool interactive) -{ - // Do duplicate simply by concatenating copy & paste currently. - // Save the clipboard state before in order to preserve the current content - db::Clipboard saved_clipboard; - db::Clipboard::instance ().swap (saved_clipboard); - - try { - copy (); - clear_selection (); - cancel (); - if (interactive) { - paste_interactive (); - } else { - paste (); - } - db::Clipboard::instance ().swap (saved_clipboard); - } catch (...) { - db::Clipboard::instance ().swap (saved_clipboard); - throw; - } -} - -void -LayoutView::do_cm_paste (bool interactive) -{ - if (! db::Clipboard::instance ().empty ()) { - cancel (); - clear_selection (); - if (interactive) { - paste_interactive (); - } else { - paste (); - } - } -} - -void -LayoutView::cm_new_cell () -{ - static double s_new_cell_window_size = 2.0; - static std::string s_new_cell_cell_name; - - NewCellPropertiesDialog cell_prop_dia (this); - if (cell_prop_dia.exec_dialog (& cellview (active_cellview_index ())->layout (), s_new_cell_cell_name, s_new_cell_window_size)) { - - db::cell_index_type new_ci = new_cell (active_cellview_index (), s_new_cell_cell_name.c_str ()); - select_cell (new_ci, active_cellview_index ()); - - db::DBox zb = db::DBox (-0.5 * s_new_cell_window_size, -0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size); - if (get_max_hier_levels () < 1 || get_min_hier_levels () > 0) { - zoom_box_and_set_hier_levels (zb, std::make_pair (0, 1)); - } else { - zoom_box (zb); - } - - } -} - -// TODO: this constant is defined in MainWindow.cc too ... -const int max_dirty_files = 15; - -void -LayoutView::cm_reload () -{ - std::vector selected; - - if (cellviews () > 1) { - - SelectCellViewForm form (0, this, tl::to_string (QObject::tr ("Select Layouts To Reload"))); - form.select_all (); - - if (form.exec () == QDialog::Accepted) { - selected = form.selected_cellviews (); - } - - } else if (cellviews () > 0) { - selected.push_back (0); - } - - if (selected.size () > 0) { - - int dirty_layouts = 0; - std::string dirty_files; - - for (std::vector ::const_iterator i = selected.begin (); i != selected.end (); ++i) { - - const lay::CellView &cv = cellview (*i); - - if (cv->layout ().is_editable () && cv->is_dirty ()) { - ++dirty_layouts; - if (dirty_layouts == max_dirty_files) { - dirty_files += "\n..."; - } else if (dirty_layouts < max_dirty_files) { - if (! dirty_files.empty ()) { - dirty_files += "\n"; - } - dirty_files += cv->name (); - } - } - - } - - bool can_reload = true; - if (dirty_layouts != 0) { - - QMessageBox mbox (this); - mbox.setText (tl::to_qstring (tl::to_string (QObject::tr ("The following layouts need saving:\n\n")) + dirty_files + "\n\nPress 'Reload Without Saving' to reload anyhow and discard changes.")); - mbox.setWindowTitle (QObject::tr ("Save Needed")); - mbox.setIcon (QMessageBox::Warning); - QAbstractButton *yes_button = mbox.addButton (QObject::tr ("Reload Without Saving"), QMessageBox::YesRole); - mbox.addButton (QMessageBox::Cancel); - - mbox.exec (); - - can_reload = (mbox.clickedButton() == yes_button); - - } - - if (can_reload) { - - // Actually reload - for (std::vector ::const_iterator i = selected.begin (); i != selected.end (); ++i) { - reload_layout (*i); - } - - } - - } -} - std::vector LayoutView::menu_symbols () { @@ -6640,309 +5564,9 @@ LayoutView::menu_activated (const std::string &symbol) } } - if (symbol == "cm_show_properties") { - show_properties (this); - } else if (symbol == "cm_delete") { - - del (); - // because a "delete" might involve objects currently edited, we cancel the edit after we have deleted the object - cancel (); - clear_selection (); - - } else if (symbol == "cm_unselect_all") { - select (db::DBox (), lay::Editable::Reset); - } else if (symbol == "cm_select_all") { - select (full_box (), lay::Editable::Replace); - } else if (symbol == "cm_lv_paste") { - cm_layer_paste (); - } else if (symbol == "cm_lv_cut") { - cm_layer_cut (); - } else if (symbol == "cm_lv_copy") { - cm_layer_copy (); - } else if (symbol == "cm_cell_paste") { - cm_cell_paste (); - } else if (symbol == "cm_cell_cut") { - cm_cell_cut (); - } else if (symbol == "cm_cell_copy") { - cm_cell_copy (); - } else if (symbol == "cm_duplicate") { - do_cm_duplicate (false); - } else if (symbol == "cm_duplicate_interactive") { - do_cm_duplicate (true); - } else if (symbol == "cm_copy") { - - copy (); - clear_selection (); - - } else if (symbol == "cm_paste") { - do_cm_paste (false); - } else if (symbol == "cm_paste_interactive") { - do_cm_paste (true); - } else if (symbol == "cm_cut") { - - cut (); - cancel (); // see del() for reason why cancel is after cut - clear_selection (); - - } else if (symbol == "cm_zoom_fit_sel") { - zoom_fit_sel (); - } else if (symbol == "cm_zoom_fit") { - zoom_fit (); - } else if (symbol == "cm_pan_left") { - pan_left (); - } else if (symbol == "cm_pan_right") { - pan_right (); - } else if (symbol == "cm_pan_up") { - pan_up (); - } else if (symbol == "cm_pan_down") { - pan_down (); - } else if (symbol == "cm_zoom_in") { - zoom_in (); - } else if (symbol == "cm_zoom_out") { - zoom_out (); - } else if (symbol == "cm_select_current_cell") { - - if (active_cellview_index () >= 0) { - lay::LayoutView::cell_path_type path; - int cvi = active_cellview_index (); - current_cell_path (path); - select_cell_fit (path, cvi); - } - - } else if (symbol == "cm_open_current_cell") { - - if (active_cellview_index () >= 0) { - cm_open_current_cell (); - } - - } else if (symbol == "cm_select_cell") { - - if (active_cellview_index () >= 0) { - - CellSelectionForm form (0, this, "cell_selection_form"); - - if (form.exec () == QDialog::Accepted && - form.selected_cellview_index () >= 0) { - select_cell (form.selected_cellview ().combined_unspecific_path (), form.selected_cellview_index ()); - set_current_cell_path (form.selected_cellview_index (), form.selected_cellview ().combined_unspecific_path ()); - zoom_fit (); - } - - } - - } else if (symbol == "cm_new_cell") { - cm_new_cell (); - } else if (symbol == "cm_adjust_origin") { - if (active_cellview_index () >= 0) { - cm_align_cell_origin (); - } - } else if (symbol == "cm_cell_convert_to_static") { - if (active_cellview_index () >= 0) { - cm_cell_convert_to_static (); - } - } else if (symbol == "cm_lay_convert_to_static") { - if (active_cellview_index () >= 0) { - cm_lay_convert_to_static (); - } - } else if (symbol == "cm_lay_move") { - if (active_cellview_index () >= 0) { - cm_lay_move (); - } - } else if (symbol == "cm_lay_scale") { - if (active_cellview_index () >= 0) { - cm_lay_scale (); - } - } else if (symbol == "cm_lay_free_rot") { - if (active_cellview_index () >= 0) { - cm_lay_free_rot (); - } - } else if (symbol == "cm_lay_rot_ccw") { - if (active_cellview_index () >= 0) { - cm_lay_rot_ccw (); - } - } else if (symbol == "cm_lay_rot_cw") { - if (active_cellview_index () >= 0) { - cm_lay_rot_cw (); - } - } else if (symbol == "cm_lay_flip_y") { - if (active_cellview_index () >= 0) { - cm_lay_flip_y (); - } - } else if (symbol == "cm_lay_flip_x") { - if (active_cellview_index () >= 0) { - cm_lay_flip_x (); - } - } else if (symbol == "cm_sel_move") { - if (active_cellview_index () >= 0) { - cm_sel_move (); - } - } else if (symbol == "cm_sel_move_to") { - if (active_cellview_index () >= 0) { - cm_sel_move_to (); - } - } else if (symbol == "cm_sel_move_interactive") { - if (active_cellview_index () >= 0) { - cm_sel_move_interactive (); - } - } else if (symbol == "cm_sel_scale") { - if (active_cellview_index () >= 0) { - cm_sel_scale (); - } - } else if (symbol == "cm_sel_free_rot") { - if (active_cellview_index () >= 0) { - cm_sel_free_rot (); - } - } else if (symbol == "cm_sel_rot_ccw") { - if (active_cellview_index () >= 0) { - cm_sel_rot_ccw (); - } - } else if (symbol == "cm_sel_rot_cw") { - if (active_cellview_index () >= 0) { - cm_sel_rot_cw (); - } - } else if (symbol == "cm_sel_flip_y") { - if (active_cellview_index () >= 0) { - cm_sel_flip_y (); - } - } else if (symbol == "cm_sel_flip_x") { - if (active_cellview_index () >= 0) { - cm_sel_flip_x (); - } - } else if (symbol == "cm_edit_layer") { - if (active_cellview_index () >= 0) { - cm_edit_layer (); - } - } else if (symbol == "cm_delete_layer") { - if (active_cellview_index () >= 0) { - cm_delete_layer (); - } - } else if (symbol == "cm_clear_layer") { - if (active_cellview_index () >= 0) { - cm_clear_layer (); - } - } else if (symbol == "cm_copy_layer") { - if (active_cellview_index () >= 0) { - cm_copy_layer (); - } - } else if (symbol == "cm_new_layer") { - if (active_cellview_index () >= 0) { - cm_new_layer (); - } - } else if (symbol == "cm_layout_props") { - LayoutPropertiesForm lp_form (this, this, "layout_props_form"); - lp_form.exec (); - } else if (symbol == "cm_layout_stats") { - LayoutStatisticsForm lp_form (this, this, "layout_props_form"); - lp_form.exec (); - } else if (symbol == "cm_reload") { - cm_reload (); - } else if (symbol == "cm_inc_max_hier") { - int new_to = get_max_hier_levels () + 1; - set_hier_levels (std::make_pair (get_min_hier_levels (), new_to)); - } else if (symbol == "cm_dec_max_hier") { - int new_to = get_max_hier_levels () > 0 ? get_max_hier_levels () - 1 : 0; - set_hier_levels (std::make_pair (std::min (get_min_hier_levels (), new_to), new_to)); - } else if (symbol == "cm_max_hier") { - max_hier (); - } else if (symbol == "cm_max_hier_0") { - set_hier_levels (std::make_pair (std::min (get_min_hier_levels (), 0), 0)); - } else if (symbol == "cm_max_hier_1") { - set_hier_levels (std::make_pair (std::min (get_min_hier_levels (), 0), 1)); - } else if (symbol == "cm_prev_display_state") { - if (has_prev_display_state ()) { - prev_display_state (); - } - } else if (symbol == "cm_next_display_state") { - if (has_next_display_state ()) { - next_display_state (); - } - } else if (symbol == "cm_redraw") { - redraw (); - } else if (symbol == "cm_cell_delete") { - cm_cell_delete (); - } else if (symbol == "cm_cell_replace") { - cm_cell_replace (); - } else if (symbol == "cm_cell_rename") { - cm_cell_rename (); - } else if (symbol == "cm_cell_flatten") { - cm_cell_flatten (); - } else if (symbol == "cm_cell_select") { - cm_cell_select (); - } else if (symbol == "cm_cell_hide") { - cm_cell_hide (); - } else if (symbol == "cm_cell_show") { - cm_cell_show (); - } else if (symbol == "cm_cell_show_all") { - cm_cell_show_all (); - } else if (symbol == "cm_cell_user_properties") { - if (active_cellview_index () >= 0) { - cm_cell_user_properties (); - } - } else if (symbol == "cm_lv_select_all") { - cm_select_all (); - } else if (symbol == "cm_lv_new_tab") { - cm_new_tab (); - } else if (symbol == "cm_lv_rename_tab") { - cm_rename_tab (); - } else if (symbol == "cm_lv_make_invalid") { - cm_make_invalid (); - } else if (symbol == "cm_lv_remove_tab") { - cm_remove_tab (); - } else if (symbol == "cm_lv_make_valid") { - cm_make_valid (); - } else if (symbol == "cm_lv_hide_all") { - cm_hide_all (); - } else if (symbol == "cm_lv_hide") { - cm_hide (); - } else if (symbol == "cm_lv_show_only") { - cm_show_only (); - } else if (symbol == "cm_lv_show_all") { - cm_show_all (); - } else if (symbol == "cm_lv_show") { - cm_show (); - } else if (symbol == "cm_lv_rename") { - cm_rename (); - } else if (symbol == "cm_lv_delete") { - cm_delete (); - } else if (symbol == "cm_lv_insert") { - cm_insert (); - } else if (symbol == "cm_lv_group") { - cm_group (); - } else if (symbol == "cm_lv_ungroup") { - cm_ungroup (); - } else if (symbol == "cm_lv_source") { - cm_source (); - } else if (symbol == "cm_lv_sort_by_name") { - cm_sort_by_name (); - } else if (symbol == "cm_lv_sort_by_ild") { - cm_sort_by_ild (); - } else if (symbol == "cm_lv_sort_by_idl") { - cm_sort_by_idl (); - } else if (symbol == "cm_lv_sort_by_ldi") { - cm_sort_by_ldi (); - } else if (symbol == "cm_lv_sort_by_dli") { - cm_sort_by_dli (); - } else if (symbol == "cm_lv_regroup_by_index") { - cm_regroup_by_index (); - } else if (symbol == "cm_lv_regroup_by_datatype") { - cm_regroup_by_datatype (); - } else if (symbol == "cm_lv_regroup_by_layer") { - cm_regroup_by_layer (); - } else if (symbol == "cm_lv_regroup_flatten") { - cm_regroup_flatten (); - } else if (symbol == "cm_lv_expand_all") { - cm_expand_all (); - } else if (symbol == "cm_lv_add_missing") { - cm_add_missing (); - } else if (symbol == "cm_lv_remove_unused") { - cm_remove_unused (); - } else { - - // distribute the menu on the plugins - one should take it. - for (std::vector::iterator p = mp_plugins.begin (); p != mp_plugins.end (); ++p) { - (*p)->menu_activated (symbol); - } - + // distribute the menu item call on the plugins - one should take it. + for (std::vector::const_iterator p = plugins ().begin (); p != plugins ().end (); ++p) { + (*p)->menu_activated (symbol); } } @@ -7132,229 +5756,6 @@ LayoutView::new_cell (int cv_index, const std::string &cell_name) return new_ci; } -void -LayoutView::do_transform (const db::DCplxTrans &tr) -{ - // end move operations, cancel edit operations - cancel_edits (); - lay::Editables::transform (tr); -} - -void -LayoutView::transform_layout (const db::DCplxTrans &tr_mic) -{ - // end move operations, cancel edit operations - cancel_edits (); - clear_selection (); - - int cv_index = active_cellview_index (); - if (cv_index >= 0) { - - db::Layout &layout = cellview (cv_index)->layout (); - - db::ICplxTrans tr (db::DCplxTrans (1.0 / layout.dbu ()) * tr_mic * db::DCplxTrans (layout.dbu ())); - - bool has_proxy = false; - for (db::Layout::const_iterator c = layout.begin (); ! has_proxy && c != layout.end (); ++c) { - has_proxy = c->is_proxy (); - } - - if (has_proxy && - QMessageBox::question (this, - QObject::tr ("Transforming PCells Or Library Cells"), - QObject::tr ("The layout contains PCells or library cells or both.\n" - "Any changes to such cells may be lost when their layout is refreshed later.\n" - "Consider using 'Convert all cells to static' before transforming the layout.\n" - "\n" - "Would you like to continue?\n" - "Choose 'Yes' to continue anyway. Choose 'No' to cancel."), - QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { - return; - } - - transaction (tl::to_string (QObject::tr ("Transform layout"))); - layout.transform (tr); - commit (); - - } -} - -void -LayoutView::cm_lay_flip_x () -{ - transform_layout (db::DCplxTrans (db::FTrans::m90)); -} - -void -LayoutView::cm_lay_flip_y () -{ - transform_layout (db::DCplxTrans (db::FTrans::m0)); -} - -void -LayoutView::cm_lay_rot_ccw () -{ - db::DCplxTrans tr (db::DFTrans::r90); - transform_layout (db::DCplxTrans (db::FTrans::r90)); -} - -void -LayoutView::cm_lay_rot_cw () -{ - transform_layout (db::DCplxTrans (db::FTrans::r270)); -} - -void -LayoutView::cm_lay_free_rot () -{ - bool ok = false; - QString s = QInputDialog::getText (QApplication::activeWindow (), - QObject::tr ("Free rotation"), - QObject::tr ("Rotation angle in degree (counterclockwise)"), - QLineEdit::Normal, QString::fromUtf8 ("0.0"), - &ok); - - if (ok) { - - double angle = 0.0; - tl::from_string (tl::to_string (s), angle); - - transform_layout (db::DCplxTrans (1.0, angle, false, db::DVector ())); - - } -} - -void -LayoutView::cm_lay_scale () -{ - bool ok = false; - QString s = QInputDialog::getText (QApplication::activeWindow (), - QObject::tr ("Scaling"), - QObject::tr ("Scaling factor"), - QLineEdit::Normal, QString::fromUtf8 ("1.0"), - &ok); - - if (ok) { - - double scale = 0.0; - tl::from_string (tl::to_string (s), scale); - - transform_layout (db::DCplxTrans (scale)); - - } -} - -void -LayoutView::cm_lay_move () -{ - lay::MoveOptionsDialog options (this); - if (options.exec_dialog (m_move_dist)) { - transform_layout (db::DCplxTrans (m_move_dist)); - } -} - -void -LayoutView::cm_sel_flip_x () -{ - db::DCplxTrans tr (db::DFTrans::m90); - db::DBox sel_bbox (lay::Editables::selection_bbox ()); - if (! sel_bbox.empty ()) { - tr = db::DCplxTrans (sel_bbox.center () - db::DPoint ()) * tr * db::DCplxTrans (db::DPoint () - sel_bbox.center ()); - } - do_transform (tr); -} - -void -LayoutView::cm_sel_flip_y () -{ - db::DCplxTrans tr (db::DFTrans::m0); - db::DBox sel_bbox (lay::Editables::selection_bbox ()); - if (! sel_bbox.empty ()) { - tr = db::DCplxTrans (sel_bbox.center () - db::DPoint ()) * tr * db::DCplxTrans (db::DPoint () - sel_bbox.center ()); - } - do_transform (tr); -} - -void -LayoutView::cm_sel_rot_ccw () -{ - db::DCplxTrans tr (db::DFTrans::r90); - db::DBox sel_bbox (lay::Editables::selection_bbox ()); - if (! sel_bbox.empty ()) { - tr = db::DCplxTrans (sel_bbox.center () - db::DPoint ()) * tr * db::DCplxTrans (db::DPoint () - sel_bbox.center ()); - } - do_transform (tr); -} - -void -LayoutView::cm_sel_rot_cw () -{ - db::DCplxTrans tr (db::DFTrans::r270); - db::DBox sel_bbox (lay::Editables::selection_bbox ()); - if (! sel_bbox.empty ()) { - tr = db::DCplxTrans (sel_bbox.center () - db::DPoint ()) * tr * db::DCplxTrans (db::DPoint () - sel_bbox.center ()); - } - do_transform (tr); -} - -void -LayoutView::cm_sel_free_rot () -{ - bool ok = false; - QString s = QInputDialog::getText (QApplication::activeWindow (), - QObject::tr ("Free rotation"), - QObject::tr ("Rotation angle in degree (counterclockwise)"), - QLineEdit::Normal, QString::fromUtf8 ("0.0"), - &ok); - - if (ok) { - - double angle = 0.0; - tl::from_string (tl::to_string (s), angle); - - db::DCplxTrans tr = db::DCplxTrans (1.0, angle, false, db::DVector ()); - db::DBox sel_bbox (lay::Editables::selection_bbox ()); - if (! sel_bbox.empty ()) { - tr = db::DCplxTrans (sel_bbox.center () - db::DPoint ()) * tr * db::DCplxTrans (db::DPoint () - sel_bbox.center ()); - } - do_transform (tr); - - } -} - -void -LayoutView::cm_sel_scale () -{ - bool ok = false; - QString s = QInputDialog::getText (QApplication::activeWindow (), - QObject::tr ("Scaling"), - QObject::tr ("Scaling factor"), - QLineEdit::Normal, QString::fromUtf8 ("1.0"), - &ok); - - if (ok) { - - double scale = 0.0; - tl::from_string (tl::to_string (s), scale); - - db::DCplxTrans tr = db::DCplxTrans (scale); - db::DBox sel_bbox (lay::Editables::selection_bbox ()); - if (! sel_bbox.empty ()) { - tr = db::DCplxTrans (sel_bbox.center () - db::DPoint ()) * tr * db::DCplxTrans (db::DPoint () - sel_bbox.center ()); - } - do_transform (tr); - - } -} - -void -LayoutView::cm_sel_move_interactive () -{ - if (mp_move_service->begin_move ()) { - switch_mode (-1); // move mode - } -} - void LayoutView::switch_mode (int m) { @@ -7364,400 +5765,6 @@ LayoutView::switch_mode (int m) } } -void -LayoutView::cm_sel_move_to () -{ - db::DBox sel_bbox (lay::Editables::selection_bbox ()); - if (sel_bbox.empty ()) { - throw tl::Exception (tl::to_string (QObject::tr ("Nothing selected to move"))); - } - - double x = sel_bbox.left () + (sel_bbox.width () * (1 + m_move_to_origin_mode_x) * 0.5); - double y = sel_bbox.bottom () + (sel_bbox.height () * (1 + m_move_to_origin_mode_y) * 0.5); - db::DPoint move_target (x, y); - - lay::MoveToOptionsDialog options (this); - if (options.exec_dialog (m_move_to_origin_mode_x, m_move_to_origin_mode_y, move_target)) { - - x = sel_bbox.left () + (sel_bbox.width () * (1 + m_move_to_origin_mode_x) * 0.5); - y = sel_bbox.bottom () + (sel_bbox.height () * (1 + m_move_to_origin_mode_y) * 0.5); - - do_transform (db::DCplxTrans (move_target - db::DPoint (x, y))); - - } -} - -void -LayoutView::cm_sel_move () -{ - lay::MoveOptionsDialog options (this); - if (options.exec_dialog (m_move_dist)) { - do_transform (db::DCplxTrans (m_move_dist)); - } -} - -void -LayoutView::cm_copy_layer () -{ - struct { int *cv; int *layer; } specs [] = { - { &m_copy_cva, &m_copy_layera }, - { &m_copy_cvr, &m_copy_layerr } - }; - - for (unsigned int i = 0; i < sizeof (specs) / sizeof (specs[0]); ++i) { - - int &cv = *(specs[i].cv); - int &layer = *(specs[i].layer); - - if (cv >= int (m_cellviews.size ())) { - cv = -1; - } - - int index = active_cellview_index (); - if (cv < 0) { - cv = index; - } - - if (cv < 0 || ! (*cellview_iter (cv))->layout ().is_valid_layer ((unsigned int) layer)) { - layer = -1; - } - - } - - lay::DuplicateLayerDialog dialog (this); - if (dialog.exec_dialog (this, m_copy_cva, m_copy_layera, m_copy_cvr, m_copy_layerr, m_duplicate_hier_mode, m_clear_before)) { - - bool supports_undo = true; - - if (manager () && manager ()->is_enabled ()) { - - lay::TipDialog td (QApplication::activeWindow (), - tl::to_string (QObject::tr ("Undo buffering for the following operation can be memory and time consuming.\nChoose \"Yes\" to use undo buffering or \"No\" for no undo buffering. Warning: in the latter case, the undo history will be lost.\n\nChoose undo buffering?")), - "copy-layer-undo-buffering", - lay::TipDialog::yesnocancel_buttons); - - lay::TipDialog::button_type button = lay::TipDialog::null_button; - td.exec_dialog (button); - if (button == lay::TipDialog::cancel_button) { - return; - } - - supports_undo = (button == lay::TipDialog::yes_button); - - } else { - supports_undo = false; - } - - cancel (); - - if (manager ()) { - if (! supports_undo) { - manager ()->clear (); - } else { - manager ()->transaction (tl::to_string (QObject::tr ("Duplicate layer"))); - } - } - - try { - - bool same_layout = (&cellview (m_copy_cvr)->layout () == &cellview (m_copy_cva)->layout ()); - if (same_layout && m_copy_layera == m_copy_layerr) { - throw tl::Exception (tl::to_string (QObject::tr ("Source and target layer must not be identical for duplicate operation"))); - } - - if (m_duplicate_hier_mode == 0) { - - // clear the result layer for all called cells in flat mode - if (m_clear_before) { - std::set called_cells; - called_cells.insert (cellview (m_copy_cvr).cell_index ()); - cellview (m_copy_cvr).cell ()->collect_called_cells (called_cells); - for (std::set::const_iterator c = called_cells.begin (); c != called_cells.end (); ++c) { - cellview (m_copy_cvr)->layout ().cell (*c).shapes (m_copy_layerr).clear (); - } - } - - db::Cell &target_cell = *cellview (m_copy_cvr).cell (); - - if (! same_layout) { - - // flat mode (different layouts) - db::PropertyMapper pm (cellview (m_copy_cvr)->layout (), cellview (m_copy_cva)->layout ()); - for (db::RecursiveShapeIterator si (cellview (m_copy_cva)->layout (), *cellview (m_copy_cva).cell (), m_copy_layera); ! si.at_end (); ++si) { - target_cell.shapes (m_copy_layerr).insert (*si, si.trans (), pm); - } - - } else { - - // flat mode (same layouts) - tl::ident_map pm1; - db::Shapes &res = target_cell.shapes (m_copy_layerr); - - db::Layout &layout = cellview (m_copy_cvr)->layout (); - try { - - // using update/start_layout and end_changes improves the performance since changing the - // shapes collection will invalidate the layout and cause updates inside the RecursiveShapeIerator - layout.update (); - layout.start_changes (); - for (db::RecursiveShapeIterator si (cellview (m_copy_cva)->layout (), *cellview (m_copy_cva).cell (), m_copy_layera); ! si.at_end (); ++si) { - res.insert (*si, si.trans (), pm1); - } - layout.end_changes (); - - } catch (...) { - layout.end_changes (); - throw; - } - - } - - } else if (m_duplicate_hier_mode == 1) { - - db::Cell &cell = *cellview (m_copy_cva).cell (); - db::Cell &target_cell = *cellview (m_copy_cvr).cell (); - - if (m_clear_before) { - target_cell.clear (m_copy_layerr); - } - - if (m_copy_cvr == m_copy_cva) { - - // current cell only mode: identical cell - cell.copy (m_copy_layera, m_copy_layerr); - - } else if (! same_layout) { - - // current cell only mode (different layouts) - db::PropertyMapper pm (cellview (m_copy_cvr)->layout (), cellview (m_copy_cva)->layout ()); - for (db::Shapes::shape_iterator si = cellview (m_copy_cva).cell ()->shapes (m_copy_layera).begin (db::ShapeIterator::All); ! si.at_end (); ++si) { - target_cell.shapes (m_copy_layerr).insert (*si, pm); - } - - } else { - - // current cell only mode (same layouts, but different cells) - for (db::Shapes::shape_iterator si = cellview (m_copy_cva).cell ()->shapes (m_copy_layera).begin (db::ShapeIterator::All); ! si.at_end (); ++si) { - target_cell.shapes (m_copy_layerr).insert (*si); - } - - } - - } else if (m_duplicate_hier_mode == 2) { - - // subcells cell by cell - source and target layout must be identical - std::set called_cells; - cellview (m_copy_cva).cell ()->collect_called_cells (called_cells); - called_cells.insert (cellview (m_copy_cva).cell_index ()); - - db::Layout &layout = cellview (m_copy_cva)->layout (); - for (std::set::const_iterator c = called_cells.begin (); c != called_cells.end (); ++c) { - db::Cell &cell = layout.cell (*c); - if (m_clear_before) { - cell.clear (m_copy_layerr); - } - cell.copy (m_copy_layera, m_copy_layerr); - } - - } - - if (manager () && supports_undo) { - manager ()->commit (); - } - - } catch (...) { - if (manager () && supports_undo) { - manager ()->commit (); - } - throw; - } - - } -} - -void -LayoutView::cm_new_layer () -{ - int index = active_cellview_index (); - - if (index >= 0 && int (m_cellviews.size ()) > index) { - - const lay::CellView &cv = cellview (index); - - lay::NewLayerPropertiesDialog prop_dia (this); - if (prop_dia.exec_dialog (cv, m_new_layer_props)) { - - for (unsigned int l = 0; l < cv->layout ().layers (); ++l) { - if (cv->layout ().is_valid_layer (l) && cv->layout ().get_properties (l).log_equal (m_new_layer_props)) { - throw tl::Exception (tl::to_string (QObject::tr ("A layer with that signature already exists: ")) + m_new_layer_props.to_string ()); - } - } - - transaction (tl::to_string (QObject::tr ("New layer"))); - - unsigned int l = cv->layout ().insert_layer (m_new_layer_props); - std::vector nl; - nl.push_back (l); - add_new_layers (nl, index); - update_content (); - - commit (); - - } - - } -} - -void -LayoutView::cm_edit_layer () -{ - lay::LayerPropertiesConstIterator sel = current_layer (); - if (sel.is_null ()) { - throw tl::Exception (tl::to_string (QObject::tr ("No layer selected for editing it's properties"))); - } - - int index = sel->cellview_index (); - if (sel->has_children () || index < 0 || int (m_cellviews.size ()) <= index || sel->layer_index () < 0) { - throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected for editing it's properties"))); - } - - const lay::CellView &cv = cellview (index); - - db::LayerProperties layer_props = cv->layout ().get_properties ((unsigned int) sel->layer_index ()); - - lay::NewLayerPropertiesDialog prop_dia (this); - if (prop_dia.exec_dialog (cv, layer_props)) { - - for (unsigned int l = 0; l < cv->layout ().layers (); ++l) { - if (cv->layout ().is_valid_layer (l) && int (l) != sel->layer_index () && cv->layout ().get_properties (l).log_equal (layer_props)) { - throw tl::Exception (tl::to_string (QObject::tr ("A layer with that signature already exists: ")) + layer_props.to_string ()); - } - } - - transaction (tl::to_string (QObject::tr ("Edit layer"))); - - cv->layout ().set_properties (sel->layer_index (), layer_props); - - lay::LayerProperties lp (*sel); - lay::ParsedLayerSource s = lp.source (false); - s.layer (layer_props.layer); - s.datatype (layer_props.datatype); - if (! layer_props.name.empty ()) { - s.name (layer_props.name); - } else { - s.clear_name (); - } - lp.set_source (s); - set_properties (sel, lp); - - update_content (); - - commit (); - - } -} - -void -LayoutView::cm_delete_layer () -{ - std::vector sel = selected_layers (); - std::sort (sel.begin (), sel.end (), CompareLayerIteratorBottomUp ()); - - // collect valid layers - std::vector valid_sel; - std::set > valid_layers; - for (std::vector::const_iterator si = sel.begin (); si != sel.end (); ++si) { - int cv_index = (*si)->cellview_index (); - const lay::CellView &cv = cellview (cv_index); - if (!(*si)->has_children () && cv_index >= 0 && int (m_cellviews.size ()) > cv_index && (*si)->layer_index () >= 0 && cv.is_valid ()) { - valid_sel.push_back (*si); - valid_layers.insert (std::make_pair (&cv->layout (), (*si)->layer_index ())); - } - } - - if (valid_sel.empty ()) { - throw tl::Exception (tl::to_string (QObject::tr ("No or no valid layer selected for deleting them"))); - } - - cancel_edits (); - clear_selection (); - - transaction (tl::to_string (QObject::tr ("Delete layers"))); - - // Hint: delete_layer must come before the layers are actually deleted in because - // for undo this must be the last thing to do (otherwise the layout is not propertly set up) - - for (std::vector::const_iterator si = valid_sel.begin (); si != valid_sel.end (); ++si) { - lay::LayerPropertiesConstIterator lp = *si; - delete_layer (lp); - } - - for (std::set >::const_iterator li = valid_layers.begin (); li != valid_layers.end(); ++li) { - - unsigned int layer_index = li->second; - db::Layout *layout = li->first; - - for (db::Layout::iterator c = layout->begin (); c != layout->end (); ++c) { - c->shapes (layer_index).clear (); - } - - layout->delete_layer (layer_index); - - } - - update_content (); - - commit (); -} - -void -LayoutView::cm_clear_layer () -{ - std::vector sel = selected_layers (); - if (sel.empty ()) { - throw tl::Exception (tl::to_string (QObject::tr ("No layer selected for clearing"))); - } - - lay::ClearLayerModeDialog mode_dialog (this); - if (mode_dialog.exec_dialog (m_layer_hier_mode)) { - - cancel_edits (); - clear_selection (); - - transaction (tl::to_string (QObject::tr ("Clear layer"))); - - for (std::vector::const_iterator si = sel.begin (); si != sel.end (); ++si) { - - if (! (*si)->has_children () && (*si)->layer_index () >= 0 && cellview ((*si)->cellview_index ()).is_valid ()) { - - int layer_index = (*si)->layer_index (); - const lay::CellView &cv = cellview ((*si)->cellview_index ()); - - if (m_layer_hier_mode == 0) { - cv.cell ()->clear ((unsigned int) layer_index); - } else if (m_layer_hier_mode == 1) { - - cv.cell ()->clear ((unsigned int) layer_index); - - std::set called_cells; - cv.cell ()->collect_called_cells (called_cells); - for (std::set ::const_iterator cc = called_cells.begin (); cc != called_cells.end (); ++cc) { - cv->layout ().cell (*cc).clear ((unsigned int) layer_index); - } - - } else { - cv->layout ().clear_layer ((unsigned int) layer_index); - } - - } - - } - - commit (); - - } -} - template static void make_unique_name (T *object, Iter from, Iter to) { @@ -7954,203 +5961,4 @@ LayoutView::sizeHint () const } } -// ------------------------------------------------------------ -// Declaration of the "plugin" for the menu entries - -class LayoutViewPluginDeclaration - : public lay::PluginDeclaration -{ -public: - virtual void get_menu_entries (std::vector &menu_entries) const - { - std::string at; - - // secret menu entries - at = "@secrets.end"; - menu_entries.push_back (lay::menu_item ("cm_paste_interactive", "paste_interactive:edit", at, tl::to_string (QObject::tr ("Paste Interactive")))); - menu_entries.push_back (lay::menu_item ("cm_duplicate_interactive", "duplicate_interactive:edit", at, tl::to_string (QObject::tr ("Duplicate Interactive")))); - menu_entries.push_back (lay::menu_item ("cm_sel_move_interactive", "sel_move_interactive:edit", at, tl::to_string (QObject::tr ("Move Interactive")))); - - at = "edit_menu.end"; - menu_entries.push_back (lay::menu_item ("cm_undo", "undo:edit", at, tl::to_string (QObject::tr ("Undo(Ctrl+Z)")))); - menu_entries.push_back (lay::menu_item ("cm_redo", "redo:edit", at, tl::to_string (QObject::tr ("Redo(Ctrl+Y)")))); - - menu_entries.push_back (lay::separator ("basic_group", at)); - menu_entries.push_back (lay::submenu ("layout_menu:edit:edit_mode", at, tl::to_string (QObject::tr ("Layout")))); - { - std::string at = "edit_menu.layout_menu.end"; - menu_entries.push_back (lay::menu_item ("cm_lay_flip_x", "lay_flip_x:edit_mode", at, tl::to_string (QObject::tr ("Flip Horizontally")))); - menu_entries.push_back (lay::menu_item ("cm_lay_flip_y", "lay_flip_y:edit_mode", at, tl::to_string (QObject::tr ("Flip Vertically")))); - menu_entries.push_back (lay::menu_item ("cm_lay_rot_cw", "lay_rot_cw:edit_mode", at, tl::to_string (QObject::tr ("Rotate Clockwise")))); - menu_entries.push_back (lay::menu_item ("cm_lay_rot_ccw", "lay_rot_ccw:edit_mode", at, tl::to_string (QObject::tr ("Rotate Counterclockwise")))); - menu_entries.push_back (lay::menu_item ("cm_lay_free_rot", "lay_free_rot:edit_mode", at, tl::to_string (QObject::tr ("Rotation By Angle")))); - menu_entries.push_back (lay::menu_item ("cm_lay_scale", "lay_scale:edit_mode", at, tl::to_string (QObject::tr ("Scale")))); - menu_entries.push_back (lay::menu_item ("cm_lay_move", "lay_move:edit_mode", at, tl::to_string (QObject::tr ("Move By")))); - menu_entries.push_back (lay::separator ("cellop_group", at)); - menu_entries.push_back (lay::menu_item ("cm_lay_convert_to_static", "lay_convert_to_static:edit_mode", at, tl::to_string (QObject::tr ("Convert All Cells To Static")))); - } - - menu_entries.push_back (lay::submenu ("cell_menu:edit:edit_mode", at, tl::to_string (QObject::tr ("Cell")))); - { - std::string at = "edit_menu.cell_menu.end"; - menu_entries.push_back (lay::menu_item ("cm_new_cell", "new_cell:edit:edit_mode", at, tl::to_string (QObject::tr ("New Cell")))); - menu_entries.push_back (lay::menu_item ("cm_cell_delete", "delete_cell:edit:edit_mode", at, tl::to_string (QObject::tr ("Delete Cell")))); - menu_entries.push_back (lay::menu_item ("cm_cell_rename", "rename_cell:edit:edit_mode", at, tl::to_string (QObject::tr ("Rename Cell")))); - menu_entries.push_back (lay::menu_item ("cm_cell_replace", "replace_cell:edit:edit_mode", at, tl::to_string (QObject::tr ("Replace Cell")))); - menu_entries.push_back (lay::menu_item ("cm_cell_flatten", "flatten_cell:edit:edit_mode", at, tl::to_string (QObject::tr ("Flatten Cell")))); - menu_entries.push_back (lay::separator ("ops_group", at)); - menu_entries.push_back (lay::menu_item ("cm_adjust_origin", "adjust_cell_origin:edit:edit_mode", at, tl::to_string (QObject::tr ("Adjust Origin")))); - menu_entries.push_back (lay::menu_item ("cm_cell_convert_to_static", "convert_cell_to_static:edit_mode", at, tl::to_string (QObject::tr ("Convert Cell To Static")))); - menu_entries.push_back (lay::separator ("props_group", at)); - menu_entries.push_back (lay::menu_item ("cm_cell_user_properties", "user_properties", at, tl::to_string (QObject::tr ("User Properties")))); - } - - menu_entries.push_back (lay::submenu ("layer_menu:edit:edit_mode", at, tl::to_string (QObject::tr ("Layer")))); - { - std::string at = "edit_menu.layer_menu.end"; - menu_entries.push_back (lay::menu_item ("cm_new_layer", "new_layer:edit:edit_mode", at, tl::to_string (QObject::tr ("New Layer")))); - menu_entries.push_back (lay::menu_item ("cm_clear_layer", "clear_layer:edit:edit_mode", at, tl::to_string (QObject::tr ("Clear Layer")))); - menu_entries.push_back (lay::menu_item ("cm_delete_layer", "delete_layer:edit:edit_mode", at, tl::to_string (QObject::tr ("Delete Layer")))); - menu_entries.push_back (lay::menu_item ("cm_copy_layer", "copy_layer:edit:edit_mode", at, tl::to_string (QObject::tr ("Copy Layer")))); - menu_entries.push_back (lay::menu_item ("cm_edit_layer", "edit_layer:edit:edit_mode", at, tl::to_string (QObject::tr ("Edit Layer Specification")))); - } - - menu_entries.push_back (lay::submenu ("selection_menu:edit", at, tl::to_string (QObject::tr ("Selection")))); - { - std::string at = "edit_menu.selection_menu.end"; - menu_entries.push_back (lay::menu_item ("cm_sel_flip_x", "sel_flip_x", at, tl::to_string (QObject::tr ("Flip Horizontally")))); - menu_entries.push_back (lay::menu_item ("cm_sel_flip_y", "sel_flip_y", at, tl::to_string (QObject::tr ("Flip Vertically")))); - menu_entries.push_back (lay::menu_item ("cm_sel_rot_cw", "sel_rot_cw", at, tl::to_string (QObject::tr ("Rotate Clockwise")))); - menu_entries.push_back (lay::menu_item ("cm_sel_rot_ccw", "sel_rot_ccw", at, tl::to_string (QObject::tr ("Rotate Counterclockwise")))); - menu_entries.push_back (lay::menu_item ("cm_sel_free_rot", "sel_free_rot", at, tl::to_string (QObject::tr ("Rotation By Angle")))); - menu_entries.push_back (lay::menu_item ("cm_sel_scale", "sel_scale", at, tl::to_string (QObject::tr ("Scale")))); - menu_entries.push_back (lay::menu_item ("cm_sel_move", "sel_move", at, tl::to_string (QObject::tr ("Move By")))); - menu_entries.push_back (lay::menu_item ("cm_sel_move_to", "sel_move_to", at, tl::to_string (QObject::tr ("Move To")))); - } - - menu_entries.push_back (lay::separator ("utils_group", at)); - menu_entries.push_back (lay::submenu ("utils_menu:edit:edit_mode", at, tl::to_string (QObject::tr ("Utilities")))); - - menu_entries.push_back (lay::separator ("misc_group", at)); - menu_entries.push_back (lay::menu_item ("cm_delete", "delete:edit", at, tl::to_string (QObject::tr ("Delete(Del)")))); - menu_entries.push_back (lay::menu_item ("cm_show_properties", "show_properties:edit", at, tl::to_string (QObject::tr ("Properties(Q)")))); - - menu_entries.push_back (lay::separator ("cpc_group", at)); - menu_entries.push_back (lay::menu_item ("cm_copy", "copy:edit", at, tl::to_string (QObject::tr ("Copy(Ctrl+C)")))); - menu_entries.push_back (lay::menu_item ("cm_cut", "cut:edit", at, tl::to_string (QObject::tr ("Cut(Ctrl+X)")))); - menu_entries.push_back (lay::menu_item ("cm_paste", "paste:edit", at, tl::to_string (QObject::tr ("Paste(Ctrl+V)")))); - menu_entries.push_back (lay::menu_item ("cm_duplicate", "duplicate:edit", at, tl::to_string (QObject::tr ("Duplicate(Ctrl+B)")))); - - menu_entries.push_back (lay::separator ("modes_group", at)); - menu_entries.push_back (lay::submenu ("mode_menu", at, tl::to_string (QObject::tr ("Mode")))); - - menu_entries.push_back (lay::submenu ("select_menu", at, tl::to_string (QObject::tr ("Select")))); - { - std::string at = "edit_menu.select_menu.end"; - menu_entries.push_back (lay::menu_item ("cm_select_all", "select_all", at, tl::to_string (QObject::tr ("Select All")))); - menu_entries.push_back (lay::menu_item ("cm_unselect_all", "unselect_all", at, tl::to_string (QObject::tr ("Unselect All")))); - menu_entries.push_back (lay::separator ("edit_select_basic_group", at)); - menu_entries.push_back (lay::menu_item ("lv:enable_all", "enable_all", at, tl::to_string (QObject::tr ("Enable All")))); - menu_entries.push_back (lay::menu_item ("lv:disable_all", "disable_all", at, tl::to_string (QObject::tr ("Disable All")))); - menu_entries.push_back (lay::separator ("edit_select_individual_group", at)); - }; - - menu_entries.push_back (lay::separator ("cancel_group", at)); - menu_entries.push_back (lay::menu_item ("cm_cancel", "cancel", at, tl::to_string (QObject::tr ("Cancel(Esc)")))); - - at = "bookmark_menu.end"; - menu_entries.push_back (lay::submenu ("goto_bookmark_menu", at, tl::to_string (QObject::tr ("Goto Bookmark")))); - menu_entries.push_back (lay::menu_item ("cm_bookmark_view", "bookmark_view", at, tl::to_string (QObject::tr ("Bookmark This View")))); - - menu_entries.push_back (lay::separator ("bookmark_mgm_group", at)); - menu_entries.push_back (lay::menu_item ("cm_manage_bookmarks", "manage_bookmarks", at, tl::to_string (QObject::tr ("Manage Bookmarks")))); - menu_entries.push_back (lay::menu_item ("cm_load_bookmarks", "load_bookmarks", at, tl::to_string (QObject::tr ("Load Bookmarks")))); - menu_entries.push_back (lay::menu_item ("cm_save_bookmarks", "save_bookmarks", at, tl::to_string (QObject::tr ("Save Bookmarks")))); - - at = "zoom_menu.end"; - menu_entries.push_back (lay::submenu ("global_trans", at, tl::to_string (QObject::tr ("Global Transformation")))); - { - std::string at = "zoom_menu.global_trans.end"; - menu_entries.push_back (lay::config_menu_item ("r0", at, tl::to_string (QObject::tr ("\\(r0\\)<:/r0.png>")), cfg_global_trans, "?r0 *1 0,0")); - menu_entries.push_back (lay::config_menu_item ("r90", at, tl::to_string (QObject::tr ("\\(r90\\)<:/r90.png>")), cfg_global_trans, "?r90 *1 0,0")); - menu_entries.push_back (lay::config_menu_item ("r180", at, tl::to_string (QObject::tr ("\\(r180\\)<:/r180.png>")), cfg_global_trans, "?r180 *1 0,0")); - menu_entries.push_back (lay::config_menu_item ("r270", at, tl::to_string (QObject::tr ("\\(r270\\)<:/r270.png>")), cfg_global_trans, "?r270 *1 0,0")); - menu_entries.push_back (lay::config_menu_item ("m0", at, tl::to_string (QObject::tr ("\\(m0\\)<:/m0.png>")), cfg_global_trans, "?m0 *1 0,0")); - menu_entries.push_back (lay::config_menu_item ("m45", at, tl::to_string (QObject::tr ("\\(m45\\)<:/m45.png>")), cfg_global_trans, "?m45 *1 0,0")); - menu_entries.push_back (lay::config_menu_item ("m90", at, tl::to_string (QObject::tr ("\\(m90\\)<:/m90.png>")), cfg_global_trans, "?m90 *1 0,0")); - menu_entries.push_back (lay::config_menu_item ("m135", at, tl::to_string (QObject::tr ("\\(m135\\)<:/m135.png>")), cfg_global_trans, "?m135 *1 0,0")); - } - - menu_entries.push_back (lay::separator ("hier_group", at)); - menu_entries.push_back (lay::menu_item ("cm_max_hier", "max_hier", at, tl::to_string (QObject::tr ("Full Hierarchy(*)")))); - menu_entries.push_back (lay::menu_item ("cm_max_hier_0", "max_hier_0", at, tl::to_string (QObject::tr ("Box Only(0)")))); - menu_entries.push_back (lay::menu_item ("cm_max_hier_1", "max_hier_1", at, tl::to_string (QObject::tr ("Top Level Only(1)")))); - menu_entries.push_back (lay::menu_item ("cm_inc_max_hier", "inc_max_hier", at, tl::to_string (QObject::tr ("Increment Hierarchy(+)")))); - menu_entries.push_back (lay::menu_item ("cm_dec_max_hier", "dec_max_hier", at, tl::to_string (QObject::tr ("Decrement Hierarchy(-)")))); - - menu_entries.push_back (lay::separator ("zoom_group", at)); - menu_entries.push_back (lay::menu_item ("cm_zoom_fit", "zoom_fit", at, tl::to_string (QObject::tr ("Zoom Fit(F2)")))); - menu_entries.push_back (lay::menu_item ("cm_zoom_fit_sel", "zoom_fit_sel", at, tl::to_string (QObject::tr ("Zoom Fit Selection(Shift+F2)")))); - menu_entries.push_back (lay::menu_item ("cm_zoom_in", "zoom_in", at, tl::to_string (QObject::tr ("Zoom In(Return)")))); - menu_entries.push_back (lay::menu_item ("cm_zoom_out", "zoom_out", at, tl::to_string (QObject::tr ("Zoom Out(Shift+Return)")))); - /* disabled because that interferes with the use of the arrow keys for moving the selection - MenuLayoutEntry::separator ("pan_group"); - menu_entries.push_back (lay::menu_item ("cm_pan_up", "pan_up", at, tl::to_string (QObject::tr ("Pan Up(Up)")))); - menu_entries.push_back (lay::menu_item ("cm_pan_down", "pan_down", at, tl::to_string (QObject::tr ("Pan Down(Down)")))); - menu_entries.push_back (lay::menu_item ("cm_pan_left", "pan_left", at, tl::to_string (QObject::tr ("Pan Left(Left)")))); - menu_entries.push_back (lay::menu_item ("cm_pan_right", "pan_right", at, tl::to_string (QObject::tr ("Pan Right(Right)")))); - */ - - menu_entries.push_back (lay::separator ("redraw_group", at)); - menu_entries.push_back (lay::menu_item ("cm_redraw", "redraw", at, tl::to_string (QObject::tr ("Redraw")))); - menu_entries.push_back (lay::separator ("state_group", at)); - menu_entries.push_back (lay::menu_item_copy ("cm_prev_display_state", "prev_display_state", at, "@toolbar.prev_display_state")); - menu_entries.push_back (lay::menu_item_copy ("cm_next_display_state", "next_display_state", at, "@toolbar.next_display_state")); - - menu_entries.push_back (lay::separator ("select_group", at)); - menu_entries.push_back (lay::menu_item ("cm_select_cell", "select_cell:edit", at, tl::to_string (QObject::tr ("Select Cell")))); - menu_entries.push_back (lay::menu_item ("cm_select_current_cell", "select_current_cell", at, tl::to_string (QObject::tr ("Show As New Top(Ctrl+S)")))); - menu_entries.push_back (lay::menu_item ("cm_goto_position", "goto_position", at, tl::to_string (QObject::tr ("Goto Position(Ctrl+G)")))); - - // Add a hook for inserting new items after the modes - menu_entries.push_back (lay::separator ("end_modes", "@toolbar.end")); - - } - - bool menu_activated (const std::string &symbol) const - { - if (symbol == "lv:enable_all") { - - for (tl::Registrar::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) { - cls->set_editable_enabled (true); - } - return true; - - } else if (symbol == "lv:disable_all") { - - for (tl::Registrar::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) { - cls->set_editable_enabled (false); - } - return true; - - } else { - return false; - } - } - - void implements_primary_mouse_modes (std::vector > > &modes) - { - std::vector mode_titles; - lay::LayoutView::intrinsic_mouse_modes (&mode_titles); - - int mode_id = 0; - for (std::vector ::const_iterator t = mode_titles.begin (); t != mode_titles.end (); ++t, --mode_id) { - // modes: pair(title, pair(insert_pos, id)) - modes.push_back (std::make_pair (*t, std::make_pair ("edit_menu.mode_menu.end;@toolbar.end_modes", mode_id))); - } - } -}; - -static tl::RegisteredClass config_decl (new LayoutViewPluginDeclaration (), -10, "LayoutViewPlugin"); - } // namespace lay diff --git a/src/laybasic/laybasic/layLayoutView.h b/src/laybasic/laybasic/layLayoutView.h index fc05c566e..0081684b4 100644 --- a/src/laybasic/laybasic/layLayoutView.h +++ b/src/laybasic/laybasic/layLayoutView.h @@ -50,7 +50,6 @@ #include "layPlugin.h" #include "layDisplayState.h" #include "layBookmarkList.h" -#include "layDialogs.h" #include "gsi.h" #include "tlException.h" #include "tlEvents.h" @@ -237,6 +236,14 @@ public: return mp_control_frame; } + /** + * @brief Gets the layer control panel + */ + lay::LayerControlPanel *control_panel () + { + return mp_control_panel; + } + /** * @brief Gets the container with the hierarchy control panel */ @@ -245,6 +252,14 @@ public: return mp_hierarchy_frame; } + /** + * @brief Gets the hierarchy panel + */ + lay::HierarchyControlPanel *hierarchy_panel () + { + return mp_hierarchy_panel; + } + /** * @brief Gets the container with the libraries view */ @@ -1958,6 +1973,14 @@ public: */ virtual void drop_url (const std::string &path_or_url); + /** + * @brief Gets a list of all plugins + */ + const std::vector &plugins () + { + return mp_plugins; + } + /** * @brief Localize a plugin by name * @@ -2582,81 +2605,6 @@ public slots: void pan_right_fast (); void pan_down_fast (); - // menu callbacks - void cm_new_layer (); - void cm_clear_layer (); - void cm_delete_layer (); - void cm_copy_layer (); - void cm_align_cell_origin (); - void cm_edit_layer (); - void cm_lay_convert_to_static (); - void cm_lay_flip_x (); - void cm_lay_flip_y (); - void cm_lay_rot_cw (); - void cm_lay_rot_ccw (); - void cm_lay_free_rot (); - void cm_lay_scale (); - void cm_lay_move (); - void cm_sel_flip_x (); - void cm_sel_flip_y (); - void cm_sel_rot_cw (); - void cm_sel_rot_ccw (); - void cm_sel_free_rot (); - 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 (); - void cm_rename_tab (); - void cm_remove_tab (); - void cm_select_all (); - void cm_make_valid (); - void cm_make_invalid (); - void cm_hide (); - void cm_hide_all (); - void cm_show (); - void cm_show_all (); - void cm_show_only (); - void cm_rename (); - void cm_delete (); - void cm_insert (); - void cm_group (); - void cm_ungroup (); - void cm_source (); - void cm_sort_by_name (); - void cm_sort_by_ild (); - void cm_sort_by_idl (); - void cm_sort_by_ldi (); - void cm_sort_by_dli (); - void cm_regroup_by_index (); - void cm_regroup_by_datatype (); - void cm_regroup_by_layer (); - void cm_regroup_flatten (); - void cm_expand_all (); - void cm_add_missing (); - void cm_remove_unused (); - void cm_layer_copy (); - void cm_layer_cut (); - void cm_layer_paste (); - - // forwarded to the cell control panel - void cm_cell_user_properties (); - void cm_cell_flatten (); - void cm_cell_rename (); - void cm_cell_replace (); - void cm_cell_delete (); - void cm_cell_select (); - void cm_open_current_cell (); - void cm_cell_hide (); - void cm_cell_show (); - void cm_cell_show_all (); - void cm_cell_copy (); - void cm_cell_cut (); - void cm_cell_paste (); - void cm_cell_convert_to_static (); - // called by children and owner void redraw (); void redraw_layer (unsigned int index); @@ -2869,17 +2817,6 @@ private: std::vector mp_plugins; - db::LayerProperties m_new_layer_props; - db::DVector m_move_dist; - int m_move_to_origin_mode_x, m_move_to_origin_mode_y; - lay::AlignCellOptions m_align_cell_options; - int m_del_cell_mode; - int m_layer_hier_mode; - int m_duplicate_hier_mode; - bool m_clear_before; - int m_copy_cva, m_copy_cvr; - int m_copy_layera, m_copy_layerr; - bool m_visibility_changed; bool m_active_cellview_changed_event_enabled; tl::DeferredMethod dm_prop_changed; @@ -2890,8 +2827,6 @@ private: void do_prop_changed (); void do_redraw (int layer); void do_redraw (); - void do_transform (const db::DCplxTrans &tr); - void transform_layout (const db::DCplxTrans &tr); void background_color (QColor c); void ctx_color (QColor c); @@ -2918,11 +2853,6 @@ private: void init_layer_properties (LayerProperties &props, const LayerPropertiesList &lp_list) const; void merge_dither_pattern (lay::LayerPropertiesList &props); - void do_cm_duplicate (bool interactive); - void do_cm_paste (bool interactive); - void cm_new_cell (); - void cm_reload (); - // overrides Editables method to display a message void signal_selection_changed (); diff --git a/src/laybasic/laybasic/layLayoutViewFunctions.cc b/src/laybasic/laybasic/layLayoutViewFunctions.cc new file mode 100644 index 000000000..5e58747a2 --- /dev/null +++ b/src/laybasic/laybasic/layLayoutViewFunctions.cc @@ -0,0 +1,2249 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "layLayoutViewFunctions.h" +#include "layLayoutView.h" +#include "layCellSelectionForm.h" +#include "layLayoutStatisticsForm.h" +#include "layLayoutPropertiesForm.h" +#include "layHierarchyControlPanel.h" +#include "layLayerControlPanel.h" +#include "layTipDialog.h" +#include "laySelectCellViewForm.h" +#include "layMove.h" +#include "laybasicConfig.h" + +#include "dbClipboard.h" +#include "dbRecursiveShapeIterator.h" +#include "dbLayoutUtils.h" + +#include +#include + +namespace lay +{ + +LayoutViewFunctions::LayoutViewFunctions (db::Manager *manager, LayoutView *view) + : lay::Plugin (view), mp_view (view), mp_manager (manager) +{ + m_del_cell_mode = 0; + m_move_to_origin_mode_x = 0; + m_move_to_origin_mode_y = 0; + m_del_cell_mode = 0; + m_layer_hier_mode = 0; + m_duplicate_hier_mode = 2; + m_clear_before = true; + m_copy_cva = -1; + m_copy_cvr = -1; + m_copy_layera = -1; + m_copy_layerr = -1; + + m_new_layer_props.layer = 1; + m_new_layer_props.datatype = 0; +} + +LayoutViewFunctions::~LayoutViewFunctions () +{ + // .. nothing yet.. +} + +void +LayoutViewFunctions::menu_activated (const std::string &symbol) +{ + if (symbol == "cm_show_properties") { + + view ()->show_properties (view ()); + + } else if (symbol == "cm_delete") { + + view ()->del (); + // because a "delete" might involve objects currently edited, we cancel the edit after we have deleted the object + view ()->cancel (); + view ()->clear_selection (); + + } else if (symbol == "cm_unselect_all") { + view ()->select (db::DBox (), lay::Editable::Reset); + } else if (symbol == "cm_select_all") { + view ()->select (view ()->full_box (), lay::Editable::Replace); + } else if (symbol == "cm_lv_paste") { + cm_layer_paste (); + } else if (symbol == "cm_lv_cut") { + cm_layer_cut (); + } else if (symbol == "cm_lv_copy") { + cm_layer_copy (); + } else if (symbol == "cm_cell_paste") { + cm_cell_paste (); + } else if (symbol == "cm_cell_cut") { + cm_cell_cut (); + } else if (symbol == "cm_cell_copy") { + cm_cell_copy (); + } else if (symbol == "cm_duplicate") { + do_cm_duplicate (false); + } else if (symbol == "cm_duplicate_interactive") { + do_cm_duplicate (true); + } else if (symbol == "cm_copy") { + + view ()->copy (); + view ()->clear_selection (); + + } else if (symbol == "cm_paste") { + do_cm_paste (false); + } else if (symbol == "cm_paste_interactive") { + do_cm_paste (true); + } else if (symbol == "cm_cut") { + + view ()->cut (); + view ()->cancel (); // see del() for reason why cancel is after cut + view ()->clear_selection (); + + } else if (symbol == "cm_zoom_fit_sel") { + view ()->zoom_fit_sel (); + } else if (symbol == "cm_zoom_fit") { + view ()->zoom_fit (); + } else if (symbol == "cm_pan_left") { + view ()->pan_left (); + } else if (symbol == "cm_pan_right") { + view ()->pan_right (); + } else if (symbol == "cm_pan_up") { + view ()->pan_up (); + } else if (symbol == "cm_pan_down") { + view ()->pan_down (); + } else if (symbol == "cm_zoom_in") { + view ()->zoom_in (); + } else if (symbol == "cm_zoom_out") { + view ()->zoom_out (); + } else if (symbol == "cm_select_current_cell") { + + if (view ()->active_cellview_index () >= 0) { + lay::LayoutView::cell_path_type path; + int cvi = view ()->active_cellview_index (); + view ()->current_cell_path (path); + view ()->select_cell_fit (path, cvi); + } + + } else if (symbol == "cm_open_current_cell") { + + if (view ()->active_cellview_index () >= 0) { + cm_open_current_cell (); + } + + } else if (symbol == "cm_select_cell") { + + if (view ()->active_cellview_index () >= 0) { + + lay::CellSelectionForm form (0, view (), "cell_selection_form"); + + if (form.exec () == QDialog::Accepted && + form.selected_cellview_index () >= 0) { + view ()->select_cell (form.selected_cellview ().combined_unspecific_path (), form.selected_cellview_index ()); + view ()->set_current_cell_path (form.selected_cellview_index (), form.selected_cellview ().combined_unspecific_path ()); + view ()->zoom_fit (); + } + + } + + } else if (symbol == "cm_new_cell") { + cm_new_cell (); + } else if (symbol == "cm_adjust_origin") { + if (view ()->active_cellview_index () >= 0) { + cm_align_cell_origin (); + } + } else if (symbol == "cm_cell_convert_to_static") { + if (view ()->active_cellview_index () >= 0) { + cm_cell_convert_to_static (); + } + } else if (symbol == "cm_lay_convert_to_static") { + if (view ()->active_cellview_index () >= 0) { + cm_lay_convert_to_static (); + } + } else if (symbol == "cm_lay_move") { + if (view ()->active_cellview_index () >= 0) { + cm_lay_move (); + } + } else if (symbol == "cm_lay_scale") { + if (view ()->active_cellview_index () >= 0) { + cm_lay_scale (); + } + } else if (symbol == "cm_lay_free_rot") { + if (view ()->active_cellview_index () >= 0) { + cm_lay_free_rot (); + } + } else if (symbol == "cm_lay_rot_ccw") { + if (view ()->active_cellview_index () >= 0) { + cm_lay_rot_ccw (); + } + } else if (symbol == "cm_lay_rot_cw") { + if (view ()->active_cellview_index () >= 0) { + cm_lay_rot_cw (); + } + } else if (symbol == "cm_lay_flip_y") { + if (view ()->active_cellview_index () >= 0) { + cm_lay_flip_y (); + } + } else if (symbol == "cm_lay_flip_x") { + if (view ()->active_cellview_index () >= 0) { + cm_lay_flip_x (); + } + } else if (symbol == "cm_sel_move") { + if (view ()->active_cellview_index () >= 0) { + cm_sel_move (); + } + } else if (symbol == "cm_sel_move_to") { + if (view ()->active_cellview_index () >= 0) { + cm_sel_move_to (); + } + } else if (symbol == "cm_sel_move_interactive") { + if (view ()->active_cellview_index () >= 0) { + cm_sel_move_interactive (); + } + } else if (symbol == "cm_sel_scale") { + if (view ()->active_cellview_index () >= 0) { + cm_sel_scale (); + } + } else if (symbol == "cm_sel_free_rot") { + if (view ()->active_cellview_index () >= 0) { + cm_sel_free_rot (); + } + } else if (symbol == "cm_sel_rot_ccw") { + if (view ()->active_cellview_index () >= 0) { + cm_sel_rot_ccw (); + } + } else if (symbol == "cm_sel_rot_cw") { + if (view ()->active_cellview_index () >= 0) { + cm_sel_rot_cw (); + } + } else if (symbol == "cm_sel_flip_y") { + if (view ()->active_cellview_index () >= 0) { + cm_sel_flip_y (); + } + } else if (symbol == "cm_sel_flip_x") { + if (view ()->active_cellview_index () >= 0) { + cm_sel_flip_x (); + } + } else if (symbol == "cm_edit_layer") { + if (view ()->active_cellview_index () >= 0) { + cm_edit_layer (); + } + } else if (symbol == "cm_delete_layer") { + if (view ()->active_cellview_index () >= 0) { + cm_delete_layer (); + } + } else if (symbol == "cm_clear_layer") { + if (view ()->active_cellview_index () >= 0) { + cm_clear_layer (); + } + } else if (symbol == "cm_copy_layer") { + if (view ()->active_cellview_index () >= 0) { + cm_copy_layer (); + } + } else if (symbol == "cm_new_layer") { + if (view ()->active_cellview_index () >= 0) { + cm_new_layer (); + } + } else if (symbol == "cm_layout_props") { + lay::LayoutPropertiesForm lp_form (view (), view (), "layout_props_form"); + lp_form.exec (); + } else if (symbol == "cm_layout_stats") { + lay::LayoutStatisticsForm lp_form (view (), view (), "layout_props_form"); + lp_form.exec (); + } else if (symbol == "cm_reload") { + cm_reload (); + } else if (symbol == "cm_inc_max_hier") { + int new_to = view ()->get_max_hier_levels () + 1; + view ()->set_hier_levels (std::make_pair (view ()->get_min_hier_levels (), new_to)); + } else if (symbol == "cm_dec_max_hier") { + int new_to = view ()->get_max_hier_levels () > 0 ? view ()->get_max_hier_levels () - 1 : 0; + view ()->set_hier_levels (std::make_pair (std::min (view ()->get_min_hier_levels (), new_to), new_to)); + } else if (symbol == "cm_max_hier") { + view ()->max_hier (); + } else if (symbol == "cm_max_hier_0") { + view ()->set_hier_levels (std::make_pair (std::min (view ()->get_min_hier_levels (), 0), 0)); + } else if (symbol == "cm_max_hier_1") { + view ()->set_hier_levels (std::make_pair (std::min (view ()->get_min_hier_levels (), 0), 1)); + } else if (symbol == "cm_prev_display_state") { + if (view ()->has_prev_display_state ()) { + view ()->prev_display_state (); + } + } else if (symbol == "cm_next_display_state") { + if (view ()->has_next_display_state ()) { + view ()->next_display_state (); + } + } else if (symbol == "cm_redraw") { + view ()->redraw (); + } else if (symbol == "cm_cell_delete") { + cm_cell_delete (); + } else if (symbol == "cm_cell_replace") { + cm_cell_replace (); + } else if (symbol == "cm_cell_rename") { + cm_cell_rename (); + } else if (symbol == "cm_cell_flatten") { + cm_cell_flatten (); + } else if (symbol == "cm_cell_select") { + cm_cell_select (); + } else if (symbol == "cm_cell_hide") { + cm_cell_hide (); + } else if (symbol == "cm_cell_show") { + cm_cell_show (); + } else if (symbol == "cm_cell_show_all") { + cm_cell_show_all (); + } else if (symbol == "cm_cell_user_properties") { + if (view ()->active_cellview_index () >= 0) { + cm_cell_user_properties (); + } + } else if (symbol == "cm_lv_select_all") { + cm_select_all (); + } else if (symbol == "cm_lv_new_tab") { + cm_new_tab (); + } else if (symbol == "cm_lv_rename_tab") { + cm_rename_tab (); + } else if (symbol == "cm_lv_make_invalid") { + cm_make_invalid (); + } else if (symbol == "cm_lv_remove_tab") { + cm_remove_tab (); + } else if (symbol == "cm_lv_make_valid") { + cm_make_valid (); + } else if (symbol == "cm_lv_hide_all") { + cm_hide_all (); + } else if (symbol == "cm_lv_hide") { + cm_hide (); + } else if (symbol == "cm_lv_show_only") { + cm_show_only (); + } else if (symbol == "cm_lv_show_all") { + cm_show_all (); + } else if (symbol == "cm_lv_show") { + cm_show (); + } else if (symbol == "cm_lv_rename") { + cm_rename (); + } else if (symbol == "cm_lv_delete") { + cm_delete (); + } else if (symbol == "cm_lv_insert") { + cm_insert (); + } else if (symbol == "cm_lv_group") { + cm_group (); + } else if (symbol == "cm_lv_ungroup") { + cm_ungroup (); + } else if (symbol == "cm_lv_source") { + cm_source (); + } else if (symbol == "cm_lv_sort_by_name") { + cm_sort_by_name (); + } else if (symbol == "cm_lv_sort_by_ild") { + cm_sort_by_ild (); + } else if (symbol == "cm_lv_sort_by_idl") { + cm_sort_by_idl (); + } else if (symbol == "cm_lv_sort_by_ldi") { + cm_sort_by_ldi (); + } else if (symbol == "cm_lv_sort_by_dli") { + cm_sort_by_dli (); + } else if (symbol == "cm_lv_regroup_by_index") { + cm_regroup_by_index (); + } else if (symbol == "cm_lv_regroup_by_datatype") { + cm_regroup_by_datatype (); + } else if (symbol == "cm_lv_regroup_by_layer") { + cm_regroup_by_layer (); + } else if (symbol == "cm_lv_regroup_flatten") { + cm_regroup_flatten (); + } else if (symbol == "cm_lv_expand_all") { + cm_expand_all (); + } else if (symbol == "cm_lv_add_missing") { + cm_add_missing (); + } else if (symbol == "cm_lv_remove_unused") { + cm_remove_unused (); + } +} + +void +LayoutViewFunctions::cm_cell_user_properties () +{ + if (! view ()->hierarchy_panel ()) { + return; + } + + int cv_index = view ()->active_cellview_index (); + lay::LayoutView::cell_path_type path; + view ()->hierarchy_panel ()->current_cell (cv_index, path); + + if (cv_index >= 0 && path.size () > 0) { + + db::Layout &layout = view ()->cellview (cv_index)->layout (); + db::Cell &cell = layout.cell (path.back ()); + db::properties_id_type prop_id = cell.prop_id (); + + lay::UserPropertiesForm props_form (view ()); + if (props_form.show (view (), cv_index, prop_id)) { + + view ()->transaction (tl::to_string (QObject::tr ("Edit cell's user propertes"))); + cell.prop_id (prop_id); + view ()->commit (); + + } + + } +} + +void +LayoutViewFunctions::cm_cell_replace () +{ + if (! view ()->hierarchy_panel ()) { + return; + } + + int cv_index = view ()->active_cellview_index (); + std::vector paths; + view ()->hierarchy_panel ()->selected_cells (cv_index, paths); + + if (cv_index >= 0 && paths.size () > 0) { + + if (paths.size () > 1) { + throw tl::Exception (tl::to_string (QObject::tr ("Replace cell cannot be used when multiple cells are selected"))); + } + + db::Layout &layout = view ()->cellview (cv_index)->layout (); + + bool needs_to_ask = false; + for (std::vector::const_iterator p = paths.begin (); p != paths.end () && ! needs_to_ask; ++p) { + if (layout.is_valid_cell_index (p->back ()) && ! layout.cell (p->back ()).is_leaf ()) { + needs_to_ask = true; + } + } + + + lay::ReplaceCellOptionsDialog mode_dialog (view ()); + + db::cell_index_type with_cell = paths.front ().back (); + int mode = needs_to_ask ? m_del_cell_mode : 0; + + if (mode_dialog.exec_dialog (view ()->cellview (cv_index), mode, with_cell)) { + + if (needs_to_ask) { + m_del_cell_mode = mode; + } + + if (with_cell != paths.front ().back ()) { + + // remember the current path + lay::LayoutView::cell_path_type cell_path (view ()->cellview (cv_index).combined_unspecific_path ()); + + view ()->clear_selection (); + + view ()->transaction (tl::to_string (QObject::tr ("Replace cells"))); + + // replace instances of the target cell with the new cell + + db::Cell &target_cell = layout.cell (paths.front ().back ()); + + std::vector > parents; + for (db::Cell::parent_inst_iterator pi = target_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { + parents.push_back (std::make_pair (pi->parent_cell_index (), pi->child_inst ())); + } + + for (std::vector >::const_iterator p = parents.begin (); p != parents.end (); ++p) { + db::CellInstArray ia = p->second.cell_inst (); + ia.object ().cell_index (with_cell); + layout.cell (p->first).replace (p->second, ia); + } + + std::set cells_to_delete; + for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { + if (! p->empty () && layout.is_valid_cell_index (p->back ())) { + cells_to_delete.insert (p->back ()); + if (mode == 2) { + layout.cell (p->back ()).collect_called_cells (cells_to_delete); + } + } + } + + // support a propagation use case: + std::set cells_below_replacement_cell; + cells_below_replacement_cell.insert (with_cell); + layout.cell (with_cell).collect_called_cells (cells_below_replacement_cell); + for (std::set::const_iterator c = cells_below_replacement_cell.begin (); c != cells_below_replacement_cell.end (); ++c) { + cells_to_delete.erase (*c); + } + + if (mode == 0 || mode == 2) { + layout.delete_cells (cells_to_delete); + } else if (mode == 1) { + layout.prune_cells (cells_to_delete); + } + + layout.cleanup (); + + view ()->commit (); + + // If one of the cells in the path was deleted, establish a valid path + + bool needs_update = false; + for (size_t i = cell_path.size (); i > 0; ) { + --i; + if (! layout.is_valid_cell_index (cell_path [i])) { + cell_path.erase (cell_path.begin () + i, cell_path.end ()); + needs_update = true; + } + } + + if (needs_update) { + view ()->select_cell (cell_path, cv_index); + } + + } + + } + + } +} + +void +LayoutViewFunctions::cm_lay_convert_to_static () +{ + // end move operations, cancel edit operations + view ()->cancel_edits (); + view ()->clear_selection (); + + int cv_index = view ()->active_cellview_index (); + if (cv_index >= 0) { + + db::Layout &layout = view ()->cellview (cv_index)->layout (); + + view ()->transaction (tl::to_string (QObject::tr ("Convert all cells to static"))); + + std::vector cells; + for (db::Layout::const_iterator c = layout.begin (); c != layout.end (); ++c) { + cells.push_back (c->cell_index ()); + } + + std::map cell_map; + for (std::vector::const_iterator c = cells.begin (); c != cells.end (); ++c) { + if (layout.is_valid_cell_index (*c)) { + db::cell_index_type new_cell = layout.convert_cell_to_static (*c); + if (new_cell != *c) { + cell_map.insert (std::make_pair (*c, new_cell)); + } + } + } + + // rewrite instances + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + for (db::Cell::const_iterator i = c->begin (); ! i.at_end (); ++i) { + std::map::const_iterator cm = cell_map.find (i->cell_index ()); + if (cm != cell_map.end ()) { + db::CellInstArray ci = i->cell_inst (); + ci.object ().cell_index (cm->second); + c->replace (*i, ci); + } + } + } + + layout.cleanup (); + + view ()->commit (); + + } +} + +void +LayoutViewFunctions::cm_cell_convert_to_static () +{ + if (! view ()->hierarchy_panel ()) { + return; + } + + int cv_index = view ()->active_cellview_index (); + std::vector paths; + view ()->hierarchy_panel ()->selected_cells (cv_index, paths); + + if (cv_index >= 0 && paths.size () > 0) { + + db::Layout &layout = view ()->cellview (cv_index)->layout (); + + // remember the current path + lay::LayoutView::cell_path_type cell_path (view ()->cellview (cv_index).combined_unspecific_path ()); + + view ()->clear_selection (); + + view ()->transaction (tl::to_string (QObject::tr ("Convert cells to static"))); + + std::map cell_map; + + for (std::vector::iterator p = paths.begin (); p != paths.end (); ++p) { + if (! p->empty () && layout.is_valid_cell_index (p->back ())) { + db::cell_index_type new_cell = layout.convert_cell_to_static (p->back ()); + if (new_cell != p->back ()) { + cell_map.insert (std::make_pair (p->back (), new_cell)); + p->back () = new_cell; + } + } + } + + // rewrite instances + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + for (db::Cell::const_iterator i = c->begin (); ! i.at_end (); ++i) { + std::map::const_iterator cm = cell_map.find (i->cell_index ()); + if (cm != cell_map.end ()) { + db::CellInstArray ci = i->cell_inst (); + ci.object ().cell_index (cm->second); + c->replace (*i, ci); + } + } + } + + layout.cleanup (); + + view ()->commit (); + + // If one of the cells in the path was deleted, establish a valid path + + bool needs_update = false; + for (size_t i = cell_path.size (); i > 0; ) { + --i; + if (! layout.is_valid_cell_index (cell_path [i])) { + cell_path.erase (cell_path.begin () + i, cell_path.end ()); + needs_update = true; + } + } + + if (needs_update) { + view ()->select_cell (cell_path, cv_index); + } + + } +} + +static void +collect_cells_to_delete (const db::Layout &layout, const db::Cell &cell, std::set &called) +{ + // don't delete proxies - they are deleted later when the layout is cleaned + for (db::Cell::child_cell_iterator cc = cell.begin_child_cells (); ! cc.at_end (); ++cc) { + if (called.find (*cc) == called.end () && !layout.cell (*cc).is_proxy ()) { + called.insert (*cc); + collect_cells_to_delete (layout, layout.cell (*cc), called); + } + } +} + +void +LayoutViewFunctions::cm_cell_delete () +{ + if (! view ()->hierarchy_panel ()) { + return; + } + + int cv_index = view ()->active_cellview_index (); + std::vector paths; + view ()->hierarchy_panel ()->selected_cells (cv_index, paths); + + if (cv_index >= 0 && paths.size () > 0) { + + db::Layout &layout = view ()->cellview (cv_index)->layout (); + + bool needs_to_ask = false; + for (std::vector::const_iterator p = paths.begin (); p != paths.end () && ! needs_to_ask; ++p) { + if (layout.is_valid_cell_index (p->back ()) && ! layout.cell (p->back ()).is_leaf ()) { + needs_to_ask = true; + } + } + + int mode = m_del_cell_mode; + if (! needs_to_ask) { + mode = 0; + } + + lay::DeleteCellModeDialog mode_dialog (view ()); + if (! needs_to_ask || mode_dialog.exec_dialog (mode)) { + + if (needs_to_ask) { + m_del_cell_mode = mode; + } + + // remember the current path + lay::LayoutView::cell_path_type cell_path (view ()->cellview (cv_index).combined_unspecific_path ()); + + view ()->clear_selection (); + + std::set cells_to_delete; + for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { + if (! p->empty () && layout.is_valid_cell_index (p->back ())) { + cells_to_delete.insert (p->back ()); + if (mode == 2) { + collect_cells_to_delete (layout, layout.cell (p->back ()), cells_to_delete); + } + } + } + + view ()->transaction (tl::to_string (QObject::tr ("Delete cells"))); + + if (mode == 0 || mode == 2) { + layout.delete_cells (cells_to_delete); + } else if (mode == 1) { + layout.prune_cells (cells_to_delete); + } + + layout.cleanup (); + + view ()->commit (); + + // If one of the cells in the path was deleted, establish a valid path + + bool needs_update = false; + for (size_t i = cell_path.size (); i > 0; ) { + --i; + if (! layout.is_valid_cell_index (cell_path [i])) { + cell_path.erase (cell_path.begin () + i, cell_path.end ()); + needs_update = true; + } + } + + if (needs_update) { + view ()->select_cell (cell_path, cv_index); + } + + } + + } +} + +void +LayoutViewFunctions::cm_layer_copy () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->copy (); + } +} + +void +LayoutViewFunctions::cm_layer_cut () +{ + if (view ()->control_panel ()) { + db::Transaction trans (manager (), tl::to_string (QObject::tr ("Cut Layers"))); + view ()->control_panel ()->cut (); + } +} + +void +LayoutViewFunctions::cm_layer_paste () +{ + if (view ()->control_panel ()) { + db::Transaction trans (manager (), tl::to_string (QObject::tr ("Paste Layers"))); + view ()->control_panel ()->paste (); + } +} + +void +LayoutViewFunctions::cm_cell_cut () +{ + if (view ()->hierarchy_panel ()) { + // TODO: currently the hierarchy panel's cut function does it's own transaction handling. + // Otherwise the cut function is not working propertly. + view ()->hierarchy_panel ()->cut (); + } +} + +void +LayoutViewFunctions::cm_cell_paste () +{ + if (view ()->hierarchy_panel ()) { + db::Transaction trans (manager (), tl::to_string (QObject::tr ("Paste Cells"))); + view ()->hierarchy_panel ()->paste (); + } +} + +void +LayoutViewFunctions::cm_cell_copy () +{ + if (view ()->hierarchy_panel ()) { + view ()->hierarchy_panel ()->copy (); + } +} + +void +LayoutViewFunctions::cm_cell_flatten () +{ + if (! view ()->hierarchy_panel ()) { + return; + } + + tl_assert (view ()->is_editable ()); + + int cv_index = view ()->active_cellview_index (); + if (cv_index >= 0) { + + const lay::CellView &cv = view ()->cellview (cv_index); + if (cv.is_valid ()) { + + std::vector paths; + view ()->hierarchy_panel ()->selected_cells (cv_index, paths); + if (paths.empty ()) { + throw tl::Exception (tl::to_string (QObject::tr ("No cells selected for flattening"))); + } + + for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { + if (p->size () > 0 && cv->layout ().cell (p->back ()).is_proxy ()) { + throw tl::Exception (tl::to_string (QObject::tr ("Cannot use this function on a PCell or library cell"))); + } + } + + FlattenInstOptionsDialog options_dialog (view ()); + + int flatten_insts_levels = -1; + bool prune = true; + if (options_dialog.exec_dialog (flatten_insts_levels, prune) && flatten_insts_levels != 0) { + + bool supports_undo = true; + + if (manager () && manager ()->is_enabled ()) { + + lay::TipDialog td (QApplication::activeWindow (), + tl::to_string (QObject::tr ("Undo buffering for the following operation can be memory and time consuming.\nChoose \"Yes\" to use undo buffering or \"No\" for no undo buffering. Warning: in the latter case, the undo history will be lost.\n\nChoose undo buffering?")), + "flatten-undo-buffering", + lay::TipDialog::yesnocancel_buttons); + + lay::TipDialog::button_type button = lay::TipDialog::null_button; + td.exec_dialog (button); + if (button == lay::TipDialog::cancel_button) { + return; + } + + supports_undo = (button == lay::TipDialog::yes_button); + + } else { + supports_undo = false; + } + + view ()->cancel_edits (); + view ()->clear_selection (); + + if (manager ()) { + if (! supports_undo) { + manager ()->clear (); + } else { + manager ()->transaction (tl::to_string (QObject::tr ("Flatten cell"))); + } + } + + db::Layout &layout = cv->layout (); + + std::set child_cells; + for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { + if (p->size () > 0) { + layout.cell (p->back ()).collect_called_cells (child_cells); + } + } + + // don't flatten cells which are child cells of the cells to flatten + std::set cells_to_flatten; + for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { + if (p->size () > 0 && child_cells.find (p->back ()) == child_cells.end ()) { + cells_to_flatten.insert (p->back ()); + } + } + + for (std::set::const_iterator c = cells_to_flatten.begin (); c != cells_to_flatten.end (); ++c) { + db::Cell &target_cell = layout.cell (*c); + layout.flatten (target_cell, flatten_insts_levels, prune); + } + + layout.cleanup (); + + if (supports_undo && manager ()) { + manager ()->commit (); + } + + } + + } + + } +} + +void +LayoutViewFunctions::cm_cell_rename () +{ + if (! view ()->hierarchy_panel ()) { + return; + } + + int cv_index = view ()->active_cellview_index (); + lay::LayoutView::cell_path_type path; + view ()->hierarchy_panel ()->current_cell (cv_index, path); + + if (cv_index >= 0 && path.size () > 0) { + + lay::RenameCellDialog name_dialog (view ()); + + db::Layout &layout = view ()->cellview (cv_index)->layout (); + std::string name (layout.cell_name (path.back ())); + if (name_dialog.exec_dialog (layout, name)) { + + view ()->transaction (tl::to_string (QObject::tr ("Rename cell"))); + layout.rename_cell (path.back (), name.c_str ()); + view ()->commit (); + + } + + } +} + +void +LayoutViewFunctions::cm_cell_select () +{ + if (view ()->hierarchy_panel ()) { + view ()->hierarchy_panel ()->cm_cell_select (); + } +} + +void +LayoutViewFunctions::cm_open_current_cell () +{ + view ()->set_current_cell_path (view ()->active_cellview_index (), view ()->cellview (view ()->active_cellview_index ()).combined_unspecific_path ()); +} + +void +LayoutViewFunctions::cm_cell_hide () +{ + if (view ()->hierarchy_panel ()) { + + std::vector paths; + view ()->hierarchy_panel ()->selected_cells (view ()->active_cellview_index (), paths); + + view ()->transaction (tl::to_string (QObject::tr ("Hide cell"))); + + for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { + if (! p->empty ()) { + view ()->hide_cell (p->back (), view ()->active_cellview_index ()); + } + } + + view ()->commit (); + + } +} + +void +LayoutViewFunctions::cm_cell_show () +{ + if (view ()->hierarchy_panel ()) { + + std::vector paths; + view ()->hierarchy_panel ()->selected_cells (view ()->active_cellview_index (), paths); + + view ()->transaction (tl::to_string (QObject::tr ("Show cell"))); + + for (std::vector::const_iterator p = paths.begin (); p != paths.end (); ++p) { + if (! p->empty ()) { + view ()->show_cell (p->back (), view ()->active_cellview_index ()); + } + } + + view ()->commit (); + + } +} + +void +LayoutViewFunctions::cm_cell_show_all () +{ + if (view ()->hierarchy_panel ()) { + view ()->transaction (tl::to_string (QObject::tr ("Show all cells"))); + view ()->show_all_cells (); + view ()->commit (); + } +} + +void +LayoutViewFunctions::cm_select_all () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_select_all (); + } +} + +void +LayoutViewFunctions::cm_new_tab () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_new_tab (); + } +} + +void +LayoutViewFunctions::cm_remove_tab () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_remove_tab (); + } +} + +void +LayoutViewFunctions::cm_rename_tab () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_rename_tab (); + } +} + +void +LayoutViewFunctions::cm_make_invalid () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_make_invalid (); + } +} + +void +LayoutViewFunctions::cm_make_valid () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_make_valid (); + } +} + +void +LayoutViewFunctions::cm_hide () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_hide (); + } +} + +void +LayoutViewFunctions::cm_hide_all () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_hide_all (); + } +} + +void +LayoutViewFunctions::cm_show_only () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_show_only (); + } +} + +void +LayoutViewFunctions::cm_show_all () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_show_all (); + } +} + +void +LayoutViewFunctions::cm_show () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_show (); + } +} + +void +LayoutViewFunctions::cm_rename () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_rename (); + } +} + +void +LayoutViewFunctions::cm_delete () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_delete (); + } +} + +void +LayoutViewFunctions::cm_insert () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_insert (); + } +} + +void +LayoutViewFunctions::cm_group () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_group (); + } +} + +void +LayoutViewFunctions::cm_ungroup () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_ungroup (); + } +} + +void +LayoutViewFunctions::cm_source () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_source (); + } +} + +void +LayoutViewFunctions::cm_sort_by_name () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_sort_by_name (); + } +} + +void +LayoutViewFunctions::cm_sort_by_ild () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_sort_by_ild (); + } +} + +void +LayoutViewFunctions::cm_sort_by_idl () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_sort_by_idl (); + } +} + +void +LayoutViewFunctions::cm_sort_by_ldi () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_sort_by_ldi (); + } +} + +void +LayoutViewFunctions::cm_sort_by_dli () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_sort_by_dli (); + } +} + +void +LayoutViewFunctions::cm_regroup_by_index () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_regroup_by_index (); + } +} + +void +LayoutViewFunctions::cm_regroup_by_datatype () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_regroup_by_datatype (); + } +} + +void +LayoutViewFunctions::cm_regroup_by_layer () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_regroup_by_layer (); + } +} + +void +LayoutViewFunctions::cm_regroup_flatten () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_regroup_flatten (); + } +} + +void +LayoutViewFunctions::cm_expand_all () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_expand_all (); + } +} + +void +LayoutViewFunctions::cm_add_missing () +{ + if (view ()->control_panel ()) { + view ()->control_panel ()->cm_add_missing (); + } +} + +void +LayoutViewFunctions::cm_remove_unused () +{ + view ()->remove_unused_layers (); +} + +void +LayoutViewFunctions::do_cm_duplicate (bool interactive) +{ + // Do duplicate simply by concatenating copy & paste currently. + // Save the clipboard state before in order to preserve the current content + db::Clipboard saved_clipboard; + db::Clipboard::instance ().swap (saved_clipboard); + + try { + view ()->copy (); + view ()->clear_selection (); + view ()->cancel (); + if (interactive) { + view ()->paste_interactive (); + } else { + view ()->paste (); + } + db::Clipboard::instance ().swap (saved_clipboard); + } catch (...) { + db::Clipboard::instance ().swap (saved_clipboard); + throw; + } +} + +void +LayoutViewFunctions::do_cm_paste (bool interactive) +{ + if (! db::Clipboard::instance ().empty ()) { + view ()->cancel (); + view ()->clear_selection (); + if (interactive) { + view ()->paste_interactive (); + } else { + view ()->paste (); + } + } +} + +void +LayoutViewFunctions::cm_new_cell () +{ + static double s_new_cell_window_size = 2.0; + static std::string s_new_cell_cell_name; + + NewCellPropertiesDialog cell_prop_dia (view ()); + if (cell_prop_dia.exec_dialog (& view ()->cellview (view ()->active_cellview_index ())->layout (), s_new_cell_cell_name, s_new_cell_window_size)) { + + db::cell_index_type new_ci = view ()->new_cell (view ()->active_cellview_index (), s_new_cell_cell_name.c_str ()); + view ()->select_cell (new_ci, view ()->active_cellview_index ()); + + db::DBox zb = db::DBox (-0.5 * s_new_cell_window_size, -0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size); + if (view ()->get_max_hier_levels () < 1 || view ()->get_min_hier_levels () > 0) { + view ()->zoom_box_and_set_hier_levels (zb, std::make_pair (0, 1)); + } else { + view ()->zoom_box (zb); + } + + } +} + +// TODO: this constant is defined in MainWindow.cc too ... +const int max_dirty_files = 15; + +void +LayoutViewFunctions::cm_reload () +{ + std::vector selected; + + if (view ()->cellviews () > 1) { + + lay::SelectCellViewForm form (0, view (), tl::to_string (QObject::tr ("Select Layouts To Reload"))); + form.select_all (); + + if (form.exec () == QDialog::Accepted) { + selected = form.selected_cellviews (); + } + + } else if (view ()->cellviews () > 0) { + selected.push_back (0); + } + + if (selected.size () > 0) { + + int dirty_layouts = 0; + std::string dirty_files; + + for (std::vector ::const_iterator i = selected.begin (); i != selected.end (); ++i) { + + const lay::CellView &cv = view ()->cellview (*i); + + if (cv->layout ().is_editable () && cv->is_dirty ()) { + ++dirty_layouts; + if (dirty_layouts == max_dirty_files) { + dirty_files += "\n..."; + } else if (dirty_layouts < max_dirty_files) { + if (! dirty_files.empty ()) { + dirty_files += "\n"; + } + dirty_files += cv->name (); + } + } + + } + + bool can_reload = true; + if (dirty_layouts != 0) { + + QMessageBox mbox (view ()); + mbox.setText (tl::to_qstring (tl::to_string (QObject::tr ("The following layouts need saving:\n\n")) + dirty_files + "\n\nPress 'Reload Without Saving' to reload anyhow and discard changes.")); + mbox.setWindowTitle (QObject::tr ("Save Needed")); + mbox.setIcon (QMessageBox::Warning); + QAbstractButton *yes_button = mbox.addButton (QObject::tr ("Reload Without Saving"), QMessageBox::YesRole); + mbox.addButton (QMessageBox::Cancel); + + mbox.exec (); + + can_reload = (mbox.clickedButton() == yes_button); + + } + + if (can_reload) { + + // Actually reload + for (std::vector ::const_iterator i = selected.begin (); i != selected.end (); ++i) { + view ()->reload_layout (*i); + } + + } + + } +} + +void +LayoutViewFunctions::do_transform (const db::DCplxTrans &tr) +{ + // end move operations, cancel edit operations + view ()->cancel_edits (); + view ()->lay::Editables::transform (tr); +} + +void +LayoutViewFunctions::transform_layout (const db::DCplxTrans &tr_mic) +{ + // end move operations, cancel edit operations + view ()->cancel_edits (); + view ()->clear_selection (); + + int cv_index = view ()->active_cellview_index (); + if (cv_index >= 0) { + + db::Layout &layout = view ()->cellview (cv_index)->layout (); + + db::ICplxTrans tr (db::DCplxTrans (1.0 / layout.dbu ()) * tr_mic * db::DCplxTrans (layout.dbu ())); + + bool has_proxy = false; + for (db::Layout::const_iterator c = layout.begin (); ! has_proxy && c != layout.end (); ++c) { + has_proxy = c->is_proxy (); + } + + if (has_proxy && + QMessageBox::question (view (), + QObject::tr ("Transforming PCells Or Library Cells"), + QObject::tr ("The layout contains PCells or library cells or both.\n" + "Any changes to such cells may be lost when their layout is refreshed later.\n" + "Consider using 'Convert all cells to static' before transforming the layout.\n" + "\n" + "Would you like to continue?\n" + "Choose 'Yes' to continue anyway. Choose 'No' to cancel."), + QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { + return; + } + + view ()->transaction (tl::to_string (QObject::tr ("Transform layout"))); + layout.transform (tr); + view ()->commit (); + + } +} + +void +LayoutViewFunctions::cm_lay_flip_x () +{ + transform_layout (db::DCplxTrans (db::FTrans::m90)); +} + +void +LayoutViewFunctions::cm_lay_flip_y () +{ + transform_layout (db::DCplxTrans (db::FTrans::m0)); +} + +void +LayoutViewFunctions::cm_lay_rot_ccw () +{ + db::DCplxTrans tr (db::DFTrans::r90); + transform_layout (db::DCplxTrans (db::FTrans::r90)); +} + +void +LayoutViewFunctions::cm_lay_rot_cw () +{ + transform_layout (db::DCplxTrans (db::FTrans::r270)); +} + +void +LayoutViewFunctions::cm_lay_free_rot () +{ + bool ok = false; + QString s = QInputDialog::getText (QApplication::activeWindow (), + QObject::tr ("Free rotation"), + QObject::tr ("Rotation angle in degree (counterclockwise)"), + QLineEdit::Normal, QString::fromUtf8 ("0.0"), + &ok); + + if (ok) { + + double angle = 0.0; + tl::from_string (tl::to_string (s), angle); + + transform_layout (db::DCplxTrans (1.0, angle, false, db::DVector ())); + + } +} + +void +LayoutViewFunctions::cm_lay_scale () +{ + bool ok = false; + QString s = QInputDialog::getText (QApplication::activeWindow (), + QObject::tr ("Scaling"), + QObject::tr ("Scaling factor"), + QLineEdit::Normal, QString::fromUtf8 ("1.0"), + &ok); + + if (ok) { + + double scale = 0.0; + tl::from_string (tl::to_string (s), scale); + + transform_layout (db::DCplxTrans (scale)); + + } +} + +void +LayoutViewFunctions::cm_lay_move () +{ + lay::MoveOptionsDialog options (view ()); + if (options.exec_dialog (m_move_dist)) { + transform_layout (db::DCplxTrans (m_move_dist)); + } +} + +void +LayoutViewFunctions::cm_sel_flip_x () +{ + db::DCplxTrans tr (db::DFTrans::m90); + db::DBox sel_bbox (view ()->lay::Editables::selection_bbox ()); + if (! sel_bbox.empty ()) { + tr = db::DCplxTrans (sel_bbox.center () - db::DPoint ()) * tr * db::DCplxTrans (db::DPoint () - sel_bbox.center ()); + } + do_transform (tr); +} + +void +LayoutViewFunctions::cm_sel_flip_y () +{ + db::DCplxTrans tr (db::DFTrans::m0); + db::DBox sel_bbox (view ()->lay::Editables::selection_bbox ()); + if (! sel_bbox.empty ()) { + tr = db::DCplxTrans (sel_bbox.center () - db::DPoint ()) * tr * db::DCplxTrans (db::DPoint () - sel_bbox.center ()); + } + do_transform (tr); +} + +void +LayoutViewFunctions::cm_sel_rot_ccw () +{ + db::DCplxTrans tr (db::DFTrans::r90); + db::DBox sel_bbox (view ()->lay::Editables::selection_bbox ()); + if (! sel_bbox.empty ()) { + tr = db::DCplxTrans (sel_bbox.center () - db::DPoint ()) * tr * db::DCplxTrans (db::DPoint () - sel_bbox.center ()); + } + do_transform (tr); +} + +void +LayoutViewFunctions::cm_sel_rot_cw () +{ + db::DCplxTrans tr (db::DFTrans::r270); + db::DBox sel_bbox (view ()->lay::Editables::selection_bbox ()); + if (! sel_bbox.empty ()) { + tr = db::DCplxTrans (sel_bbox.center () - db::DPoint ()) * tr * db::DCplxTrans (db::DPoint () - sel_bbox.center ()); + } + do_transform (tr); +} + +void +LayoutViewFunctions::cm_sel_free_rot () +{ + bool ok = false; + QString s = QInputDialog::getText (QApplication::activeWindow (), + QObject::tr ("Free rotation"), + QObject::tr ("Rotation angle in degree (counterclockwise)"), + QLineEdit::Normal, QString::fromUtf8 ("0.0"), + &ok); + + if (ok) { + + double angle = 0.0; + tl::from_string (tl::to_string (s), angle); + + db::DCplxTrans tr = db::DCplxTrans (1.0, angle, false, db::DVector ()); + db::DBox sel_bbox (view ()->lay::Editables::selection_bbox ()); + if (! sel_bbox.empty ()) { + tr = db::DCplxTrans (sel_bbox.center () - db::DPoint ()) * tr * db::DCplxTrans (db::DPoint () - sel_bbox.center ()); + } + do_transform (tr); + + } +} + +void +LayoutViewFunctions::cm_sel_scale () +{ + bool ok = false; + QString s = QInputDialog::getText (QApplication::activeWindow (), + QObject::tr ("Scaling"), + QObject::tr ("Scaling factor"), + QLineEdit::Normal, QString::fromUtf8 ("1.0"), + &ok); + + if (ok) { + + double scale = 0.0; + tl::from_string (tl::to_string (s), scale); + + db::DCplxTrans tr = db::DCplxTrans (scale); + db::DBox sel_bbox (view ()->lay::Editables::selection_bbox ()); + if (! sel_bbox.empty ()) { + tr = db::DCplxTrans (sel_bbox.center () - db::DPoint ()) * tr * db::DCplxTrans (db::DPoint () - sel_bbox.center ()); + } + do_transform (tr); + + } +} + +void +LayoutViewFunctions::cm_sel_move_interactive () +{ + if (view ()->move_service ()->begin_move ()) { + view ()->switch_mode (-1); // move mode + } +} + +void +LayoutViewFunctions::cm_sel_move_to () +{ + db::DBox sel_bbox (view ()->lay::Editables::selection_bbox ()); + if (sel_bbox.empty ()) { + throw tl::Exception (tl::to_string (QObject::tr ("Nothing selected to move"))); + } + + double x = sel_bbox.left () + (sel_bbox.width () * (1 + m_move_to_origin_mode_x) * 0.5); + double y = sel_bbox.bottom () + (sel_bbox.height () * (1 + m_move_to_origin_mode_y) * 0.5); + db::DPoint move_target (x, y); + + lay::MoveToOptionsDialog options (view ()); + if (options.exec_dialog (m_move_to_origin_mode_x, m_move_to_origin_mode_y, move_target)) { + + x = sel_bbox.left () + (sel_bbox.width () * (1 + m_move_to_origin_mode_x) * 0.5); + y = sel_bbox.bottom () + (sel_bbox.height () * (1 + m_move_to_origin_mode_y) * 0.5); + + do_transform (db::DCplxTrans (move_target - db::DPoint (x, y))); + + } +} + +void +LayoutViewFunctions::cm_sel_move () +{ + lay::MoveOptionsDialog options (view ()); + if (options.exec_dialog (m_move_dist)) { + do_transform (db::DCplxTrans (m_move_dist)); + } +} + +void +LayoutViewFunctions::cm_copy_layer () +{ + struct { int *cv; int *layer; } specs [] = { + { &m_copy_cva, &m_copy_layera }, + { &m_copy_cvr, &m_copy_layerr } + }; + + for (unsigned int i = 0; i < sizeof (specs) / sizeof (specs[0]); ++i) { + + int &cv = *(specs[i].cv); + int &layer = *(specs[i].layer); + + if (cv >= int (view ()->cellviews ())) { + cv = -1; + } + + int index = view ()->active_cellview_index (); + if (cv < 0) { + cv = index; + } + + if (cv < 0 || ! view ()->cellview (cv)->layout ().is_valid_layer ((unsigned int) layer)) { + layer = -1; + } + + } + + lay::DuplicateLayerDialog dialog (view ()); + if (dialog.exec_dialog (view (), m_copy_cva, m_copy_layera, m_copy_cvr, m_copy_layerr, m_duplicate_hier_mode, m_clear_before)) { + + bool supports_undo = true; + + if (manager () && manager ()->is_enabled ()) { + + lay::TipDialog td (QApplication::activeWindow (), + tl::to_string (QObject::tr ("Undo buffering for the following operation can be memory and time consuming.\nChoose \"Yes\" to use undo buffering or \"No\" for no undo buffering. Warning: in the latter case, the undo history will be lost.\n\nChoose undo buffering?")), + "copy-layer-undo-buffering", + lay::TipDialog::yesnocancel_buttons); + + lay::TipDialog::button_type button = lay::TipDialog::null_button; + td.exec_dialog (button); + if (button == lay::TipDialog::cancel_button) { + return; + } + + supports_undo = (button == lay::TipDialog::yes_button); + + } else { + supports_undo = false; + } + + view ()->cancel (); + + if (manager ()) { + if (! supports_undo) { + manager ()->clear (); + } else { + manager ()->transaction (tl::to_string (QObject::tr ("Duplicate layer"))); + } + } + + try { + + bool same_layout = (&view ()->cellview (m_copy_cvr)->layout () == &view ()->cellview (m_copy_cva)->layout ()); + if (same_layout && m_copy_layera == m_copy_layerr) { + throw tl::Exception (tl::to_string (QObject::tr ("Source and target layer must not be identical for duplicate operation"))); + } + + if (m_duplicate_hier_mode == 0) { + + // clear the result layer for all called cells in flat mode + if (m_clear_before) { + std::set called_cells; + called_cells.insert (view ()->cellview (m_copy_cvr).cell_index ()); + view ()->cellview (m_copy_cvr).cell ()->collect_called_cells (called_cells); + for (std::set::const_iterator c = called_cells.begin (); c != called_cells.end (); ++c) { + view ()->cellview (m_copy_cvr)->layout ().cell (*c).shapes (m_copy_layerr).clear (); + } + } + + db::Cell &target_cell = *view ()->cellview (m_copy_cvr).cell (); + + if (! same_layout) { + + // flat mode (different layouts) + db::PropertyMapper pm (view ()->cellview (m_copy_cvr)->layout (), view ()->cellview (m_copy_cva)->layout ()); + for (db::RecursiveShapeIterator si (view ()->cellview (m_copy_cva)->layout (), *view ()->cellview (m_copy_cva).cell (), m_copy_layera); ! si.at_end (); ++si) { + target_cell.shapes (m_copy_layerr).insert (*si, si.trans (), pm); + } + + } else { + + // flat mode (same layouts) + tl::ident_map pm1; + db::Shapes &res = target_cell.shapes (m_copy_layerr); + + db::Layout &layout = view ()->cellview (m_copy_cvr)->layout (); + try { + + // using update/start_layout and end_changes improves the performance since changing the + // shapes collection will invalidate the layout and cause updates inside the RecursiveShapeIerator + layout.update (); + layout.start_changes (); + for (db::RecursiveShapeIterator si (view ()->cellview (m_copy_cva)->layout (), *view ()->cellview (m_copy_cva).cell (), m_copy_layera); ! si.at_end (); ++si) { + res.insert (*si, si.trans (), pm1); + } + layout.end_changes (); + + } catch (...) { + layout.end_changes (); + throw; + } + + } + + } else if (m_duplicate_hier_mode == 1) { + + db::Cell &cell = *view ()->cellview (m_copy_cva).cell (); + db::Cell &target_cell = *view ()->cellview (m_copy_cvr).cell (); + + if (m_clear_before) { + target_cell.clear (m_copy_layerr); + } + + if (m_copy_cvr == m_copy_cva) { + + // current cell only mode: identical cell + cell.copy (m_copy_layera, m_copy_layerr); + + } else if (! same_layout) { + + // current cell only mode (different layouts) + db::PropertyMapper pm (view ()->cellview (m_copy_cvr)->layout (), view ()->cellview (m_copy_cva)->layout ()); + for (db::Shapes::shape_iterator si = view ()->cellview (m_copy_cva).cell ()->shapes (m_copy_layera).begin (db::ShapeIterator::All); ! si.at_end (); ++si) { + target_cell.shapes (m_copy_layerr).insert (*si, pm); + } + + } else { + + // current cell only mode (same layouts, but different cells) + for (db::Shapes::shape_iterator si = view ()->cellview (m_copy_cva).cell ()->shapes (m_copy_layera).begin (db::ShapeIterator::All); ! si.at_end (); ++si) { + target_cell.shapes (m_copy_layerr).insert (*si); + } + + } + + } else if (m_duplicate_hier_mode == 2) { + + // subcells cell by cell - source and target layout must be identical + std::set called_cells; + view ()->cellview (m_copy_cva).cell ()->collect_called_cells (called_cells); + called_cells.insert (view ()->cellview (m_copy_cva).cell_index ()); + + db::Layout &layout = view ()->cellview (m_copy_cva)->layout (); + for (std::set::const_iterator c = called_cells.begin (); c != called_cells.end (); ++c) { + db::Cell &cell = layout.cell (*c); + if (m_clear_before) { + cell.clear (m_copy_layerr); + } + cell.copy (m_copy_layera, m_copy_layerr); + } + + } + + if (manager () && supports_undo) { + manager ()->commit (); + } + + } catch (...) { + if (manager () && supports_undo) { + manager ()->commit (); + } + throw; + } + + } +} + +void +LayoutViewFunctions::cm_new_layer () +{ + int index = view ()->active_cellview_index (); + + if (index >= 0 && int (view ()->cellviews ()) > index) { + + const lay::CellView &cv = view ()->cellview (index); + + lay::NewLayerPropertiesDialog prop_dia (view ()); + if (prop_dia.exec_dialog (cv, m_new_layer_props)) { + + for (unsigned int l = 0; l < cv->layout ().layers (); ++l) { + if (cv->layout ().is_valid_layer (l) && cv->layout ().get_properties (l).log_equal (m_new_layer_props)) { + throw tl::Exception (tl::to_string (QObject::tr ("A layer with that signature already exists: ")) + m_new_layer_props.to_string ()); + } + } + + view ()->transaction (tl::to_string (QObject::tr ("New layer"))); + + unsigned int l = cv->layout ().insert_layer (m_new_layer_props); + std::vector nl; + nl.push_back (l); + view ()->add_new_layers (nl, index); + view ()->update_content (); + + view ()->commit (); + + } + + } +} + +void +LayoutViewFunctions::cm_align_cell_origin () +{ + int cv_index = view ()->active_cellview_index (); + if (cv_index >= 0) { + + const db::Cell *cell = view ()->cellview (cv_index).cell (); + if (! cell) { + return; + } + if (cell->is_proxy ()) { + throw tl::Exception (tl::to_string (QObject::tr ("Cannot use this function on a PCell or library cell"))); + } + + lay::AlignCellOptionsDialog dialog (view ()); + if (dialog.exec_dialog (m_align_cell_options)) { + + view ()->clear_selection (); + + view ()->transaction (tl::to_string (QObject::tr ("Align cell origin"))); + + db::Box bbox; + + if (m_align_cell_options.visible_only) { + for (lay::LayerPropertiesConstIterator l = view ()->begin_layers (); !l.at_end (); ++l) { + if (! l->has_children () && l->layer_index () >= 0 && l->cellview_index () == cv_index && l->visible (true /*real*/)) { + bbox += cell->bbox (l->layer_index ()); + } + } + } else { + bbox = cell->bbox (); + } + + db::Coord refx, refy; + switch (m_align_cell_options.mode_x) { + case -1: + refx = bbox.left (); + break; + case 1: + refx = bbox.right (); + break; + default: + refx = bbox.center ().x (); + break; + } + switch (m_align_cell_options.mode_y) { + case -1: + refy = bbox.bottom (); + break; + case 1: + refy = bbox.top (); + break; + default: + refy = bbox.center ().y (); + break; + } + + db::Layout &layout = view ()->cellview (cv_index)->layout (); + db::Cell &nc_cell = layout.cell (cell->cell_index ()); + + db::Trans t (db::Vector (-refx + db::coord_traits::rounded (m_align_cell_options.xpos / layout.dbu ()), -refy + db::coord_traits::rounded (m_align_cell_options.ypos / layout.dbu ()))); + + for (unsigned int i = 0; i < layout.layers (); ++i) { + if (layout.is_valid_layer (i)) { + db::Shapes &shapes = nc_cell.shapes (i); + for (db::Shapes::shape_iterator s = shapes.begin (db::ShapeIterator::All); ! s.at_end (); ++s) { + shapes.transform (*s, t); + } + } + } + + for (db::Cell::const_iterator inst = nc_cell.begin (); ! inst.at_end (); ++inst) { + nc_cell.transform (*inst, t); + } + + if (m_align_cell_options.adjust_parents) { + + std::vector > insts_to_modify; + for (db::Cell::parent_inst_iterator pi = nc_cell.begin_parent_insts (); ! pi.at_end (); ++pi) { + insts_to_modify.push_back (std::make_pair (& layout.cell (pi->parent_cell_index ()), pi->child_inst ())); + } + + db::Trans ti (db::Vector (refx, refy)); + for (std::vector >::const_iterator im = insts_to_modify.begin (); im != insts_to_modify.end (); ++im) { + im->first->transform (im->second, db::Trans (db::Vector (im->second.complex_trans ().trans (db::Vector (refx, refy))))); + } + + } + + view ()->commit (); + + } + + } +} + +void +LayoutViewFunctions::cm_edit_layer () +{ + lay::LayerPropertiesConstIterator sel = view ()->current_layer (); + if (sel.is_null ()) { + throw tl::Exception (tl::to_string (QObject::tr ("No layer selected for editing it's properties"))); + } + + int index = sel->cellview_index (); + if (sel->has_children () || index < 0 || int (view ()->cellviews ()) <= index || sel->layer_index () < 0) { + throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected for editing it's properties"))); + } + + const lay::CellView &cv = view ()->cellview (index); + + db::LayerProperties layer_props = cv->layout ().get_properties ((unsigned int) sel->layer_index ()); + + lay::NewLayerPropertiesDialog prop_dia (view ()); + if (prop_dia.exec_dialog (cv, layer_props)) { + + for (unsigned int l = 0; l < cv->layout ().layers (); ++l) { + if (cv->layout ().is_valid_layer (l) && int (l) != sel->layer_index () && cv->layout ().get_properties (l).log_equal (layer_props)) { + throw tl::Exception (tl::to_string (QObject::tr ("A layer with that signature already exists: ")) + layer_props.to_string ()); + } + } + + view ()->transaction (tl::to_string (QObject::tr ("Edit layer"))); + + cv->layout ().set_properties (sel->layer_index (), layer_props); + + lay::LayerProperties lp (*sel); + lay::ParsedLayerSource s = lp.source (false); + s.layer (layer_props.layer); + s.datatype (layer_props.datatype); + if (! layer_props.name.empty ()) { + s.name (layer_props.name); + } else { + s.clear_name (); + } + lp.set_source (s); + view ()->set_properties (sel, lp); + + view ()->update_content (); + + view ()->commit (); + + } +} + +void +LayoutViewFunctions::cm_delete_layer () +{ + std::vector sel = view ()->selected_layers (); + std::sort (sel.begin (), sel.end (), CompareLayerIteratorBottomUp ()); + + // collect valid layers + std::vector valid_sel; + std::set > valid_layers; + for (std::vector::const_iterator si = sel.begin (); si != sel.end (); ++si) { + int cv_index = (*si)->cellview_index (); + const lay::CellView &cv = view ()->cellview (cv_index); + if (!(*si)->has_children () && cv_index >= 0 && int (view ()->cellviews ()) > cv_index && (*si)->layer_index () >= 0 && cv.is_valid ()) { + valid_sel.push_back (*si); + valid_layers.insert (std::make_pair (&cv->layout (), (*si)->layer_index ())); + } + } + + if (valid_sel.empty ()) { + throw tl::Exception (tl::to_string (QObject::tr ("No or no valid layer selected for deleting them"))); + } + + view ()->cancel_edits (); + view ()->clear_selection (); + + view ()->transaction (tl::to_string (QObject::tr ("Delete layers"))); + + // Hint: delete_layer must come before the layers are actually deleted in because + // for undo this must be the last thing to do (otherwise the layout is not propertly set up) + + for (std::vector::const_iterator si = valid_sel.begin (); si != valid_sel.end (); ++si) { + lay::LayerPropertiesConstIterator lp = *si; + view ()->delete_layer (lp); + } + + for (std::set >::const_iterator li = valid_layers.begin (); li != valid_layers.end(); ++li) { + + unsigned int layer_index = li->second; + db::Layout *layout = li->first; + + for (db::Layout::iterator c = layout->begin (); c != layout->end (); ++c) { + c->shapes (layer_index).clear (); + } + + layout->delete_layer (layer_index); + + } + + view ()->update_content (); + + view ()->commit (); +} + +void +LayoutViewFunctions::cm_clear_layer () +{ + std::vector sel = view ()->selected_layers (); + if (sel.empty ()) { + throw tl::Exception (tl::to_string (QObject::tr ("No layer selected for clearing"))); + } + + lay::ClearLayerModeDialog mode_dialog (view ()); + if (mode_dialog.exec_dialog (m_layer_hier_mode)) { + + view ()->cancel_edits (); + view ()->clear_selection (); + + view ()->transaction (tl::to_string (QObject::tr ("Clear layer"))); + + for (std::vector::const_iterator si = sel.begin (); si != sel.end (); ++si) { + + if (! (*si)->has_children () && (*si)->layer_index () >= 0 && view ()->cellview ((*si)->cellview_index ()).is_valid ()) { + + int layer_index = (*si)->layer_index (); + const lay::CellView &cv = view ()->cellview ((*si)->cellview_index ()); + + if (m_layer_hier_mode == 0) { + cv.cell ()->clear ((unsigned int) layer_index); + } else if (m_layer_hier_mode == 1) { + + cv.cell ()->clear ((unsigned int) layer_index); + + std::set called_cells; + cv.cell ()->collect_called_cells (called_cells); + for (std::set ::const_iterator cc = called_cells.begin (); cc != called_cells.end (); ++cc) { + cv->layout ().cell (*cc).clear ((unsigned int) layer_index); + } + + } else { + cv->layout ().clear_layer ((unsigned int) layer_index); + } + + } + + } + + view ()->commit (); + + } +} + +// ------------------------------------------------------------ +// Declaration of the "plugin" for the menu entries + +class LayoutViewPluginDeclaration + : public lay::PluginDeclaration +{ +public: + virtual void get_menu_entries (std::vector &menu_entries) const + { + std::string at; + + // secret menu entries + at = "@secrets.end"; + menu_entries.push_back (lay::menu_item ("cm_paste_interactive", "paste_interactive:edit", at, tl::to_string (QObject::tr ("Paste Interactive")))); + menu_entries.push_back (lay::menu_item ("cm_duplicate_interactive", "duplicate_interactive:edit", at, tl::to_string (QObject::tr ("Duplicate Interactive")))); + menu_entries.push_back (lay::menu_item ("cm_sel_move_interactive", "sel_move_interactive:edit", at, tl::to_string (QObject::tr ("Move Interactive")))); + + at = "edit_menu.end"; + menu_entries.push_back (lay::menu_item ("cm_undo", "undo:edit", at, tl::to_string (QObject::tr ("Undo(Ctrl+Z)")))); + menu_entries.push_back (lay::menu_item ("cm_redo", "redo:edit", at, tl::to_string (QObject::tr ("Redo(Ctrl+Y)")))); + + menu_entries.push_back (lay::separator ("basic_group", at)); + menu_entries.push_back (lay::submenu ("layout_menu:edit:edit_mode", at, tl::to_string (QObject::tr ("Layout")))); + { + std::string at = "edit_menu.layout_menu.end"; + menu_entries.push_back (lay::menu_item ("cm_lay_flip_x", "lay_flip_x:edit_mode", at, tl::to_string (QObject::tr ("Flip Horizontally")))); + menu_entries.push_back (lay::menu_item ("cm_lay_flip_y", "lay_flip_y:edit_mode", at, tl::to_string (QObject::tr ("Flip Vertically")))); + menu_entries.push_back (lay::menu_item ("cm_lay_rot_cw", "lay_rot_cw:edit_mode", at, tl::to_string (QObject::tr ("Rotate Clockwise")))); + menu_entries.push_back (lay::menu_item ("cm_lay_rot_ccw", "lay_rot_ccw:edit_mode", at, tl::to_string (QObject::tr ("Rotate Counterclockwise")))); + menu_entries.push_back (lay::menu_item ("cm_lay_free_rot", "lay_free_rot:edit_mode", at, tl::to_string (QObject::tr ("Rotation By Angle")))); + menu_entries.push_back (lay::menu_item ("cm_lay_scale", "lay_scale:edit_mode", at, tl::to_string (QObject::tr ("Scale")))); + menu_entries.push_back (lay::menu_item ("cm_lay_move", "lay_move:edit_mode", at, tl::to_string (QObject::tr ("Move By")))); + menu_entries.push_back (lay::separator ("cellop_group", at)); + menu_entries.push_back (lay::menu_item ("cm_lay_convert_to_static", "lay_convert_to_static:edit_mode", at, tl::to_string (QObject::tr ("Convert All Cells To Static")))); + } + + menu_entries.push_back (lay::submenu ("cell_menu:edit:edit_mode", at, tl::to_string (QObject::tr ("Cell")))); + { + std::string at = "edit_menu.cell_menu.end"; + menu_entries.push_back (lay::menu_item ("cm_new_cell", "new_cell:edit:edit_mode", at, tl::to_string (QObject::tr ("New Cell")))); + menu_entries.push_back (lay::menu_item ("cm_cell_delete", "delete_cell:edit:edit_mode", at, tl::to_string (QObject::tr ("Delete Cell")))); + menu_entries.push_back (lay::menu_item ("cm_cell_rename", "rename_cell:edit:edit_mode", at, tl::to_string (QObject::tr ("Rename Cell")))); + menu_entries.push_back (lay::menu_item ("cm_cell_replace", "replace_cell:edit:edit_mode", at, tl::to_string (QObject::tr ("Replace Cell")))); + menu_entries.push_back (lay::menu_item ("cm_cell_flatten", "flatten_cell:edit:edit_mode", at, tl::to_string (QObject::tr ("Flatten Cell")))); + menu_entries.push_back (lay::separator ("ops_group", at)); + menu_entries.push_back (lay::menu_item ("cm_adjust_origin", "adjust_cell_origin:edit:edit_mode", at, tl::to_string (QObject::tr ("Adjust Origin")))); + menu_entries.push_back (lay::menu_item ("cm_cell_convert_to_static", "convert_cell_to_static:edit_mode", at, tl::to_string (QObject::tr ("Convert Cell To Static")))); + menu_entries.push_back (lay::separator ("props_group", at)); + menu_entries.push_back (lay::menu_item ("cm_cell_user_properties", "user_properties", at, tl::to_string (QObject::tr ("User Properties")))); + } + + menu_entries.push_back (lay::submenu ("layer_menu:edit:edit_mode", at, tl::to_string (QObject::tr ("Layer")))); + { + std::string at = "edit_menu.layer_menu.end"; + menu_entries.push_back (lay::menu_item ("cm_new_layer", "new_layer:edit:edit_mode", at, tl::to_string (QObject::tr ("New Layer")))); + menu_entries.push_back (lay::menu_item ("cm_clear_layer", "clear_layer:edit:edit_mode", at, tl::to_string (QObject::tr ("Clear Layer")))); + menu_entries.push_back (lay::menu_item ("cm_delete_layer", "delete_layer:edit:edit_mode", at, tl::to_string (QObject::tr ("Delete Layer")))); + menu_entries.push_back (lay::menu_item ("cm_copy_layer", "copy_layer:edit:edit_mode", at, tl::to_string (QObject::tr ("Copy Layer")))); + menu_entries.push_back (lay::menu_item ("cm_edit_layer", "edit_layer:edit:edit_mode", at, tl::to_string (QObject::tr ("Edit Layer Specification")))); + } + + menu_entries.push_back (lay::submenu ("selection_menu:edit", at, tl::to_string (QObject::tr ("Selection")))); + { + std::string at = "edit_menu.selection_menu.end"; + menu_entries.push_back (lay::menu_item ("cm_sel_flip_x", "sel_flip_x", at, tl::to_string (QObject::tr ("Flip Horizontally")))); + menu_entries.push_back (lay::menu_item ("cm_sel_flip_y", "sel_flip_y", at, tl::to_string (QObject::tr ("Flip Vertically")))); + menu_entries.push_back (lay::menu_item ("cm_sel_rot_cw", "sel_rot_cw", at, tl::to_string (QObject::tr ("Rotate Clockwise")))); + menu_entries.push_back (lay::menu_item ("cm_sel_rot_ccw", "sel_rot_ccw", at, tl::to_string (QObject::tr ("Rotate Counterclockwise")))); + menu_entries.push_back (lay::menu_item ("cm_sel_free_rot", "sel_free_rot", at, tl::to_string (QObject::tr ("Rotation By Angle")))); + menu_entries.push_back (lay::menu_item ("cm_sel_scale", "sel_scale", at, tl::to_string (QObject::tr ("Scale")))); + menu_entries.push_back (lay::menu_item ("cm_sel_move", "sel_move", at, tl::to_string (QObject::tr ("Move By")))); + menu_entries.push_back (lay::menu_item ("cm_sel_move_to", "sel_move_to", at, tl::to_string (QObject::tr ("Move To")))); + } + + menu_entries.push_back (lay::separator ("utils_group", at)); + menu_entries.push_back (lay::submenu ("utils_menu:edit:edit_mode", at, tl::to_string (QObject::tr ("Utilities")))); + + menu_entries.push_back (lay::separator ("misc_group", at)); + menu_entries.push_back (lay::menu_item ("cm_delete", "delete:edit", at, tl::to_string (QObject::tr ("Delete(Del)")))); + menu_entries.push_back (lay::menu_item ("cm_show_properties", "show_properties:edit", at, tl::to_string (QObject::tr ("Properties(Q)")))); + + menu_entries.push_back (lay::separator ("cpc_group", at)); + menu_entries.push_back (lay::menu_item ("cm_copy", "copy:edit", at, tl::to_string (QObject::tr ("Copy(Ctrl+C)")))); + menu_entries.push_back (lay::menu_item ("cm_cut", "cut:edit", at, tl::to_string (QObject::tr ("Cut(Ctrl+X)")))); + menu_entries.push_back (lay::menu_item ("cm_paste", "paste:edit", at, tl::to_string (QObject::tr ("Paste(Ctrl+V)")))); + menu_entries.push_back (lay::menu_item ("cm_duplicate", "duplicate:edit", at, tl::to_string (QObject::tr ("Duplicate(Ctrl+B)")))); + + menu_entries.push_back (lay::separator ("modes_group", at)); + menu_entries.push_back (lay::submenu ("mode_menu", at, tl::to_string (QObject::tr ("Mode")))); + + menu_entries.push_back (lay::submenu ("select_menu", at, tl::to_string (QObject::tr ("Select")))); + { + std::string at = "edit_menu.select_menu.end"; + menu_entries.push_back (lay::menu_item ("cm_select_all", "select_all", at, tl::to_string (QObject::tr ("Select All")))); + menu_entries.push_back (lay::menu_item ("cm_unselect_all", "unselect_all", at, tl::to_string (QObject::tr ("Unselect All")))); + menu_entries.push_back (lay::separator ("edit_select_basic_group", at)); + menu_entries.push_back (lay::menu_item ("lv:enable_all", "enable_all", at, tl::to_string (QObject::tr ("Enable All")))); + menu_entries.push_back (lay::menu_item ("lv:disable_all", "disable_all", at, tl::to_string (QObject::tr ("Disable All")))); + menu_entries.push_back (lay::separator ("edit_select_individual_group", at)); + }; + + menu_entries.push_back (lay::separator ("cancel_group", at)); + menu_entries.push_back (lay::menu_item ("cm_cancel", "cancel", at, tl::to_string (QObject::tr ("Cancel(Esc)")))); + + at = "bookmark_menu.end"; + menu_entries.push_back (lay::submenu ("goto_bookmark_menu", at, tl::to_string (QObject::tr ("Goto Bookmark")))); + menu_entries.push_back (lay::menu_item ("cm_bookmark_view", "bookmark_view", at, tl::to_string (QObject::tr ("Bookmark This View")))); + + menu_entries.push_back (lay::separator ("bookmark_mgm_group", at)); + menu_entries.push_back (lay::menu_item ("cm_manage_bookmarks", "manage_bookmarks", at, tl::to_string (QObject::tr ("Manage Bookmarks")))); + menu_entries.push_back (lay::menu_item ("cm_load_bookmarks", "load_bookmarks", at, tl::to_string (QObject::tr ("Load Bookmarks")))); + menu_entries.push_back (lay::menu_item ("cm_save_bookmarks", "save_bookmarks", at, tl::to_string (QObject::tr ("Save Bookmarks")))); + + at = "zoom_menu.end"; + menu_entries.push_back (lay::submenu ("global_trans", at, tl::to_string (QObject::tr ("Global Transformation")))); + { + std::string at = "zoom_menu.global_trans.end"; + menu_entries.push_back (lay::config_menu_item ("r0", at, tl::to_string (QObject::tr ("\\(r0\\)<:/r0.png>")), cfg_global_trans, "?r0 *1 0,0")); + menu_entries.push_back (lay::config_menu_item ("r90", at, tl::to_string (QObject::tr ("\\(r90\\)<:/r90.png>")), cfg_global_trans, "?r90 *1 0,0")); + menu_entries.push_back (lay::config_menu_item ("r180", at, tl::to_string (QObject::tr ("\\(r180\\)<:/r180.png>")), cfg_global_trans, "?r180 *1 0,0")); + menu_entries.push_back (lay::config_menu_item ("r270", at, tl::to_string (QObject::tr ("\\(r270\\)<:/r270.png>")), cfg_global_trans, "?r270 *1 0,0")); + menu_entries.push_back (lay::config_menu_item ("m0", at, tl::to_string (QObject::tr ("\\(m0\\)<:/m0.png>")), cfg_global_trans, "?m0 *1 0,0")); + menu_entries.push_back (lay::config_menu_item ("m45", at, tl::to_string (QObject::tr ("\\(m45\\)<:/m45.png>")), cfg_global_trans, "?m45 *1 0,0")); + menu_entries.push_back (lay::config_menu_item ("m90", at, tl::to_string (QObject::tr ("\\(m90\\)<:/m90.png>")), cfg_global_trans, "?m90 *1 0,0")); + menu_entries.push_back (lay::config_menu_item ("m135", at, tl::to_string (QObject::tr ("\\(m135\\)<:/m135.png>")), cfg_global_trans, "?m135 *1 0,0")); + } + + menu_entries.push_back (lay::separator ("hier_group", at)); + menu_entries.push_back (lay::menu_item ("cm_max_hier", "max_hier", at, tl::to_string (QObject::tr ("Full Hierarchy(*)")))); + menu_entries.push_back (lay::menu_item ("cm_max_hier_0", "max_hier_0", at, tl::to_string (QObject::tr ("Box Only(0)")))); + menu_entries.push_back (lay::menu_item ("cm_max_hier_1", "max_hier_1", at, tl::to_string (QObject::tr ("Top Level Only(1)")))); + menu_entries.push_back (lay::menu_item ("cm_inc_max_hier", "inc_max_hier", at, tl::to_string (QObject::tr ("Increment Hierarchy(+)")))); + menu_entries.push_back (lay::menu_item ("cm_dec_max_hier", "dec_max_hier", at, tl::to_string (QObject::tr ("Decrement Hierarchy(-)")))); + + menu_entries.push_back (lay::separator ("zoom_group", at)); + menu_entries.push_back (lay::menu_item ("cm_zoom_fit", "zoom_fit", at, tl::to_string (QObject::tr ("Zoom Fit(F2)")))); + menu_entries.push_back (lay::menu_item ("cm_zoom_fit_sel", "zoom_fit_sel", at, tl::to_string (QObject::tr ("Zoom Fit Selection(Shift+F2)")))); + menu_entries.push_back (lay::menu_item ("cm_zoom_in", "zoom_in", at, tl::to_string (QObject::tr ("Zoom In(Return)")))); + menu_entries.push_back (lay::menu_item ("cm_zoom_out", "zoom_out", at, tl::to_string (QObject::tr ("Zoom Out(Shift+Return)")))); + /* disabled because that interferes with the use of the arrow keys for moving the selection + MenuLayoutEntry::separator ("pan_group"); + menu_entries.push_back (lay::menu_item ("cm_pan_up", "pan_up", at, tl::to_string (QObject::tr ("Pan Up(Up)")))); + menu_entries.push_back (lay::menu_item ("cm_pan_down", "pan_down", at, tl::to_string (QObject::tr ("Pan Down(Down)")))); + menu_entries.push_back (lay::menu_item ("cm_pan_left", "pan_left", at, tl::to_string (QObject::tr ("Pan Left(Left)")))); + menu_entries.push_back (lay::menu_item ("cm_pan_right", "pan_right", at, tl::to_string (QObject::tr ("Pan Right(Right)")))); + */ + + menu_entries.push_back (lay::separator ("redraw_group", at)); + menu_entries.push_back (lay::menu_item ("cm_redraw", "redraw", at, tl::to_string (QObject::tr ("Redraw")))); + menu_entries.push_back (lay::separator ("state_group", at)); + menu_entries.push_back (lay::menu_item_copy ("cm_prev_display_state", "prev_display_state", at, "@toolbar.prev_display_state")); + menu_entries.push_back (lay::menu_item_copy ("cm_next_display_state", "next_display_state", at, "@toolbar.next_display_state")); + + menu_entries.push_back (lay::separator ("select_group", at)); + menu_entries.push_back (lay::menu_item ("cm_select_cell", "select_cell:edit", at, tl::to_string (QObject::tr ("Select Cell")))); + menu_entries.push_back (lay::menu_item ("cm_select_current_cell", "select_current_cell", at, tl::to_string (QObject::tr ("Show As New Top(Ctrl+S)")))); + menu_entries.push_back (lay::menu_item ("cm_goto_position", "goto_position", at, tl::to_string (QObject::tr ("Goto Position(Ctrl+G)")))); + + // Add a hook for inserting new items after the modes + menu_entries.push_back (lay::separator ("end_modes", "@toolbar.end")); + + } + + bool menu_activated (const std::string &symbol) const + { + if (symbol == "lv:enable_all") { + + for (tl::Registrar::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) { + cls->set_editable_enabled (true); + } + return true; + + } else if (symbol == "lv:disable_all") { + + for (tl::Registrar::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) { + cls->set_editable_enabled (false); + } + return true; + + } else { + return false; + } + } + + void implements_primary_mouse_modes (std::vector > > &modes) + { + std::vector mode_titles; + lay::LayoutView::intrinsic_mouse_modes (&mode_titles); + + int mode_id = 0; + for (std::vector ::const_iterator t = mode_titles.begin (); t != mode_titles.end (); ++t, --mode_id) { + // modes: pair(title, pair(insert_pos, id)) + modes.push_back (std::make_pair (*t, std::make_pair ("edit_menu.mode_menu.end;@toolbar.end_modes", mode_id))); + } + } + + lay::Plugin *create_plugin (db::Manager *manager, Dispatcher *, LayoutView *view) const + { + return new LayoutViewFunctions (manager, view); + } +}; + +static tl::RegisteredClass config_decl (new LayoutViewPluginDeclaration (), -10, "LayoutViewPlugin"); + +} // namespace lay diff --git a/src/laybasic/laybasic/layLayoutViewFunctions.h b/src/laybasic/laybasic/layLayoutViewFunctions.h new file mode 100644 index 000000000..15b2f3f56 --- /dev/null +++ b/src/laybasic/laybasic/layLayoutViewFunctions.h @@ -0,0 +1,171 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_layLayoutViewFunctions +#define HDR_layLayoutViewFunctions + +#include "laybasicCommon.h" + +#include "layPlugin.h" +#include "layDialogs.h" // For AlignCellOptions + +#include "dbTrans.h" +#include "dbLayerProperties.h" + +namespace lay { + +class LayoutView; + +/** + * @brief The layout view's functions implementation + */ +class LAYBASIC_PUBLIC LayoutViewFunctions + : public lay::Plugin +{ +public: + /** + * @brief Constructor + */ + LayoutViewFunctions (db::Manager *manager, lay::LayoutView *view); + + /** + * @brief Destructor + */ + ~LayoutViewFunctions (); + + // Plugin interface implementation + void menu_activated (const std::string &symbol); + + // menu callbacks + void cm_new_layer (); + void cm_clear_layer (); + void cm_delete_layer (); + void cm_copy_layer (); + void cm_align_cell_origin (); + void cm_edit_layer (); + void cm_lay_convert_to_static (); + void cm_lay_flip_x (); + void cm_lay_flip_y (); + void cm_lay_rot_cw (); + void cm_lay_rot_ccw (); + void cm_lay_free_rot (); + void cm_lay_scale (); + void cm_lay_move (); + void cm_sel_flip_x (); + void cm_sel_flip_y (); + void cm_sel_rot_cw (); + void cm_sel_rot_ccw (); + void cm_sel_free_rot (); + 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 (); + void cm_rename_tab (); + void cm_remove_tab (); + void cm_select_all (); + void cm_make_valid (); + void cm_make_invalid (); + void cm_hide (); + void cm_hide_all (); + void cm_show (); + void cm_show_all (); + void cm_show_only (); + void cm_rename (); + void cm_delete (); + void cm_insert (); + void cm_group (); + void cm_ungroup (); + void cm_source (); + void cm_sort_by_name (); + void cm_sort_by_ild (); + void cm_sort_by_idl (); + void cm_sort_by_ldi (); + void cm_sort_by_dli (); + void cm_regroup_by_index (); + void cm_regroup_by_datatype (); + void cm_regroup_by_layer (); + void cm_regroup_flatten (); + void cm_expand_all (); + void cm_add_missing (); + void cm_remove_unused (); + void cm_layer_copy (); + void cm_layer_cut (); + void cm_layer_paste (); + + // forwarded to the cell control panel + void cm_cell_user_properties (); + void cm_cell_flatten (); + void cm_cell_rename (); + void cm_cell_replace (); + void cm_cell_delete (); + void cm_cell_select (); + void cm_open_current_cell (); + void cm_cell_hide (); + void cm_cell_show (); + void cm_cell_show_all (); + void cm_cell_copy (); + void cm_cell_cut (); + void cm_cell_paste (); + void cm_cell_convert_to_static (); + +protected: + lay::LayoutView *view () + { + return mp_view; + } + + db::Manager *manager () + { + return mp_manager; + } + + void do_cm_duplicate (bool interactive); + void do_cm_paste (bool interactive); + void cm_new_cell (); + void cm_reload (); + + void do_transform (const db::DCplxTrans &tr); + void transform_layout (const db::DCplxTrans &tr); + +private: + lay::LayoutView *mp_view; + db::Manager *mp_manager; + db::LayerProperties m_new_layer_props; + db::DVector m_move_dist; + int m_move_to_origin_mode_x, m_move_to_origin_mode_y; + lay::AlignCellOptions m_align_cell_options; + int m_del_cell_mode; + int m_layer_hier_mode; + int m_duplicate_hier_mode; + bool m_clear_before; + int m_copy_cva, m_copy_cvr; + int m_copy_layera, m_copy_layerr; +}; + +} + +#endif + diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro index 2e3e2b4c3..95d6f4f00 100644 --- a/src/laybasic/laybasic/laybasic.pro +++ b/src/laybasic/laybasic/laybasic.pro @@ -184,7 +184,8 @@ SOURCES = \ layDispatcher.cc \ laySelectCellViewForm.cc \ layLayoutStatisticsForm.cc \ - gsiDeclLayNetlistBrowserDialog.cc + gsiDeclLayNetlistBrowserDialog.cc \ + layLayoutViewFunctions.cc HEADERS = \ gtf.h \ @@ -285,7 +286,8 @@ HEADERS = \ layGenericSyntaxHighlighter.h \ layDispatcher.h \ laySelectCellViewForm.h \ - layLayoutStatisticsForm.h + layLayoutStatisticsForm.h \ + layLayoutViewFunctions.h INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LYM_INC DEPENDPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LYM_INC