From 5faf7625717cfaa1849f025c8dc7c4e11728ffa5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 30 Jul 2019 23:22:26 +0200 Subject: [PATCH] WIP: libraries view - basic skeleton --- src/lay/lay/layConfig.h | 1 + src/lay/lay/layMainConfigPages.cc | 1 + src/lay/lay/layMainWindow.cc | 32 + src/lay/lay/layMainWindow.h | 6 +- src/laybasic/laybasic/layLayoutView.cc | 30 +- src/laybasic/laybasic/layLayoutView.h | 45 +- src/laybasic/laybasic/layLibrariesView.cc | 1011 +++++++++++++++++++++ src/laybasic/laybasic/layLibrariesView.h | 310 +++++++ src/laybasic/laybasic/laybasic.pro | 6 +- 9 files changed, 1419 insertions(+), 23 deletions(-) create mode 100644 src/laybasic/laybasic/layLibrariesView.cc create mode 100644 src/laybasic/laybasic/layLibrariesView.h diff --git a/src/lay/lay/layConfig.h b/src/lay/lay/layConfig.h index ade67ad0b..2181893aa 100644 --- a/src/lay/lay/layConfig.h +++ b/src/lay/lay/layConfig.h @@ -49,6 +49,7 @@ static const std::string cfg_navigator_all_hier_levels ("navigator-show-all-hier static const std::string cfg_navigator_show_images ("navigator-show-images"); static const std::string cfg_show_layer_toolbox ("show-layer-toolbox"); static const std::string cfg_show_hierarchy_panel ("show-hierarchy-panel"); +static const std::string cfg_show_libraries_view ("show-libraries-view"); static const std::string cfg_show_layer_panel ("show-layer-panel"); static const std::string cfg_window_state ("window-state"); static const std::string cfg_layout_file_watcher_enabled ("layout-file-watcher-enabled"); diff --git a/src/lay/lay/layMainConfigPages.cc b/src/lay/lay/layMainConfigPages.cc index 25e2bbd4a..f2af1a973 100644 --- a/src/lay/lay/layMainConfigPages.cc +++ b/src/lay/lay/layMainConfigPages.cc @@ -68,6 +68,7 @@ public: options.push_back (std::pair (cfg_show_toolbar, "true")); options.push_back (std::pair (cfg_show_layer_toolbox, "true")); options.push_back (std::pair (cfg_show_hierarchy_panel, "true")); + options.push_back (std::pair (cfg_show_libraries_view, "true")); options.push_back (std::pair (cfg_show_layer_panel, "true")); options.push_back (std::pair (cfg_layout_file_watcher_enabled, "true")); options.push_back (std::pair (cfg_window_state, "")); diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index 349ad61ec..31f3d8ce3 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -506,6 +506,13 @@ MainWindow::MainWindow (QApplication *app, lay::Plugin *plugin_parent, const cha connect (mp_hp_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool))); m_hp_visible = true; + mp_libs_dock_widget = new QDockWidget (QObject::tr ("Libraries"), this); + mp_libs_dock_widget->setObjectName (QString::fromUtf8 ("libs_dock_widget")); + mp_libs_stack = new ControlWidgetStack (mp_libs_dock_widget, "libs_stack"); + mp_libs_dock_widget->setWidget (mp_libs_stack); + connect (mp_libs_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool))); + m_libs_visible = true; + mp_view_stack = new ViewWidgetStack (mp_main_frame); mp_view_stack->setObjectName (QString::fromUtf8 ("view_stack")); vbl->addWidget (mp_view_stack); @@ -537,6 +544,7 @@ MainWindow::MainWindow (QApplication *app, lay::Plugin *plugin_parent, const cha #endif addDockWidget(Qt::LeftDockWidgetArea, mp_navigator_dock_widget); addDockWidget(Qt::LeftDockWidgetArea, mp_hp_dock_widget); + addDockWidget(Qt::LeftDockWidgetArea, mp_libs_dock_widget); addDockWidget(Qt::RightDockWidgetArea, mp_lp_dock_widget); addDockWidget(Qt::RightDockWidgetArea, mp_layer_toolbox_dock_widget); @@ -849,6 +857,7 @@ MainWindow::init_menu () MenuLayoutEntry ("show_layer_panel", tl::to_string (QObject::tr ("Layers")), std::make_pair (cfg_show_layer_panel, "?")), MenuLayoutEntry ("show_layer_toolbox", tl::to_string (QObject::tr ("Layer Toolbox")), std::make_pair (cfg_show_layer_toolbox, "?")), MenuLayoutEntry ("show_hierarchy_panel", tl::to_string (QObject::tr ("Cells")), std::make_pair (cfg_show_hierarchy_panel, "?")), + MenuLayoutEntry ("show_libraries_view", tl::to_string (QObject::tr ("Libraries")), std::make_pair (cfg_show_libraries_view, "?")), MenuLayoutEntry ("reset_window_state", tl::to_string (QObject::tr ("Restore Window")), SLOT (cm_reset_window_state ())), MenuLayoutEntry::separator ("selection_group"), MenuLayoutEntry ("transient_selection", tl::to_string (QObject::tr ("Highlight Object Under Mouse")), std::make_pair (cfg_sel_transient_mode, "?")), @@ -1073,6 +1082,8 @@ MainWindow::dock_widget_visibility_changed (bool /*visible*/) plugin_root ()->config_set (cfg_show_layer_panel, tl::to_string (!mp_lp_dock_widget->isHidden ())); } else if (sender () == mp_hp_dock_widget) { plugin_root ()->config_set (cfg_show_hierarchy_panel, tl::to_string (!mp_hp_dock_widget->isHidden ())); + } else if (sender () == mp_libs_dock_widget) { + plugin_root ()->config_set (cfg_show_libraries_view, tl::to_string (!mp_libs_dock_widget->isHidden ())); } else if (sender () == mp_navigator_dock_widget) { plugin_root ()->config_set (cfg_show_navigator, tl::to_string (!mp_navigator_dock_widget->isHidden ())); } else if (sender () == mp_layer_toolbox_dock_widget) { @@ -1685,6 +1696,17 @@ MainWindow::configure (const std::string &name, const std::string &value) return true; + } else if (name == cfg_show_libraries_view) { + + tl::from_string (value, m_libs_visible); + if (m_libs_visible) { + mp_libs_dock_widget->show (); + } else { + mp_libs_dock_widget->hide (); + } + + return true; + } else if (name == cfg_show_layer_panel) { tl::from_string (value, m_lp_visible); @@ -1797,6 +1819,7 @@ MainWindow::read_dock_widget_state () { plugin_root ()->config_set (cfg_show_layer_panel, tl::to_string (!mp_lp_dock_widget->isHidden ())); plugin_root ()->config_set (cfg_show_hierarchy_panel, tl::to_string (!mp_hp_dock_widget->isHidden ())); + plugin_root ()->config_set (cfg_show_libraries_view, tl::to_string (!mp_libs_dock_widget->isHidden ())); plugin_root ()->config_set (cfg_show_navigator, tl::to_string (!mp_navigator_dock_widget->isHidden ())); plugin_root ()->config_set (cfg_show_layer_toolbox, tl::to_string (!mp_layer_toolbox_dock_widget->isHidden ())); } @@ -1810,6 +1833,12 @@ MainWindow::update_dock_widget_state () mp_hp_dock_widget->hide (); } + if (m_libs_visible) { + mp_libs_dock_widget->show (); + } else { + mp_libs_dock_widget->hide (); + } + if (m_lp_visible) { mp_lp_dock_widget->show (); } else { @@ -3694,6 +3723,7 @@ MainWindow::clone_current_view () mp_view_stack->addWidget (view); mp_lp_stack->addWidget (view->layer_control_frame ()); mp_hp_stack->addWidget (view->hierarchy_control_frame ()); + mp_libs_stack->addWidget (view->libraries_frame ()); bool f = m_disable_tab_selected; m_disable_tab_selected = true; @@ -4312,6 +4342,7 @@ MainWindow::create_view () mp_view_stack->addWidget (mp_views.back ()); mp_lp_stack->addWidget (mp_views.back ()->layer_control_frame ()); mp_hp_stack->addWidget (mp_views.back ()->hierarchy_control_frame ()); + mp_libs_stack->addWidget (mp_views.back ()->libraries_frame ()); bool f = m_disable_tab_selected; m_disable_tab_selected = true; @@ -4373,6 +4404,7 @@ MainWindow::create_or_load_layout (const std::string *filename, const db::LoadLa mp_view_stack->addWidget (mp_views.back ()); mp_lp_stack->addWidget (mp_views.back ()->layer_control_frame ()); mp_hp_stack->addWidget (mp_views.back ()->hierarchy_control_frame ()); + mp_libs_stack->addWidget (mp_views.back ()->libraries_frame ()); bool f = m_disable_tab_selected; m_disable_tab_selected = true; diff --git a/src/lay/lay/layMainWindow.h b/src/lay/lay/layMainWindow.h index 782dc512e..de4ef64ec 100644 --- a/src/lay/lay/layMainWindow.h +++ b/src/lay/lay/layMainWindow.h @@ -872,9 +872,9 @@ private: QToolBar *mp_tool_bar; QDockWidget *mp_navigator_dock_widget; lay::Navigator *mp_navigator; - QDockWidget *mp_hp_dock_widget, *mp_lp_dock_widget; - ControlWidgetStack *mp_hp_stack, *mp_lp_stack; - bool m_hp_visible, m_lp_visible, m_navigator_visible, m_layer_toolbox_visible; + QDockWidget *mp_hp_dock_widget, *mp_lp_dock_widget, *mp_libs_dock_widget; + ControlWidgetStack *mp_hp_stack, *mp_lp_stack, *mp_libs_stack; + bool m_hp_visible, m_lp_visible, m_libs_visible, m_navigator_visible, m_layer_toolbox_visible; QDockWidget *mp_layer_toolbox_dock_widget; lay::LayerToolbox *mp_layer_toolbox; ViewWidgetStack *mp_view_stack; diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index 54b498936..79c6b694b 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -61,6 +61,7 @@ #include "layLayoutCanvas.h" #include "layLayerControlPanel.h" #include "layHierarchyControlPanel.h" +#include "layLibrariesView.h" #include "layBrowser.h" #include "layRedrawThread.h" #include "layRedrawThreadWorker.h" @@ -356,6 +357,8 @@ LayoutView::init (db::Manager *mgr, lay::PluginRoot *root, QWidget * /*parent*/) mp_control_frame = 0; mp_hierarchy_panel = 0; mp_hierarchy_frame = 0; + mp_libraries_view = 0; + mp_libraries_frame = 0; mp_min_hier_spbx = 0; mp_max_hier_spbx = 0; m_from_level = 0; @@ -491,6 +494,25 @@ LayoutView::init (db::Manager *mgr, lay::PluginRoot *root, QWidget * /*parent*/) } + if ((m_options & LV_NoLibrariesView) == 0 && (m_options & LV_Naked) == 0) { + + QFrame *libraries_frame = new QFrame (0); + libraries_frame->setObjectName (QString::fromUtf8 ("libs_frame")); + mp_libraries_frame = libraries_frame; + QVBoxLayout *left_frame_ly = new QVBoxLayout (libraries_frame); + left_frame_ly->setMargin (0); + left_frame_ly->setSpacing (0); + + mp_libraries_view = new lay::LibrariesView (this, libraries_frame, "libs"); + left_frame_ly->addWidget (mp_libraries_view, 1 /*stretch*/); + +#if 0 // @@@ + connect (mp_libraries_view, SIGNAL (cell_selected (cell_path_type, int)), this, SLOT (select_cell_dispatch (cell_path_type, int))); + connect (mp_libraries_view, SIGNAL (active_cellview_changed (int)), this, SLOT (active_cellview_changed (int))); +#endif + + } + mp_canvas = new lay::LayoutCanvas (this, this); vbl->addWidget (mp_canvas); connect (mp_canvas, SIGNAL (left_arrow_key_pressed ()), this, SLOT (pan_left ())); @@ -628,6 +650,12 @@ LayoutView::~LayoutView () } mp_hierarchy_frame = 0; mp_hierarchy_panel = 0; + + if (mp_libraries_frame) { + delete mp_libraries_frame; + } + mp_libraries_frame = 0; + mp_libraries_view = 0; } void LayoutView::hideEvent (QHideEvent *) @@ -7243,7 +7271,7 @@ LayoutView::sizeHint () const { if ((m_options & LV_Naked) != 0) { return QSize (200, 200); - } else if ((m_options & LV_NoLayers) != 0 || (m_options & LV_NoHierarchyPanel) != 0) { + } else if ((m_options & LV_NoLayers) != 0 || (m_options & LV_NoHierarchyPanel) != 0 || (m_options & LV_NoLibrariesView) != 0) { return QSize (400, 200); } else { return QSize (600, 200); diff --git a/src/laybasic/laybasic/layLayoutView.h b/src/laybasic/laybasic/layLayoutView.h index 5b871e7a4..b4869799e 100644 --- a/src/laybasic/laybasic/layLayoutView.h +++ b/src/laybasic/laybasic/layLayoutView.h @@ -70,6 +70,7 @@ namespace lay { class AbstractMenu; class LayerControlPanel; class HierarchyControlPanel; +class LibrariesView; class MouseTracker; class ZoomService; class SelectionService; @@ -168,13 +169,14 @@ public: LV_Normal = 0, LV_NoLayers = 1, LV_NoHierarchyPanel = 2, - LV_Naked = 4, - LV_NoZoom = 8, - LV_NoGrid = 16, - LV_NoMove = 32, - LV_NoTracker = 64, - LV_NoSelection = 128, - LV_NoPlugins = 256, + LV_NoLibrariesView = 4, + LV_Naked = 8, + LV_NoZoom = 16, + LV_NoGrid = 32, + LV_NoMove = 64, + LV_NoTracker = 128, + LV_NoSelection = 256, + LV_NoPlugins = 512, LV_NoServices = LV_NoMove + LV_NoTracker + LV_NoSelection + LV_NoPlugins }; @@ -221,7 +223,7 @@ public: bool has_selection (); /** - * @brief Get the container with the layer control panel + * @brief Gets the container with the layer control panel */ QWidget *layer_control_frame () { @@ -229,7 +231,7 @@ public: } /** - * @brief Get the container with the hierarchy control panel + * @brief Gets the container with the hierarchy control panel */ QWidget *hierarchy_control_frame () { @@ -237,7 +239,15 @@ public: } /** - * @brief Paste from clipboard + * @brief Gets the container with the libraries view + */ + QWidget *libraries_frame () + { + return mp_libraries_frame; + } + + /** + * @brief Pastes from clipboard * * This reimplementation of the lay::Editables interface additionally * looks for paste receivers in the tree views for example. @@ -245,7 +255,7 @@ public: void paste (); /** - * @brief Copy to clipboard + * @brief Copies to clipboard * * This reimplementation of the lay::Editables interface additionally * looks for copy providers in the tree views for example. @@ -253,7 +263,7 @@ public: void copy (); /** - * @brief Cut to clipboard + * @brief Cuts to clipboard * * This reimplementation of the lay::Editables interface additionally * looks for cut & copy providers in the tree views for example. @@ -261,7 +271,7 @@ public: void cut (); /** - * @brief Get the explicit title string of the view + * @brief Gets the explicit title string of the view * * This is the one explicitly set, not the one displayed. The displayed text is composed of internal information * if no title string is set. @@ -272,17 +282,17 @@ public: } /** - * @brief Get the window title of the view + * @brief Gets the window title of the view */ std::string title () const; /** - * @brief Set the window title to an explicit string + * @brief Sets the window title to an explicit string */ void set_title (const std::string &t); /** - * @brief Reset the explicit title and enable the automatic naming + * @brief Resets the explicit title and enable the automatic naming */ void reset_title (); @@ -2695,7 +2705,8 @@ private: QFrame *mp_left_frame; lay::LayerControlPanel *mp_control_panel; lay::HierarchyControlPanel *mp_hierarchy_panel; - QWidget *mp_control_frame, *mp_hierarchy_frame; + lay::LibrariesView *mp_libraries_view; + QWidget *mp_control_frame, *mp_hierarchy_frame, *mp_libraries_frame; QSpinBox *mp_min_hier_spbx; QSpinBox *mp_max_hier_spbx; std::list m_cellviews; diff --git a/src/laybasic/laybasic/layLibrariesView.cc b/src/laybasic/laybasic/layLibrariesView.cc new file mode 100644 index 000000000..b958a2ea3 --- /dev/null +++ b/src/laybasic/laybasic/layLibrariesView.cc @@ -0,0 +1,1011 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dbClipboard.h" +#include "dbClipboardData.h" +#include "layLibrariesView.h" +#include "layCellTreeModel.h" +#include "layLayoutView.h" +#include "layAbstractMenu.h" +#include "layAbstractMenuProvider.h" +#include "layDialogs.h" +#include "tlExceptions.h" +#include "laybasicConfig.h" +#include "tlInternational.h" +#include "tlString.h" +#include "gtf.h" + +namespace lay +{ + +// -------------------------------------------------------------------- +// A helper class the identifies clipboard data + +class CellClipboardData + : public db::ClipboardData +{ +public: + CellClipboardData () { } +}; + +// -------------------------------------------------------------------- +// LibraryTreeWidget implementation + +LibraryTreeWidget::LibraryTreeWidget (QWidget *parent, const char *name, QWidget *key_event_receiver) + : QTreeView (parent), mp_key_event_receiver (key_event_receiver) +{ + // Allow dragging from here to + setDragDropMode (QAbstractItemView::DragOnly); + + setObjectName (QString::fromUtf8 (name)); +} + + +bool +LibraryTreeWidget::event (QEvent *event) +{ +#if 0 + // Handling this event makes the widget receive all keystrokes. + // Without this code, shortcuts override the search function. + if (event->type () == QEvent::ShortcutOverride) { + QKeyEvent *ke = static_cast (event); + QString t = ke->text (); + if (!t.isEmpty () && t[0].isPrint ()) { + ke->accept (); + } + } +#endif + return QTreeView::event (event); +} + +bool +LibraryTreeWidget::focusNextPrevChild (bool /*next*/) +{ + return false; +} + +void +LibraryTreeWidget::keyPressEvent (QKeyEvent *event) +{ + QString t = event->text (); + if (! t.isEmpty () && t[0].isPrint ()) { + // "/" is a search initiator + if (t == QString::fromUtf8 ("/")) { + t.clear (); + } + emit search_triggered (t); + } else if (mp_key_event_receiver) { + // send other key events to the alternative receiver - this way we can make the + // view receive arrow keys for panning. + QCoreApplication::sendEvent (mp_key_event_receiver, event); + } else { + return QTreeView::keyPressEvent (event); + } +} + +void +LibraryTreeWidget::startDrag (Qt::DropActions supportedActions) +{ +#if 0 // @@@ + QModelIndex index = selectionModel ()->currentIndex (); + if (index.isValid ()) { + + QModelIndexList indexes; + indexes << index; + QMimeData *data = model ()->mimeData (indexes); + if (!data) { + return; + } + + QDrag *drag = new QDrag (this); + drag->setMimeData(data); + QPixmap px (1, 1); + px.fill (QColor (0, 0, 0)); + px.createMaskFromColor (QColor (0, 0, 0), Qt::MaskOutColor); + drag->setPixmap (px); + + Qt::DropAction defaultDropAction = Qt::IgnoreAction; + if (supportedActions & Qt::CopyAction) { + defaultDropAction = Qt::CopyAction; + } + + drag->exec(supportedActions, defaultDropAction); + + } +#endif // @@@ +} + +void +LibraryTreeWidget::mouseDoubleClickEvent (QMouseEvent *event) +{ + QModelIndex index (indexAt (event->pos ())); + if (index.isValid ()) { + emit cell_double_clicked (index); + } +} + +void +LibraryTreeWidget::mousePressEvent (QMouseEvent *event) +{ + if (event->button () == Qt::MidButton) { + // eat this event. + } else { + QModelIndex index (indexAt (event->pos ())); + if (index.isValid ()) { + emit cell_clicked (index); + } + QTreeView::mousePressEvent (event); + } +} + +void +LibraryTreeWidget::mouseReleaseEvent (QMouseEvent *event) +{ + if (event->button () == Qt::MidButton) { + QModelIndex index (indexAt (event->pos ())); + if (index.isValid ()) { + emit cell_middle_clicked (index); + } + } else { + QTreeView::mouseReleaseEvent (event); + } +} + + +// -------------------------------------------------------------------- +// LibrariesView implementation + +const int max_cellviews_in_split_mode = 5; + +void +LibrariesView::init_menu (lay::AbstractMenu &menu) +{ + MenuLayoutEntry context_menu [] = { + MenuLayoutEntry ("split_mode", tl::to_string (QObject::tr ("Split Mode")), std::make_pair (cfg_split_cell_list, "?")), +#if 0 // @@@ + MenuLayoutEntry::separator ("operations_group"), + MenuLayoutEntry ("new_cell:edit:edit_mode", tl::to_string (QObject::tr ("New Cell")), SLOT (cm_new_cell ())), + MenuLayoutEntry ("delete_cell:edit:edit_mode", tl::to_string (QObject::tr ("Delete Cell")), SLOT (cm_cell_delete ())), + MenuLayoutEntry ("rename_cell:edit:edit_mode", tl::to_string (QObject::tr ("Rename Cell")), SLOT (cm_cell_rename ())), + MenuLayoutEntry ("replace_cell:edit:edit_mode", tl::to_string (QObject::tr ("Replace Cell")), SLOT (cm_cell_replace ())), + MenuLayoutEntry ("flatten_cell:edit:edit_mode", tl::to_string (QObject::tr ("Flatten Cell")), SLOT (cm_cell_flatten ())), + MenuLayoutEntry ("cell_user_properties", tl::to_string (QObject::tr ("User Properties")), SLOT (cm_cell_user_properties ())), + MenuLayoutEntry::separator ("clipboard_group:edit_mode"), + MenuLayoutEntry ("copy:edit_mode", tl::to_string (QObject::tr ("Copy")), SLOT (cm_cell_copy ())), + MenuLayoutEntry ("cut:edit_mode", tl::to_string (QObject::tr ("Cut")), SLOT (cm_cell_cut ())), + MenuLayoutEntry ("paste:edit_mode", tl::to_string (QObject::tr ("Paste")), SLOT (cm_cell_paste ())), + MenuLayoutEntry::separator ("select_group"), + MenuLayoutEntry ("show_as_top", tl::to_string (QObject::tr ("Show As New Top")), SLOT (cm_cell_select ())), + MenuLayoutEntry::separator ("visibility_group"), + MenuLayoutEntry ("hide_cell", tl::to_string (QObject::tr ("Hide")), SLOT (cm_cell_hide ())), + MenuLayoutEntry ("show_cell", tl::to_string (QObject::tr ("Show")), SLOT (cm_cell_show ())), + MenuLayoutEntry ("show_all", tl::to_string (QObject::tr ("Show All")), SLOT (cm_cell_show_all ())), + MenuLayoutEntry::separator ("utils_group"), + MenuLayoutEntry ("open_current", tl::to_string (QObject::tr ("Where Am I?")), SLOT (cm_open_current_cell ())), + MenuLayoutEntry::separator ("file_group"), + MenuLayoutEntry ("save_cell_as:hide_vo", tl::to_string (QObject::tr ("Save Selected Cells As")), SLOT (cm_save_current_cell_as ())), + #endif + MenuLayoutEntry::last () + }; + + MenuLayoutEntry main_menu [] = { + MenuLayoutEntry ("@lib_context_menu", "", context_menu), + MenuLayoutEntry::last () + }; + + menu.init (main_menu); +} + +LibrariesView::LibrariesView (lay::LayoutView *view, QWidget *parent, const char *name) + : QFrame (parent), + m_enable_cb (true), + mp_view (view), + m_split_mode (false), + m_do_update_content_dm (this, &LibrariesView::do_update_content), + m_do_full_update_content_dm (this, &LibrariesView::do_full_update_content) +{ + setObjectName (QString::fromUtf8 (name)); + + QVBoxLayout *ly = new QVBoxLayout (this); + ly->setSpacing (0); + ly->setContentsMargins (0, 0, 0, 0); + + mp_selector = new QComboBox (this); + mp_selector->setObjectName (QString::fromUtf8 ("cellview_selection")); + ly->addWidget (mp_selector); + + mp_search_frame = new QFrame (this); + ly->addWidget (mp_search_frame); + mp_search_frame->hide (); + mp_search_frame->setAutoFillBackground (true); + mp_search_frame->setObjectName (QString::fromUtf8 ("panel")); + mp_search_frame->setFrameStyle (QFrame::Panel | QFrame::Raised); + mp_search_frame->setLineWidth (1); + mp_search_frame->setBackgroundRole (QPalette::Highlight); + + QHBoxLayout *sf_ly = new QHBoxLayout (mp_search_frame); + sf_ly->setMargin (0); + sf_ly->setContentsMargins (0, 0, 0, 0); + sf_ly->setSpacing (0); + + mp_search_close_cb = new QCheckBox (mp_search_frame); + sf_ly->addWidget (mp_search_close_cb); + + mp_search_close_cb->setFocusPolicy (Qt::NoFocus); + mp_search_close_cb->setBackgroundRole (QPalette::Highlight); + mp_search_close_cb->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Preferred)); + QPalette pl (mp_search_close_cb->palette ()); + pl.setColor (QPalette::Foreground, pl.color (QPalette::Active, QPalette::HighlightedText)); + mp_search_close_cb->setPalette (pl); + mp_search_close_cb->setMaximumSize (QSize (mp_search_close_cb->maximumSize ().width (), mp_search_close_cb->sizeHint ().height () - 4)); + connect (mp_search_close_cb, SIGNAL (clicked ()), this, SLOT (search_editing_finished ())); + + mp_search_model = 0; + mp_search_edit_box = new lay::DecoratedLineEdit (mp_search_frame); + mp_search_edit_box->setObjectName (QString::fromUtf8 ("cellview_search_edit_box")); + mp_search_edit_box->set_escape_signal_enabled (true); + mp_search_edit_box->set_tab_signal_enabled (true); + connect (mp_search_edit_box, SIGNAL (returnPressed ()), this, SLOT (search_editing_finished ())); + connect (mp_search_edit_box, SIGNAL (textEdited (const QString &)), this, SLOT (search_edited ())); + connect (mp_search_edit_box, SIGNAL (esc_pressed ()), this, SLOT (search_editing_finished ())); + connect (mp_search_edit_box, SIGNAL (tab_pressed ()), this, SLOT (search_next ())); + connect (mp_search_edit_box, SIGNAL (backtab_pressed ()), this, SLOT (search_prev ())); + sf_ly->addWidget (mp_search_edit_box); + + mp_use_regular_expressions = new QAction (this); + mp_use_regular_expressions->setCheckable (true); + mp_use_regular_expressions->setChecked (true); + mp_use_regular_expressions->setText (tr ("Use expressions (use * and ? for any character)")); + + mp_case_sensitive = new QAction (this); + mp_case_sensitive->setCheckable (true); + mp_case_sensitive->setChecked (true); + mp_case_sensitive->setText (tr ("Case sensitive search")); + + QMenu *m = new QMenu (mp_search_edit_box); + m->addAction (mp_use_regular_expressions); + m->addAction (mp_case_sensitive); + connect (mp_use_regular_expressions, SIGNAL (triggered ()), this, SLOT (search_edited ())); + connect (mp_case_sensitive, SIGNAL (triggered ()), this, SLOT (search_edited ())); + + mp_search_edit_box->set_clear_button_enabled (true); + mp_search_edit_box->set_options_button_enabled (true); + mp_search_edit_box->set_options_menu (m); + + QToolButton *sf_next = new QToolButton (mp_search_frame); + sf_next->setAutoRaise (true); + sf_next->setToolTip (tr ("Find next")); + sf_next->setIcon (QIcon (QString::fromUtf8 (":/find.png"))); + connect (sf_next, SIGNAL (clicked ()), this, SLOT (search_next ())); + sf_ly->addWidget (sf_next); + + mp_splitter = new QSplitter (Qt::Vertical, this); + ly->addWidget (mp_splitter); + + connect (mp_selector, SIGNAL (activated (int)), this, SLOT (selection_changed (int))); + + QSizePolicy sp (QSizePolicy::Minimum, QSizePolicy::Preferred); + sp.setHorizontalStretch (0); + sp.setVerticalStretch (0); + setSizePolicy (sp); + +#if 0 // @@@ TODO: attach to library controller + mp_view->cellviews_changed_event.add (this, &LibrariesView::update_required); + mp_view->hier_changed_event.add (this, &LibrariesView::update_required); +#endif + + do_update_content (); +} + +LibrariesView::~LibrariesView () +{ + // .. nothing yet .. +} + +QSize +LibrariesView::sizeHint () const +{ + int w = 120; // TODO: better(?): mp_cell_list->sizeHint ().width (); + return QSize (w, 0); +} + +bool +LibrariesView::event (QEvent *e) +{ + if (e->type () == QEvent::MaxUser) { + // GTF probe event + e->accept (); + return true; + } else { + return QFrame::event (e); + } +} + +void +LibrariesView::context_menu (const QPoint &p) +{ + tl_assert (lay::AbstractMenuProvider::instance () != 0); + + QTreeView *cell_list = dynamic_cast (sender ()); + if (cell_list) { +// @@@ set_active_celltree_from_sender (); + QMenu *ctx_menu = lay::AbstractMenuProvider::instance ()->menu ()->detached_menu ("lib_context_menu"); + ctx_menu->exec (cell_list->mapToGlobal (p)); + } +} + +void +LibrariesView::set_split_mode (bool f) +{ + if (f != m_split_mode) { + m_split_mode = f; + m_do_update_content_dm (); + } +} + +#if 0 // @@@ +void +LibrariesView::clear_all () +{ + m_cellviews.clear (); + m_needs_update.clear (); + m_force_close.clear (); + + for (size_t i = 0; i < mp_cell_list_frames.size (); ++i) { + delete mp_cell_list_frames [i]; + } + mp_cell_list_frames.clear (); + mp_cell_list_headers.clear (); + mp_cell_lists.clear (); +} +#endif + +void +LibrariesView::cm_cell_select () +{ +#if 0 // @@@ + cell_path_type path; + current_cell (active (), path); + emit cell_selected (path, active ()); +#endif +} + +void +LibrariesView::search_triggered (const QString &t) +{ + mp_search_model = 0; +#if 0 // @@@ + lay::LibraryTreeWidget *w = dynamic_cast (sender ()); + if (w) { + for (size_t i = 0; i < mp_cell_lists.size (); ++i) { + if (mp_cell_lists [i] == w) { + // Switch the active list for split mode -> CAUTION: this may trigger a search_editing_finished call + select_active (int (i)); + mp_search_model = dynamic_cast (w->model ()); + break; + } + } + } +#endif // @@@ + + if (mp_search_model) { + mp_search_close_cb->setChecked (true); + mp_search_frame->show (); + mp_search_edit_box->setText (t); + mp_search_edit_box->setFocus (); + search_edited (); + } +} + +void +LibrariesView::search_edited () +{ + QString t = mp_search_edit_box->text (); + + for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) { + if ((*v)->model () == mp_search_model) { + if (t.isEmpty ()) { + mp_search_model->clear_locate (); + (*v)->setCurrentIndex (QModelIndex ()); + } else { + QModelIndex found = mp_search_model->locate (t.toUtf8 ().constData (), mp_use_regular_expressions->isChecked (), mp_case_sensitive->isChecked (), false); + (*v)->setCurrentIndex (found); + if (found.isValid ()) { + (*v)->scrollTo (found); + } + } + break; + } + } +} + +void +LibrariesView::search_next () +{ + for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) { + if ((*v)->model () == mp_search_model) { + QModelIndex found = mp_search_model->locate_next (); + if (found.isValid ()) { + (*v)->setCurrentIndex (found); + (*v)->scrollTo (found); + } + break; + } + } +} + +void +LibrariesView::search_prev () +{ + for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) { + if ((*v)->model () == mp_search_model) { + QModelIndex found = mp_search_model->locate_prev (); + if (found.isValid ()) { + (*v)->setCurrentIndex (found); + (*v)->scrollTo (found); + } + break; + } + } +} + +void +LibrariesView::search_editing_finished () +{ + for (std::vector ::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) { + CellTreeModel *m = dynamic_cast ((*v)->model ()); + if (m) { + m->clear_locate (); + } + } + +#if 0 // @@@ + // give back the focus to the cell list + for (size_t i = 0; i < mp_cell_lists.size (); ++i) { + if (mp_cell_lists [i]->model () == mp_search_model) { + mp_cell_lists [i]->setFocus (); + break; + } + } +#endif + + mp_search_frame->hide (); + mp_search_model = 0; +} + +void +LibrariesView::middle_clicked (const QModelIndex &index) +{ +#if 0 // @@@ + BEGIN_PROTECTED + if (index.isValid ()) { + set_active_celltree_from_sender (); + cell_path_type path; + path_from_index (index, m_active_index, path); + emit cell_selected (path, active ()); + } + END_PROTECTED +#endif +} + +#if 0 // @@@ +void +LibrariesView::path_from_index (const QModelIndex &index, int cv_index, cell_path_type &path) const +{ + // build the path to the cell given by the index + path.clear (); + + if (index.isValid ()) { + + CellTreeItem *item = (CellTreeItem *) index.internalPointer (); + + if (m_flat && cv_index >= 0 && cv_index < int (m_cellviews.size ()) && item) { + + // construct a path in the flat case + lay::CellView cv (m_cellviews [cv_index]); + cv.set_cell (item->cell_index ()); + path = cv.unspecific_path (); + + } else { + + while (item) { + path.push_back (item->cell_index ()); + item = item->parent (); + } + + if (! path.empty ()) { + std::reverse (path.begin (), path.end ()); + } + + } + + } +} + +void +LibrariesView::set_active_celltree_from_sender () +{ + for (int i = 0; i < int (mp_cell_lists.size ()); ++i) { + if (mp_cell_lists [i] == sender ()) { + select_active (i); + return; + } + if (mp_cell_list_headers [i] == sender ()) { + select_active (i); + return; + } + } +} +#endif // @@@ + +void +LibrariesView::header_clicked () +{ +#if 0 // @@@ + QToolButton *cb = dynamic_cast (sender ()); + if (cb) { + cb->setChecked (true); + set_active_celltree_from_sender (); + } +#endif +} + +void +LibrariesView::clicked (const QModelIndex & /*index*/) +{ +#if 0 // @@@ + set_active_celltree_from_sender (); +#endif +} + +void +LibrariesView::double_clicked (const QModelIndex &index) +{ +#if 0 // @@@ + BEGIN_PROTECTED + if (index.isValid ()) { + set_active_celltree_from_sender (); + mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Show or hide cell"))); + CellTreeItem *item = (CellTreeItem *) index.internalPointer (); + if (mp_view->is_cell_hidden (item->cell_index (), m_active_index)) { + mp_view->show_cell (item->cell_index (), m_active_index); + } else { + mp_view->hide_cell (item->cell_index (), m_active_index); + } + mp_view->manager ()->commit (); + } + END_PROTECTED +#endif +} + +#if 0 // @@@ +void +LibrariesView::set_current_cell (int cv_index, const cell_path_type &path) +{ + if (cv_index < 0 || cv_index >= int (mp_cell_lists.size ())) { + return; + } + + QModelIndex index = index_from_path (path, cv_index); + if (index.isValid ()) { + mp_cell_lists [cv_index]->scrollTo (index); + mp_cell_lists [cv_index]->clearSelection (); + mp_cell_lists [cv_index]->setCurrentIndex (index); + } +} +#endif + +#if 0 // @@@ +void +LibrariesView::selected_cells (int cv_index, std::vector &paths) const +{ + if (cv_index >= 0 && cv_index < int (mp_cell_lists.size ())) { + QModelIndexList sel = mp_cell_lists [cv_index]->selectionModel ()->selectedIndexes (); + for (QModelIndexList::const_iterator s = sel.begin (); s != sel.end (); ++s) { + paths.push_back (LibrariesView::cell_path_type ()); + path_from_index (*s, cv_index, paths.back ()); + } + } +} +#endif + +#if 0 // @@@ +void +LibrariesView::current_cell (int cv_index, LibrariesView::cell_path_type &path) const +{ + if (cv_index >= 0 && cv_index < int (mp_cell_lists.size ())) { + path_from_index (mp_cell_lists [cv_index]->currentIndex (), cv_index, path); + } +} +#endif + +void +LibrariesView::set_background_color (QColor c) +{ + m_background_color = c; + for (std::vector ::const_iterator f = mp_cell_lists.begin (); f != mp_cell_lists.end (); ++f) { + QPalette pl ((*f)->palette ()); + pl.setColor (QPalette::Base, c); + (*f)->setPalette (pl); + } +} + +void +LibrariesView::set_text_color (QColor c) +{ + m_text_color = c; + for (std::vector ::const_iterator f = mp_cell_lists.begin (); f != mp_cell_lists.end (); ++f) { + QPalette pl ((*f)->palette ()); + pl.setColor (QPalette::Text, c); + (*f)->setPalette (pl); + } +} + +#if 0 // @@@ +void +LibrariesView::do_full_update_content () +{ + size_t i = 0; + for (std::vector ::const_iterator cv = m_cellviews.begin (); cv != m_cellviews.end (); ++cv, ++i) { + if (m_needs_update.size () > i) { + m_needs_update [i] = true; + } + if (m_force_close.size () > i) { + m_force_close [i] = true; + } + } + + do_update_content (); +} + +void +LibrariesView::update_required () +{ + m_do_full_update_content_dm (); +} + +void +LibrariesView::select_active (int cellview_index) +{ + if (cellview_index != m_active_index) { + mp_selector->setCurrentIndex (cellview_index); + selection_changed (cellview_index); + } +} + +void +LibrariesView::selection_changed (int index) +{ + if (index != m_active_index) { + + m_active_index = index; + + bool split_mode = m_split_mode; + // for more than max_cellviews_in_split_mode cellviews, switch to overlay mode + if (int (m_cellviews.size ()) > max_cellviews_in_split_mode) { + split_mode = false; + } + + int i = 0; + for (std::vector ::const_iterator f = mp_cell_list_frames.begin (); f != mp_cell_list_frames.end (); ++f, ++i) { + (*f)->setVisible (i == index || split_mode); + } + + i = 0; + for (std::vector ::const_iterator f = mp_cell_list_headers.begin (); f != mp_cell_list_headers.end (); ++f, ++i) { + (*f)->setChecked (i == index); + } + + emit active_cellview_changed (index); + + } +} + +QModelIndex +LibrariesView::index_from_path (const cell_path_type &path, int cv_index) +{ + if (cv_index >= 0 && cv_index < int (mp_cell_lists.size ()) && ! path.empty ()) { + + CellTreeModel *model = dynamic_cast (mp_cell_lists [cv_index]->model ()); + if (! model) { + return QModelIndex (); + } + + if (m_flat) { + + // TODO: linear search might not be effective enough .. + for (int c = 0; c < model->toplevel_items (); ++c) { + CellTreeItem *item = model->toplevel_item (c); + if (item->cell_index () == path.back ()) { + return model->model_index (item); + } + } + + } else { + + for (int c = 0; c < model->toplevel_items (); ++c) { + CellTreeItem *item = model->toplevel_item (c); + if (item->cell_index () == path.front ()) { + item = find_child_item (path.begin () + 1, path.end (), item); + if (item) { + return model->model_index (item); + } + } + } + + } + + } + + return QModelIndex (); +} + +CellTreeItem * +LibrariesView::find_child_item (cell_path_type::const_iterator start, cell_path_type::const_iterator end, CellTreeItem *p) +{ + if (start == end) { + return p; + } else { + + for (int n = 0; n < p->children (); ++n) { + CellTreeItem *item = p->child (n); + if (item && item->cell_index () == *start) { + return find_child_item (start + 1, end, item); + } + } + + // not found + return 0; + + } +} + +std::string +LibrariesView::display_string (int n) const +{ + return m_cellviews [n]->name () + " (@" + tl::to_string (n + 1) + ")"; +} + +void +LibrariesView::do_update_content (int cv_index) +{ + // close the search box since we will modify the model + mp_search_frame->hide (); + mp_search_model = 0; + + unsigned int imin = (cv_index < 0 ? 0 : (unsigned int) cv_index); + unsigned int imax = (cv_index < 0 ? std::numeric_limits ::max () : (unsigned int) cv_index); + + for (unsigned int i = imin; i < mp_view->cellviews () && i <= imax; ++i) { + if (i >= m_force_close.size ()) { + m_force_close.push_back (true); + } + if (i >= m_needs_update.size ()) { + m_needs_update.push_back (true); + } + if (i >= m_cellviews.size ()) { + m_force_close [i] = true; + m_needs_update [i] = true; + } + } + + unsigned int n = std::min ((unsigned int) m_cellviews.size (), mp_view->cellviews ()); + for (unsigned int i = imin; i < n && i <= imax; ++i) { + + if (&m_cellviews [i]->layout () != &mp_view->cellview (i)->layout ()) { + m_needs_update [i] = true; + m_force_close [i] = true; + } else if (m_cellviews [i].combined_unspecific_path () != mp_view->cellview (i).combined_unspecific_path ()) { + m_needs_update [i] = true; + } + + if (m_needs_update [i]) { + mp_cell_lists [i]->doItemsLayout (); // this schedules a redraw + } + + m_cellviews [i] = mp_view->cellview (i); + + } + + if (m_cellviews.size () < mp_view->cellviews ()) { + for (unsigned int i = n; i < mp_view->cellviews (); ++i) { + m_cellviews.push_back (mp_view->cellview (i)); + } + } else if (m_cellviews.size () > mp_view->cellviews ()) { + m_cellviews.erase (m_cellviews.begin () + mp_view->cellviews (), m_cellviews.end ()); + } + + bool split_mode = m_split_mode; + // for more than max_cellviews_in_split_mode cellviews, switch to overlay mode + if (int (m_cellviews.size ()) > max_cellviews_in_split_mode) { + split_mode = false; + } + + while (mp_cell_lists.size () < m_cellviews.size ()) { + + QPalette pl; + + int cv_index = int (mp_cell_lists.size ()); + + QFrame *cl_frame = new QFrame (this); + cl_frame->setFrameShape (QFrame::NoFrame); + QVBoxLayout *cl_ly = new QVBoxLayout (cl_frame); + cl_ly->setSpacing (0); + cl_ly->setContentsMargins (0, 0, 0, 0); + + QToolButton *header = new QToolButton (cl_frame); + connect (header, SIGNAL (clicked ()), this, SLOT (header_clicked ())); + header->setText (tl::to_qstring (display_string (cv_index))); + header->setFocusPolicy (Qt::NoFocus); + header->setSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred); + header->setCheckable (true); + header->setAutoRaise (true); + header->setAutoFillBackground (true); + header->setVisible (split_mode); + cl_ly->addWidget (header); + + LibraryTreeWidget *cell_list = new LibraryTreeWidget (cl_frame, "tree", mp_view->view_object_widget ()); + cl_ly->addWidget (cell_list); + cell_list->setModel (new CellTreeModel (cell_list, mp_view, cv_index, m_flat ? CellTreeModel::Flat : 0, 0, m_sorting)); + cell_list->setUniformRowHeights (true); + + pl = cell_list->palette (); + if (m_text_color.isValid ()) { + pl.setColor (QPalette::Text, m_text_color); + } + if (m_background_color.isValid ()) { + pl.setColor (QPalette::Base, m_background_color); + } + cell_list->setPalette (pl); + + cell_list->header ()->hide (); + cell_list->setSelectionMode (QTreeView::ExtendedSelection); + cell_list->setRootIsDecorated (true); + cell_list->setIndentation (14); + cell_list->setContextMenuPolicy (Qt::CustomContextMenu); + + connect (cell_list, SIGNAL (customContextMenuRequested (const QPoint &)), this, SLOT (context_menu (const QPoint &))); + connect (cell_list, SIGNAL (cell_clicked (const QModelIndex &)), this, SLOT (clicked (const QModelIndex &))); + connect (cell_list, SIGNAL (cell_double_clicked (const QModelIndex &)), this, SLOT (double_clicked (const QModelIndex &))); + connect (cell_list, SIGNAL (cell_middle_clicked (const QModelIndex &)), this, SLOT (middle_clicked (const QModelIndex &))); + connect (cell_list, SIGNAL (search_triggered (const QString &)), this, SLOT (search_triggered (const QString &))); + + mp_cell_lists.push_back (cell_list); + mp_cell_list_frames.push_back (cl_frame); + mp_cell_list_headers.push_back (header); + + mp_splitter->addWidget (cl_frame); + + } + + while (mp_cell_lists.size () > m_cellviews.size ()) { + delete mp_cell_list_frames.back (); + mp_cell_list_frames.pop_back (); + mp_cell_list_headers.pop_back (); + mp_cell_lists.pop_back (); + } + + for (unsigned int i = imin; i < m_cellviews.size () && i < (unsigned int) mp_selector->count () && i <= imax; ++i) { + mp_selector->setItemText (i, tl::to_qstring (display_string (i))); + } + while (mp_selector->count () < int (m_cellviews.size ())) { + mp_selector->addItem (tl::to_qstring (display_string (mp_selector->count ()))); + } + while (mp_selector->count () > int (m_cellviews.size ())) { + mp_selector->removeItem (mp_selector->count () - 1); + } + + if (m_active_index >= int (m_cellviews.size ())) { + m_active_index = int (m_cellviews.size ()) - 1; + } else if (m_active_index < 0 && ! m_cellviews.empty ()) { + m_active_index = 0; + } + mp_selector->setCurrentIndex (m_active_index); + mp_selector->setVisible (mp_cell_lists.size () > 1 && ! split_mode); + + for (unsigned int i = imin; i < m_cellviews.size () && i <= imax; ++i) { + + if (m_needs_update [i]) { + + mp_cell_list_headers [i]->setText (tl::to_qstring (display_string (i))); + + // draw the cells in the level of the current cell, + // add an "above" entry if there is a level above. + // highlight the current entry. If the index is + // invalid, just clear the list. + + if (m_force_close [i]) { + + m_force_close [i] = false; + + CellTreeModel *model = dynamic_cast (mp_cell_lists [i]->model ()); + if (model) { + model->configure (mp_view, i, m_flat ? CellTreeModel::Flat : 0, 0, m_sorting); + } + + } + + m_needs_update [i] = false; + + } + + mp_cell_list_headers [i]->setVisible (split_mode && m_cellviews.size () > 1); + mp_cell_list_headers [i]->setChecked (int (i) == m_active_index); + + mp_cell_list_frames [i]->setVisible (int (i) == m_active_index || split_mode); + + } +} + +CellTreeItem * +LibrariesView::current_item () const +{ + if (m_active_index < 0 || m_active_index >= int (mp_cell_lists.size ())) { + return 0; + } + if (mp_cell_lists [m_active_index]->currentIndex ().isValid ()) { + return (CellTreeItem *) mp_cell_lists [m_active_index]->currentIndex ().internalPointer (); + } else { + return 0; + } +} +#endif + +void +LibrariesView::do_update_content () +{ + // @@@ +} + +void +LibrariesView::do_full_update_content () +{ + // @@@ +} + +bool +LibrariesView::has_focus () const +{ + return m_active_index >= 0 && m_active_index < int (mp_cell_lists.size ()) && mp_cell_lists [m_active_index]->hasFocus (); +} + +} // namespace lay diff --git a/src/laybasic/laybasic/layLibrariesView.h b/src/laybasic/laybasic/layLibrariesView.h new file mode 100644 index 000000000..e5d496c99 --- /dev/null +++ b/src/laybasic/laybasic/layLibrariesView.h @@ -0,0 +1,310 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2019 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_layLibrariesView +#define HDR_layLibrariesView + +#include +#include +#include + +#include +#include + +#include "dbLayout.h" +#include "layCanvasPlane.h" +#include "layViewOp.h" +#include "layLayoutView.h" +#include "layCellTreeModel.h" +#include "layWidgets.h" +#include "tlDeferredExecution.h" + +class QModelIndex; +class QComboBox; +class QMenu; +class QSplitter; +class QFrame; +class QToolButton; +class QLineEdit; +class QAction; +class QCheckBox; + +namespace lay +{ + +/** + * @brief A special QTreeView customization + * + * A customized QTreeView that is used to receive middle-mouse-button + * events and processes double clicks by bypassing the standard implementation + * that closes and opens branches. + */ +class LibraryTreeWidget + : public QTreeView +{ +Q_OBJECT + +public: + LibraryTreeWidget (QWidget *parent, const char *name, QWidget *key_event_receiver); + +signals: + void cell_clicked (const QModelIndex &); + void cell_double_clicked (const QModelIndex &); + void cell_middle_clicked (const QModelIndex &); + void search_triggered (const QString &t); + +protected: + virtual void mouseDoubleClickEvent (QMouseEvent *event); + virtual void mousePressEvent (QMouseEvent *event); + virtual void mouseReleaseEvent (QMouseEvent *event); + virtual void startDrag (Qt::DropActions supportedActions); + virtual bool focusNextPrevChild (bool next); + virtual void keyPressEvent (QKeyEvent *event); + virtual bool event (QEvent *event); + + QWidget *mp_key_event_receiver; +}; + +/** + * @brief The hierarchy control panel + * + * The hierarchy control panel allows changing the cell shown, to + * browse the hierarchy and disable/enable cells + * + * The class communicates with a Layout interface for + * retrieval of the cell hierarchy + */ +class LibrariesView + : public QFrame, + public tl::Object +{ +Q_OBJECT + +public: + /** + * @brief Constructor + * + * @param parent The Qt parent widget + * @param name The layer control panel's widget name + */ + LibrariesView (lay::LayoutView *view, QWidget *parent = 0, const char *name = "libraries_view"); + + /** + * @brief Destructor + */ + ~LibrariesView (); + + /** + * @brief Perform the cell control panel's initialisations on the main menu + */ + static void init_menu (lay::AbstractMenu &menu); + + /** + * @brief The sizeHint implementation for Qt layout management + */ + virtual QSize sizeHint () const; + + /** + * @brief Changing of the background color + */ + void set_background_color (QColor c); + + /** + * @brief Changing of the text color + */ + void set_text_color (QColor c); + +#if 0 // @@@ + /** + * @brief Select the active cellview + * + * selects the active cellview by index. The index must be + * a valid index within the context of the layout view. + */ + void select_active (int cellview_index); + + /** + * @brief Get the active cellview + * + * get the active cellview index. + */ + int active () + { + return m_active_index; + } + + /** + * @brief Returns the paths of the selected cells + */ + void selected_cells (int cv_index, std::vector &paths) const; + + /** + * @brief Return the path to the current cell for the given cellview index + * + * The current cell is the cell that is highlighted. + */ + void current_cell (int cv_index, cell_path_type &path) const; + + /** + * @brief Set the path to the current cell + * + * The current cell is the cell that is highlighted. The current cv index + * can be obtained with the "active" method. + */ + void set_current_cell (int cv_index, const cell_path_type &path); + + /** + * @brief Update the contents if necessary + * + * Update the cell trees according to the hierarchy found in + * the layouts. This version includes a hint which cellview has changed. + */ + void do_update_content (int cv_index); + + /** + * @brief Update the contents if necessary + * + * Update the cell trees according to the hierarchy found in + * the layouts. + */ + void do_update_content () + { + do_update_content (-1); + } +#endif + + /** + * @brief Event handler + * + * The object subclasses the event handler in order to intercept + * the GTF probe events (Qt::MaxUser). + */ + virtual bool event (QEvent *e); + + /** + * @brief Return true, if the tree view has the focus + */ + bool has_focus () const; + + /** + * @brief Select split mode + * In split mode all cell trees are shown stacked + */ + void set_split_mode (bool sbs); + + /** + * @brief Returns true if side-by-side mode is set + */ + bool split_mode () const + { + return m_split_mode; + } + + /** + * @brief Gets the layout view this panel is attached to + */ + lay::LayoutView *view () + { + return mp_view; + } + +#if 0 +signals: + void cell_selected (cell_path_type path, int cellview_index); + void active_cellview_changed (int cellview_index); +#endif + +public slots: + void clicked (const QModelIndex &index); + void header_clicked (); + void double_clicked (const QModelIndex &index); + void middle_clicked (const QModelIndex &index); + // @@@ void selection_changed (int index); + void context_menu (const QPoint &pt); + void search_triggered (const QString &t); + void search_edited (); + void search_editing_finished (); + void search_next (); + void search_prev (); + void cm_cell_select (); + +private: + db::Layout *mp_layout; + bool m_enable_cb; + lay::LayoutView *mp_view; + std::vector mp_cell_lists; + std::vector mp_cell_list_headers; + std::vector mp_cell_list_frames; + std::vector m_force_close; + std::vector m_needs_update; + int m_active_index; + bool m_split_mode; + QComboBox *mp_selector; + lay::DecoratedLineEdit *mp_search_edit_box; + QAction *mp_case_sensitive; + QAction *mp_use_regular_expressions; + CellTreeModel *mp_search_model; + QFrame *mp_search_frame; + QCheckBox *mp_search_close_cb; + QSplitter *mp_splitter; + QColor m_background_color; + QColor m_text_color; + tl::DeferredMethod m_do_update_content_dm; + tl::DeferredMethod m_do_full_update_content_dm; + std::auto_ptr mp_tree_style; + +#if 0 // @@@ + // locate the CellTreeItem in the tree corresponding to a partial path starting from p. + CellTreeItem *find_child_item (cell_path_type::const_iterator start, cell_path_type::const_iterator end, CellTreeItem *p); + + // get the current item + CellTreeItem *current_item () const; + + // event listener for changes in the cellview and layout + void update_required (); + + // path from index and item from path .. + void path_from_index (const QModelIndex &index, int cv_index, cell_path_type &path) const; + QModelIndex index_from_path (const cell_path_type &path, int cv_index); + + // display string of nth cellview + std::string display_string (int n) const; + + // select active cellview from sender (sender must be a cell tree) + void set_active_celltree_from_sender (); + + // clears all widgets of the cell lists + void clear_all (); +#endif + + // forces a complete update + void do_full_update_content (); + + // updates the contents if necessary + void do_update_content (); +}; + +} // namespace lay + +#endif + diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro index b285677ca..5d59bd3af 100644 --- a/src/laybasic/laybasic/laybasic.pro +++ b/src/laybasic/laybasic/laybasic.pro @@ -175,7 +175,8 @@ SOURCES = \ layNetlistBrowserModel.cc \ layIndexedNetlistModel.cc \ layNetlistCrossReferenceModel.cc \ - layNetlistBrowserTreeModel.cc + layNetlistBrowserTreeModel.cc \ + layLibrariesView.cc HEADERS = \ gtf.h \ @@ -271,7 +272,8 @@ HEADERS = \ layNetlistBrowserModel.h \ layIndexedNetlistModel.h \ layNetlistCrossReferenceModel.h \ - layNetlistBrowserTreeModel.h + layNetlistBrowserTreeModel.h \ + layLibrariesView.h INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC DEPENDPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC