WIP: preparing integration of editor options pages and config pages into plugin API

This commit is contained in:
Matthias Koefferlein 2025-08-25 00:04:44 +02:00
parent ac9a589d6f
commit acfc2aae09
11 changed files with 331 additions and 55 deletions

View File

@ -24,38 +24,180 @@
#include "gsiDecl.h"
#include "gsiDeclBasic.h"
#include "layPlugin.h"
#include "layPluginConfigPage.h"
#include "layEditorOptionsPage.h"
#include "layEditorOptionsPages.h"
#include "layViewObject.h"
#include "layLayoutViewBase.h"
#include "layCursor.h"
namespace gsi
{
class PluginFactoryBase;
class PluginBase;
// TODO: these static variables are a bad hack!
// However it's not easy to pass parameters to a C++ classes constructor in Ruby without
// compromising the capability to derive from that class (at least I have not learned how
// to create a "new" in the super class *and* allow a "new" of the derived class). Anyway,
// since PluginBase object are only allowed to be created inside the create_plugin method
// of the factory, this hack is a quick but dirty workaround.
class PluginFactoryBase;
class PluginBase;
#if defined(HAVE_QTBINDINGS)
class EditorOptionsPageImpl
: public lay::EditorOptionsPage
{
public:
EditorOptionsPageImpl (const std::string &title, int index)
: lay::EditorOptionsPage (), m_title (title), m_index (index)
{
// .. nothing yet ..
}
virtual std::string title () const
{
return m_title;
}
virtual int order () const
{
return m_index;
}
void apply_impl (lay::Dispatcher *root)
{
lay::EditorOptionsPage::apply (root);
}
virtual void apply (lay::Dispatcher *root)
{
if (f_apply.can_issue ()) {
f_apply.issue<EditorOptionsPageImpl, lay::Dispatcher *> (&EditorOptionsPageImpl::apply_impl, root);
} else {
EditorOptionsPageImpl::apply_impl (root);
}
}
void setup_impl (lay::Dispatcher *root)
{
lay::EditorOptionsPage::setup (root);
}
virtual void setup (lay::Dispatcher *root)
{
if (f_setup.can_issue ()) {
f_setup.issue<EditorOptionsPageImpl, lay::Dispatcher *> (&EditorOptionsPageImpl::setup_impl, root);
} else {
EditorOptionsPageImpl::setup_impl (root);
}
}
gsi::Callback f_apply;
gsi::Callback f_setup;
private:
tl::weak_ptr<lay::LayoutViewBase> mp_view;
tl::weak_ptr<lay::Dispatcher> mp_dispatcher;
std::string m_title;
int m_index;
};
EditorOptionsPageImpl *new_editor_options_page (const std::string &title, int index)
{
return new EditorOptionsPageImpl (title, index);
}
// @@@ methods:
// constructor new_editor_options_page
// view()
// edited()
// callback apply(dispatcher)
// callback setup(dispatcher)
// base: QWidget
class ConfigPageImpl
: public lay::ConfigPage
{
public:
ConfigPageImpl (const std::string &title)
: lay::ConfigPage (0), m_title (title)
{
// .. nothing yet ..
}
virtual std::string title () const
{
return m_title;
}
void commit_impl (lay::Dispatcher *root)
{
lay::ConfigPage::commit (root);
}
virtual void commit (lay::Dispatcher *root)
{
if (f_commit.can_issue ()) {
f_commit.issue<ConfigPageImpl, lay::Dispatcher *> (&ConfigPageImpl::commit_impl, root);
} else {
ConfigPageImpl::commit_impl (root);
}
}
void setup_impl (lay::Dispatcher *root)
{
lay::ConfigPage::setup (root);
}
virtual void setup (lay::Dispatcher *root)
{
if (f_setup.can_issue ()) {
f_setup.issue<ConfigPageImpl, lay::Dispatcher *> (&ConfigPageImpl::setup_impl, root);
} else {
ConfigPageImpl::setup_impl (root);
}
}
gsi::Callback f_commit;
gsi::Callback f_setup;
private:
tl::weak_ptr<lay::LayoutViewBase> mp_view;
tl::weak_ptr<lay::Dispatcher> mp_dispatcher;
std::string m_title;
std::string m_index;
};
ConfigPageImpl *new_config_page (const std::string &title)
{
return new ConfigPageImpl (title);
}
// @@@ methods:
// constructor new_config_page
// callback apply(dispatcher) = commit
// callback setup(dispatcher)
// base: QFrame
#endif
// HACK: used to track if we're inside a create_plugin method and can be sure that "init" is called
static bool s_in_create_plugin = false;
static lay::LayoutViewBase *sp_view = 0;
static lay::Dispatcher *sp_dispatcher = 0;
class PluginBase
: public lay::Plugin, public lay::ViewService
{
public:
PluginBase ()
: lay::Plugin (sp_dispatcher), lay::ViewService (sp_view ? sp_view->canvas () : 0),
mp_view (sp_view), mp_dispatcher (sp_dispatcher)
: lay::Plugin (), lay::ViewService (),
mp_view (0), mp_dispatcher (0)
{
if (! s_in_create_plugin) {
throw tl::Exception (tl::to_string (tr ("A PluginBase object can only be created in the PluginFactory's create_plugin method")));
}
}
void init (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
{
mp_view = view;
mp_dispatcher = dispatcher;
lay::Plugin::init (dispatcher);
lay::ViewService::init (view ? view->canvas () : 0);
}
void grab_mouse ()
{
if (ui ()) {
@ -282,6 +424,18 @@ public:
return mp_dispatcher.get ();
}
#if defined(HAVE_QTBINDINGS)
std::vector<lay::EditorOptionsPage *> editor_option_pages ()
{
lay::EditorOptionsPages *eo_pages = view ()->editor_options_pages ();
if (!eo_pages) {
return std::vector<lay::EditorOptionsPage *> ();
} else {
return eo_pages->pages ();
}
}
#endif
gsi::Callback f_menu_activated;
gsi::Callback f_configure;
gsi::Callback f_config_finalize;
@ -416,8 +570,79 @@ public:
}
}
#if defined(HAVE_QTBINDINGS)
std::vector<EditorOptionsPageImpl *> get_editor_options_pages_impl () const
{
return std::vector<EditorOptionsPageImpl *> ();
}
virtual void get_editor_options_pages (std::vector<lay::EditorOptionsPage *> &pages_out, lay::LayoutViewBase *view, lay::Dispatcher *dispatcher) const
{
try {
std::vector<EditorOptionsPageImpl *> pages;
if (f_get_editor_options_pages.can_issue ()) {
pages = f_get_editor_options_pages.issue<PluginFactoryBase, std::vector<EditorOptionsPageImpl *> > (&PluginFactoryBase::get_editor_options_pages_impl);
} else {
pages = get_editor_options_pages_impl ();
}
pages_out.clear ();
for (auto i = pages.begin (); i != pages.end (); ++i) {
if (*i) {
(*i)->init (view, dispatcher);
pages_out.push_back (*i);
}
}
} catch (tl::Exception &ex) {
tl::error << ex.msg ();
} catch (std::exception &ex) {
tl::error << ex.what ();
} catch (...) {
}
}
std::vector<ConfigPageImpl *> get_config_pages_impl () const
{
return std::vector<ConfigPageImpl *> ();
}
virtual std::vector<std::pair <std::string, lay::ConfigPage *> > config_pages (QWidget *parent) const
{
std::vector<std::pair <std::string, lay::ConfigPage *> > pages_out;
try {
std::vector<ConfigPageImpl *> pages;
if (f_config_pages.can_issue ()) {
pages = f_config_pages.issue<PluginFactoryBase, std::vector<ConfigPageImpl *> > (&PluginFactoryBase::get_config_pages_impl);
} else {
pages = get_config_pages_impl ();
}
pages_out.clear ();
for (auto i = pages.begin (); i != pages.end (); ++i) {
if (*i) {
(*i)->setParent (parent);
pages_out.push_back (std::make_pair ((*i)->title (), *i));
}
}
} catch (tl::Exception &ex) {
tl::error << ex.msg ();
} catch (std::exception &ex) {
tl::error << ex.what ();
} catch (...) {
}
return pages_out;
}
#endif
virtual lay::Plugin *create_plugin (db::Manager *manager, lay::Dispatcher *root, lay::LayoutViewBase *view) const
{
{
if (f_create_plugin.can_issue ()) {
return create_plugin_gsi (manager, root, view);
} else {
@ -427,22 +652,25 @@ public:
virtual gsi::PluginBase *create_plugin_gsi (db::Manager *manager, lay::Dispatcher *root, lay::LayoutViewBase *view) const
{
// TODO: this is a hack. See notes above at s_in_create_plugin
s_in_create_plugin = true;
sp_view = view;
sp_dispatcher = root;
gsi::PluginBase *ret = 0;
try {
ret = f_create_plugin.issue<PluginFactoryBase, gsi::PluginBase *, db::Manager *, lay::Dispatcher *, lay::LayoutViewBase *> (&PluginFactoryBase::create_plugin_gsi, manager, root, view);
s_in_create_plugin = false;
sp_view = 0;
sp_dispatcher = 0;
if (ret) {
ret->init (view, root);
}
} catch (tl::Exception &ex) {
tl::error << ex.msg ();
} catch (std::exception &ex) {
tl::error << ex.what ();
} catch (...) {
s_in_create_plugin = false;
sp_view = 0;
sp_dispatcher = 0;
}
s_in_create_plugin = false;
return ret;
}
@ -512,6 +740,8 @@ public:
gsi::Callback f_configure;
gsi::Callback f_config_finalize;
gsi::Callback f_menu_activated;
gsi::Callback f_get_editor_options_pages;
gsi::Callback f_config_pages;
private:
std::vector<std::pair<std::string, std::string> > m_options;
@ -521,6 +751,12 @@ private:
tl::RegisteredClass <lay::PluginDeclaration> *mp_registration;
};
// @@@
#if defined(HAVE_QTBINDINGS)
// get_editor_options_pages -> "create_editor_option_pages"
// config_pages -> "create_config_pages"
#endif
Class<gsi::PluginFactoryBase> decl_PluginFactory ("lay", "PluginFactory",
method ("register", &PluginFactoryBase::register_gsi, gsi::arg ("position"), gsi::arg ("name"), gsi::arg ("title"),
"@brief Registers the plugin factory\n"

View File

@ -39,6 +39,20 @@ EditorOptionsPage::EditorOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher
attach_events ();
}
EditorOptionsPage::EditorOptionsPage ()
: QWidget (0), mp_owner (0), m_active (true), mp_plugin_declaration (0), mp_dispatcher (0), mp_view (0)
{
// .. nothing here -> call init to set view and dispatcher
}
void
EditorOptionsPage::init (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher)
{
mp_view = view;
mp_dispatcher = dispatcher;
attach_events ();
}
EditorOptionsPage::~EditorOptionsPage ()
{
set_owner (0);

View File

@ -25,7 +25,7 @@
#ifndef HDR_layEditorOptionsPage
#define HDR_layEditorOptionsPage
#include "layuiCommon.h"
#include "laybasicCommon.h"
#include "tlObject.h"
@ -44,13 +44,14 @@ class EditorOptionsPages;
/**
* @brief The base class for a object properties page
*/
class LAYUI_PUBLIC EditorOptionsPage
class LAYBASIC_PUBLIC EditorOptionsPage
: public QWidget, public tl::Object
{
Q_OBJECT
public:
EditorOptionsPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
EditorOptionsPage ();
virtual ~EditorOptionsPage ();
virtual std::string title () const = 0;
@ -66,13 +67,8 @@ public:
const lay::PluginDeclaration *plugin_declaration () const { return mp_plugin_declaration; }
void set_plugin_declaration (const lay::PluginDeclaration *pd) { mp_plugin_declaration = pd; }
protected slots:
void edited ()
{
apply (dispatcher ());
}
void init (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher);
protected:
lay::Dispatcher *dispatcher () const
{
return mp_dispatcher;
@ -83,6 +79,13 @@ protected:
return mp_view;
}
protected slots:
void edited ()
{
apply (dispatcher ());
}
protected:
virtual void active_cellview_changed () { }
virtual void technology_changed (const std::string & /*tech*/) { }

View File

@ -27,7 +27,6 @@
#include "tlExceptions.h"
#include "layPlugin.h"
#include "layLayoutViewBase.h"
#include "layQtTools.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
@ -197,22 +196,6 @@ BEGIN_PROTECTED
END_PROTECTED_W (this)
}
// ------------------------------------------------------------------
// Indicates an error on a line edit
template <class Value>
static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le, const std::string &cfg_name)
{
try {
Value value = Value (0);
tl::from_string_ext (tl::to_string (le->text ()), value);
dispatcher->config_set (cfg_name, tl::to_string (value));
lay::indicate_error (le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
}
}
}
#endif

View File

@ -25,7 +25,7 @@
#ifndef HDR_layEditorOptionsPages
#define HDR_layEditorOptionsPages
#include "layuiCommon.h"
#include "laybasicCommon.h"
#include "layEditorOptionsPage.h"
#include <tlVariant.h>
@ -47,7 +47,7 @@ class Plugin;
/**
* @brief The object properties dialog
*/
class LAYUI_PUBLIC EditorOptionsPages
class LAYBASIC_PUBLIC EditorOptionsPages
: public QFrame
{
Q_OBJECT

View File

@ -308,8 +308,23 @@ PluginDeclaration::register_plugin ()
// Plugin implementation
Plugin::Plugin (Plugin *parent, bool standalone)
: mp_parent (parent), mp_plugin_declaration (0), dm_finalize_config (this, &lay::Plugin::config_end), m_standalone (standalone)
: mp_parent (0), mp_plugin_declaration (0), dm_finalize_config (this, &lay::Plugin::config_end), m_standalone (false)
{
init (parent, standalone);
}
Plugin::Plugin ()
: mp_parent (0), mp_plugin_declaration (0), dm_finalize_config (this, &lay::Plugin::config_end), m_standalone (false)
{
// .. nothing yet (waiting for init) ..
}
void
Plugin::init (Plugin *parent, bool standalone)
{
mp_parent = parent;
m_standalone = standalone;
if (! parent) {
if (! standalone) {
// load the root with the default configuration
@ -324,6 +339,7 @@ Plugin::Plugin (Plugin *parent, bool standalone)
}
}
Plugin::~Plugin ()
{
if (mp_parent) {

View File

@ -504,6 +504,18 @@ public:
*/
Plugin (Plugin *parent, bool standalone = false);
/**
* @brief The default constructor
*
* This constructor needs to be followed by init()
*/
Plugin ();
/**
* @brief Initialization, following the default constructor
*/
void init (Plugin *parent, bool standalone = false);
/**
* @brief The destructor
*/

View File

@ -191,8 +191,15 @@ ViewObject::freeze ()
// ViewService implementation
ViewService::ViewService (ViewObjectUI *widget)
: mp_widget (widget), m_abs_grab (false), m_enabled (true)
: mp_widget (0), m_abs_grab (false), m_enabled (true)
{
init (widget);
}
void
ViewService::init (ViewObjectUI *widget)
{
mp_widget = widget;
if (widget) {
widget->register_service (this);
}

View File

@ -104,6 +104,11 @@ public:
*/
ViewService (ViewObjectUI *widget = 0);
/**
* @brief Initialization, can follow default constructor
*/
void init (ViewObjectUI *widget);
/**
* @brief Destructor
*/

View File

@ -35,6 +35,8 @@ SOURCES += \
gsiDeclLayTlAdded.cc \
gsiDeclLayRdbAdded.cc \
layAbstractMenu.cc \
layEditorOptionsPage.cc \
layEditorOptionsPages.cc \
layLayoutViewConfig.cc \
layMargin.cc \
laybasicForceLink.cc \
@ -87,6 +89,8 @@ SOURCES += \
layUtils.cc \
HEADERS += \
layEditorOptionsPage.h \
layEditorOptionsPages.h \
layMargin.h \
laybasicConfig.h \
laybasicForceLink.h \

View File

@ -104,8 +104,6 @@ SOURCES = \
layEditStippleWidget.cc \
layEditStipplesForm.cc \
layEditorOptionsFrame.cc \
layEditorOptionsPage.cc \
layEditorOptionsPages.cc \
layFileDialog.cc \
layGenericSyntaxHighlighter.cc \
layHierarchyControlPanel.cc \
@ -164,8 +162,6 @@ HEADERS = \
layEditStippleWidget.h \
layEditStipplesForm.h \
layEditorOptionsFrame.h \
layEditorOptionsPage.h \
layEditorOptionsPages.h \
layFileDialog.h \
layGenericSyntaxHighlighter.h \
layHierarchyControlPanel.h \