mirror of https://github.com/KLayout/klayout.git
WIP: Enhancements to EditorOptionsPages API
- Make RBA::LayoutViewBase derived from Dispatcher, so we can pass LayoutView to methods asking for a dispatcher - For this, the Dispatcher needs to be the first base class of LayoutViewBase and gsiDeclLayDispatcher is moved to laybasic - API for editor options pages and message passing (callbacks)
This commit is contained in:
parent
0447080d17
commit
b9115fc0a2
|
|
@ -59,19 +59,16 @@ Class<lay::EditorOptionsPage> decl_EditorOptionsPageBase (QT_EXTERNAL_BASE (QWid
|
|||
) +
|
||||
method ("show", &lay::EditorOptionsPage::show,
|
||||
"@brief Shows the page\n"
|
||||
"@return A value indicating whether the page was opened non-modal (-1), accepted (1) or rejected (0)\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"),
|
||||
method ("apply", &lay::EditorOptionsPage::apply, gsi::arg ("dispatcher"),
|
||||
"@brief Transfers data from the page to the configuration\n"
|
||||
"Calling this method will call the actual 'apply' implementation which is "
|
||||
"provided by a reimplementation - either on C++ or script side."
|
||||
) +
|
||||
method ("do_setup", &lay::EditorOptionsPage::setup, gsi::arg ("dispatcher"),
|
||||
method ("setup", &lay::EditorOptionsPage::setup, gsi::arg ("dispatcher"),
|
||||
"@brief Transfers data from the configuration to the page\n"
|
||||
"Calling this method will call the actual 'setup' implementation which is "
|
||||
"provided by a reimplementation - either on C++ or script side."
|
||||
),
|
||||
"@brief The plugin framework's editor options page base class\n"
|
||||
"\n"
|
||||
|
|
@ -100,6 +97,16 @@ EditorOptionsPageImpl::call_edited ()
|
|||
lay::EditorOptionsPage::edited ();
|
||||
}
|
||||
|
||||
static void apply_fb (EditorOptionsPageImpl *ep, lay::Dispatcher *root)
|
||||
{
|
||||
ep->lay::EditorOptionsPage::apply (root);
|
||||
}
|
||||
|
||||
static void setup_fb (EditorOptionsPageImpl *ep, lay::Dispatcher *root)
|
||||
{
|
||||
ep->lay::EditorOptionsPage::setup (root);
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPageImpl::apply_impl (lay::Dispatcher *root)
|
||||
{
|
||||
|
|
@ -148,11 +155,15 @@ Class<EditorOptionsPageImpl> decl_EditorOptionsPage (decl_EditorOptionsPageBase,
|
|||
"When some entry widget (for example 'editingFinished' slot of a QLineEdit), "
|
||||
"call this method to initiate a transfer of information from the page to the plugin.\n"
|
||||
) +
|
||||
// prevents infinite recursion
|
||||
method_ext ("apply", &apply_fb, gsi::arg ("dispatcher"), "@hide") +
|
||||
callback ("apply", &EditorOptionsPageImpl::apply, &EditorOptionsPageImpl::f_apply, gsi::arg ("dispatcher"),
|
||||
"@brief Reimplement this method to transfer data from the page to the configuration\n"
|
||||
"In this method, you should transfer all widget data into corresponding configuration updates.\n"
|
||||
"Use \\Dispatcher#set_config on the dispatcher object ('dispatcher' argument) to set a configuration parameter.\n"
|
||||
) +
|
||||
// prevents infinite recursion
|
||||
method_ext ("setup", &setup_fb, gsi::arg ("dispatcher"), "@hide") +
|
||||
callback ("setup", &EditorOptionsPageImpl::setup, &EditorOptionsPageImpl::f_setup, gsi::arg ("dispatcher"),
|
||||
"@brief Reimplement this method to transfer data from the configuration to the page\n"
|
||||
"In this method, you should transfer all configuration data to the widgets.\n"
|
||||
|
|
|
|||
|
|
@ -51,9 +51,7 @@ public:
|
|||
}
|
||||
|
||||
void call_edited ();
|
||||
void apply_impl (lay::Dispatcher *root);
|
||||
virtual void apply (lay::Dispatcher *root);
|
||||
void setup_impl (lay::Dispatcher *root);
|
||||
virtual void setup (lay::Dispatcher *root);
|
||||
|
||||
gsi::Callback f_apply;
|
||||
|
|
@ -64,6 +62,9 @@ private:
|
|||
tl::weak_ptr<lay::Dispatcher> mp_dispatcher;
|
||||
std::string m_title;
|
||||
int m_index;
|
||||
|
||||
void apply_impl (lay::Dispatcher *root);
|
||||
void setup_impl (lay::Dispatcher *root);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -646,6 +646,15 @@ PluginImpl::tracking_position () const
|
|||
}
|
||||
}
|
||||
|
||||
int PluginImpl::focus_page_open(lay::EditorOptionsPage *fp)
|
||||
{
|
||||
if (f_focus_page_open.can_issue ()) {
|
||||
return f_focus_page_open.issue<lay::EditorServiceBase, int, lay::EditorOptionsPage *> (&lay::EditorServiceBase::focus_page_open, fp);
|
||||
} else {
|
||||
return lay::EditorServiceBase::focus_page_open (fp);
|
||||
}
|
||||
}
|
||||
|
||||
lay::angle_constraint_type
|
||||
PluginImpl::connect_ac (lay::angle_constraint_type ac) const
|
||||
{
|
||||
|
|
@ -970,6 +979,22 @@ Class<gsi::PluginImpl> decl_Plugin (decl_PluginBase, "lay", "Plugin",
|
|||
"\n"
|
||||
"This method has been added in version 0.30.4."
|
||||
) +
|
||||
gsi::method ("focus_page", &gsi::PluginImpl::focus_page,
|
||||
"@brief Gets the (first) focus page\n"
|
||||
"Focus pages are editor options pages that have a true value for \\EditorOptionsPage#is_focus_page.\n"
|
||||
"The pages can be navigated to quickly or can be shown in a modal dialog from the editor function.\n"
|
||||
"This method returns the first focus page present in the editor options pages stack.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.30.4."
|
||||
) +
|
||||
callback ("focus_page_open", &gsi::PluginImpl::focus_page_open, &gsi::PluginImpl::f_focus_page_open, gsi::arg ("focus_page"),
|
||||
"@brief Gets called when the focus page wants to be opened - i.e. if 'Tab' is pressed during editing\n"
|
||||
"The default implementation calls \\EditorOptionsPage#show. This method can be overloaded to provide certain actions before "
|
||||
"or after the page is shown, specifically if the page is a modal one. For example, it can update the page with current "
|
||||
"dimensions of a shape that is created and after committing the page, adjust the shape accordingly.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.30.4."
|
||||
) +
|
||||
#endif
|
||||
gsi::method ("view", &gsi::PluginImpl::view,
|
||||
"@brief Gets the view object the plugin is associated with\n"
|
||||
|
|
|
|||
|
|
@ -95,6 +95,8 @@ public:
|
|||
db::DPoint tracking_position_test () const;
|
||||
virtual db::DPoint tracking_position () const;
|
||||
|
||||
virtual int focus_page_open (lay::EditorOptionsPage *fp);
|
||||
|
||||
virtual lay::ViewService *view_service_interface ()
|
||||
{
|
||||
return this;
|
||||
|
|
@ -128,6 +130,7 @@ public:
|
|||
gsi::Callback f_update;
|
||||
gsi::Callback f_has_tracking_position;
|
||||
gsi::Callback f_tracking_position;
|
||||
gsi::Callback f_focus_page_open;
|
||||
|
||||
private:
|
||||
tl::weak_ptr<lay::LayoutViewBase> mp_view;
|
||||
|
|
|
|||
|
|
@ -121,7 +121,6 @@ FORMS = \
|
|||
SOURCES = \
|
||||
gsiDeclLayApplication.cc \
|
||||
gsiDeclLayConfigPage.cc \
|
||||
gsiDeclLayDispatcher.cc \
|
||||
gsiDeclLayEditorOptionsPage.cc \
|
||||
gsiDeclLayHelpDialog.cc \
|
||||
gsiDeclLayMainWindow.cc \
|
||||
|
|
|
|||
|
|
@ -497,7 +497,9 @@ static bool view_is_dirty (lay::LayoutViewBase *view)
|
|||
return view->is_dirty ();
|
||||
}
|
||||
|
||||
LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase ("lay", "LayoutViewBase",
|
||||
extern Class<lay::Dispatcher> decl_Dispatcher;
|
||||
|
||||
LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase (decl_Dispatcher, "lay", "LayoutViewBase",
|
||||
gsi::constant ("LV_NoLayers", (unsigned int) lay::LayoutViewBase::LV_NoLayers,
|
||||
"@brief With this option, no layers view will be provided (see \\layer_control_frame)\n"
|
||||
"Use this value with the constructor's 'options' argument.\n"
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "layEditorOptionsPage.h"
|
||||
#include "layEditorOptionsPages.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
#include "tlExceptions.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QKeyEvent>
|
||||
|
|
@ -92,20 +93,19 @@ EditorOptionsPage::focusNextPrevChild (bool next)
|
|||
void
|
||||
EditorOptionsPage::keyPressEvent (QKeyEvent *event)
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
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 ();
|
||||
apply (dispatcher ());
|
||||
if (view ()->canvas ()->widget ()) {
|
||||
view ()->canvas ()->widget ()->setFocus (Qt::TabFocusReason);
|
||||
}
|
||||
|
||||
event->accept ();
|
||||
|
||||
} else {
|
||||
QWidget::keyPressEvent (event);
|
||||
}
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -115,14 +115,15 @@ EditorOptionsPage::set_focus ()
|
|||
QWidget::focusNextPrevChild (true);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
EditorOptionsPage::show ()
|
||||
{
|
||||
if (mp_owner && m_active) {
|
||||
if (! is_modal_page ()) {
|
||||
mp_owner->make_page_current (this);
|
||||
return -1;
|
||||
} else {
|
||||
mp_owner->exec_modal (this);
|
||||
return mp_owner->exec_modal (this) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,11 @@ public:
|
|||
void activate (bool active);
|
||||
void set_owner (EditorOptionsPages *owner);
|
||||
|
||||
void show ();
|
||||
/**
|
||||
* @brief Shows the editor page
|
||||
* @return -1, if the page is shown non-modal, otherwise 1 or 0 if the dialog was accepted (1) or rejected (0)
|
||||
*/
|
||||
int show ();
|
||||
|
||||
const lay::PluginDeclaration *plugin_declaration () const { return mp_plugin_declaration; }
|
||||
void set_plugin_declaration (const lay::PluginDeclaration *pd) { mp_plugin_declaration = pd; }
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ EditorOptionsPages::exec_modal (EditorOptionsPage *page)
|
|||
|
||||
// found the page - make it current and show the dialog
|
||||
mp_modal_pages->set_current_index (i);
|
||||
page->setup (mp_dispatcher);
|
||||
page->set_focus ();
|
||||
return mp_modal_pages->exec () != 0;
|
||||
|
||||
|
|
@ -165,6 +166,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->setup (mp_dispatcher);
|
||||
page->set_focus ();
|
||||
break;
|
||||
}
|
||||
|
|
@ -256,16 +258,17 @@ BEGIN_PROTECTED
|
|||
|
||||
// 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 ();
|
||||
do_apply (false);
|
||||
do_apply (true);
|
||||
|
||||
END_PROTECTED_W (this)
|
||||
}
|
||||
|
||||
void
|
||||
EditorOptionsPages::do_apply ()
|
||||
EditorOptionsPages::do_apply (bool modal)
|
||||
{
|
||||
for (std::vector <lay::EditorOptionsPage *>::iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
|
||||
if ((*p)->active ()) {
|
||||
if ((*p)->active () && modal == (*p)->is_modal_page ()) {
|
||||
// NOTE: we apply to the root dispatcher, so other dispatchers (views) get informed too.
|
||||
(*p)->apply (mp_dispatcher->dispatcher ());
|
||||
}
|
||||
|
|
@ -276,7 +279,7 @@ void
|
|||
EditorOptionsPages::apply ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
do_apply ();
|
||||
do_apply (false);
|
||||
END_PROTECTED_W (this)
|
||||
}
|
||||
|
||||
|
|
@ -417,8 +420,10 @@ EditorOptionsModalPages::widget (int index)
|
|||
void
|
||||
EditorOptionsModalPages::accept ()
|
||||
{
|
||||
mp_parent->apply ();
|
||||
BEGIN_PROTECTED
|
||||
mp_parent->do_apply (true);
|
||||
QDialog::accept ();
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -430,9 +435,11 @@ EditorOptionsModalPages::reject ()
|
|||
void
|
||||
EditorOptionsModalPages::clicked (QAbstractButton *button)
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
if (button == mp_button_box->button (QDialogButtonBox::Apply)) {
|
||||
mp_parent->apply ();
|
||||
mp_parent->do_apply (true);
|
||||
}
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ public:
|
|||
|
||||
bool has_content () const;
|
||||
bool has_modal_content () const;
|
||||
void do_apply (bool modal);
|
||||
|
||||
public slots:
|
||||
void apply ();
|
||||
|
|
@ -85,7 +86,6 @@ private:
|
|||
EditorOptionsModalPages *mp_modal_pages;
|
||||
|
||||
void update (lay::EditorOptionsPage *page);
|
||||
void do_apply ();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -344,6 +344,7 @@ EditorServiceBase::activated ()
|
|||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
|
||||
std::vector<lay::EditorOptionsPage *>
|
||||
EditorServiceBase::editor_options_pages ()
|
||||
{
|
||||
|
|
@ -360,23 +361,52 @@ EditorServiceBase::editor_options_pages ()
|
|||
return pages;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
lay::EditorOptionsPage *
|
||||
EditorServiceBase::focus_page ()
|
||||
{
|
||||
auto pages = editor_options_pages ();
|
||||
for (auto p = pages.begin (); p != pages.end (); ++p) {
|
||||
if ((*p)->is_focus_page ()) {
|
||||
return *p;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
EditorServiceBase::key_event (unsigned int key, unsigned int buttons)
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
if (is_active () && key == Qt::Key_Tab && buttons == 0) {
|
||||
auto pages = editor_options_pages ();
|
||||
for (auto p = pages.begin (); p != pages.end (); ++p) {
|
||||
if ((*p)->is_focus_page ()) {
|
||||
(*p)->show ();
|
||||
return true;
|
||||
}
|
||||
EditorOptionsPage *fp = focus_page ();
|
||||
if (fp) {
|
||||
focus_page_open (fp);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
EditorServiceBase::focus_page_open (EditorOptionsPage *fp)
|
||||
{
|
||||
return fp->show ();
|
||||
}
|
||||
|
||||
void
|
||||
EditorServiceBase::show_error (tl::Exception &ex)
|
||||
{
|
||||
tl::error << ex.msg ();
|
||||
QMessageBox::critical (ui ()->widget (), tr ("Error"), tl::to_qstring (ex.msg ()));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool
|
||||
EditorServiceBase::key_event (unsigned int key, unsigned int buttons)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -384,9 +414,14 @@ void
|
|||
EditorServiceBase::show_error (tl::Exception &ex)
|
||||
{
|
||||
tl::error << ex.msg ();
|
||||
#if defined(HAVE_QT)
|
||||
QMessageBox::critical (ui ()->widget (), tr ("Error"), tl::to_qstring (ex.msg ()));
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
EditorServiceBase::focus_page_enter ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -270,6 +270,18 @@ public:
|
|||
* @brief Gets the editor options pages associated with this plugin
|
||||
*/
|
||||
std::vector<lay::EditorOptionsPage *> editor_options_pages ();
|
||||
|
||||
/**
|
||||
* @brief Gets the focus page or 0 if there is none
|
||||
*/
|
||||
lay::EditorOptionsPage *focus_page ();
|
||||
|
||||
/**
|
||||
* @brief Gets called when the focus page opens
|
||||
*
|
||||
* The default implementation will call fp->show() and return its return value.
|
||||
*/
|
||||
virtual int focus_page_open (EditorOptionsPage *fp);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -157,8 +157,8 @@ struct LAYBASIC_PUBLIC LayerDisplayProperties
|
|||
* It manages the layer display list, bookmark list etc.
|
||||
*/
|
||||
class LAYBASIC_PUBLIC LayoutViewBase :
|
||||
public lay::Editables,
|
||||
public lay::Dispatcher
|
||||
public lay::Dispatcher, // needs to be first as it is the GSI base class
|
||||
public lay::Editables
|
||||
{
|
||||
public:
|
||||
typedef lay::CellView::unspecific_cell_path_type cell_path_type;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ DEFINES += MAKE_LAYBASIC_LIBRARY
|
|||
|
||||
SOURCES += \
|
||||
gsiDeclLayLayers.cc \
|
||||
gsiDeclLayDispatcher.cc \
|
||||
gsiDeclLayLayoutViewBase.cc \
|
||||
gsiDeclLayMarker.cc \
|
||||
gsiDeclLayMenu.cc \
|
||||
|
|
|
|||
Loading…
Reference in New Issue