mirror of https://github.com/KLayout/klayout.git
Improvements on layer list search and filtering
This commit is contained in:
parent
71f64f5f63
commit
0f8dc9ac13
|
|
@ -34,6 +34,7 @@
|
|||
#include "layDialogs.h"
|
||||
#include "layLayoutCanvas.h"
|
||||
#include "layAbstractMenu.h"
|
||||
#include "layQtTools.h"
|
||||
#include "tlExceptions.h"
|
||||
#include "tlInternational.h"
|
||||
#include "tlAssert.h"
|
||||
|
|
@ -203,12 +204,10 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage
|
|||
mp_view (view),
|
||||
m_needs_update (true),
|
||||
m_tabs_need_update (true),
|
||||
m_force_update_hidden_flags (true),
|
||||
m_in_update (false),
|
||||
m_phase (0),
|
||||
m_do_update_content_dm (this, &LayerControlPanel::do_update_content),
|
||||
m_hide_empty_layers (false),
|
||||
m_test_shapes_in_view (false),
|
||||
m_do_update_hidden_flags_dm (this, &LayerControlPanel::do_update_hidden_flags),
|
||||
m_no_stipples (false)
|
||||
{
|
||||
setObjectName (QString::fromUtf8 (name));
|
||||
|
|
@ -269,11 +268,18 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage
|
|||
mp_case_sensitive->setChecked (true);
|
||||
mp_case_sensitive->setText (tr ("Case sensitive search"));
|
||||
|
||||
mp_filter = new QAction (this);
|
||||
mp_filter->setCheckable (true);
|
||||
mp_filter->setChecked (false);
|
||||
mp_filter->setText (tr ("Apply as filter"));
|
||||
|
||||
QMenu *m = new QMenu (mp_search_edit_box);
|
||||
m->addAction (mp_use_regular_expressions);
|
||||
m->addAction (mp_case_sensitive);
|
||||
m->addAction (mp_filter);
|
||||
connect (mp_use_regular_expressions, SIGNAL (triggered ()), this, SLOT (search_edited ()));
|
||||
connect (mp_case_sensitive, SIGNAL (triggered ()), this, SLOT (search_edited ()));
|
||||
connect (mp_filter, SIGNAL (triggered ()), this, SLOT (search_edited ()));
|
||||
|
||||
mp_search_edit_box->set_clear_button_enabled (true);
|
||||
mp_search_edit_box->set_options_button_enabled (true);
|
||||
|
|
@ -370,6 +376,8 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage
|
|||
m_no_stipples_label->setPixmap (QPixmap (QString::fromUtf8 (":/important.png")));
|
||||
m_no_stipples_label->setToolTip (tr ("Stipples are disabled - unselect \"View/Show Layers Without Fill\" to re-enable them"));
|
||||
ltb->addWidget (m_no_stipples_label);
|
||||
|
||||
connect (mp_model, SIGNAL (hidden_flags_need_update ()), this, SLOT (update_hidden_flags ()));
|
||||
}
|
||||
|
||||
LayerControlPanel::~LayerControlPanel ()
|
||||
|
|
@ -1126,6 +1134,10 @@ LayerControlPanel::search_edited ()
|
|||
return;
|
||||
}
|
||||
|
||||
mp_model->set_filter_mode (mp_filter->isChecked ());
|
||||
|
||||
bool filter_invalid = false;
|
||||
|
||||
QString t = mp_search_edit_box->text ();
|
||||
if (t.isEmpty ()) {
|
||||
mp_model->clear_locate ();
|
||||
|
|
@ -1135,8 +1147,12 @@ LayerControlPanel::search_edited ()
|
|||
mp_layer_list->setCurrentIndex (found);
|
||||
if (found.isValid ()) {
|
||||
mp_layer_list->scrollTo (found);
|
||||
} else {
|
||||
filter_invalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
lay::indicate_error (mp_search_edit_box, filter_invalid);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1642,27 +1658,28 @@ LayerControlPanel::set_text_color (QColor c)
|
|||
mp_model->set_text_color (c);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
LayerControlPanel::update_hidden_flags ()
|
||||
{
|
||||
m_do_update_hidden_flags_dm ();
|
||||
}
|
||||
|
||||
void
|
||||
LayerControlPanel::set_hide_empty_layers (bool f)
|
||||
{
|
||||
if (f != m_hide_empty_layers) {
|
||||
m_hide_empty_layers = f;
|
||||
m_force_update_hidden_flags = true;
|
||||
m_do_update_content_dm ();
|
||||
}
|
||||
mp_model->set_hide_empty_layers (f);
|
||||
}
|
||||
|
||||
bool
|
||||
LayerControlPanel::hide_empty_layers ()
|
||||
{
|
||||
return mp_model->get_hide_empty_layers ();
|
||||
}
|
||||
|
||||
void
|
||||
LayerControlPanel::set_test_shapes_in_view (bool f)
|
||||
{
|
||||
if (f != m_test_shapes_in_view) {
|
||||
m_test_shapes_in_view = f;
|
||||
mp_model->set_test_shapes_in_view (f);
|
||||
if (m_hide_empty_layers) {
|
||||
m_force_update_hidden_flags = true;
|
||||
}
|
||||
m_do_update_content_dm ();
|
||||
}
|
||||
mp_model->set_test_shapes_in_view (f);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1707,7 +1724,6 @@ LayerControlPanel::cancel_updates ()
|
|||
void
|
||||
LayerControlPanel::end_updates ()
|
||||
{
|
||||
m_force_update_hidden_flags = true;
|
||||
do_update_content ();
|
||||
}
|
||||
|
||||
|
|
@ -1721,7 +1737,7 @@ LayerControlPanel::set_phase (int phase)
|
|||
}
|
||||
|
||||
static void
|
||||
set_hidden_flags_within_view_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent, bool hide_empty)
|
||||
set_hidden_flags_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent)
|
||||
{
|
||||
int rows = model->rowCount (parent);
|
||||
for (int r = 0; r < rows; ++r) {
|
||||
|
|
@ -1730,7 +1746,7 @@ set_hidden_flags_within_view_rec (LayerTreeModel *model, QTreeView *tree_view, c
|
|||
|
||||
if (! model->hasChildren (index)) {
|
||||
|
||||
if (hide_empty && model->empty_within_view_predicate (index)) {
|
||||
if (model->is_hidden (index)) {
|
||||
tree_view->setRowHidden (r, parent, true);
|
||||
} else {
|
||||
tree_view->setRowHidden (r, parent, false);
|
||||
|
|
@ -1738,43 +1754,33 @@ set_hidden_flags_within_view_rec (LayerTreeModel *model, QTreeView *tree_view, c
|
|||
|
||||
} else {
|
||||
tree_view->setRowHidden (r, parent, false);
|
||||
set_hidden_flags_within_view_rec (model, tree_view, index, hide_empty);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_hidden_flags_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent, bool hide_empty)
|
||||
{
|
||||
int rows = model->rowCount (parent);
|
||||
for (int r = 0; r < rows; ++r) {
|
||||
|
||||
QModelIndex index = model->index (r, 0, parent);
|
||||
|
||||
if (! model->hasChildren (index)) {
|
||||
|
||||
if (hide_empty && model->empty_predicate (index)) {
|
||||
tree_view->setRowHidden (r, parent, true);
|
||||
} else {
|
||||
tree_view->setRowHidden (r, parent, false);
|
||||
}
|
||||
|
||||
} else {
|
||||
tree_view->setRowHidden (r, parent, false);
|
||||
set_hidden_flags_rec (model, tree_view, index, hide_empty);
|
||||
set_hidden_flags_rec (model, tree_view, index);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayerControlPanel::do_update_hidden_flags ()
|
||||
{
|
||||
set_hidden_flags_rec (mp_model, mp_layer_list, QModelIndex ());
|
||||
|
||||
// scroll the current index into view if it was not visible before
|
||||
QModelIndex current = mp_layer_list->currentIndex ();
|
||||
if (current.isValid ()) {
|
||||
QModelIndex parent = mp_layer_list->model ()->parent (current);
|
||||
if (! mp_layer_list->isRowHidden (current.row (), parent)) {
|
||||
QRect visual_rect = mp_layer_list->visualRect (current);
|
||||
if (! visual_rect.intersects (mp_layer_list->viewport ()->rect ())) {
|
||||
mp_layer_list->scrollTo (current, QAbstractItemView::PositionAtCenter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayerControlPanel::do_update_content ()
|
||||
{
|
||||
// clear search. TODO: update search instead of clearing
|
||||
mp_search_edit_box->clear ();
|
||||
mp_model->clear_locate();
|
||||
|
||||
mp_model->set_phase (m_phase);
|
||||
|
||||
if (m_tabs_need_update) {
|
||||
|
|
@ -1853,48 +1859,21 @@ LayerControlPanel::do_update_content ()
|
|||
|
||||
m_needs_update = false;
|
||||
|
||||
} else if (m_needs_update) {
|
||||
|
||||
m_needs_update = false;
|
||||
|
||||
bool has_children = false;
|
||||
for (lay::LayerPropertiesConstIterator l = mp_view->begin_layers (); l != mp_view->end_layers () && ! has_children; ++l) {
|
||||
if (l->has_children ()) {
|
||||
has_children = true;
|
||||
}
|
||||
}
|
||||
mp_layer_list->setRootIsDecorated (has_children);
|
||||
mp_layer_list->reset ();
|
||||
|
||||
} else {
|
||||
|
||||
if (m_needs_update) {
|
||||
|
||||
m_needs_update = false;
|
||||
|
||||
bool has_children = false;
|
||||
for (lay::LayerPropertiesConstIterator l = mp_view->begin_layers (); l != mp_view->end_layers () && ! has_children; ++l) {
|
||||
if (l->has_children ()) {
|
||||
has_children = true;
|
||||
}
|
||||
}
|
||||
mp_layer_list->setRootIsDecorated (has_children);
|
||||
mp_layer_list->reset ();
|
||||
|
||||
} else {
|
||||
mp_model->signal_data_changed (); // this makes the view redraw the data
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (m_hide_empty_layers || m_force_update_hidden_flags) {
|
||||
|
||||
m_force_update_hidden_flags = false;
|
||||
if (m_test_shapes_in_view) {
|
||||
set_hidden_flags_within_view_rec (mp_model, mp_layer_list, QModelIndex (), m_hide_empty_layers);
|
||||
} else {
|
||||
set_hidden_flags_rec (mp_model, mp_layer_list, QModelIndex (), m_hide_empty_layers);
|
||||
}
|
||||
|
||||
// scroll the current index into view if it was not visible before
|
||||
QModelIndex current = mp_layer_list->currentIndex ();
|
||||
if (current.isValid ()) {
|
||||
QModelIndex parent = mp_layer_list->model ()->parent (current);
|
||||
if (! mp_layer_list->isRowHidden (current.row (), parent)) {
|
||||
QRect visual_rect = mp_layer_list->visualRect (current);
|
||||
if (! visual_rect.intersects (mp_layer_list->viewport ()->rect ())) {
|
||||
mp_layer_list->scrollTo (current, QAbstractItemView::PositionAtCenter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mp_model->signal_data_changed (); // this makes the view redraw the data
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1975,7 +1954,7 @@ LayerControlPanel::redo (db::Op *op)
|
|||
void
|
||||
LayerControlPanel::signal_vp_changed ()
|
||||
{
|
||||
if (m_test_shapes_in_view) {
|
||||
if (mp_model->get_test_shapes_in_view ()) {
|
||||
update_required (1);
|
||||
}
|
||||
}
|
||||
|
|
@ -2028,7 +2007,7 @@ LayerControlPanel::update_required (int f)
|
|||
}
|
||||
|
||||
if ((f & 3) != 0) {
|
||||
m_force_update_hidden_flags = true;
|
||||
m_do_update_hidden_flags_dm ();
|
||||
}
|
||||
|
||||
m_do_update_content_dm ();
|
||||
|
|
|
|||
|
|
@ -184,10 +184,7 @@ public:
|
|||
/**
|
||||
* @brief Get the "hide empty layers" flag
|
||||
*/
|
||||
bool hide_empty_layers ()
|
||||
{
|
||||
return m_hide_empty_layers;
|
||||
}
|
||||
bool hide_empty_layers ();
|
||||
|
||||
/**
|
||||
* @brief Set the "test_shapes_in_view" flag
|
||||
|
|
@ -201,7 +198,7 @@ public:
|
|||
*/
|
||||
bool test_shapes_in_view ()
|
||||
{
|
||||
return m_test_shapes_in_view;
|
||||
return mp_model->get_test_shapes_in_view ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -333,6 +330,9 @@ public slots:
|
|||
void search_next ();
|
||||
void search_prev ();
|
||||
|
||||
private slots:
|
||||
void update_hidden_flags ();
|
||||
|
||||
private:
|
||||
QTabBar *mp_tab_bar;
|
||||
LCPTreeWidget *mp_layer_list;
|
||||
|
|
@ -341,19 +341,17 @@ private:
|
|||
lay::LayoutView *mp_view;
|
||||
bool m_needs_update;
|
||||
bool m_tabs_need_update;
|
||||
bool m_force_update_hidden_flags;
|
||||
bool m_in_update;
|
||||
std::vector<size_t> m_new_sel;
|
||||
int m_phase;
|
||||
tl::DeferredMethod<LayerControlPanel> m_do_update_content_dm;
|
||||
bool m_hide_empty_layers;
|
||||
bool m_test_shapes_in_view;
|
||||
tl::DeferredMethod<LayerControlPanel> m_do_update_content_dm, m_do_update_hidden_flags_dm;
|
||||
std::set<unsigned int> m_expanded;
|
||||
bool m_no_stipples;
|
||||
QLabel *m_no_stipples_label;
|
||||
lay::DecoratedLineEdit *mp_search_edit_box;
|
||||
QAction *mp_case_sensitive;
|
||||
QAction *mp_use_regular_expressions;
|
||||
QAction *mp_filter;
|
||||
QFrame *mp_search_frame;
|
||||
QCheckBox *mp_search_close_cb;
|
||||
|
||||
|
|
@ -369,6 +367,7 @@ private:
|
|||
void signal_vp_changed ();
|
||||
|
||||
void do_update_content ();
|
||||
void do_update_hidden_flags ();
|
||||
void do_delete ();
|
||||
void do_copy ();
|
||||
void recover ();
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ EmptyWithinViewCache::determine_empty_layers (const db::Layout *layout, unsigned
|
|||
|
||||
LayerTreeModel::LayerTreeModel (QWidget *parent, lay::LayoutView *view)
|
||||
: QAbstractItemModel (parent),
|
||||
mp_view (view), m_id_start (0), m_id_end (0), m_phase ((unsigned int) -1), m_test_shapes_in_view (false)
|
||||
mp_view (view), m_filter_mode (false), m_id_start (0), m_id_end (0), m_phase ((unsigned int) -1), m_test_shapes_in_view (false), m_hide_empty_layers (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -210,6 +210,37 @@ LayerTreeModel::set_text_color (QColor color)
|
|||
signal_data_changed ();
|
||||
}
|
||||
|
||||
void
|
||||
LayerTreeModel::set_test_shapes_in_view (bool f)
|
||||
{
|
||||
if (m_test_shapes_in_view != f) {
|
||||
m_test_shapes_in_view = f;
|
||||
if (m_hide_empty_layers) {
|
||||
emit hidden_flags_need_update ();
|
||||
}
|
||||
signal_data_changed ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayerTreeModel::set_hide_empty_layers (bool f)
|
||||
{
|
||||
if (m_hide_empty_layers != f) {
|
||||
m_hide_empty_layers = f;
|
||||
// we actually can't do this ourselves.
|
||||
emit hidden_flags_need_update ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayerTreeModel::set_filter_mode (bool f)
|
||||
{
|
||||
if (f != m_filter_mode) {
|
||||
m_filter_mode = f;
|
||||
emit hidden_flags_need_update ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayerTreeModel::set_background_color (QColor background)
|
||||
{
|
||||
|
|
@ -288,6 +319,10 @@ LayerTreeModel::clear_locate ()
|
|||
m_selected_ids.clear ();
|
||||
|
||||
signal_data_changed ();
|
||||
|
||||
if (m_filter_mode) {
|
||||
emit hidden_flags_need_update ();
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex
|
||||
|
|
@ -358,6 +393,10 @@ LayerTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive
|
|||
|
||||
signal_data_changed ();
|
||||
|
||||
if (m_filter_mode) {
|
||||
emit hidden_flags_need_update ();
|
||||
}
|
||||
|
||||
m_current_index = m_selected_indexes.begin ();
|
||||
if (m_current_index == m_selected_indexes.end ()) {
|
||||
return QModelIndex ();
|
||||
|
|
@ -481,6 +520,22 @@ single_bitmap_to_image (const lay::ViewOp &view_op, lay::Bitmap &bitmap,
|
|||
lay::bitmaps_to_image (view_ops, pbitmaps, dither_pattern, line_styles, pimage, width, height, false, 0);
|
||||
}
|
||||
|
||||
bool
|
||||
LayerTreeModel::is_hidden (const QModelIndex &index) const
|
||||
{
|
||||
if (m_filter_mode && ! m_selected_ids.empty () && m_selected_ids.find (size_t (index.internalPointer ())) == m_selected_ids.end ()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (! m_hide_empty_layers) {
|
||||
return false;
|
||||
} else if (m_test_shapes_in_view) {
|
||||
return empty_within_view_predicate (index);
|
||||
} else {
|
||||
return empty_predicate (index);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
LayerTreeModel::empty_predicate (const QModelIndex &index) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -126,21 +126,9 @@ public:
|
|||
lay::LayerPropertiesConstIterator iterator (const QModelIndex &index) const;
|
||||
|
||||
/**
|
||||
* @brief Get a flag indicating that a layer is empty
|
||||
* @brief Get a flag indicating that an entry is hidden
|
||||
*/
|
||||
bool empty_predicate (const QModelIndex &index) const;
|
||||
|
||||
/**
|
||||
* @brief Get a flag indicating that a layer does not have shapes within the shown area
|
||||
*/
|
||||
bool empty_within_view_predicate (const QModelIndex &index) const;
|
||||
|
||||
/**
|
||||
* @brief Set the non-empty layers (the "uint" for the layer iterators) for the "test shapes is view" mode
|
||||
*
|
||||
* @return True, if a change has been made.
|
||||
*/
|
||||
bool set_non_empty_layers (const std::set <size_t> &non_empty_layers);
|
||||
bool is_hidden (const QModelIndex &index) const;
|
||||
|
||||
/**
|
||||
* @brief Set the animation phase
|
||||
|
|
@ -201,13 +189,42 @@ public:
|
|||
void clear_locate ();
|
||||
|
||||
/**
|
||||
* @brief Set the test_shapes_in_view flag
|
||||
*
|
||||
* This method does not issue a data changed signal. This has to be done somewhere else.
|
||||
* @brief Sets a flag indicating whether to test shapes in view for highlighting non-empty layers
|
||||
*/
|
||||
void set_test_shapes_in_view (bool f)
|
||||
void set_test_shapes_in_view (bool f);
|
||||
|
||||
/**
|
||||
* @brief Gets a flag indicating whether to test shapes in view for highlighting non-empty layers
|
||||
*/
|
||||
bool get_test_shapes_in_view ()
|
||||
{
|
||||
m_test_shapes_in_view = f;
|
||||
return m_test_shapes_in_view;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the flag indicating whether to hide empty layers
|
||||
*/
|
||||
void set_hide_empty_layers (bool f);
|
||||
|
||||
/**
|
||||
* @brief Gets the flag indicating whether to hide empty layers
|
||||
*/
|
||||
bool get_hide_empty_layers () const
|
||||
{
|
||||
return m_hide_empty_layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating whether selected indexes are filtered or highlighted
|
||||
*/
|
||||
void set_filter_mode (bool f);
|
||||
|
||||
/**
|
||||
* @brief Gets a flag indicating whether selected indexes are filtered or highlighted
|
||||
*/
|
||||
bool get_filter_mode () const
|
||||
{
|
||||
return m_filter_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -220,11 +237,19 @@ public:
|
|||
*/
|
||||
void signal_layer_changed ();
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief This signal is emitted to indicate
|
||||
*/
|
||||
void hidden_flags_need_update ();
|
||||
|
||||
private:
|
||||
lay::LayoutView *mp_view;
|
||||
bool m_filter_mode;
|
||||
size_t m_id_start, m_id_end;
|
||||
unsigned int m_phase;
|
||||
bool m_test_shapes_in_view;
|
||||
bool m_hide_empty_layers;
|
||||
QFont m_font;
|
||||
QColor m_text_color, m_background_color;
|
||||
mutable EmptyWithinViewCache m_test_shapes_cache;
|
||||
|
|
@ -232,6 +257,16 @@ private:
|
|||
std::vector <QModelIndex> m_selected_indexes;
|
||||
std::vector <QModelIndex>::const_iterator m_current_index;
|
||||
|
||||
/**
|
||||
* @brief Get a flag indicating that a layer is empty
|
||||
*/
|
||||
bool empty_predicate (const QModelIndex &index) const;
|
||||
|
||||
/**
|
||||
* @brief Get a flag indicating that a layer does not have shapes within the shown area
|
||||
*/
|
||||
bool empty_within_view_predicate (const QModelIndex &index) const;
|
||||
|
||||
void search_children (const tl::GlobPattern &pattern, const QModelIndex &parent, bool recurse);
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue