Styling of LVSDB browser

This commit is contained in:
Matthias Koefferlein 2019-05-23 23:54:51 +02:00
parent 3269c4cd15
commit 875609ffb1
11 changed files with 186 additions and 113 deletions

View File

@ -238,6 +238,12 @@
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<attribute name="headerCascadingSectionResizes">
<bool>false</bool>
</attribute>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>

View File

@ -191,6 +191,16 @@ static size_t index_from_attr (const std::pair<const Attr *, const Attr *> &attr
return cc->second;
}
std::string
SingleIndexedNetlistModel::column_title (int section) const
{
if (section == 0) {
return tl::to_string (tr ("Object"));
} else if (section == 1) {
return tl::to_string (tr ("Connections"));
}
}
size_t
SingleIndexedNetlistModel::circuit_count () const
{

View File

@ -67,6 +67,8 @@ public:
typedef std::pair<const db::Pin *, const db::Pin *> pin_pair;
typedef std::pair<const db::SubCircuit *, const db::SubCircuit *> subcircuit_pair;
virtual std::string column_title (int section) const = 0;
virtual size_t circuit_count () const = 0;
virtual size_t net_count (const circuit_pair &circuits) const = 0;
virtual size_t net_terminal_count (const net_pair &nets) const = 0;
@ -121,6 +123,8 @@ public:
return true;
}
virtual std::string column_title (int section) const;
virtual size_t circuit_count () const;
virtual size_t net_count (const circuit_pair &circuits) const;
virtual size_t net_terminal_count (const net_pair &nets) const;

View File

@ -699,7 +699,7 @@ NetlistBrowserDialog::activated ()
if (lay::PluginRoot::instance ()) {
lay::PluginRoot::instance ()->config_get (cfg_l2ndb_window_state, state);
}
lay::restore_dialog_state (this, state);
lay::restore_dialog_state (this, state, false /*don't adjust the section sizes*/);
// Switch to the active cellview index when no valid one is set.
lay::CellView cv = view ()->cellview (m_cv_index);
@ -778,7 +778,7 @@ NetlistBrowserDialog::deactivated ()
release_mouse ();
if (lay::PluginRoot::instance ()) {
lay::PluginRoot::instance ()->config_set (cfg_l2ndb_window_state, lay::save_dialog_state (this).c_str ());
lay::PluginRoot::instance ()->config_set (cfg_l2ndb_window_state, lay::save_dialog_state (this, false /*don't store the section sizes*/).c_str ());
}
browser_frame->set_l2ndb (0);

View File

