diff --git a/src/edt/edt/edtUtils.h b/src/edt/edt/edtUtils.h index a978246c6..ba5cab1a6 100644 --- a/src/edt/edt/edtUtils.h +++ b/src/edt/edt/edtUtils.h @@ -29,6 +29,8 @@ #include #include +#include "edtCommon.h" + #include "layObjectInstPath.h" #include "laySnap.h" @@ -54,17 +56,17 @@ class Service; * This implements the standard modifiers for angle constraints - i.e. * ortho for "Shift". */ -extern lay::angle_constraint_type ac_from_buttons (unsigned int buttons); +EDT_PUBLIC lay::angle_constraint_type ac_from_buttons (unsigned int buttons); /** * @brief Serializes PCell parameters to a string */ -std::string pcell_parameters_to_string (const std::map ¶meters); +EDT_PUBLIC std::string pcell_parameters_to_string (const std::map ¶meters); /** * @brief Deserializes PCell parameters from a string */ -std::map pcell_parameters_from_string (const std::string &s); +EDT_PUBLIC std::map pcell_parameters_from_string (const std::string &s); /** * @brief Fetch PCell parameters from a cell and merge the guiding shapes into them @@ -74,13 +76,13 @@ std::map pcell_parameters_from_string (const std::stri * @param parameters_for_pcell Will receive the parameters * @return true, if the cell is a PCell and parameters have been fetched */ -bool +EDT_PUBLIC bool get_parameters_from_pcell_and_guiding_shapes (db::Layout *layout, db::cell_index_type cell_index, db::pcell_parameters_type ¶meters_for_pcell); /** * @brief A helper class that identifies clipboard data for edt:: */ -class ClipboardData +class EDT_PUBLIC ClipboardData : public db::ClipboardData { public: @@ -90,7 +92,7 @@ public: /** * @brief A cache for the transformation variants for a certain layer and cell view index for a lay::LayoutView */ -class TransformationVariants +class EDT_PUBLIC TransformationVariants { public: TransformationVariants (const lay::LayoutViewBase *view, bool per_cv_and_layer = true, bool per_cv = true); diff --git a/src/lay/lay/gsiDeclLayPlugin.cc b/src/lay/lay/gsiDeclLayPlugin.cc index d5b17bb58..d0847ebb6 100644 --- a/src/lay/lay/gsiDeclLayPlugin.cc +++ b/src/lay/lay/gsiDeclLayPlugin.cc @@ -404,6 +404,12 @@ public: return f_configure.can_issue () ? f_configure.issue (&PluginBase::configure, name, value) : lay::Plugin::configure (name, value); } + // for testing + void configure_test (const std::string &name, const std::string &value) + { + configure_edt (name, value); + } + virtual bool configure (const std::string &name, const std::string &value) { configure_edt (name, value); @@ -633,21 +639,43 @@ public: lay::EditorServiceBase::add_edge_marker (p, cv_index, cv.context_trans (), *tv_list, emphasize); } + // for testing + bool has_tracking_position_test () const + { + return has_tracking_position (); + } + + bool has_tracking_position_base () const + { + return lay::EditorServiceBase::has_tracking_position (); + } + virtual bool has_tracking_position () const { if (f_has_tracking_position.can_issue ()) { return f_has_tracking_position.issue (&lay::EditorServiceBase::has_tracking_position); } else { - return lay::EditorServiceBase::has_tracking_position (); + return has_tracking_position_base (); } } + // for testing + db::DPoint tracking_position_test () const + { + return tracking_position (); + } + + db::DPoint tracking_position_base () const + { + return lay::EditorServiceBase::tracking_position (); + } + virtual db::DPoint tracking_position () const { if (f_tracking_position.can_issue ()) { return f_tracking_position.issue (&lay::EditorServiceBase::tracking_position); } else { - return lay::EditorServiceBase::tracking_position (); + return tracking_position_base (); } } @@ -662,13 +690,17 @@ public: } #if defined(HAVE_QTBINDINGS) - std::vector editor_options_pages () + std::vector editor_options_pages () { lay::EditorOptionsPages *eo_pages = view ()->editor_options_pages (); if (!eo_pages) { - return std::vector (); + return std::vector (); } else { - return eo_pages->pages (); + std::vector pages; + for (auto p = eo_pages->pages ().begin (); p != eo_pages->pages ().end (); ++p) { + pages.push_back (*p); + } + return pages; } } #endif @@ -1281,6 +1313,7 @@ Class decl_Plugin ("lay", "Plugin", "When a menu item is clicked which was registered with the plugin factory, the plugin's 'menu_activated' method is " "called for the current view. The symbol registered for the menu item is passed in the 'symbol' argument." ) + + method ("configure_test", &gsi::PluginBase::configure_test, gsi::arg ("name"), gsi::arg ("value"), "@hide") + callback ("configure", &gsi::PluginBase::configure_impl, &gsi::PluginBase::f_configure, gsi::arg ("name"), gsi::arg ("value"), "@brief Sends configuration requests to the plugin\n" "@param name The name of the configuration variable as registered in the plugin factory\n" @@ -1384,6 +1417,8 @@ Class decl_Plugin ("lay", "Plugin", "\n" "The cursor type is one of the cursor constants in the \\Cursor class, i.e. 'CursorArrow' for the normal cursor." ) + + method ("has_tracking_position_test", &gsi::PluginBase::has_tracking_position_test, "@hide") + + method ("has_tracking_position", &gsi::PluginBase::has_tracking_position_base, "@hide") + callback ("has_tracking_position", &gsi::PluginBase::has_tracking_position, &gsi::PluginBase::f_has_tracking_position, "@brief Gets a value indicating whether the plugin provides a tracking position\n" "The tracking position is shown in the lower-left corner of the layout window to indicate the current position.\n" @@ -1392,6 +1427,8 @@ Class decl_Plugin ("lay", "Plugin", "\n" "This method has been added in version 0.27.6." ) + + method ("tracking_position_test", &gsi::PluginBase::tracking_position_test, "@hide") + + method ("tracking_position", &gsi::PluginBase::tracking_position_base, "@hide") + callback ("tracking_position", &gsi::PluginBase::tracking_position, &gsi::PluginBase::f_tracking_position, "@brief Gets the tracking position\n" "See \\has_tracking_position for details.\n" diff --git a/src/laybasic/laybasic/layEditorServiceBase.h b/src/laybasic/laybasic/layEditorServiceBase.h index d17c77255..f41afbf85 100644 --- a/src/laybasic/laybasic/layEditorServiceBase.h +++ b/src/laybasic/laybasic/layEditorServiceBase.h @@ -141,8 +141,14 @@ public: */ void show_error (tl::Exception &ex); -protected: + /** + * @brief Sets a configuration option + */ virtual bool configure (const std::string &name, const std::string &value); + + /** + * @brief Called when the plugin is deactivated + */ virtual void deactivated (); private: diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc index a11ddf17a..960e1df97 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.cc +++ b/src/laybasic/laybasic/layLayoutViewBase.cc @@ -602,20 +602,25 @@ void LayoutViewBase::create_plugins (const lay::PluginDeclaration *except_this) clear_plugins (); // create the plugins - for (tl::Registrar::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) { + for (tl::Registrar::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ) { - if (&*cls != except_this) { + // NOTE: during "create_plugin" a plugin may be unregistered, so don't increment the iterator after + auto current = cls.operator-> (); + std::string current_name = cls.current_name (); + ++cls; + + if (current != except_this) { // TODO: clean solution. The following is a HACK: - if (cls.current_name () == "ant::Plugin" || cls.current_name () == "img::Plugin") { + if (current_name == "ant::Plugin" || current_name == "img::Plugin") { // ant and img are created always - create_plugin (&*cls); + create_plugin (current); } else if ((options () & LV_NoPlugins) == 0) { // others: only create unless LV_NoPlugins is set - create_plugin (&*cls); - } else if ((options () & LV_NoGrid) == 0 && cls.current_name () == "GridNetPlugin") { + create_plugin (current); + } else if ((options () & LV_NoGrid) == 0 && current_name == "GridNetPlugin") { // except grid net plugin which is created on request - create_plugin (&*cls); + create_plugin (current); } } diff --git a/src/rba/unit_tests/rbaTests.cc b/src/rba/unit_tests/rbaTests.cc index e2ff18d3a..aa4aedb71 100644 --- a/src/rba/unit_tests/rbaTests.cc +++ b/src/rba/unit_tests/rbaTests.cc @@ -152,6 +152,7 @@ RUBYTEST (layMainWindow, "layMainWindow.rb") RUBYTEST (layMarkers, "layMarkers.rb") RUBYTEST (layMacro, "layMacro.rb") RUBYTEST (layMenuTest, "layMenuTest.rb") +RUBYTEST (layPluginTests, "layPluginTests.rb") RUBYTEST (layPixelBuffer, "layPixelBuffer.rb") RUBYTEST (laySession, "laySession.rb") RUBYTEST (laySaveLayoutOptions, "laySaveLayoutOptions.rb") diff --git a/testdata/ruby/layPluginTests.rb b/testdata/ruby/layPluginTests.rb new file mode 100644 index 000000000..cdd5638b6 --- /dev/null +++ b/testdata/ruby/layPluginTests.rb @@ -0,0 +1,145 @@ +# encoding: UTF-8 + +# KLayout Layout Viewer +# Copyright (C) 2006-2025 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 + +if !$:.member?(File::dirname($0)) + $:.push(File::dirname($0)) +end + +load("test_prologue.rb") + +class PluginFactory < RBA::PluginFactory + def initialize() + register(1000, "plugin_for_test", "Plugin") + @pi = nil + end + def create_plugin(manager, unused, view) + @pi = RBA::Plugin::new + @pi + end + def pi + @pi + end +end + +class Plugin2 < RBA::Plugin + def set_tp(tp) + @tp = tp + end + def has_tracking_position + !!@tp + end + def tracking_position + @tp || RBA::DPoint::new + end +end + +class PluginFactory2 < RBA::PluginFactory + def initialize() + register(1001, "plugin_for_test2", "Plugin2") + @pi = nil + end + def create_plugin(manager, unused, view) + @pi = Plugin2::new + @pi + end + def pi + @pi + end +end + +class LayPlugin_TestClass < TestBase + + def test_1 + + assert_equal(RBA::Plugin::AC_Global.to_s, "AC_Global") + assert_equal(RBA::Plugin::AC_Any.to_s, "AC_Any") + assert_equal(RBA::Plugin::AC_Diagonal.to_s, "AC_Diagonal") + assert_equal(RBA::Plugin::AC_Horizontal.to_s, "AC_Horizontal") + assert_equal(RBA::Plugin::AC_Vertical.to_s, "AC_Vertical") + + assert_equal(RBA::Plugin::ac_from_buttons(0), RBA::Plugin::AC_Global) + assert_equal(RBA::Plugin::ac_from_buttons(1), RBA::Plugin::AC_Ortho) + assert_equal(RBA::Plugin::ac_from_buttons(2), RBA::Plugin::AC_Diagonal) + + begin + + dpi = PluginFactory::new + dpi2 = PluginFactory2::new + + # Create a new layout + main_window = RBA::MainWindow.instance() + main_window.close_all + main_window.create_layout(2) + + pi = dpi.pi + pi2 = dpi2.pi + + # smoke test + pi.grab_mouse + pi.ungrab_mouse + pi.set_cursor(RBA::Cursor::Wait) + pi.add_edge_marker(RBA::DEdge::new) + pi.add_mouse_cursor(RBA::DPoint::new) + pi.clear_mouse_cursors + + # virtual methods + assert_equal(pi.has_tracking_position_test, false) + pi.clear_mouse_cursors + pi.add_mouse_cursor(RBA::DPoint::new(1, 2)) + assert_equal(pi.has_tracking_position_test, true) + assert_equal(pi.tracking_position_test.to_s, "1,2") + pi.clear_mouse_cursors + assert_equal(pi.has_tracking_position_test, false) + + assert_equal(pi2.has_tracking_position_test, false) + pi2.set_tp(RBA::DPoint::new(2, 3)) + assert_equal(pi2.has_tracking_position_test, true) + assert_equal(pi2.tracking_position_test.to_s, "2,3") + pi2.set_tp(nil) + assert_equal(pi2.has_tracking_position_test, false) + + pi.configure_test("edit-grid", "0.0") + assert_equal(pi.snap(RBA::DPoint::new(0.01, 0.02)).to_s, "0.01,0.02") + assert_equal(pi.snap(RBA::DVector::new(0.01, 0.02)).to_s, "0.01,0.02") + pi.configure_test("edit-grid", "0.1") + assert_equal(pi.snap(RBA::DPoint::new(0.11, 0.18)).to_s, "0.1,0.2") + assert_equal(pi.snap(RBA::DVector::new(0.11, 0.18)).to_s, "0.1,0.2") + + pi.configure_test("edit-connect-angle-mode", "ortho") + assert_equal(pi.snap(RBA::DPoint::new(1.5, 2.1), RBA::DPoint::new(1, 2), true).to_s, "1.5,2") + assert_equal(pi.snap(RBA::DPoint::new(1.5, 2.1), RBA::DPoint::new(1, 2), false).to_s, "1.5,2.1") + assert_equal(pi.snap(RBA::DPoint::new(1.5, 2.1), RBA::DPoint::new(1, 2), false, RBA::Plugin::AC_Ortho).to_s, "1.5,2") + + pi.configure_test("edit-connect-angle-mode", "ortho") + assert_equal(pi.snap(RBA::DVector::new(0.5, 2.1), true).to_s, "0,2.1") + assert_equal(pi.snap(RBA::DVector::new(0.5, 2.1), false).to_s, "0.5,2.1") + assert_equal(pi.snap(RBA::DVector::new(0.5, 2.1), false, RBA::Plugin::AC_Ortho).to_s, "0,2.1") + + ensure + main_window.close_all + dpi._destroy + dpi2._destroy + end + + end + +end + +load("test_epilogue.rb") +