Implemented solution for #2306

First of all, NetlistBrowserDialog#current_path now has a setter.
Changing the selection will navigate to the location of the
selected object, but not issue an "on_selection_changed" event.

In addition, the following features have been added:
* NetlistBrowserDialog#db_index
* NetlistBrowserDialog#view
This commit is contained in:
Matthias Koefferlein 2026-03-21 20:32:32 +01:00
parent 415650bb3a
commit c211925d2a
7 changed files with 108 additions and 31 deletions

View File

@ -169,6 +169,20 @@ static lay::NetlistObjectPath current_path_second (lay::NetlistBrowserDialog *di
return dialog->current_path ().second (); return dialog->current_path ().second ();
} }
static void set_current_path (lay::NetlistBrowserDialog *dialog, const lay::NetlistObjectsPath *path)
{
if (! path) {
dialog->set_current_path (lay::NetlistObjectsPath ());
} else {
dialog->set_current_path (*path);
}
}
static lay::LayoutViewBase *get_view (lay::NetlistBrowserDialog *dialog)
{
return dialog->view ();
}
Class<lay::NetlistBrowserDialog> decl_NetlistBrowserDialog ("lay", "NetlistBrowserDialog", Class<lay::NetlistBrowserDialog> decl_NetlistBrowserDialog ("lay", "NetlistBrowserDialog",
gsi::event ("on_current_db_changed", &lay::NetlistBrowserDialog::current_db_changed_event, gsi::event ("on_current_db_changed", &lay::NetlistBrowserDialog::current_db_changed_event,
"@brief This event is triggered when the current database is changed.\n" "@brief This event is triggered when the current database is changed.\n"
@ -187,6 +201,16 @@ Class<lay::NetlistBrowserDialog> decl_NetlistBrowserDialog ("lay", "NetlistBrows
gsi::method ("db", &lay::NetlistBrowserDialog::db, gsi::method ("db", &lay::NetlistBrowserDialog::db,
"@brief Gets the database the browser is connected to.\n" "@brief Gets the database the browser is connected to.\n"
) + ) +
gsi::method ("db_index", &lay::NetlistBrowserDialog::l2n_index,
"@brief Gets the database index inside the view the browser is connected to.\n"
"\n"
"This attribute has been introduced in version 0.30.8.\n"
) +
gsi::method_ext ("view", &get_view,
"@brief Gets the view the browser is connected to.\n"
"\n"
"This attribute has been introduced in version 0.30.8.\n"
) +
gsi::method_ext ("current_path_first", &current_path_first, gsi::method_ext ("current_path_first", &current_path_first,
"@brief Gets the path of the current object on the first (layout in case of LVS database) side.\n" "@brief Gets the path of the current object on the first (layout in case of LVS database) side.\n"
) + ) +
@ -196,6 +220,14 @@ Class<lay::NetlistBrowserDialog> decl_NetlistBrowserDialog ("lay", "NetlistBrows
gsi::method ("current_path", &lay::NetlistBrowserDialog::current_path, gsi::method ("current_path", &lay::NetlistBrowserDialog::current_path,
"@brief Gets the path of the current object as a path pair (combines layout and schematic object paths in case of a LVS database view).\n" "@brief Gets the path of the current object as a path pair (combines layout and schematic object paths in case of a LVS database view).\n"
) + ) +
gsi::method_ext ("current_path=", &set_current_path,
"@brief Sets the current path.\n"
"This is the setter corresponding to the 'current_path' getter. Passing nil clears the selection.\n"
"Changing the selection will update the highlights and navigate to the location depending on the "
"settings. An \\on_selection_changed signal is not emitted.\n"
"\n"
"This setter has been introduced in version 0.30.8.\n"
) +
gsi::method ("selected_paths", &lay::NetlistBrowserDialog::selected_paths, gsi::method ("selected_paths", &lay::NetlistBrowserDialog::selected_paths,
"@brief Gets the nets currently selected objects (paths) in the netlist database browser.\n" "@brief Gets the nets currently selected objects (paths) in the netlist database browser.\n"
"The result is an array of path pairs. See \\NetlistObjectsPath for details about these pairs." "The result is an array of path pairs. See \\NetlistObjectsPath for details about these pairs."

View File

@ -306,28 +306,28 @@ SingleIndexedNetlistModel::parent_of (const subcircuit_pair &subcircuits) const
return std::make_pair (subcircuits.first ? subcircuits.first->circuit () : 0, (const db::Circuit *) 0); return std::make_pair (subcircuits.first ? subcircuits.first->circuit () : 0, (const db::Circuit *) 0);
} }
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::top_circuit_from_index(size_t index) const std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::top_circuit_from_index (size_t index) const
{ {
db::Netlist::const_top_down_circuit_iterator none; db::Netlist::const_top_down_circuit_iterator none;
return std::make_pair (attr_by_object_and_index (std::make_pair ((const db::Circuit *) 0, (const db::Circuit *) 0), index, mp_netlist->begin_top_down (), mp_netlist->begin_top_down () + mp_netlist->top_circuit_count (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); return std::make_pair (attr_by_object_and_index (std::make_pair ((const db::Circuit *) 0, (const db::Circuit *) 0), index, mp_netlist->begin_top_down (), mp_netlist->begin_top_down () + mp_netlist->top_circuit_count (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
} }
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::child_circuit_from_index(const circuit_pair &circuits, size_t index) const std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::child_circuit_from_index (const circuit_pair &circuits, size_t index) const
{ {
db::Circuit::const_child_circuit_iterator none; db::Circuit::const_child_circuit_iterator none;
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_children (), circuits.first->end_children (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_children (), circuits.first->end_children (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
} }
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::circuit_from_index(size_t index) const std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::circuit_from_index (size_t index) const
{ {
db::Netlist::const_circuit_iterator none; db::Netlist::const_circuit_iterator none;
return std::make_pair (attr_by_object_and_index (std::make_pair (mp_netlist, (const db::Netlist *) 0), index, mp_netlist->begin_circuits (), mp_netlist->end_circuits (), none, none, m_circuit_by_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); return std::make_pair (attr_by_object_and_index (std::make_pair (mp_netlist, (const db::Netlist *) 0), index, mp_netlist->begin_circuits (), mp_netlist->end_circuits (), none, none, m_circuit_by_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
} }
std::pair<IndexedNetlistModel::net_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::net_from_index(const circuit_pair &circuits, size_t index) const std::pair<IndexedNetlistModel::net_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::net_from_index (const circuit_pair &circuits, size_t index) const
{ {
db::Circuit::const_net_iterator none; db::Circuit::const_net_iterator none;
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_nets (), circuits.first->end_nets (), none, none, m_net_by_circuit_and_index, sort_by_expanded_name<db::Net> ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); return std::make_pair (attr_by_object_and_index (std::make_pair (circuits.first, (const db::Circuit *) 0), index, circuits.first->begin_nets (), circuits.first->end_nets (), none, none, m_net_by_circuit_and_index, sort_by_expanded_name<db::Net> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
} }
const db::Net * const db::Net *
@ -346,12 +346,15 @@ IndexedNetlistModel::net_subcircuit_pin_pair
SingleIndexedNetlistModel::net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const SingleIndexedNetlistModel::net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const
{ {
db::Net::const_subcircuit_pin_iterator none; db::Net::const_subcircuit_pin_iterator none;
return attr_by_object_and_index (nets, index, nets.first->begin_subcircuit_pins (), nets.first->end_subcircuit_pins (), none, none, m_subcircuit_pinref_by_net_and_index, sort_by_pin_name<db::NetSubcircuitPinRef> ()); return attr_by_object_and_index (std::make_pair (nets.first, (const db::Net *) 0), index, nets.first->begin_subcircuit_pins (), nets.first->end_subcircuit_pins (), none, none, m_subcircuit_pinref_by_net_and_index, sort_by_pin_name<db::NetSubcircuitPinRef> ());
} }
IndexedNetlistModel::net_subcircuit_pin_pair IndexedNetlistModel::net_subcircuit_pin_pair
SingleIndexedNetlistModel::subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const SingleIndexedNetlistModel::subcircuit_pinref_from_index (const subcircuit_pair &subcircuits_in, size_t index) const
{ {
subcircuit_pair subcircuits = subcircuits_in;
subcircuits.second = 0;
if (! subcircuits.first) { if (! subcircuits.first) {
return IndexedNetlistModel::net_subcircuit_pin_pair ((const db::NetSubcircuitPinRef *) 0, (const db::NetSubcircuitPinRef *) 0); return IndexedNetlistModel::net_subcircuit_pin_pair ((const db::NetSubcircuitPinRef *) 0, (const db::NetSubcircuitPinRef *) 0);
} }
@ -381,62 +384,68 @@ IndexedNetlistModel::net_terminal_pair
SingleIndexedNetlistModel::net_terminalref_from_index (const net_pair &nets, size_t index) const SingleIndexedNetlistModel::net_terminalref_from_index (const net_pair &nets, size_t index) const
{ {
db::Net::const_terminal_iterator none; db::Net::const_terminal_iterator none;
return attr_by_object_and_index (nets, index, nets.first->begin_terminals (), nets.first->end_terminals (), none, none, m_terminalref_by_net_and_index, sort_by_terminal_id<db::NetTerminalRef> ()); return attr_by_object_and_index (std::make_pair (nets.first, (const db::Net *) 0), index, nets.first->begin_terminals (), nets.first->end_terminals (), none, none, m_terminalref_by_net_and_index, sort_by_terminal_id<db::NetTerminalRef> ());
} }
IndexedNetlistModel::net_pin_pair IndexedNetlistModel::net_pin_pair
SingleIndexedNetlistModel::net_pinref_from_index (const net_pair &nets, size_t index) const SingleIndexedNetlistModel::net_pinref_from_index (const net_pair &nets, size_t index) const
{ {
db::Net::const_pin_iterator none; db::Net::const_pin_iterator none;
return attr_by_object_and_index (nets, index, nets.first->begin_pins (), nets.first->end_pins (), none, none, m_pinref_by_net_and_index, sort_by_pin_name<db::NetPinRef> ()); return attr_by_object_and_index (std::make_pair (nets.first, (const db::Net *) 0), index, nets.first->begin_pins (), nets.first->end_pins (), none, none, m_pinref_by_net_and_index, sort_by_pin_name<db::NetPinRef> ());
} }
std::pair<IndexedNetlistModel::device_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::device_from_index(const circuit_pair &circuits, size_t index) const std::pair<IndexedNetlistModel::device_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::device_from_index (const circuit_pair &circuits, size_t index) const
{ {
db::Circuit::const_device_iterator none; db::Circuit::const_device_iterator none;
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_devices (), circuits.first->end_devices (), none, none, m_device_by_circuit_and_index, sort_by_expanded_name<db::Device> ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); return std::make_pair (attr_by_object_and_index (std::make_pair (circuits.first, (const db::Circuit *) 0), index, circuits.first->begin_devices (), circuits.first->end_devices (), none, none, m_device_by_circuit_and_index, sort_by_expanded_name<db::Device> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
} }
std::pair<IndexedNetlistModel::pin_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::pin_from_index(const circuit_pair &circuits, size_t index) const std::pair<IndexedNetlistModel::pin_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::pin_from_index (const circuit_pair &circuits, size_t index) const
{ {
db::Circuit::const_pin_iterator none; db::Circuit::const_pin_iterator none;
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_pins (), circuits.first->end_pins (), none, none, m_pin_by_circuit_and_index, Unsorted ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); return std::make_pair (attr_by_object_and_index (std::make_pair (circuits.first, (const db::Circuit *) 0), index, circuits.first->begin_pins (), circuits.first->end_pins (), none, none, m_pin_by_circuit_and_index, Unsorted ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
} }
std::pair<IndexedNetlistModel::subcircuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::subcircuit_from_index(const circuit_pair &circuits, size_t index) const std::pair<IndexedNetlistModel::subcircuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const
{ {
db::Circuit::const_subcircuit_iterator none; db::Circuit::const_subcircuit_iterator none;
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_subcircuits (), circuits.first->end_subcircuits (), none, none, m_subcircuit_by_circuit_and_index, sort_by_expanded_name<db::SubCircuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); return std::make_pair (attr_by_object_and_index (std::make_pair (circuits.first, (const db::Circuit *) 0), index, circuits.first->begin_subcircuits (), circuits.first->end_subcircuits (), none, none, m_subcircuit_by_circuit_and_index, sort_by_expanded_name<db::SubCircuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
} }
size_t size_t
SingleIndexedNetlistModel::circuit_index (const circuit_pair &circuits) const SingleIndexedNetlistModel::circuit_index (const circuit_pair &circuits) const
{ {
db::Netlist::const_circuit_iterator none; db::Netlist::const_circuit_iterator none;
return index_from_attr (circuits, mp_netlist->begin_circuits (), mp_netlist->end_circuits (), none, none, m_circuit_index_by_object, sort_by_name<db::Circuit> ()); return index_from_attr (std::make_pair (circuits.first, (const db::Circuit *) 0), mp_netlist->begin_circuits (), mp_netlist->end_circuits (), none, none, m_circuit_index_by_object, sort_by_name<db::Circuit> ());
} }
size_t size_t
SingleIndexedNetlistModel::net_index (const net_pair &nets) const SingleIndexedNetlistModel::net_index (const net_pair &nets_in) const
{ {
db::Circuit::const_net_iterator none; db::Circuit::const_net_iterator none;
net_pair nets = nets_in;
nets.second = 0;
circuit_pair circuits = parent_of (nets); circuit_pair circuits = parent_of (nets);
return index_from_attr (nets, return index_from_attr (nets,
circuits.first ? circuits.first->begin_nets () : none, circuits.first ? circuits.first->end_nets () : none, circuits.first ? circuits.first->begin_nets () : none, circuits.first ? circuits.first->end_nets () : none,
circuits.second ? circuits.second->begin_nets () : none, circuits.second ? circuits.second->end_nets () : none, none, none,
m_net_index_by_object, sort_by_expanded_name<db::Net> ()); m_net_index_by_object, sort_by_expanded_name<db::Net> ());
} }
size_t size_t
SingleIndexedNetlistModel::device_index (const device_pair &devices) const SingleIndexedNetlistModel::device_index (const device_pair &devices_in) const
{ {
db::Circuit::const_device_iterator none; db::Circuit::const_device_iterator none;
device_pair devices = devices_in;
devices.second = 0;
circuit_pair circuits = parent_of (devices); circuit_pair circuits = parent_of (devices);
return index_from_attr (devices, return index_from_attr (devices,
circuits.first ? circuits.first->begin_devices () : none, circuits.first ? circuits.first->end_devices () : none, circuits.first ? circuits.first->begin_devices () : none, circuits.first ? circuits.first->end_devices () : none,
circuits.second ? circuits.second->begin_devices () : none, circuits.second ? circuits.second->end_devices () : none, none, none,
m_device_index_by_object, sort_by_expanded_name<db::Device> ()); m_device_index_by_object, sort_by_expanded_name<db::Device> ());
} }
@ -445,21 +454,24 @@ SingleIndexedNetlistModel::pin_index (const pin_pair &pins, const circuit_pair &
{ {
db::Circuit::const_pin_iterator none; db::Circuit::const_pin_iterator none;
return index_from_attr (pins, return index_from_attr (std::make_pair (pins.first, (const db::Pin *) 0),
circuits.first ? circuits.first->begin_pins () : none, circuits.first ? circuits.first->end_pins () : none, circuits.first ? circuits.first->begin_pins () : none, circuits.first ? circuits.first->end_pins () : none,
circuits.second ? circuits.second->begin_pins () : none, circuits.second ? circuits.second->end_pins () : none, none, none,
m_pin_index_by_object, sort_by_expanded_name<db::Pin> ()); m_pin_index_by_object, sort_by_expanded_name<db::Pin> ());
} }
size_t size_t
SingleIndexedNetlistModel::subcircuit_index (const subcircuit_pair &subcircuits) const SingleIndexedNetlistModel::subcircuit_index (const subcircuit_pair &subcircuits_in) const
{ {
db::Circuit::const_subcircuit_iterator none; db::Circuit::const_subcircuit_iterator none;
subcircuit_pair subcircuits = subcircuits_in;
subcircuits.second = 0;
circuit_pair circuits = parent_of (subcircuits); circuit_pair circuits = parent_of (subcircuits);
return index_from_attr (subcircuits, return index_from_attr (subcircuits,
circuits.first ? circuits.first->begin_subcircuits () : none, circuits.first ? circuits.first->end_subcircuits () : none, circuits.first ? circuits.first->begin_subcircuits () : none, circuits.first ? circuits.first->end_subcircuits () : none,
circuits.second ? circuits.second->begin_subcircuits () : none, circuits.second ? circuits.second->end_subcircuits () : none, none, none,
m_subcircuit_index_by_object, sort_by_expanded_name<db::SubCircuit> ()); m_subcircuit_index_by_object, sort_by_expanded_name<db::SubCircuit> ());
} }

View File

@ -141,6 +141,12 @@ NetlistBrowserDialog::db ()
return mp_ui->browser_page->db (); return mp_ui->browser_page->db ();
} }
int
NetlistBrowserDialog::l2n_index ()
{
return m_l2n_index;
}
const lay::NetlistObjectsPath & const lay::NetlistObjectsPath &
NetlistBrowserDialog::current_path () const NetlistBrowserDialog::current_path () const
{ {
@ -152,6 +158,14 @@ NetlistBrowserDialog::current_path () const
} }
} }
void
NetlistBrowserDialog::set_current_path (const lay::NetlistObjectsPath &path)
{
if (mp_ui->browser_page) {
mp_ui->browser_page->select_path (path);
}
}
const std::vector<lay::NetlistObjectsPath> & const std::vector<lay::NetlistObjectsPath> &
NetlistBrowserDialog::selected_paths () const NetlistBrowserDialog::selected_paths () const
{ {

View File

@ -77,11 +77,26 @@ public:
*/ */
db::LayoutToNetlist *db (); db::LayoutToNetlist *db ();
/**
* @brief Gets the index of the currently selected database in the view
*/
int l2n_index ();
/** /**
* @brief Gets the current object's path * @brief Gets the current object's path
*/ */
const lay::NetlistObjectsPath &current_path () const; const lay::NetlistObjectsPath &current_path () const;
/**
* @brief Sets the current object's path
*
* This will make the given netlist object the current one and change the
* selection to this one.
*
* Passing a null path will clear the selection.
*/
void set_current_path (const lay::NetlistObjectsPath &path);
/** /**
* @brief Gets the selected nets * @brief Gets the selected nets
*/ */

View File

@ -3025,9 +3025,9 @@ NetlistBrowserModel::index_from_subcircuit (const std::pair<const db::SubCircuit
} }
QModelIndex QModelIndex
NetlistBrowserModel::index_from_circuit (const db::Circuit *net) const NetlistBrowserModel::index_from_circuit (const db::Circuit *circuit) const
{ {
return index_from_circuit (std::make_pair (net, mp_indexer->second_circuit_for (net))); return index_from_circuit (std::make_pair (circuit, mp_indexer->second_circuit_for (circuit)));
} }
std::pair<const db::Circuit *, const db::Circuit *> std::pair<const db::Circuit *, const db::Circuit *>

View File

@ -502,9 +502,9 @@ NetlistBrowserPage::select_path (const lay::NetlistObjectsPath &path)
{ {
if (path.is_null ()) { if (path.is_null ()) {
nl_directory_tree->clearSelection (); nl_directory_tree->setCurrentIndex (QModelIndex ());
sch_directory_tree->clearSelection (); sch_directory_tree->setCurrentIndex (QModelIndex ());
xref_directory_tree->clearSelection (); xref_directory_tree->setCurrentIndex (QModelIndex ());
} else { } else {
@ -1315,7 +1315,7 @@ NetlistBrowserPage::clear_highlights ()
void void
NetlistBrowserPage::highlight (const NetlistObjectsPath &current_path, const std::vector<NetlistObjectsPath> &selected_paths) NetlistBrowserPage::highlight (const NetlistObjectsPath &current_path, const std::vector<NetlistObjectsPath> &selected_paths)
{ {
if (current_path != m_current_path && selected_paths != m_selected_paths) { if (current_path != m_current_path || selected_paths != m_selected_paths) {
m_current_path = current_path; m_current_path = current_path;
m_selected_paths = selected_paths; m_selected_paths = selected_paths;

View File

@ -169,6 +169,11 @@ public:
*/ */
void update_highlights (); void update_highlights ();
/**
* @brief Adjusts the view depending on the current settings
*/
void adjust_view ();
/** /**
* @brief Gets the current object's path * @brief Gets the current object's path
*/ */
@ -255,7 +260,6 @@ private:
void setup_trees (); void setup_trees ();
void add_to_history (const QModelIndex &index, bool fwd); void add_to_history (const QModelIndex &index, bool fwd);
void navigate_to (const QModelIndex &index, bool forward = true); void navigate_to (const QModelIndex &index, bool forward = true);
void adjust_view ();
void clear_markers (); void clear_markers ();
void highlight (const NetlistObjectsPath &current_path, const std::vector<NetlistObjectsPath> &selected_paths); void highlight (const NetlistObjectsPath &current_path, const std::vector<NetlistObjectsPath> &selected_paths);
void clear_highlights (); void clear_highlights ();