@ -648,68 +648,56 @@ NetlistBrowserModel::data (const QModelIndex &index, int role) const
}
template <class Obj>
static std::string str_from_expanded_name (const Obj *obj)
static std::string str_from_expanded_name (const Obj *obj, bool dash_for_empty = false)
{
if (obj) {
return obj->expanded_name ();
} else if (dash_for_empty) {
return std::string ("-");
} else {
return std::string ();
}
}
template <class Obj>
static std::string str_from_name (const Obj *obj)
static std::string str_from_name (const Obj *obj, bool dash_for_empty = false)
{
if (obj) {
return obj->name ();
} else if (dash_for_empty) {
return std::string ("-");
} else {
return std::string ();
}
}
const std::string var_sep ("");
template <class Obj>
static std::string str_from_expanded_names (const std::pair<const Obj *, const Obj *> &objs, bool is_single)
{
std::string s;
if (objs.first) {
s += objs.first->expanded_name ();
} else if (! is_single) {
s += "-";
}
std::string s = str_from_expanded_name (objs.first, ! is_single);
if (! is_single) {
s += "/";
if (objs.second) {
s += objs.second->expanded_name ();
} else {
s += "-";
std::string t = str_from_expanded_name (objs.second, ! is_single);
if (t != s) {
s += var_sep;
s += t;
}
}
return s;
}
template <class Obj>
static std::string str_from_names (const std::pair<const Obj *, const Obj *> &objs, bool is_single)
{
std::string s;
if (objs.first) {
s += objs.first->name ();
} else if (! is_single) {
s += "-";
}
std::string s = str_from_name (objs.first, ! is_single);
if (! is_single) {
s += "/";
if (objs.second) {
s += objs.second->name ();
} else {
s += "-";
std::string t = str_from_name (objs.second, ! is_single);
if (t != s) {
s += var_sep;
s += t;
}
}
return s;
}
@ -741,24 +729,29 @@ std::string device_string (const db::Device *device)
return s;
}
static
std::string device_class_string (const db::Device *device, bool dash_for_empty = false)
{
std::string s;
if (device && device->device_class ()) {
s = device->device_class ()->name ();
} else if (dash_for_empty) {
s = "-";
}
return s;
}
static
std::string devices_string (const std::pair<const db::Device *, const db::Device *> &devices, bool is_single)
{
if (devices.first || devices.second) {
std::string s;
if (devices.first && devices.first->device_class ()) {
s += devices.first->device_class ()->name ();
} else if (! is_single) {
s += "-";
}
std::string s = device_class_string (devices.first, ! is_single);
if (! is_single) {
s += "/";
if (devices.second && devices.second->device_class ()) {
s += devices.second->device_class ()->name ();
} else {
s += "-";
std::string t = device_class_string (devices.second, ! is_single);
if (t != s) {
s += var_sep;
s += t;
}
}
@ -769,58 +762,103 @@ std::string devices_string (const std::pair<const db::Device *, const db::Device
}
}
QString
NetlistBrowserModel::make_link_to (const std::pair<const db::Net *, const db::Net *> &nets) const
static QString build_url (void *id, const std::string &tag, const std::string &title)
{
if (! nets.first && ! nets.second) {
std::string s = std::string ("<a href='int:");
s += tag;
s += "?id=";
s += tl::to_string (reinterpret_cast<size_t> (id));
s += "'>";
s += tl::escaped_to_html (title);
s += "</a>";
return tl::to_qstring (s);
}
QString
NetlistBrowserModel::make_link_to (const std::pair<const db::Net *, const db::Net *> &nets, int column) const
{
if ((! nets.first || column == 2) && (! nets.second || column == 1)) {
return QString ();
} else {
void *id = make_id_circuit_net (mp_indexer->circuit_index (mp_indexer->parent_of (nets)), mp_indexer->net_index (nets));
return tl::to_qstring (tl::sprintf ("<a href='int:net?id=%s'>%s</a>", tl::to_string (reinterpret_cast<size_t> (id)), str_from_expanded_names (nets, mp_indexer->is_single ())));
if (mp_indexer->is_single () || column == 1) {
return build_url (id, "net", str_from_expanded_name (nets.first));
} else if (column == 2) {
return build_url (id, "net", str_from_expanded_name (nets.second));
} else {
return build_url (id, "net", str_from_expanded_names (nets, mp_indexer->is_single ()));
}
}
}
QString
NetlistBrowserModel::make_link_to (const std::pair<const db::Device *, const db::Device *> &devices) const
NetlistBrowserModel::make_link_to (const std::pair<const db::Device *, const db::Device *> &devices, int column) const
{
if (! devices.first && ! devices.second) {
if ((! devices.first || column == 2) && (! devices.second || column == 1)) {
return QString ();
} else {
void *id = make_id_circuit_device (mp_indexer->circuit_index (mp_indexer->parent_of (devices)), mp_indexer->device_index (devices));
return tl::to_qstring (tl::sprintf ("<a href='int:device?id=%s'>%s</a>", tl::to_string (reinterpret_cast<size_t> (id)), str_from_expanded_names (devices, mp_indexer->is_single ())));
if (mp_indexer->is_single () || column == 1) {
return build_url (id, "device", str_from_expanded_name (devices.first));
} else if (column == 2) {
return build_url (id, "device", str_from_expanded_name (devices.second));
} else {
return build_url (id, "device", str_from_expanded_names (devices, mp_indexer->is_single ()));
}
}
}
QString
NetlistBrowserModel::make_link_to (const std::pair<const db::Pin *, const db::Pin *> &pins, const std::pair<const db::Circuit *, const db::Circuit *> &circuits) const
NetlistBrowserModel::make_link_to (const std::pair<const db::Pin *, const db::Pin *> &pins, const std::pair<const db::Circuit *, const db::Circuit *> &circuits, int column) const
{
if (! pins.first && ! pins.second) {
if ((! pins.first || column == 2) && (! pins.second || column == 1)) {
return QString ();
} else {
void *id = make_id_circuit_pin (mp_indexer->circuit_index (circuits), mp_indexer->pin_index (pins, circuits));
return tl::to_qstring (tl::sprintf ("<a href='int:pin?id=%s'>%s</a>", tl::to_string (reinterpret_cast<size_t> (id)), str_from_expanded_names (pins, mp_indexer->is_single ())));
if (mp_indexer->is_single () || column == 1) {
return build_url (id, "pin", str_from_expanded_name (pins.first));
} else if (column == 2) {
return build_url (id, "pin", str_from_expanded_name (pins.second));
} else {
return build_url (id, "pin", str_from_expanded_names (pins, mp_indexer->is_single ()));
}
}
}
QString
NetlistBrowserModel::make_link_to (const std::pair<const db::Circuit *, const db::Circuit *> &circuits) const
NetlistBrowserModel::make_link_to (const std::pair<const db::Circuit *, const db::Circuit *> &circuits, int column) const
{
if (! circuits.first && ! circuits.second) {
if ((! circuits.first || column == 2) && (! circuits.second || column == 1)) {
return QString ();
} else {
void *id = make_id_circuit (mp_indexer->circuit_index (circuits));
return tl::to_qstring (tl::sprintf ("<a href='int:circuit?id=%s'>%s</a>", tl::to_string (reinterpret_cast<size_t> (id)), str_from_names (circuits, mp_indexer->is_single ())));
if (mp_indexer->is_single () || column == 1) {
return build_url (id, "circuit", str_from_name (circuits.first));
} else if (column == 2) {
return build_url (id, "circuit", str_from_name (circuits.second));
} else {
return build_url (id, "circuit", str_from_names (circuits, mp_indexer->is_single ()));
}
}
}
QString
NetlistBrowserModel::make_link_to (const std::pair<const db::SubCircuit *, const db::SubCircuit *> &subcircuits) const
NetlistBrowserModel::make_link_to (const std::pair<const db::SubCircuit *, const db::SubCircuit *> &subcircuits, int column) const
{
if (! subcircuits.first && ! subcircuits.second) {
if ((! subcircuits.first || column == 2) && (! subcircuits.second || column == 1)) {
return QString ();
} else {
void *id = make_id_circuit_subcircuit (mp_indexer->circuit_index (mp_indexer->parent_of (subcircuits)), mp_indexer->subcircuit_index (subcircuits));
return tl::to_qstring (tl::sprintf ("<a href='int:subcircuit?id=%s'>%s</a>", tl::to_string (reinterpret_cast<size_t> (id)), str_from_expanded_names (subcircuits, mp_indexer->is_single ())));
if (mp_indexer->is_single () || column == 1) {
return build_url (id, "subcircuit", str_from_expanded_name (subcircuits.first));
} else if (column == 2) {
return build_url (id, "subcircuit", str_from_expanded_name (subcircuits.second));
} else {
return build_url (id, "subcircuit", str_from_expanded_names (subcircuits, mp_indexer->is_single ()));
}
}
}
@ -957,6 +995,7 @@ IndexedNetlistModel::net_pair nets_from_device_terminals (const IndexedNetlistMo
return std::make_pair (net1, net2);
}
const std::string field_sep (" / ");
QString
NetlistBrowserModel::text (const QModelIndex &index) const
@ -997,9 +1036,8 @@ NetlistBrowserModel::text (const QModelIndex &index) const
if (index.column () == 0) {
return tl::to_qstring (str_from_expanded_names (nets, mp_indexer->is_single ()));
} else {
return make_link_to (nets);
return make_link_to (nets, index.column ());
}
// TODO: in case of compare, column 1 is name(a):name(b), 2 is link name(a) and 3 is link name(b)
} else if (is_id_circuit_device (id)) {
@ -1019,9 +1057,9 @@ NetlistBrowserModel::text (const QModelIndex &index) const
if (index.column () == 0) {
return tl::to_qstring (devices_string (devices, mp_indexer->is_single ()));
} else if (index.column () == 1) {
return tl::to_qstring (str_from_expanded_name (devices.first) + " - " + device_string (devices.first));
return tl::to_qstring (str_from_expanded_name (devices.first) + field_sep + device_string (devices.first));
} else if (index.column () == 2) {
return tl::to_qstring (str_from_expanded_name (devices.second) + " - " + device_string (devices.second));
return tl::to_qstring (str_from_expanded_name (devices.second) + field_sep + device_string (devices.second));
}
}
@ -1042,10 +1080,9 @@ NetlistBrowserModel::text (const QModelIndex &index) const
} else {
IndexedNetlistModel::net_pair nets = nets_from_device_terminals (devices, termdefs);
return make_link_to (nets);
return make_link_to (nets, index.column ());
}
// TODO: in case of compare, column 1 is terminal, 2 is linke net(a) and 3 is link net(b)
} else if (is_id_circuit_subcircuit (id)) {
@ -1054,10 +1091,11 @@ NetlistBrowserModel::text (const QModelIndex &index) const
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits);
if (index.column () == 0) {
return make_link_to (circuit_refs);
} else {
return tl::to_qstring (str_from_expanded_names (subcircuits, mp_indexer->is_single ()));
} else if (mp_indexer->is_single () || index.column () == 1) {
return tl::to_qstring (str_from_expanded_name (subcircuits.first));
} else if (index.column () == 2) {
return tl::to_qstring (str_from_expanded_name (subcircuits.second));
}
// TODO: in case of compare, column 1 is circuit name(a):circuit name(b), 2 is subcircuit name(a) and 3 is subcircuit name(b)
} else if (is_id_circuit_subcircuit_pin (id)) {
@ -1069,9 +1107,8 @@ NetlistBrowserModel::text (const QModelIndex &index) const
if (index.column () == 0) {
return make_link_to (pins, circuit_refs);
} else {
return make_link_to (nets_from_subcircuit_pins (subcircuits, pins));
return make_link_to (nets_from_subcircuit_pins (subcircuits, pins), index.column ());
}
// TODO: in case of compare, column 1 is name(a):name(b), 2 is link net(a) and 3 is link net(b)
} else if (is_id_circuit_net (id)) {
@ -1090,12 +1127,11 @@ NetlistBrowserModel::text (const QModelIndex &index) const
// circuit/net/pin: header column = pin name, second column empty (for now)
IndexedNetlistModel::net_pin_pair pinrefs = net_pinrefs_from_id (id);
IndexedNetlistModel::circuit_pair circuits = circuits_from_id (id);
if (index.column () == 0) {
if (mp_indexer->is_single () && index.column () == 0) {
return make_link_to (pins_from_pinrefs (pinrefs), circuits);
} else if (! mp_indexer->is_single ()) {
return make_link_to (pins_from_pinrefs (pinrefs), circuits, index.column ());
}
// TODO: in case of compare use second and third column
} else if (is_id_circuit_net_subcircuit_pin (id)) {
@ -1105,16 +1141,10 @@ NetlistBrowserModel::text (const QModelIndex &index) const
IndexedNetlistModel::circuit_pair circuit_refs = circuit_refs_from_subcircuits (subcircuits);
if (index.column () == 0) {
return make_link_to (pins_from_pinrefs (pinrefs), circuit_refs) + tl::to_qstring (" - ") + make_link_to (circuit_refs);
} else if (index.column () == 1) {
return make_link_to (subcircuits_from_pinrefs (pinrefs));
return make_link_to (pins_from_pinrefs (pinrefs), circuit_refs) + tl::to_qstring (field_sep) + make_link_to (circuit_refs);
} else {
return make_link_to (subcircuits_from_pinrefs (pinrefs), index.column ());
}
// TODO: in case of compare, column 1 is pin link(a):pin link(b) - circuit link(a):circuit link(b),
// columns 2 is subcircuit link(a), columns (3) is subcircuit link(b)
} else if (is_id_circuit_net_subcircuit_pin_others (id)) {
@ -1129,9 +1159,8 @@ NetlistBrowserModel::text (const QModelIndex &index) const
if (index.column () == 0) {
return make_link_to (pins, circuit_refs);
} else {
return make_link_to (nets_from_subcircuit_pins (subcircuits, pins));
return make_link_to (nets_from_subcircuit_pins (subcircuits, pins), index.column ());
}
// TODO: columns 2 and 3
} else if (is_id_circuit_net_device_terminal (id)) {
@ -1144,15 +1173,14 @@ NetlistBrowserModel::text (const QModelIndex &index) const
std::pair<const db::DeviceTerminalDefinition *, const db::DeviceTerminalDefinition *> termdefs = terminal_defs_from_terminal_refs (refs);
if (mp_indexer->is_single ()) {
return tl::to_qstring (str_from_name (termdefs.first) + " - " + device_string (devices.first));
return tl::to_qstring (str_from_name (termdefs.first) + field_sep + device_string (devices.first));
} else {
return tl::to_qstring (str_from_names (termdefs, mp_indexer->is_single ()) + " - " + devices_string (devices, mp_indexer->is_single ()));
return tl::to_qstring (str_from_names (termdefs, mp_indexer->is_single ()) + field_sep + devices_string (devices, mp_indexer->is_single ()));
}
} else {
return make_link_to (devices);
return make_link_to (devices, index.column ());
}
// TODO: columns 2 and 3
} else if (is_id_circuit_net_device_terminal_others (id)) {
@ -1171,10 +1199,9 @@ NetlistBrowserModel::text (const QModelIndex &index) const
} else {
IndexedNetlistModel::net_pair nets = nets_from_device_terminals (devices, termdefs);
return make_link_to (nets);
return make_link_to (nets, index.column ());
}
// TODO: other columns
}
@ -1526,7 +1553,7 @@ NetlistBrowserModel::icon (const QModelIndex &index) const
return icon_for_devices (device_classes);
} else if (is_id_circuit_net_device_terminal_others (id) || is_id_circuit_net_subcircuit_pin_others (id)) {
} else if (is_id_circuit_pin_net (id) || is_id_circuit_device_terminal (id) || is_id_circuit_net_device_terminal_others (id) || is_id_circuit_net_subcircuit_pin_others (id)) {
IndexedNetlistModel::net_pair nets = net_from_index (index);
return icon_for_connection (nets);
@ -1653,15 +1680,10 @@ QVariant
NetlistBrowserModel::headerData (int section, Qt::Orientation /*orientation*/, int role) const
{
if (role == Qt::DisplayRole) {
if (section == 0) {
return tr ("Object");
} else if (section == 1) {
// TODO: 2 and 3 columns
return tr ("Name (Items)");
}
return tl::to_qstring (mp_indexer->column_title (section));
} else {
return QVariant ();
}
return QVariant ();
}
QModelIndex

View File

@ -189,11 +189,11 @@ private:
QString text (const QModelIndex &index) const;
QString search_text (const QModelIndex &index) const;
QIcon icon (const QModelIndex &index) const;
QString make_link_to (const std::pair<const db::Net *, const db::Net *> &nets) const;
QString make_link_to (const std::pair<const db::Device *, const db::Device *> &devices) const;
QString make_link_to (const std::pair<const db::Pin *, const db::Pin *> &pins, const std::pair<const db::Circuit *, const db::Circuit *> &circuits) const;
QString make_link_to (const std::pair<const db::Circuit *, const db::Circuit *> &circuits) const;
QString make_link_to (const std::pair<const db::SubCircuit *, const db::SubCircuit *> &sub_circuits) const;
QString make_link_to (const std::pair<const db::Net *, const db::Net *> &nets, int column = 0) const;
QString make_link_to (const std::pair<const db::Device *, const db::Device *> &devices, int column = 0) const;
QString make_link_to (const std::pair<const db::Pin *, const db::Pin *> &pins, const std::pair<const db::Circuit *, const db::Circuit *> &circuits, int column = 0) const;
QString make_link_to (const std::pair<const db::Circuit *, const db::Circuit *> &circuits, int column = 0) const;
QString make_link_to (const std::pair<const db::SubCircuit *, const db::SubCircuit *> &sub_circuits, int column = 0) const;
std::pair<const db::Netlist *, const db::Netlist *> netlists () const
{

View File

@ -141,8 +141,16 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/)
directory_tree->addAction (actionExportSelected);
directory_tree->addAction (actionExportAll);
directory_tree->header ()->setDefaultSectionSize (150);
lay::HTMLItemDelegate *delegate;
delegate = new lay::HTMLItemDelegate (this);
delegate->set_text_margin (2);
delegate->set_anchors_clickable (true);
connect (delegate, SIGNAL (anchor_clicked (const QString &)), this, SLOT (anchor_clicked (const QString &)));
directory_tree->setItemDelegateForColumn (2, delegate);
delegate = new lay::HTMLItemDelegate (this);
delegate->set_text_margin (2);
delegate->set_anchors_clickable (true);
@ -646,13 +654,22 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
new_model = new NetlistBrowserModel (directory_tree, l2ndb, &m_colorizer);
}
int columns = directory_tree->model () ? directory_tree->model ()->columnCount (QModelIndex ()) : 0;
int new_columns = new_model->columnCount (QModelIndex ());
delete directory_tree->model ();
directory_tree->setModel (new_model);
connect (directory_tree->selectionModel (), SIGNAL (currentChanged (const QModelIndex &, const QModelIndex &)), this, SLOT (current_index_changed (const QModelIndex &)));
connect (directory_tree->selectionModel (), SIGNAL (selectionChanged (const QItemSelection &, const QItemSelection &)), this, SLOT (selection_changed ()));
directory_tree->header ()->show ();
directory_tree->header ()->setSortIndicatorShown (true);
directory_tree->header ()->setStretchLastSection (true);
if (columns < new_columns) {
// makes sure new columns are properly size-adjusted
for (int i = std::max (0, columns - 1); i < new_columns; ++i) {
directory_tree->header ()->resizeSection (i, directory_tree->header ()->defaultSectionSize ());
}
}
find_text->setText (QString ());
}

View File

@ -32,6 +32,18 @@ NetlistCrossReferenceModel::NetlistCrossReferenceModel (const db::NetlistCrossRe
// .. nothing yet ..
}
std::string
NetlistCrossReferenceModel::column_title (int section) const
{
if (section == 0) {
return tl::to_string (tr ("Objects"));
} else if (section == 1) {
return tl::to_string (tr ("Layout"));
} else if (section == 2) {
return tl::to_string (tr ("Reference"));
}
}
size_t NetlistCrossReferenceModel::circuit_count () const
{
return mp_cross_ref->circuit_count ();

View File

@ -43,6 +43,8 @@ public:
virtual bool is_single () const { return false; }
virtual std::string column_title (int section) const;
virtual size_t circuit_count () const;
virtual size_t net_count (const circuit_pair &circuits) const;
virtual size_t net_terminal_count (const net_pair &nets) const;

View File

@ -68,7 +68,7 @@ void register_help_handler (QObject *object, const char *slot, const char *modal
// --------------------------------------------------------------------------------
std::string
save_dialog_state (QWidget *w)
save_dialog_state (QWidget *w, bool with_section_sizes)
{
std::string s;
@ -86,7 +86,7 @@ save_dialog_state (QWidget *w)
s += (dynamic_cast<QSplitter *> (w))->saveState ().toBase64 ().constData ();
s += "\";";
} else if (dynamic_cast<QTreeView *> (w)) {
} else if (with_section_sizes && dynamic_cast<QTreeView *> (w)) {
s += tl::to_string (w->objectName ());
s += "=\"";
@ -112,7 +112,7 @@ save_dialog_state (QWidget *w)
}
void
restore_dialog_state (QWidget *dialog, const std::string &s)
restore_dialog_state (QWidget *dialog, const std::string &s, bool with_section_sizes)
{
if (! dialog) {
return;
@ -145,7 +145,7 @@ restore_dialog_state (QWidget *dialog, const std::string &s)
(dynamic_cast<QSplitter *> (widgets.front ()))->restoreState (QByteArray::fromBase64 (value.c_str ()));
} else if (dynamic_cast<QTreeView *> (widgets.front ())) {
} else if (with_section_sizes && dynamic_cast<QTreeView *> (widgets.front ())) {
#if QT_VERSION >= 0x040500
(dynamic_cast<QTreeView *> (widgets.front ()))->header ()->restoreState (QByteArray::fromBase64 (value.c_str ()));

View File

@ -40,12 +40,12 @@ namespace lay
*
* The state can be recovered from the string using restore_dialog_state;
*/
LAYBASIC_PUBLIC std::string save_dialog_state (QWidget *dialog);
LAYBASIC_PUBLIC std::string save_dialog_state (QWidget *dialog, bool with_section_sizes = true);
/**
* @brief Restore the dialog's state from the given string
*/
LAYBASIC_PUBLIC void restore_dialog_state (QWidget *dialog, const std::string &s);
LAYBASIC_PUBLIC void restore_dialog_state (QWidget *dialog, const std::string &s, bool with_section_sizes = true);
/**
* @brief A utility function connecting a label's linkActivated event with the help browser