Merge branch 'master' into complex_drc_ops

This commit is contained in:
Matthias Koefferlein 2021-01-17 19:55:28 +01:00
commit 081c445cd8
21 changed files with 280 additions and 70 deletions

4
.gitignore vendored
View File

@ -57,10 +57,12 @@ src/klayout.pro.user
build/ build/
dist/ dist/
# IDEs # IDEs
.vscode .vscode
# vim
.*.swp
.*.swo
# Macos artifacts # Macos artifacts
*.dmg *.dmg

View File

@ -1642,7 +1642,7 @@ Service::reduce_rulers (int num)
void void
Service::cut () Service::cut ()
{ {
if (selection_size () > 0) { if (has_selection ()) {
// copy & delete the selected rulers // copy & delete the selected rulers
copy_selected (); copy_selected ();
@ -1701,7 +1701,7 @@ Service::paste ()
void void
Service::del () Service::del ()
{ {
if (selection_size () > 0) { if (has_selection ()) {
// delete the selected rulers // delete the selected rulers
del_selected (); del_selected ();
@ -1727,12 +1727,24 @@ Service::del_selected ()
mp_view->annotation_shapes ().erase_positions (positions.begin (), positions.end ()); mp_view->annotation_shapes ().erase_positions (positions.begin (), positions.end ());
} }
bool
Service::has_selection ()
{
return ! m_selected.empty ();
}
size_t size_t
Service::selection_size () Service::selection_size ()
{ {
return m_selected.size (); return m_selected.size ();
} }
bool
Service::has_transient_selection ()
{
return mp_transient_ruler != 0;
}
bool bool
Service::select (obj_iterator obj, lay::Editable::SelectionMode mode) Service::select (obj_iterator obj, lay::Editable::SelectionMode mode)
{ {
@ -1934,7 +1946,7 @@ Service::transient_select (const db::DPoint &pos)
mp_transient_ruler = new ant::View (this, robj, true /*selected*/); mp_transient_ruler = new ant::View (this, robj, true /*selected*/);
} }
if (any_selected && editables ()->selection_size () == 0) { if (any_selected && ! editables ()->has_selection ()) {
display_status (true); display_status (true);
} }

View File

@ -256,10 +256,20 @@ public:
virtual void paste (); virtual void paste ();
/** /**
* @brief Tell the number of selected objects * @brief Indicates whether there are selection objects
*/
virtual bool has_selection ();
/**
* @brief Indicates how many objects are selected
*/ */
virtual size_t selection_size (); virtual size_t selection_size ();
/**
* @brief Indicates whether there are selection objects in transient mode
*/
virtual bool has_transient_selection ();
/** /**
* @brief point selection proximity predicate * @brief point selection proximity predicate
*/ */

View File

@ -1117,7 +1117,7 @@ static bool has_annotation_selection (const lay::LayoutView *view)
{ {
std::vector<ant::Service *> ant_services = view->get_plugins <ant::Service> (); std::vector<ant::Service *> ant_services = view->get_plugins <ant::Service> ();
for (std::vector<ant::Service *>::const_iterator s = ant_services.begin (); s != ant_services.end (); ++s) { for (std::vector<ant::Service *>::const_iterator s = ant_services.begin (); s != ant_services.end (); ++s) {
if ((*s)->selection_size () > 0) { if ((*s)->has_selection ()) {
return true; return true;
} }
} }

View File

@ -202,7 +202,7 @@ gsi::EnumIn<db::LoadLayoutOptions, db::CellConflictResolution> decl_dbCommonRead
gsi::enum_const ("RenameCell", db::RenameCell, gsi::enum_const ("RenameCell", db::RenameCell,
"@brief The new cell will be renamed to become unique\n" "@brief The new cell will be renamed to become unique\n"
), ),
"@brief This enum specifies how cell conflicts are handled if a layout read into another layout and a cell name conflict arises. " "@brief This enum specifies how cell conflicts are handled if a layout read into another layout and a cell name conflict arises.\n"
"Until version 0.26.8 and before, the mode was always 'AddToCell'. On reading, a cell was 'reopened' when encountering a cell name " "Until version 0.26.8 and before, the mode was always 'AddToCell'. On reading, a cell was 'reopened' when encountering a cell name "
"which already existed. This mode is still the default. The other modes are made available to support other ways of merging layouts.\n" "which already existed. This mode is still the default. The other modes are made available to support other ways of merging layouts.\n"
"\n" "\n"

View File

@ -2032,12 +2032,25 @@ PartialService::mouse_release_event (const db::DPoint &p, unsigned int buttons,
return false; return false;
} }
bool
PartialService::has_selection ()
{
return ! m_selection.empty ();
}
size_t size_t
PartialService::selection_size () PartialService::selection_size ()
{ {
return m_selection.size (); return m_selection.size ();
} }
bool
PartialService::has_transient_selection ()
{
// there is no specific transient selection for the partial editor
return false;
}
void void
PartialService::del () PartialService::del ()
{ {

View File

@ -240,10 +240,20 @@ public:
virtual double catch_distance (); virtual double catch_distance ();
/** /**
* @brief Returns the number of selected objects * @brief Indicates whether objects are selected
*/
virtual bool has_selection ();
/**
* @brief Indicates how many objects are selected
*/ */
virtual size_t selection_size (); virtual size_t selection_size ();
/**
* @brief Indicates whether objects are selected in transient mode
*/
virtual bool has_transient_selection ();
/** /**
* @brief Implement the "select" method at least to clear the selection * @brief Implement the "select" method at least to clear the selection
*/ */

View File

@ -293,7 +293,7 @@ Service::highlight (unsigned int n)
void void
Service::cut () Service::cut ()
{ {
if (selection_size () > 0 && view ()->is_editable ()) { if (has_selection () && view ()->is_editable ()) {
// copy & delete the selected objects // copy & delete the selected objects
copy_selected (); copy_selected ();
del_selected (); del_selected ();
@ -834,7 +834,7 @@ Service::edit_cancel ()
void void
Service::del () Service::del ()
{ {
if (selection_size () > 0 && view ()->is_editable ()) { if (has_selection () && view ()->is_editable ()) {
// delete the selected objects // delete the selected objects
del_selected (); del_selected ();
} }
@ -871,13 +871,18 @@ Service::del_selected ()
} }
} }
bool
Service::has_selection ()
{
return ! m_selection.empty ();
}
size_t size_t
Service::selection_size () Service::selection_size ()
{ {
return m_selection.size (); return m_selection.size ();
} }
bool bool
Service::has_transient_selection () Service::has_transient_selection ()
{ {
@ -1016,7 +1021,7 @@ Service::transient_select (const db::DPoint &pos)
} }
if (editables ()->selection_size () == 0) { if (! editables ()->has_selection ()) {
display_status (true); display_status (true);
} }
@ -1055,7 +1060,7 @@ Service::transient_select (const db::DPoint &pos)
mp_transient_marker = marker; mp_transient_marker = marker;
if (editables ()->selection_size () == 0) { if (! editables ()->has_selection ()) {
display_status (true); display_status (true);
} }
@ -1410,7 +1415,7 @@ Service::move_markers (const db::DTrans &t)
if (m_move_trans != t) { if (m_move_trans != t) {
// display current move vector // display current move vector
if (selection_size () > 0) { if (has_selection ()) {
std::string pos = std::string ("dx: ") + tl::micron_to_string (t.disp ().x ()) + " dy: " + tl::micron_to_string (t.disp ().y ()); std::string pos = std::string ("dx: ") + tl::micron_to_string (t.disp ().x ()) + " dy: " + tl::micron_to_string (t.disp ().y ());
if (t.rot () != 0) { if (t.rot () != 0) {
pos += std::string (" ") + ((const db::DFTrans &) t).to_string (); pos += std::string (" ") + ((const db::DFTrans &) t).to_string ();

View File

@ -159,12 +159,17 @@ public:
virtual void end_move (const db::DPoint &p, lay::angle_constraint_type ac); virtual void end_move (const db::DPoint &p, lay::angle_constraint_type ac);
/** /**
* @brief Tell the number of selected objects * @brief Indicates whether objects are selected
*/
virtual bool has_selection ();
/**
* @brief Indicates how many objects are selected
*/ */
virtual size_t selection_size (); virtual size_t selection_size ();
/** /**
* @brief Tell if anything is selected in the transient selection * @brief Indicates whether objects are selected in transient mode
*/ */
virtual bool has_transient_selection (); virtual bool has_transient_selection ();

View File

@ -525,7 +525,7 @@ static bool has_object_selection (const lay::LayoutView *view)
{ {
std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> (); std::vector<edt::Service *> edt_services = view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) { for (std::vector<edt::Service *>::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) {
if ((*s)->selection_size () > 0) { if ((*s)->has_selection ()) {
return true; return true;
} }
} }

View File

@ -1336,7 +1336,7 @@ static bool has_image_selection (const lay::LayoutView *view)
{ {
std::vector<img::Service *> img = view->get_plugins <img::Service> (); std::vector<img::Service *> img = view->get_plugins <img::Service> ();
for (std::vector<img::Service *>::const_iterator s = img.begin (); s != img.end (); ++s) { for (std::vector<img::Service *>::const_iterator s = img.begin (); s != img.end (); ++s) {
if ((*s)->selection_size () > 0) { if ((*s)->has_selection ()) {
return true; return true;
} }
} }

View File

@ -1006,7 +1006,7 @@ Service::edit_cancel ()
void void
Service::cut () Service::cut ()
{ {
if (selection_size () > 0) { if (has_selection ()) {
// copy & delete the selected images // copy & delete the selected images
copy_selected (); copy_selected ();
@ -1052,7 +1052,7 @@ Service::paste ()
void void
Service::del () Service::del ()
{ {
if (selection_size () > 0) { if (has_selection ()) {
// delete the selected images // delete the selected images
del_selected (); del_selected ();
@ -1078,12 +1078,24 @@ Service::del_selected ()
mp_view->annotation_shapes ().erase_positions (positions.begin (), positions.end ()); mp_view->annotation_shapes ().erase_positions (positions.begin (), positions.end ());
} }
bool
Service::has_selection ()
{
return ! m_selected.empty ();
}
size_t size_t
Service::selection_size () Service::selection_size ()
{ {
return m_selected.size (); return m_selected.size ();
} }
bool
Service::has_transient_selection ()
{
return mp_transient_view != 0;
}
void void
Service::clear_previous_selection () Service::clear_previous_selection ()
{ {
@ -1193,7 +1205,7 @@ Service::transient_select (const db::DPoint &pos)
// if in move mode (which also receives transient_select requests) the move will take the selection, // if in move mode (which also receives transient_select requests) the move will take the selection,
// hence only highlight the transient selection if it's part of the current selection. // hence only highlight the transient selection if it's part of the current selection.
if (view ()->selection_size () > 0 && view ()->is_move_mode () && m_selected.find (imin) == m_selected.end ()) { if (view ()->has_selection () && view ()->is_move_mode () && m_selected.find (imin) == m_selected.end ()) {
return false; return false;
} }
@ -1208,7 +1220,7 @@ Service::transient_select (const db::DPoint &pos)
} }
if (any_selected && editables ()->selection_size () == 0) { if (any_selected && ! editables ()->has_selection ()) {
display_status (true); display_status (true);
} }

View File

@ -275,10 +275,20 @@ public:
virtual void paste (); virtual void paste ();
/** /**
* @brief Tell the number of selected objects * @brief Indicates if any objects are selected
*/
virtual bool has_selection ();
/**
* @brief Indicates how many objects are selected
*/ */
virtual size_t selection_size (); virtual size_t selection_size ();
/**
* @brief Indicates if any objects are selected in transient mode
*/
virtual bool has_transient_selection ();
/** /**
* @brief point selection proximity predicate * @brief point selection proximity predicate
*/ */

View File

@ -23,6 +23,7 @@
#include "gsiDecl.h" #include "gsiDecl.h"
#include "gsiSignals.h" #include "gsiSignals.h"
#include "gsiEnums.h"
#include "rdb.h" #include "rdb.h"
#include "layLayoutView.h" #include "layLayoutView.h"
#include "layDitherPattern.h" #include "layDitherPattern.h"
@ -978,11 +979,32 @@ Class<lay::LayoutView> decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou
"selection. Calling this method is useful to ensure there are no potential interactions with the script's " "selection. Calling this method is useful to ensure there are no potential interactions with the script's "
"functionality.\n" "functionality.\n"
) + ) +
gsi::method ("clear_selection", &lay::LayoutView::clear_selection, gsi::method ("clear_selection", (void (lay::LayoutView::*) ()) &lay::LayoutView::clear_selection,
"@brief Clears the selection of all objects (shapes, annotations, images ...)\n" "@brief Clears the selection of all objects (shapes, annotations, images ...)\n"
"\n" "\n"
"This method has been introduced in version 0.26.2\n" "This method has been introduced in version 0.26.2\n"
) + ) +
gsi::method ("select_all", (void (lay::LayoutView::*) ()) &lay::LayoutView::select,
"@brief Selects all objects from the view\n"
"\n"
"This method has been introduced in version 0.27\n"
) +
gsi::method ("select_from", (void (lay::LayoutView::*) (const db::DPoint &, lay::Editable::SelectionMode)) &lay::LayoutView::select, gsi::arg ("point"), gsi::arg ("mode", lay::Editable::SelectionMode::Replace, "Replace"),
"@brief Selects the objects from a given point\n"
"\n"
"The mode indicates whether to add to the selection, replace the selection, remove from selection or invert the selected status of the objects "
"found around the given point.\n"
"\n"
"This method has been introduced in version 0.27\n"
) +
gsi::method ("select_from", (void (lay::LayoutView::*) (const db::DBox &, lay::Editable::SelectionMode)) &lay::LayoutView::select, gsi::arg ("box"), gsi::arg ("mode", lay::Editable::SelectionMode::Replace, "Replace"),
"@brief Selects the objects from a given box\n"
"\n"
"The mode indicates whether to add to the selection, replace the selection, remove from selection or invert the selected status of the objects "
"found inside the given box.\n"
"\n"
"This method has been introduced in version 0.27\n"
) +
gsi::method ("clear_transient_selection", &lay::LayoutView::clear_transient_selection, gsi::method ("clear_transient_selection", &lay::LayoutView::clear_transient_selection,
"@brief Clears the transient selection (mouse-over hightlights) of all objects (shapes, annotations, images ...)\n" "@brief Clears the transient selection (mouse-over hightlights) of all objects (shapes, annotations, images ...)\n"
"\n" "\n"
@ -1001,6 +1023,16 @@ Class<lay::LayoutView> decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou
"\n" "\n"
"This method has been introduced in version 0.26.2\n" "This method has been introduced in version 0.26.2\n"
) + ) +
gsi::method ("selection_size", (size_t (lay::LayoutView::*) ()) &lay::LayoutView::selection_size,
"@brief Returns the number of selected objects\n"
"\n"
"This method has been introduced in version 0.27\n"
) +
gsi::method ("has_selection?", (bool (lay::LayoutView::*) ()) &lay::LayoutView::has_selection,
"@brief Indicates whether any objects are selected\n"
"\n"
"This method has been introduced in version 0.27\n"
) +
gsi::method ("stop", &lay::LayoutView::stop, gsi::method ("stop", &lay::LayoutView::stop,
"@brief Stops redraw thread and close any browsers\n" "@brief Stops redraw thread and close any browsers\n"
"This method usually does not need to be called explicitly. The redraw thread is stopped automatically." "This method usually does not need to be called explicitly. The redraw thread is stopped automatically."
@ -1867,6 +1899,27 @@ Class<lay::LayoutView> decl_LayoutView (QT_EXTERNAL_BASE (QWidget) "lay", "Layou
"This object controls these aspects of the view and controls the appearance of the data. " "This object controls these aspects of the view and controls the appearance of the data. "
); );
gsi::EnumIn<lay::LayoutView, lay::Editable::SelectionMode> decl_layLayoutView_SelectionMode ("lay", "SelectionMode",
gsi::enum_const ("Add", lay::Editable::SelectionMode::Add,
"@brief Adds to any existing selection\n"
) +
gsi::enum_const ("Reset", lay::Editable::SelectionMode::Reset,
"@brief Removes from any existing selection\n"
) +
gsi::enum_const ("Replace", lay::Editable::SelectionMode::Replace,
"@brief Replaces the existing selection\n"
) +
gsi::enum_const ("Invert", lay::Editable::SelectionMode::Invert,
"@brief Adds to any existing selection, if it's not there yet or removes it from the selection if it's already selected\n"
),
"@brief Specifies how selected objects interact with already selected ones.\n"
"\n"
"This enum was introduced in version 0.27.\n"
);
// Inject the NetlistCrossReference::Status declarations into NetlistCrossReference:
gsi::ClassExt<lay::LayoutView> inject_SelectionMode_in_parent (decl_layLayoutView_SelectionMode.defs ());
static db::Layout *get_layout (const lay::CellViewRef *cv) static db::Layout *get_layout (const lay::CellViewRef *cv)
{ {
if ((*cv).operator-> ()) { if ((*cv).operator-> ()) {

View File

@ -92,7 +92,7 @@ Editables::del (db::Transaction *transaction)
{ {
std::auto_ptr<db::Transaction> trans_holder (transaction ? transaction : new db::Transaction (manager (), tl::to_string (QObject::tr ("Delete")))); std::auto_ptr<db::Transaction> trans_holder (transaction ? transaction : new db::Transaction (manager (), tl::to_string (QObject::tr ("Delete"))));
if (selection_size () > 0) { if (has_selection ()) {
try { try {
@ -118,7 +118,7 @@ Editables::del (db::Transaction *transaction)
void void
Editables::cut () Editables::cut ()
{ {
if (selection_size () > 0) { if (has_selection ()) {
cancel_edits (); cancel_edits ();
@ -136,7 +136,7 @@ Editables::cut ()
void void
Editables::copy () Editables::copy ()
{ {
if (selection_size () > 0) { if (has_selection ()) {
db::Clipboard::instance ().clear (); db::Clipboard::instance ().clear ();
for (iterator e = begin (); e != end (); ++e) { for (iterator e = begin (); e != end (); ++e) {
e->copy (); e->copy ();
@ -170,7 +170,7 @@ Editables::transform (const db::DCplxTrans &tr, db::Transaction *transaction)
{ {
std::auto_ptr<db::Transaction> trans_holder (transaction ? transaction : new db::Transaction (manager (), tl::to_string (QObject::tr ("Transform")))); std::auto_ptr<db::Transaction> trans_holder (transaction ? transaction : new db::Transaction (manager (), tl::to_string (QObject::tr ("Transform"))));
if (selection_size () > 0) { if (has_selection ()) {
try { try {
@ -298,19 +298,33 @@ Editables::clear_previous_selection ()
void void
Editables::clear_transient_selection () Editables::clear_transient_selection ()
{ {
bool had_transient_selection = false;
for (iterator e = begin (); e != end (); ++e) { for (iterator e = begin (); e != end (); ++e) {
if (e->has_transient_selection ()) {
had_transient_selection = true;
}
e->clear_transient_selection (); e->clear_transient_selection ();
} }
// send a signal to the observers // send a signal to the observers
signal_transient_selection_changed (); if (had_transient_selection) {
signal_transient_selection_changed ();
}
} }
void void
Editables::transient_to_selection () Editables::transient_to_selection ()
{ {
bool had_transient_selection = false;
bool had_selection = false;
cancel_edits (); cancel_edits ();
for (iterator e = begin (); e != end (); ++e) { for (iterator e = begin (); e != end (); ++e) {
if (e->has_selection ()) {
had_selection = true;
}
if (e->has_transient_selection ()) {
had_transient_selection = true;
}
e->select (db::DBox (), lay::Editable::Reset); // clear selection e->select (db::DBox (), lay::Editable::Reset); // clear selection
e->clear_previous_selection (); e->clear_previous_selection ();
e->transient_to_selection (); e->transient_to_selection ();
@ -318,22 +332,41 @@ Editables::transient_to_selection ()
} }
// send a signal to the observers // send a signal to the observers
signal_transient_selection_changed (); if (had_transient_selection) {
signal_selection_changed (); signal_transient_selection_changed ();
}
if (had_selection || had_transient_selection) {
signal_selection_changed ();
}
} }
void void
Editables::clear_selection () Editables::clear_selection ()
{ {
cancel_edits (); cancel_edits ();
bool had_transient_selection = false;
bool had_selection = false;
for (iterator e = begin (); e != end (); ++e) { for (iterator e = begin (); e != end (); ++e) {
if (e->has_selection ()) {
had_selection = true;
}
if (e->has_transient_selection ()) {
had_transient_selection = true;
}
e->select (db::DBox (), lay::Editable::Reset); // clear selection e->select (db::DBox (), lay::Editable::Reset); // clear selection
e->clear_transient_selection (); e->clear_transient_selection ();
e->clear_previous_selection (); e->clear_previous_selection ();
} }
// send a signal to the observers // send a signal to the observers
signal_selection_changed (); if (had_transient_selection) {
signal_transient_selection_changed ();
}
if (had_selection) {
signal_selection_changed ();
}
} }
void void
@ -479,7 +512,7 @@ Editables::begin_move (const db::DPoint &p, lay::angle_constraint_type ac)
// sort the plugins found by the proximity // sort the plugins found by the proximity
std::sort (plugins.begin (), plugins.end (), first_of_pair_cmp_f<double, iterator> ()); std::sort (plugins.begin (), plugins.end (), first_of_pair_cmp_f<double, iterator> ());
if (selection_size () > 0 && selection_catch_bbox ().contains (p)) { if (has_selection () && selection_catch_bbox ().contains (p)) {
// if anything is selected and we are within the selection bbox, // if anything is selected and we are within the selection bbox,
// issue a move operation on all editables: first try a Partial mode begin_move // issue a move operation on all editables: first try a Partial mode begin_move
@ -527,7 +560,7 @@ Editables::begin_move (const db::DPoint &p, lay::angle_constraint_type ac)
select (p, Editable::Replace); select (p, Editable::Replace);
// now we assume we have a selection - try to begin_move on this. // now we assume we have a selection - try to begin_move on this.
if (selection_size () > 0) { if (has_selection ()) {
m_move_selection = true; m_move_selection = true;
for (iterator e = begin (); e != end (); ++e) { for (iterator e = begin (); e != end (); ++e) {
e->begin_move (Editable::Selected, p, ac); e->begin_move (Editable::Selected, p, ac);
@ -601,6 +634,17 @@ Editables::selection_size ()
return c; return c;
} }
bool
Editables::has_selection ()
{
for (iterator e = begin (); e != end (); ++e) {
if (e->has_selection ()) {
return true;
}
}
return false;
}
void void
Editables::edit_cancel () Editables::edit_cancel ()
{ {
@ -627,7 +671,7 @@ Editables::cancel_edits ()
void void
Editables::show_properties (QWidget *parent) Editables::show_properties (QWidget *parent)
{ {
if (selection_size () == 0) { if (! has_selection ()) {
// try to use the transient selection for the real one // try to use the transient selection for the real one
transient_to_selection (); transient_to_selection ();
} }

View File

@ -319,16 +319,29 @@ public:
} }
/** /**
* @brief Tell how many objects are selected * @brief Indicates if any objects are selected
* */
* This method is used to determine if anything is selected - i.e. virtual bool has_selection ()
* anything can be copied. {
return false;
}
/**
* @brief Indicates how many objects are selected
*/ */
virtual size_t selection_size () virtual size_t selection_size ()
{ {
return 0; return 0;
} }
/**
* @brief Indicates if any objects are selected in the transient selection
*/
virtual bool has_transient_selection ()
{
return false;
}
/** /**
* @brief Create a "properties page" object * @brief Create a "properties page" object
* *
@ -528,12 +541,17 @@ public:
void end_move (const db::DPoint &p, lay::angle_constraint_type ac, db::Transaction *transaction = 0); void end_move (const db::DPoint &p, lay::angle_constraint_type ac, db::Transaction *transaction = 0);
/** /**
* @brief Tell how many objects are selected. * @brief Indicates how many objects are selected.
* *
* This method will return the number of selected objects. * This method will return the number of selected objects.
*/ */
size_t selection_size (); size_t selection_size ();
/**
* @brief Indicates whether any object is selected.
*/
bool has_selection ();
/** /**
* @brief Cancel any pending operations * @brief Cancel any pending operations
*/ */

View File

@ -5246,7 +5246,7 @@ LayoutView::has_selection ()
} else if (mp_hierarchy_panel && mp_hierarchy_panel->has_focus ()) { } else if (mp_hierarchy_panel && mp_hierarchy_panel->has_focus ()) {
return mp_hierarchy_panel->has_selection (); return mp_hierarchy_panel->has_selection ();
} else { } else {
return lay::Editables::selection_size () > 0; return lay::Editables::has_selection ();
} }
} }
@ -5319,7 +5319,7 @@ LayoutView::copy ()
mp_control_panel->copy (); mp_control_panel->copy ();
} else { } else {
if (lay::Editables::selection_size () == 0) { if (! lay::Editables::has_selection ()) {
// try to use the transient selection for the real one // try to use the transient selection for the real one
lay::Editables::transient_to_selection (); lay::Editables::transient_to_selection ();
} }
@ -5341,7 +5341,7 @@ LayoutView::cut ()
mp_control_panel->cut (); mp_control_panel->cut ();
} else { } else {
if (lay::Editables::selection_size () == 0) { if (! lay::Editables::has_selection ()) {
// try to use the transient selection for the real one // try to use the transient selection for the real one
lay::Editables::transient_to_selection (); lay::Editables::transient_to_selection ();
} }

View File

@ -100,7 +100,7 @@ MoveService::key_event (unsigned int key, unsigned int /*buttons*/)
dx = 1.0; dx = 1.0;
} }
if (! m_dragging && fabs (dx + dy) > 0.0 && mp_editables->selection_size () > 0) { if (! m_dragging && fabs (dx + dy) > 0.0 && mp_editables->has_selection ()) {
// determine a shift distance which is 2, 5 or 10 times the grid and is more than 5 pixels // determine a shift distance which is 2, 5 or 10 times the grid and is more than 5 pixels
double dmin = double (5 /*pixels min shift*/) / widget ()->mouse_event_trans ().mag (); double dmin = double (5 /*pixels min shift*/) / widget ()->mouse_event_trans ().mag ();
@ -250,13 +250,13 @@ MoveService::begin_move (db::Transaction *transaction, bool selected_after_move)
std::auto_ptr<db::Transaction> trans_holder (transaction); std::auto_ptr<db::Transaction> trans_holder (transaction);
bool drag_transient = ! selected_after_move; bool drag_transient = ! selected_after_move;
if (mp_editables->selection_size () == 0) { if (! mp_editables->has_selection ()) {
// try to use the transient selection for the real one // try to use the transient selection for the real one
mp_editables->transient_to_selection (); mp_editables->transient_to_selection ();
drag_transient = true; drag_transient = true;
} }
if (mp_editables->selection_size () == 0) { if (! mp_editables->has_selection ()) {
// still nothing selected // still nothing selected
return false; return false;
} }

View File

@ -227,7 +227,9 @@ URI::resolved (const URI &other) const
if (other.path ()[0] == '/') { if (other.path ()[0] == '/') {
res.m_path = other.path (); res.m_path = other.path ();
} else { } else {
res.m_path += "/"; if (! res.m_path.empty ()) {
res.m_path += "/";
}
res.m_path += other.path (); res.m_path += other.path ();
} }
} }

View File

@ -78,6 +78,8 @@ TEST(1)
{ {
tl::URI uri; tl::URI uri;
EXPECT_EQ (uri2string (uri), ""); EXPECT_EQ (uri2string (uri), "");
EXPECT_EQ (uri2string (uri.resolved (tl::URI ("http://www.klayout.de"))), "<http>://<www.klayout.de>");
EXPECT_EQ (uri2string (uri.resolved (tl::URI ("anyfile.txt"))), "<anyfile.txt>");
uri = tl::URI ("scheme:"); uri = tl::URI ("scheme:");
EXPECT_EQ (uri2string (uri), "<scheme>:"); EXPECT_EQ (uri2string (uri), "<scheme>:");

View File

@ -180,6 +180,25 @@ class LAYLayoutView_TestClass < TestBase
assert_equal(cv1.index, 0) assert_equal(cv1.index, 0)
assert_equal(view.has_selection?, false)
assert_equal(view.selection_size, 0)
view.select_from(RBA::DBox::new(-1.0, -1.0, 1.0, 1.0))
assert_equal(selection_changed, 1)
assert_equal(view.selection_size, 4)
assert_equal(view.has_selection?, true)
view.select_from(RBA::DPoint::new(0, 0), RBA::LayoutView::Invert)
assert_equal(selection_changed, 2)
assert_equal(view.selection_size, 3)
assert_equal(view.has_selection?, true)
view.clear_selection
assert_equal(selection_changed, 3)
assert_equal(view.has_selection?, false)
assert_equal(view.selection_size, 0)
selection_changed = 0
cv2 = mw.load_layout(ENV["TESTSRC"] + "/testdata/gds/t10.gds", 2) cv2 = mw.load_layout(ENV["TESTSRC"] + "/testdata/gds/t10.gds", 2)
assert_equal(RBA::CellView::active.index, 1) assert_equal(RBA::CellView::active.index, 1)
assert_equal(cv2.index, 1) assert_equal(cv2.index, 1)
@ -196,8 +215,7 @@ class LAYLayoutView_TestClass < TestBase
assert_equal(layer_list_deleted, 0) assert_equal(layer_list_deleted, 0)
assert_equal(current_layer_list_changed, 0) assert_equal(current_layer_list_changed, 0)
assert_equal(cell_visibility_changed, 0) assert_equal(cell_visibility_changed, 0)
# TODO: spontaneous event: does it hurt? assert_equal(selection_changed, 0)
assert_equal(selection_changed, 1)
view.pan_up view.pan_up
assert_equal(viewport_changed, 2) assert_equal(viewport_changed, 2)
@ -234,8 +252,7 @@ class LAYLayoutView_TestClass < TestBase
assert_equal(layer_list_deleted, 0) assert_equal(layer_list_deleted, 0)
assert_equal(current_layer_list_changed, 0) assert_equal(current_layer_list_changed, 0)
assert_equal(cell_visibility_changed, 0) assert_equal(cell_visibility_changed, 0)
# TODO: spontaneous event: does it hurt? assert_equal(selection_changed, 0)
assert_equal(selection_changed, 1)
cv2.path = [ cv2.layout.cell("RINGO").cell_index, cv2.layout.cell("INV2").cell_index, cv2.layout.cell("TRANS").cell_index ] cv2.path = [ cv2.layout.cell("RINGO").cell_index, cv2.layout.cell("INV2").cell_index, cv2.layout.cell("TRANS").cell_index ]
assert_equal(cv2.cell_name, "TRANS") assert_equal(cv2.cell_name, "TRANS")
@ -252,8 +269,7 @@ class LAYLayoutView_TestClass < TestBase
assert_equal(layer_list_deleted, 0) assert_equal(layer_list_deleted, 0)
assert_equal(current_layer_list_changed, 0) assert_equal(current_layer_list_changed, 0)
assert_equal(cell_visibility_changed, 0) assert_equal(cell_visibility_changed, 0)
# TODO: spontaneous event: does it hurt? assert_equal(selection_changed, 0)
assert_equal(selection_changed, 2)
cv2.path = [ cv2.layout.cell("RINGO").cell_index, cv2.layout.cell("INV2").cell_index ] cv2.path = [ cv2.layout.cell("RINGO").cell_index, cv2.layout.cell("INV2").cell_index ]
assert_equal(cv2.cell_name, "INV2") assert_equal(cv2.cell_name, "INV2")
@ -270,8 +286,7 @@ class LAYLayoutView_TestClass < TestBase
assert_equal(layer_list_deleted, 0) assert_equal(layer_list_deleted, 0)
assert_equal(current_layer_list_changed, 0) assert_equal(current_layer_list_changed, 0)
assert_equal(cell_visibility_changed, 0) assert_equal(cell_visibility_changed, 0)
# TODO: spontaneous event: does it hurt? assert_equal(selection_changed, 0)
assert_equal(selection_changed, 3)
sp = [] sp = []
cv2.cell.each_inst { |i| sp << RBA::InstElement::new(i); break } cv2.cell.each_inst { |i| sp << RBA::InstElement::new(i); break }
@ -291,8 +306,7 @@ class LAYLayoutView_TestClass < TestBase
assert_equal(layer_list_deleted, 0) assert_equal(layer_list_deleted, 0)
assert_equal(current_layer_list_changed, 0) assert_equal(current_layer_list_changed, 0)
assert_equal(cell_visibility_changed, 0) assert_equal(cell_visibility_changed, 0)
# TODO: spontaneous event: does it hurt? assert_equal(selection_changed, 0)
assert_equal(selection_changed, 4)
cv2.ascend cv2.ascend
@ -310,8 +324,7 @@ class LAYLayoutView_TestClass < TestBase
assert_equal(layer_list_deleted, 0) assert_equal(layer_list_deleted, 0)
assert_equal(current_layer_list_changed, 0) assert_equal(current_layer_list_changed, 0)
assert_equal(cell_visibility_changed, 0) assert_equal(cell_visibility_changed, 0)
# TODO: spontaneous event: does it hurt? assert_equal(selection_changed, 0)
assert_equal(selection_changed, 5)
assert_equal(view.cellviews, 2) assert_equal(view.cellviews, 2)
@ -332,8 +345,7 @@ class LAYLayoutView_TestClass < TestBase
assert_equal(layer_list_deleted, 0) assert_equal(layer_list_deleted, 0)
assert_equal(current_layer_list_changed, 0) assert_equal(current_layer_list_changed, 0)
assert_equal(cell_visibility_changed, 0) assert_equal(cell_visibility_changed, 0)
# TODO: spontaneous event: does it hurt? assert_equal(selection_changed, 0)
assert_equal(selection_changed, 6)
active_cellview_changed = 0 active_cellview_changed = 0
cellviews_changed = 0 cellviews_changed = 0