2017-02-12 13:21:08 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
KLayout Layout Viewer
|
2017-02-12 15:28:14 +01:00
|
|
|
Copyright (C) 2006-2017 Matthias Koefferlein
|
2017-02-12 13:21:08 +01:00
|
|
|
|
|
|
|
|
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 "layClipDialog.h"
|
|
|
|
|
|
|
|
|
|
#include "dbClip.h"
|
|
|
|
|
#include "antService.h"
|
|
|
|
|
#include "tlException.h"
|
|
|
|
|
#include "tlString.h"
|
|
|
|
|
#include "tlExceptions.h"
|
|
|
|
|
|
|
|
|
|
namespace lay
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------
|
|
|
|
|
// Declaration of the configuration options
|
|
|
|
|
|
|
|
|
|
class ClipDialogPluginDeclaration
|
|
|
|
|
: public lay::PluginDeclaration
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual void get_options (std::vector < std::pair<std::string, std::string> > & /*options*/) const
|
|
|
|
|
{
|
|
|
|
|
// .. no options yet ..
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual lay::ConfigPage *config_page (QWidget * /*parent*/, std::string & /*title*/) const
|
|
|
|
|
{
|
|
|
|
|
return 0; // .. no config page yet ..
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void get_menu_entries (std::vector<lay::MenuEntry> &menu_entries) const
|
|
|
|
|
{
|
|
|
|
|
lay::PluginDeclaration::get_menu_entries (menu_entries);
|
|
|
|
|
menu_entries.push_back (lay::MenuEntry ("clip_tool::show", "clip_tool:edit_mode", "edit_menu.utils_menu.end", tl::to_string (QObject::tr ("Clip Tool"))));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual lay::Plugin *create_plugin (db::Manager *, lay::PluginRoot *root, lay::LayoutView *view) const
|
|
|
|
|
{
|
|
|
|
|
return new ClipDialog (root, view);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new ClipDialogPluginDeclaration (), 20000, "ClipDialogPlugin");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
ClipDialog::ClipDialog (lay::PluginRoot *root, lay::LayoutView *vw)
|
|
|
|
|
: lay::Browser (root, vw),
|
|
|
|
|
Ui::ClipDialog ()
|
|
|
|
|
{
|
|
|
|
|
Ui::ClipDialog::setupUi (this);
|
|
|
|
|
|
|
|
|
|
connect (rb_box1, SIGNAL (clicked ()), this, SLOT (box1_clicked ()));
|
|
|
|
|
connect (rb_box2, SIGNAL (clicked ()), this, SLOT (box2_clicked ()));
|
|
|
|
|
connect (rb_rulers, SIGNAL (clicked ()), this, SLOT (rulers_clicked ()));
|
|
|
|
|
connect (rb_shapes, SIGNAL (clicked ()), this, SLOT (shapes_clicked ()));
|
|
|
|
|
connect (button_box, SIGNAL (accepted ()), this, SLOT (ok_pressed ()));
|
|
|
|
|
|
|
|
|
|
box1_clicked ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ClipDialog::menu_activated (const std::string &symbol)
|
|
|
|
|
{
|
|
|
|
|
if (symbol == "clip_tool::show") {
|
|
|
|
|
|
|
|
|
|
lay::CellView cv = view ()->cellview (view ()->active_cellview_index ());
|
|
|
|
|
if (cv.is_valid ()) {
|
|
|
|
|
cb_layer->set_layout (&cv->layout ());
|
|
|
|
|
show ();
|
|
|
|
|
activate ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
lay::Browser::menu_activated (symbol);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClipDialog::~ClipDialog ()
|
|
|
|
|
{
|
|
|
|
|
// .. nothing yet ..
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ClipDialog::ok_pressed ()
|
|
|
|
|
{
|
|
|
|
|
BEGIN_PROTECTED
|
|
|
|
|
|
|
|
|
|
std::string clip_cell_name (tl::to_string (le_cell_name->text ()));
|
|
|
|
|
if (clip_cell_name.empty ()) {
|
|
|
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Clip cell name must not be empty")));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector <db::Box> clip_boxes;
|
|
|
|
|
lay::CellView cv = view ()->cellview (view ()->active_cellview_index ());
|
|
|
|
|
|
|
|
|
|
if (rb_box1->isChecked ()) {
|
|
|
|
|
|
|
|
|
|
if (le_x1->text ().isEmpty () || le_x2->text ().isEmpty () ||
|
|
|
|
|
le_y1->text ().isEmpty () || le_y2->text ().isEmpty ()) {
|
|
|
|
|
throw tl::Exception (tl::to_string (QObject::tr ("All four coordinates of the clip box must be given")));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double x1 = 0.0, y1 = 0.0;
|
|
|
|
|
double x2 = 0.0, y2 = 0.0;
|
|
|
|
|
tl::from_string (tl::to_string (le_x1->text ()), x1);
|
|
|
|
|
tl::from_string (tl::to_string (le_x2->text ()), x2);
|
|
|
|
|
tl::from_string (tl::to_string (le_y1->text ()), y1);
|
|
|
|
|
tl::from_string (tl::to_string (le_y2->text ()), y2);
|
|
|
|
|
|
|
|
|
|
clip_boxes.push_back (db::Box (db::DBox (db::DPoint (x1, y1), db::DPoint (x2, y2)) * (1.0 / cv->layout ().dbu ())));
|
|
|
|
|
|
|
|
|
|
} else if (rb_box2->isChecked ()) {
|
|
|
|
|
|
|
|
|
|
if (le_x->text ().isEmpty () || le_y->text ().isEmpty () ||
|
|
|
|
|
le_w->text ().isEmpty () || le_h->text ().isEmpty ()) {
|
|
|
|
|
throw tl::Exception (tl::to_string (QObject::tr ("All four coordinates of the clip box must be given")));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double x = 0.0, y = 0.0;
|
|
|
|
|
double w = 0.0, h = 0.0;
|
|
|
|
|
tl::from_string (tl::to_string (le_x->text ()), x);
|
|
|
|
|
tl::from_string (tl::to_string (le_y->text ()), y);
|
|
|
|
|
tl::from_string (tl::to_string (le_w->text ()), w);
|
|
|
|
|
tl::from_string (tl::to_string (le_h->text ()), h);
|
|
|
|
|
|
|
|
|
|
clip_boxes.push_back (db::Box (db::DBox (db::DPoint (x - 0.5 * w, y - 0.5 * h), db::DPoint (x + 0.5 * w, y + 0.5 * h)) * (1.0 / cv->layout ().dbu ())));
|
|
|
|
|
|
|
|
|
|
} else if (rb_rulers->isChecked ()) {
|
|
|
|
|
|
|
|
|
|
ant::Service *ant_service = view ()->get_plugin <ant::Service> ();
|
|
|
|
|
if (ant_service) {
|
|
|
|
|
ant::AnnotationIterator ant = ant_service->begin_annotations ();
|
|
|
|
|
while (! ant.at_end ()) {
|
|
|
|
|
clip_boxes.push_back (db::Box (db::DBox (ant->p1 (), ant->p2 ()) * (1.0 / cv->layout ().dbu ())));
|
|
|
|
|
++ant;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (rb_shapes->isChecked ()) {
|
|
|
|
|
|
|
|
|
|
int sel_layer = cb_layer->current_layer ();
|
|
|
|
|
if (sel_layer < 0 || ! cv->layout ().is_valid_layer (sel_layer)) {
|
|
|
|
|
throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected to get clip boxes from")));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
db::collect_clip_boxes (cv->layout (), cv.cell_index (), (unsigned int) sel_layer, clip_boxes);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// large scale operation - do not provide undo (TODO: warn about that?)
|
|
|
|
|
view ()->manager ()->clear ();
|
|
|
|
|
|
|
|
|
|
if (! clip_boxes.empty ()) {
|
|
|
|
|
|
|
|
|
|
std::sort (clip_boxes.begin (), clip_boxes.end ());
|
|
|
|
|
clip_boxes.erase (std::unique (clip_boxes.begin (), clip_boxes.end ()), clip_boxes.end ());
|
|
|
|
|
|
|
|
|
|
std::vector<db::cell_index_type> new_cells = db::clip_layout (cv->layout (), cv->layout (), cv.cell_index (), clip_boxes, false);
|
|
|
|
|
|
|
|
|
|
if (new_cells.size () > 1) {
|
|
|
|
|
|
|
|
|
|
// need to create a new master top cell
|
|
|
|
|
db::cell_index_type clip_top = cv->layout ().add_cell (clip_cell_name.c_str ());
|
|
|
|
|
db::Cell &clip_top_cell = cv->layout ().cell (clip_top);
|
|
|
|
|
|
|
|
|
|
for (std::vector <db::cell_index_type>::const_iterator cc = new_cells.begin (); cc != new_cells.end (); ++cc) {
|
|
|
|
|
clip_top_cell.insert (db::CellInstArray (db::CellInst (*cc), db::Trans ()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// select that cell as new cell
|
|
|
|
|
view ()->select_cell (clip_top, view ()->active_cellview_index ());
|
|
|
|
|
|
|
|
|
|
} else if (new_cells.size () > 0 && new_cells [0] != cv.cell_index ()) {
|
|
|
|
|
|
|
|
|
|
// it is sufficient to rename the new cell ..
|
|
|
|
|
cv->layout ().rename_cell (new_cells [0], cv->layout ().uniquify_cell_name (clip_cell_name.c_str ()).c_str ());
|
|
|
|
|
|
|
|
|
|
// select that cell as new cell
|
|
|
|
|
view ()->select_cell (new_cells [0], view ()->active_cellview_index ());
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// close this dialog
|
|
|
|
|
QDialog::accept ();
|
|
|
|
|
|
|
|
|
|
END_PROTECTED
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ClipDialog::box1_clicked ()
|
|
|
|
|
{
|
|
|
|
|
rb_box2->setChecked (false);
|
|
|
|
|
rb_shapes->setChecked (false);
|
|
|
|
|
rb_rulers->setChecked (false);
|
|
|
|
|
cb_layer->setEnabled (false);
|
|
|
|
|
grp_box1->setEnabled (true);
|
|
|
|
|
grp_box2->setEnabled (false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ClipDialog::box2_clicked ()
|
|
|
|
|
{
|
|
|
|
|
rb_box1->setChecked (false);
|
|
|
|
|
rb_shapes->setChecked (false);
|
|
|
|
|
rb_rulers->setChecked (false);
|
|
|
|
|
cb_layer->setEnabled (false);
|
|
|
|
|
grp_box1->setEnabled (false);
|
|
|
|
|
grp_box2->setEnabled (true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ClipDialog::rulers_clicked ()
|
|
|
|
|
{
|
|
|
|
|
rb_box1->setChecked (false);
|
|
|
|
|
rb_box2->setChecked (false);
|
|
|
|
|
rb_shapes->setChecked (false);
|
|
|
|
|
cb_layer->setEnabled (false);
|
|
|
|
|
grp_box1->setEnabled (false);
|
|
|
|
|
grp_box2->setEnabled (false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ClipDialog::shapes_clicked ()
|
|
|
|
|
{
|
|
|
|
|
rb_box1->setChecked (false);
|
|
|
|
|
rb_box2->setChecked (false);
|
|
|
|
|
rb_rulers->setChecked (false);
|
|
|
|
|
cb_layer->setEnabled (true);
|
|
|
|
|
grp_box1->setEnabled (false);
|
|
|
|
|
grp_box2->setEnabled (false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ClipDialog::configure (const std::string & /*name*/, const std::string & /*value*/)
|
|
|
|
|
{
|
|
|
|
|
// .. nothing yet ..
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|