mirror of https://github.com/KLayout/klayout.git
WIP: experimental - modal editor options pages
This commit is contained in:
parent
53a7414757
commit
2b04ecb1f7
|
|
@ -48,10 +48,20 @@ Class<lay::EditorOptionsPage> decl_EditorOptionsPageBase (QT_EXTERNAL_BASE (QWid
|
|||
"@brief Sets a flag indicating whether the page is a focus page\n"
|
||||
"The focus page is the page that is selected when the tab key is pressed during some plugin action.\n"
|
||||
) +
|
||||
method ("make_current", &lay::EditorOptionsPage::make_current,
|
||||
"@brief Brings the page to the front of the tab stack\n"
|
||||
"Calling this method will make this page the current one in the tab stack, provided "
|
||||
"the page is visible."
|
||||
method ("is_modal_page?", &lay::EditorOptionsPage::is_modal_page,
|
||||
"@brief Gets a flag indicating whether the page is a modal page\n"
|
||||
"See \\modal_page= for a description is this attribute.\n"
|
||||
) +
|
||||
method ("modal_page=", &lay::EditorOptionsPage::set_modal_page, gsi::arg ("flag"),
|
||||
"@brief Sets a flag indicating whether the page is a modal page\n"
|
||||
"A modal page is shown in a modal dialog upon \\show. Non-modal pages are shown in the "
|
||||
"editor options dock.\n"
|
||||
) +
|
||||
method ("show", &lay::EditorOptionsPage::show,
|
||||
"@brief Shows the page\n"
|
||||
"Provided the page is selected because the plugin is active, this method will "
|
||||
"open a dialog to show the page if it is modal, or locate the page in the editor options "
|
||||
"dock and bring it to the front if it is non-modal."
|
||||
) +
|
||||
method ("do_apply", &lay::EditorOptionsPage::apply, gsi::arg ("dispatcher"),
|
||||
"@brief Transfers data from the page to the configuration\n"
|
||||
|
|
@ -72,6 +82,9 @@ Class<lay::EditorOptionsPage> decl_EditorOptionsPageBase (QT_EXTERNAL_BASE (QWid
|
|||
"It features some useful methods such as 'view' and provides a slot to call for triggering a data "
|
||||
"transfer ('edited').\n"
|
||||
"\n"
|
||||
"Note that even though the page class is derived from QWidget, you can call QWidget methods "
|
||||
"but not overload virtual methods from QWidget.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.30.4.\n"
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@
|
|||
#include "layEditorOptionsPages.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QKeyEvent>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
|
|
@ -34,15 +37,20 @@ namespace lay
|
|||
// EditorOptionsPage implementation
|
||||
|
||||
EditorOptionsPage::EditorOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
|
||||
: QWidget (0), mp_owner (0), m_active (true), m_focus_page (false), mp_plugin_declaration (0), mp_dispatcher (dispatcher), mp_view (view)
|
||||
: QWidget (0), mp_owner (0), m_active (true), m_focus_page (false), m_modal_page (false), mp_plugin_declaration (0), mp_dispatcher (dispatcher), mp_view (view)
|
||||
{
|
||||
attach_events ();
|
||||
}
|
||||
|
||||
EditorOptionsPage::EditorOptionsPage ()
|
||||
: QWidget (0), mp_owner (0), m_active (true), m_focus_page (false), mp_plugin_declaration (0), mp_dispatcher (0), mp_view (0)
|
||||
: QWidget (0), mp_owner (0), m_active (true), m_focus_page (false), m_modal_page (false), mp_plugin_declaration (0), mp_dispatcher (0), mp_view (0)
|
||||
{
|
||||
// .. nothing here -> call init to set view and dispatcher
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
EditorOptionsPage::~EditorOptionsPage ()
|
||||
{
|
||||
set_owner (0);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -53,16 +61,69 @@ EditorOptionsPage::init (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
|
|||
attach_events ();
|
||||
}
|
||||
|
||||
EditorOptionsPage::~EditorOptionsPage ()
|
||||
void
|
||||
EditorOptionsPage::edited ()
|
||||
{
|
||||
set_owner (0);
|
||||
apply (dispatcher ());
|
||||
}
|
||||
|
||||
static bool is_parent_widget (QWidget *w, QWidget *parent)
|
||||
{
|
||||
while (w && w != parent) {
|
||||
w = dynamic_cast<QWidget *> (w->parent ());
|
||||
}
|
||||
return w == parent;
|
||||
}
|
||||
|
||||
bool
|
||||
EditorOptionsPage::focusNextPrevChild (bool next)
|
||||
{
|
||||
bool res = QWidget::focusNextPrevChild (next);
|
||||
|
||||
// Stop making the focus leave the page - this way we can jump back to the
|
||||
// view on "enter"
|
||||
if (res && ! is_modal_page () && ! is_parent_widget (QApplication::focusWidget (), this) && focusWidget ()) {
|
||||
focusWidget ()->setFocus ();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPage::make_current ()
|
||||
EditorOptionsPage::keyPressEvent (QKeyEvent *event)
|
||||
{
|
||||
if (! is_modal_page () && event->modifiers () == Qt::NoModifier && event->key () == Qt::Key_Return) {
|
||||
|
||||
// The Return key on a non-modal page commits the values and gives back the focus
|
||||
// to the view
|
||||
edited ();
|
||||
if (view ()->canvas ()->widget ()) {
|
||||
view ()->canvas ()->widget ()->setFocus (Qt::TabFocusReason);
|
||||
}
|
||||
|
||||
event->accept ();
|
||||
|
||||
} else {
|
||||
QWidget::keyPressEvent (event);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPage::set_focus ()
|
||||
{
|
||||
setFocus (Qt::TabFocusReason);
|
||||
QWidget::focusNextPrevChild (true);
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPage::show ()
|
||||
{
|
||||
if (mp_owner && m_active) {
|
||||
mp_owner->make_page_current (this);
|
||||
if (! is_modal_page ()) {
|
||||
mp_owner->make_page_current (this);
|
||||
} else {
|
||||
mp_owner->exec_modal (this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,11 +68,16 @@ public:
|
|||
|
||||
bool is_focus_page () const { return m_focus_page; }
|
||||
void set_focus_page (bool f) { m_focus_page = f; }
|
||||
void set_focus ();
|
||||
|
||||
bool is_modal_page () const { return m_modal_page; }
|
||||
void set_modal_page (bool f) { m_modal_page = f; }
|
||||
|
||||
bool active () const { return m_active; }
|
||||
void activate (bool active);
|
||||
void set_owner (EditorOptionsPages *owner);
|
||||
|
||||
void make_current ();
|
||||
void show ();
|
||||
|
||||
const lay::PluginDeclaration *plugin_declaration () const { return mp_plugin_declaration; }
|
||||
void set_plugin_declaration (const lay::PluginDeclaration *pd) { mp_plugin_declaration = pd; }
|
||||
|
|
@ -90,19 +95,20 @@ public:
|
|||
}
|
||||
|
||||
protected slots:
|
||||
void edited ()
|
||||
{
|
||||
apply (dispatcher ());
|
||||
}
|
||||
void edited ();
|
||||
|
||||
protected:
|
||||
virtual void active_cellview_changed () { }
|
||||
virtual void technology_changed (const std::string & /*tech*/) { }
|
||||
|
||||
virtual bool focusNextPrevChild (bool next);
|
||||
virtual void keyPressEvent (QKeyEvent *event);
|
||||
|
||||
private:
|
||||
EditorOptionsPages *mp_owner;
|
||||
bool m_active;
|
||||
bool m_focus_page;
|
||||
bool m_modal_page;
|
||||
const lay::PluginDeclaration *mp_plugin_declaration;
|
||||
lay::Dispatcher *mp_dispatcher;
|
||||
lay::LayoutViewBase *mp_view;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@
|
|||
#include <QToolButton>
|
||||
#include <QCompleter>
|
||||
#include <QLineEdit>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
|
@ -52,6 +54,8 @@ struct EOPCompareOp
|
|||
EditorOptionsPages::EditorOptionsPages (QWidget *parent, const std::vector<lay::EditorOptionsPage *> &pages, lay::Dispatcher *dispatcher)
|
||||
: QFrame (parent), mp_dispatcher (dispatcher)
|
||||
{
|
||||
mp_modal_pages = new EditorOptionsModalPages (this);
|
||||
|
||||
QVBoxLayout *ly1 = new QVBoxLayout (this);
|
||||
ly1->setContentsMargins (0, 0, 0, 0);
|
||||
|
||||
|
|
@ -73,6 +77,9 @@ EditorOptionsPages::~EditorOptionsPages ()
|
|||
while (m_pages.size () > 0) {
|
||||
delete m_pages.front ();
|
||||
}
|
||||
|
||||
delete mp_modal_pages;
|
||||
mp_modal_pages = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -84,17 +91,51 @@ EditorOptionsPages::focusInEvent (QFocusEvent * /*event*/)
|
|||
}
|
||||
}
|
||||
|
||||
bool EditorOptionsPages::has_content () const
|
||||
bool
|
||||
EditorOptionsPages::has_content () const
|
||||
{
|
||||
for (std::vector <lay::EditorOptionsPage *>::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
|
||||
if ((*p)->active ()) {
|
||||
if ((*p)->active () && ! (*p)->is_modal_page ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditorOptionsPages::activate (const lay::Plugin *plugin)
|
||||
bool
|
||||
EditorOptionsPages::has_modal_content () const
|
||||
{
|
||||
for (std::vector <lay::EditorOptionsPage *>::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
|
||||
if ((*p)->active () && (*p)->is_modal_page ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
EditorOptionsPages::exec_modal (EditorOptionsPage *page)
|
||||
{
|
||||
QTabWidget *modal_pages = mp_modal_pages->pages_widget ();
|
||||
|
||||
for (int i = 0; i < modal_pages->count (); ++i) {
|
||||
|
||||
if (modal_pages->widget (i) == page) {
|
||||
|
||||
// found the page - make it current and show the dialog
|
||||
modal_pages->setCurrentIndex (i);
|
||||
page->set_focus ();
|
||||
return mp_modal_pages->exec () != 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPages::activate (const lay::Plugin *plugin)
|
||||
{
|
||||
for (auto op = m_pages.begin (); op != m_pages.end (); ++op) {
|
||||
bool is_active = false;
|
||||
|
|
@ -126,6 +167,7 @@ EditorOptionsPages::make_page_current (lay::EditorOptionsPage *page)
|
|||
for (int i = 0; i < mp_pages->count (); ++i) {
|
||||
if (mp_pages->widget (i) == page) {
|
||||
mp_pages->setCurrentIndex (i);
|
||||
page->set_focus ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -151,6 +193,8 @@ EditorOptionsPages::update (lay::EditorOptionsPage *page)
|
|||
std::vector <lay::EditorOptionsPage *> sorted_pages = m_pages;
|
||||
std::sort (sorted_pages.begin (), sorted_pages.end (), EOPCompareOp ());
|
||||
|
||||
QTabWidget *modal_pages = mp_modal_pages->pages_widget ();
|
||||
|
||||
if (! page && m_pages.size () > 0) {
|
||||
page = m_pages.back ();
|
||||
}
|
||||
|
|
@ -158,17 +202,39 @@ EditorOptionsPages::update (lay::EditorOptionsPage *page)
|
|||
while (mp_pages->count () > 0) {
|
||||
mp_pages->removeTab (0);
|
||||
}
|
||||
|
||||
while (modal_pages->count () > 0) {
|
||||
modal_pages->removeTab (0);
|
||||
}
|
||||
|
||||
int index = -1;
|
||||
int modal_index = -1;
|
||||
|
||||
for (std::vector <lay::EditorOptionsPage *>::iterator p = sorted_pages.begin (); p != sorted_pages.end (); ++p) {
|
||||
if ((*p)->active ()) {
|
||||
if ((*p) == page) {
|
||||
index = mp_pages->count ();
|
||||
if (! (*p)->is_modal_page ()) {
|
||||
if ((*p) == page) {
|
||||
index = mp_pages->count ();
|
||||
}
|
||||
mp_pages->addTab (*p, tl::to_qstring ((*p)->title ()));
|
||||
} else {
|
||||
if ((*p) == page) {
|
||||
modal_index = modal_pages->count ();
|
||||
}
|
||||
modal_pages->addTab (*p, tl::to_qstring ((*p)->title ()));
|
||||
}
|
||||
mp_pages->addTab (*p, tl::to_qstring ((*p)->title ()));
|
||||
} else {
|
||||
(*p)->setParent (0);
|
||||
}
|
||||
}
|
||||
|
||||
lay::EditorOptionsPage *single_modal_page = modal_pages->count () == 1 ? dynamic_cast<lay::EditorOptionsPage *> (modal_pages->widget (0)) : 0;
|
||||
if (single_modal_page) {
|
||||
mp_modal_pages->setWindowTitle (tl::to_qstring (single_modal_page->title ()));
|
||||
} else {
|
||||
mp_modal_pages->setWindowTitle (tr ("Editor Options"));
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
index = mp_pages->currentIndex ();
|
||||
}
|
||||
|
|
@ -177,27 +243,33 @@ EditorOptionsPages::update (lay::EditorOptionsPage *page)
|
|||
}
|
||||
mp_pages->setCurrentIndex (index);
|
||||
|
||||
if (modal_index < 0) {
|
||||
modal_index = modal_pages->currentIndex ();
|
||||
}
|
||||
if (modal_index >= int (modal_pages->count ())) {
|
||||
modal_index = modal_pages->count () - 1;
|
||||
}
|
||||
modal_pages->setCurrentIndex (modal_index);
|
||||
|
||||
setVisible (mp_pages->count () > 0);
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPages::setup ()
|
||||
{
|
||||
try {
|
||||
BEGIN_PROTECTED
|
||||
|
||||
for (std::vector <lay::EditorOptionsPage *>::iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
|
||||
if ((*p)->active ()) {
|
||||
(*p)->setup (mp_dispatcher);
|
||||
}
|
||||
for (std::vector <lay::EditorOptionsPage *>::iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
|
||||
if ((*p)->active ()) {
|
||||
(*p)->setup (mp_dispatcher);
|
||||
}
|
||||
|
||||
// make the display consistent with the status (this is important for
|
||||
// PCell parameters where the PCell may be asked to modify the parameters)
|
||||
do_apply ();
|
||||
|
||||
} catch (...) {
|
||||
// catch any errors related to configuration file errors etc.
|
||||
}
|
||||
|
||||
// make the display consistent with the status (this is important for
|
||||
// PCell parameters where the PCell may be asked to modify the parameters)
|
||||
do_apply ();
|
||||
|
||||
END_PROTECTED_W (this)
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -219,6 +291,54 @@ BEGIN_PROTECTED
|
|||
END_PROTECTED_W (this)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// EditorOptionsModalPages implementation
|
||||
|
||||
EditorOptionsModalPages::EditorOptionsModalPages (EditorOptionsPages *parent)
|
||||
: QDialog (parent), mp_parent (parent)
|
||||
{
|
||||
QVBoxLayout *ly = new QVBoxLayout (this);
|
||||
|
||||
mp_pages = new QTabWidget (this);
|
||||
ly->addWidget (mp_pages, 1);
|
||||
mp_pages->setTabBarAutoHide (true);
|
||||
|
||||
mp_button_box = new QDialogButtonBox (this);
|
||||
ly->addWidget (mp_button_box);
|
||||
mp_button_box->setOrientation (Qt::Horizontal);
|
||||
mp_button_box->setStandardButtons (QDialogButtonBox::Cancel | QDialogButtonBox::Apply | QDialogButtonBox::Ok);
|
||||
|
||||
connect (mp_button_box, SIGNAL (clicked(QAbstractButton *)), this, SLOT (clicked(QAbstractButton *)));
|
||||
connect (mp_button_box, SIGNAL (accepted()), this, SLOT (accept()));
|
||||
connect (mp_button_box, SIGNAL (rejected()), this, SLOT (reject()));
|
||||
}
|
||||
|
||||
EditorOptionsModalPages::~EditorOptionsModalPages ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsModalPages::accept ()
|
||||
{
|
||||
mp_parent->apply ();
|
||||
QDialog::accept ();
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsModalPages::reject ()
|
||||
{
|
||||
QDialog::reject ();
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsModalPages::clicked (QAbstractButton *button)
|
||||
{
|
||||
if (button == mp_button_box->button (QDialogButtonBox::Apply)) {
|
||||
mp_parent->apply ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -28,14 +28,16 @@
|
|||
#include "laybasicCommon.h"
|
||||
#include "layEditorOptionsPage.h"
|
||||
|
||||
#include <tlVariant.h>
|
||||
|
||||
#include <QFrame>
|
||||
#include <QDialog>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class QTabWidget;
|
||||
class QLabel;
|
||||
class QDialogButtonBox;
|
||||
class QAbstractButton;
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
|
@ -43,9 +45,10 @@ namespace lay
|
|||
class PluginDeclaration;
|
||||
class Dispatcher;
|
||||
class Plugin;
|
||||
class EditorOptionsModalPages;
|
||||
|
||||
/**
|
||||
* @brief The object properties dialog
|
||||
* @brief The object properties tab widget
|
||||
*/
|
||||
class LAYBASIC_PUBLIC EditorOptionsPages
|
||||
: public QFrame
|
||||
|
|
@ -61,6 +64,7 @@ public:
|
|||
void activate (const lay::Plugin *plugin);
|
||||
void focusInEvent (QFocusEvent *event);
|
||||
void make_page_current (lay::EditorOptionsPage *page);
|
||||
bool exec_modal (lay::EditorOptionsPage *page);
|
||||
|
||||
const std::vector <lay::EditorOptionsPage *> &pages () const
|
||||
{
|
||||
|
|
@ -68,6 +72,7 @@ public:
|
|||
}
|
||||
|
||||
bool has_content () const;
|
||||
bool has_modal_content () const;
|
||||
|
||||
public slots:
|
||||
void apply ();
|
||||
|
|
@ -77,11 +82,40 @@ private:
|
|||
std::vector <lay::EditorOptionsPage *> m_pages;
|
||||
lay::Dispatcher *mp_dispatcher;
|
||||
QTabWidget *mp_pages;
|
||||
EditorOptionsModalPages *mp_modal_pages;
|
||||
|
||||
void update (lay::EditorOptionsPage *page);
|
||||
void do_apply ();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The object properties modal page dialog
|
||||
*/
|
||||
class LAYBASIC_PUBLIC EditorOptionsModalPages
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditorOptionsModalPages (EditorOptionsPages *parent);
|
||||
~EditorOptionsModalPages ();
|
||||
|
||||
QTabWidget *pages_widget ()
|
||||
{
|
||||
return mp_pages;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void accept ();
|
||||
void reject ();
|
||||
void clicked (QAbstractButton *button);
|
||||
|
||||
private:
|
||||
EditorOptionsPages *mp_parent;
|
||||
QTabWidget *mp_pages;
|
||||
QDialogButtonBox *mp_button_box;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -367,8 +367,7 @@ EditorServiceBase::key_event (unsigned int key, unsigned int buttons)
|
|||
auto pages = editor_options_pages ();
|
||||
for (auto p = pages.begin (); p != pages.end (); ++p) {
|
||||
if ((*p)->is_focus_page ()) {
|
||||
(*p)->make_current ();
|
||||
(*p)->setFocus (Qt::TabFocusReason);
|
||||
(*p)->show ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue