Some refactoring, editor options are shown more consistently now

Specifically, in move mode, now the editor options
are shown too. This makes sense as some of these
options there are also effective in move mode.
This commit is contained in:
Matthias Koefferlein 2025-08-30 18:39:41 +02:00
parent f1c16a0242
commit 340c1ef6e9
18 changed files with 238 additions and 76 deletions

View File

@ -1664,32 +1664,38 @@ MainWindow::select_mode (int m)
}
}
// if the current mode supports editing, show the editor options panel
update_editor_options_dock ();
const lay::PluginDeclaration *pd_sel = 0;
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
const lay::PluginDeclaration *pd = cls.operator-> ();
if (pd->id () == m_mode) {
pd_sel = pd;
}
}
}
}
bool eo_visible = false;
if (mp_eo_stack && pd_sel) {
eo_visible = pd_sel->editable_enabled ();
}
if (current_view () && eo_visible) {
lay::EditorOptionsPages *eo_pages = current_view ()->editor_options_pages ();
if (! eo_pages || ! eo_pages->has_content ()) {
eo_visible = false;
}
}
void
MainWindow::update_editor_options_dock ()
{
// if the current mode supports editing, show the editor options panel
if (eo_visible != m_eo_visible) {
m_eo_visible = eo_visible;
show_dock_widget (mp_eo_dock_widget, m_eo_visible);
const lay::PluginDeclaration *pd_sel = 0;
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
const lay::PluginDeclaration *pd = cls.operator-> ();
if (pd->id () == m_mode) {
pd_sel = pd;
}
}
bool eo_visible = false;
if (mp_eo_stack && pd_sel) {
eo_visible = pd_sel->editable_enabled ();
}
if (current_view () && eo_visible) {
lay::EditorOptionsPages *eo_pages = current_view ()->editor_options_pages ();
if (! eo_pages || ! eo_pages->has_content ()) {
eo_visible = false;
}
}
if (eo_visible != m_eo_visible) {
m_eo_visible = eo_visible;
show_dock_widget (mp_eo_dock_widget, m_eo_visible);
}
}
@ -2439,6 +2445,7 @@ MainWindow::select_view (int index)
current_view_changed ();
update_editor_options_dock ();
clear_current_pos ();
edits_enabled_changed ();
clear_message ();

View File

@ -857,6 +857,7 @@ private:
void interactive_close_view (int from, int to, bool invert_range, bool all_cellviews);
void call_on_current_view (void (lay::LayoutView::*func) (), const std::string &op_desc);
void current_view_changed ();
void update_editor_options_dock ();
void update_window_title ();
void update_tab_title (int i);
void add_view (LayoutViewWidget *view);

View File

@ -81,20 +81,32 @@ EditorOptionsPages::focusInEvent (QFocusEvent * /*event*/)
// Sends the focus to the current page's last focus owner
if (mp_pages->currentWidget () && mp_pages->currentWidget ()->focusWidget ()) {
mp_pages->currentWidget ()->focusWidget ()->setFocus ();
}
}
}
bool EditorOptionsPages::has_content () const
{
for (std::vector <lay::EditorOptionsPage *>::const_iterator p = m_pages.begin (); p != m_pages.end (); ++p) {
// NOTE: we ignore unspecific pages because they are always visible and don't contribute specific content
if ((*p)->active () && (*p)->plugin_declaration () != 0) {
if ((*p)->active ()) {
return true;
}
}
return false;
}
void EditorOptionsPages::activate (const lay::Plugin *plugin)
{
for (auto op = m_pages.begin (); op != m_pages.end (); ++op) {
bool is_active = false;
if ((*op)->plugin_declaration () == 0) {
is_active = (plugin && plugin->plugin_declaration ()->enable_catchall_editor_options_pages ());
} else if (plugin && plugin->plugin_declaration () == (*op)->plugin_declaration ()) {
is_active = true;
}
(*op)->activate (is_active);
}
}
void
EditorOptionsPages::unregister_page (lay::EditorOptionsPage *page)
{

View File

@ -58,6 +58,7 @@ public:
void unregister_page (lay::EditorOptionsPage *page);
void activate_page (lay::EditorOptionsPage *page);
void activate (const lay::Plugin *plugin);
void focusInEvent (QFocusEvent *event);
const std::vector <lay::EditorOptionsPage *> &pages () const

View File

@ -398,21 +398,6 @@ LayoutViewBase::init (db::Manager *mgr)
mp_canvas = new lay::LayoutCanvas (this);
// occupy services and editables:
// these services get deleted by the canvas destructor automatically:
if ((m_options & LV_NoTracker) == 0) {
mp_tracker = new lay::MouseTracker (this);
}
if ((m_options & LV_NoZoom) == 0) {
mp_zoom_service = new lay::ZoomService (this);
}
if ((m_options & LV_NoSelection) == 0) {
mp_selection_service = new lay::SelectionService (this);
}
if ((m_options & LV_NoMove) == 0) {
mp_move_service = new lay::MoveService (this);
}
create_plugins ();
}
@ -615,10 +600,26 @@ void LayoutViewBase::create_plugins (const lay::PluginDeclaration *except_this)
if (current_name == "ant::Plugin" || current_name == "img::Plugin") {
// ant and img are created always
create_plugin (current);
} else if (current_name == "laybasic::MouseTrackerPlugin") {
if ((m_options & LV_NoTracker) == 0) {
mp_tracker = dynamic_cast<lay::MouseTracker *> (create_plugin (current));
}
} else if (current_name == "laybasic::MoveServicePlugin") {
if ((m_options & LV_NoMove) == 0) {
mp_move_service = dynamic_cast<lay::MoveService *> (create_plugin (current));
}
} else if (current_name == "laybasic::SelectionServicePlugin") {
if ((m_options & LV_NoSelection) == 0) {
mp_selection_service = dynamic_cast<lay::SelectionService *> (create_plugin (current));
}
} else if (current_name == "laybasic::ZoomServicePlugin") {
if ((m_options & LV_NoZoom) == 0) {
mp_zoom_service = dynamic_cast<lay::ZoomService *> (create_plugin (current));
}
} else if ((options () & LV_NoPlugins) == 0) {
// others: only create unless LV_NoPlugins is set
create_plugin (current);
} else if ((options () & LV_NoGrid) == 0 && current_name == "GridNetPlugin") {
} else if ((options () & LV_NoGrid) == 0 && current_name == "lay::GridNetPlugin") {
// except grid net plugin which is created on request
create_plugin (current);
}
@ -5790,20 +5791,12 @@ LayoutViewBase::mode (int m)
m_mode = m;
mp_active_plugin = 0;
if (m > 0) {
for (std::vector<lay::Plugin *>::iterator p = mp_plugins.begin (); p != mp_plugins.end (); ++p) {
if ((*p)->plugin_declaration ()->id () == m) {
mp_active_plugin = *p;
mp_canvas->activate ((*p)->view_service_interface ());
break;
}
for (std::vector<lay::Plugin *>::iterator p = mp_plugins.begin (); p != mp_plugins.end (); ++p) {
if ((*p)->plugin_declaration ()->id () == m) {
mp_active_plugin = *p;
mp_canvas->activate ((*p)->view_service_interface ());
break;
}
} else if (m == 0 && mp_selection_service) {
mp_canvas->activate (mp_selection_service);
} else if (m == -1 && mp_move_service) {
mp_canvas->activate (mp_move_service);
}
}

View File

@ -31,7 +31,7 @@ namespace lay
{
MouseTracker::MouseTracker (lay::LayoutViewBase *view)
: lay::ViewService (view->canvas ()), mp_view (view),
: lay::ViewService (view->canvas ()), lay::Plugin (view), mp_view (view),
m_cursor_color (tl::Color ()), m_cursor_line_style (0), m_cursor_enabled (false)
{
ui ()->grab_mouse (this, false);
@ -129,5 +129,31 @@ MouseTracker::mouse_move_event (const db::DPoint &p, unsigned int /*buttons*/, b
return false;
}
} // namespace lay
// ----------------------------------------------------------------------------
// NOTE: configuration currently is not declared here.
// Same for the configuration pages.
class MouseTrackerDeclaration
: public lay::PluginDeclaration
{
public:
MouseTrackerDeclaration ()
{
// .. nothing yet ..
}
virtual lay::Plugin *create_plugin (db::Manager * /*manager*/, lay::Dispatcher * /*dispatcher*/, lay::LayoutViewBase *view) const
{
return new MouseTracker (view);
}
virtual bool enable_catchall_editor_options_pages () const
{
return false;
}
};
static tl::RegisteredClass<lay::PluginDeclaration> tracker_decl (new MouseTrackerDeclaration (), -1000, "laybasic::MouseTrackerPlugin");
} // namespace lay

View File

@ -26,6 +26,7 @@
#include "layViewObject.h"
#include "layMarker.h"
#include "layPlugin.h"
#include "tlObject.h"
class QMouseEvent;
@ -36,7 +37,7 @@ class LayoutCanvas;
class LayoutViewBase;
class MouseTracker
: public lay::ViewService
: public lay::ViewService, public lay::Plugin
{
public:
MouseTracker (lay::LayoutViewBase *view);

View File

@ -36,6 +36,7 @@ namespace lay
MoveService::MoveService (lay::LayoutViewBase *view)
: lay::ViewService (view->canvas ()),
lay::Plugin (view),
m_dragging (false),
m_dragging_transient (false),
mp_editables (view),
@ -366,5 +367,24 @@ MoveService::finish ()
}
}
}
// ----------------------------------------------------------------------------
class MoveServiceDeclaration
: public lay::PluginDeclaration
{
public:
MoveServiceDeclaration ()
: lay::PluginDeclaration (-1)
{
// .. nothing yet ..
}
virtual lay::Plugin *create_plugin (db::Manager * /*manager*/, lay::Dispatcher * /*dispatcher*/, lay::LayoutViewBase *view) const
{
return new MoveService (view);
}
};
static tl::RegisteredClass<lay::PluginDeclaration> move_service_decl (new MoveServiceDeclaration (), -970, "laybasic::MoveServicePlugin");
}

View File

@ -24,8 +24,9 @@
#define HDR_layMove
#include "laybasicCommon.h"
#include "dbManager.h"
#include "layViewObject.h"
#include "layPlugin.h"
#include "dbManager.h"
#include <memory>
@ -35,7 +36,7 @@ class Editables;
class LayoutViewBase;
class LAYBASIC_PUBLIC MoveService :
public lay::ViewService
public lay::ViewService, public lay::Plugin
{
public:
MoveService (lay::LayoutViewBase *view);

View File

@ -55,6 +55,12 @@ PluginDeclaration::PluginDeclaration ()
// .. nothing yet ..
}
PluginDeclaration::PluginDeclaration (int id)
: m_id (id), m_editable_enabled (true)
{
// .. nothing yet ..
}
PluginDeclaration::~PluginDeclaration ()
{
if (Dispatcher::instance ()) {

View File

@ -160,6 +160,11 @@ public:
*/
PluginDeclaration ();
/**
* @brief Constructor with a fixed ID
*/
PluginDeclaration (int id);
/**
* @brief Destructor
*/
@ -331,6 +336,18 @@ public:
{
// .. no pages in the default implementation ..
}
/**
* @brief Gets a value indicating whether "catchall" editor options pages shall be included
*
* "catchall" editor options pages are ones that are unspecific and render a null "plugin_declaration".
* A plugin can choose to include these pages if it listens to global configuration events.
* Otherwise it should return false here to suppress these pages.
*/
virtual bool enable_catchall_editor_options_pages () const
{
return true;
}
#endif
/**

View File

@ -43,6 +43,7 @@ SelectionService::SelectionService (lay::LayoutViewBase *view) :
QObject (),
#endif
lay::ViewService (view->canvas ()),
lay::Plugin (view),
mp_view (view),
mp_box (0),
m_color (0),
@ -317,4 +318,29 @@ SelectionService::begin (const db::DPoint &pos)
ui ()->grab_mouse (this, true);
}
// ----------------------------------------------------------------------------
class SelectionServiceDeclaration
: public lay::PluginDeclaration
{
public:
SelectionServiceDeclaration ()
: lay::PluginDeclaration (0)
{
// .. nothing yet ..
}
virtual lay::Plugin *create_plugin (db::Manager * /*manager*/, lay::Dispatcher * /*dispatcher*/, lay::LayoutViewBase *view) const
{
return new SelectionService (view);
}
virtual bool enable_catchall_editor_options_pages () const
{
return false;
}
};
static tl::RegisteredClass<lay::PluginDeclaration> selection_service_decl (new SelectionServiceDeclaration (), -980, "laybasic::SelectionServicePlugin");
}

View File

@ -29,6 +29,7 @@
#include "layViewObject.h"
#include "layEditable.h"
#include "layPlugin.h"
#if defined (HAVE_QT)
# include <QTimer>
@ -45,7 +46,8 @@ class LAYBASIC_PUBLIC SelectionService :
#if defined (HAVE_QT)
public QObject,
#endif
public lay::ViewService
public lay::ViewService,
public lay::Plugin
{
#if defined (HAVE_QT)
Q_OBJECT

View File

@ -32,7 +32,7 @@ namespace lay
// ZoomService implementation
ZoomService::ZoomService (lay::LayoutViewBase *view)
: lay::ViewService (view->canvas ()),
: lay::ViewService (view->canvas ()), lay::Plugin (view),
mp_view (view),
mp_box (0),
m_color (0)
@ -282,5 +282,28 @@ ZoomService::begin (const db::DPoint &pos)
ui ()->grab_mouse (this, true);
}
}
// ----------------------------------------------------------------------------
class ZoomServiceDeclaration
: public lay::PluginDeclaration
{
public:
ZoomServiceDeclaration ()
{
// .. nothing yet ..
}
virtual lay::Plugin *create_plugin (db::Manager * /*manager*/, lay::Dispatcher * /*dispatcher*/, lay::LayoutViewBase *view) const
{
return new ZoomService (view);
}
virtual bool enable_catchall_editor_options_pages () const
{
return false;
}
};
static tl::RegisteredClass<lay::PluginDeclaration> zoom_service_decl (new ZoomServiceDeclaration (), -990, "laybasic::ZoomServicePlugin");
}

View File

@ -26,6 +26,7 @@
#define HDR_layZoomBox
#include "layViewObject.h"
#include "layPlugin.h"
namespace lay
{
@ -35,7 +36,7 @@ class LayoutCanvas;
class RubberBox;
class LAYBASIC_PUBLIC ZoomService
: public lay::ViewService
: public lay::ViewService, public lay::Plugin
{
public:
ZoomService (lay::LayoutViewBase *view);

View File

@ -129,7 +129,7 @@ GridNetPluginDeclaration::create_plugin (db::Manager *, Dispatcher *, lay::Layou
return new lay::GridNet (view);
}
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new GridNetPluginDeclaration (), 2010, "GridNetPlugin");
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new GridNetPluginDeclaration (), 2010, "lay::GridNetPlugin");
// ------------------------------------------------------------
// Implementation of the GridNet object

View File

@ -1591,18 +1591,7 @@ LayoutView::activate_editor_option_pages ()
{
lay::EditorOptionsPages *eo_pages = editor_options_pages ();
if (eo_pages) {
// TODO: this is very inefficient as each "activate" will regenerate the tabs
for (std::vector<lay::EditorOptionsPage *>::const_iterator op = eo_pages->pages ().begin (); op != eo_pages->pages ().end (); ++op) {
bool is_active = false;
if ((*op)->plugin_declaration () == 0) {
is_active = true;
} else if (active_plugin () && active_plugin ()->plugin_declaration () == (*op)->plugin_declaration ()) {
is_active = true;
}
(*op)->activate (is_active);
}
eo_pages->activate (active_plugin ());
}
}

View File

@ -173,6 +173,42 @@ TEST(4)
EXPECT_EQ ((int) img.height (), 217);
}
// options
TEST(5)
{
std::unique_ptr<lay::LayoutView> lv;
lv.reset (new lay::LayoutView (0, false, 0));
EXPECT_EQ (lv->mouse_tracker () == 0, false);
EXPECT_EQ (lv->zoom_service () == 0, false);
EXPECT_EQ (lv->move_service () == 0, false);
EXPECT_EQ (lv->selection_service () == 0, false);
lv.reset (new lay::LayoutView (0, false, 0, lay::LayoutView::LV_NoMove));
EXPECT_EQ (lv->mouse_tracker () == 0, false);
EXPECT_EQ (lv->zoom_service () == 0, false);
EXPECT_EQ (lv->move_service () == 0, true);
EXPECT_EQ (lv->selection_service () == 0, false);
lv.reset (new lay::LayoutView (0, false, 0, lay::LayoutView::LV_NoTracker));
EXPECT_EQ (lv->mouse_tracker () == 0, true);
EXPECT_EQ (lv->zoom_service () == 0, false);
EXPECT_EQ (lv->move_service () == 0, false);
EXPECT_EQ (lv->selection_service () == 0, false);
lv.reset (new lay::LayoutView (0, false, 0, lay::LayoutView::LV_NoZoom));
EXPECT_EQ (lv->mouse_tracker () == 0, false);
EXPECT_EQ (lv->zoom_service () == 0, true);
EXPECT_EQ (lv->move_service () == 0, false);
EXPECT_EQ (lv->selection_service () == 0, false);
lv.reset (new lay::LayoutView (0, false, 0, lay::LayoutView::LV_NoSelection));
EXPECT_EQ (lv->mouse_tracker () == 0, false);
EXPECT_EQ (lv->zoom_service () == 0, false);
EXPECT_EQ (lv->move_service () == 0, false);
EXPECT_EQ (lv->selection_service () == 0, true);
}
#if defined(HAVE_PNG)
TEST(11)
{