Merge pull request #1761 from KLayout/feature/issue-1655

Feature/issue 1655
This commit is contained in:
Matthias Köfferlein 2024-07-01 18:24:22 +02:00 committed by GitHub
commit 3237f5ec4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 216 additions and 55 deletions

View File

@ -28,6 +28,7 @@
#include "layLayoutViewBase.h"
#include "layDitherPattern.h"
#include "layLineStyles.h"
#include "layMarker.h"
#include "dbSaveLayoutOptions.h"
#include "dbLayoutToNetlist.h"
#include "dbLayoutVsSchematic.h"
@ -469,6 +470,22 @@ static LayerPropertiesConstIteratorWrapper each_layer2 (lay::LayoutViewBase *vie
return LayerPropertiesConstIteratorWrapper (view->begin_layers (list_index));
}
static void add_marker (lay::LayoutViewBase *view, lay::ManagedDMarker *object)
{
if (view->canvas ()) {
object->keep ();
object->set_view (view);
}
}
static void clear_markers (lay::LayoutViewBase *view)
{
// NOTE: this will clear *all* persistent objects, not just our markers
if (view->canvas ()) {
view->canvas ()->clear_objects ();
}
}
static lay::AbstractMenu *menu (lay::LayoutViewBase *view)
{
return view->menu ();
@ -679,6 +696,30 @@ LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase ("lay", "LayoutVi
"\n"
"In 0.25, this method has been moved from MainWindow to LayoutView.\n"
) +
gsi::method_ext ("add_marker", &add_marker, gsi::arg ("marker"),
"@brief Adds a persistent marker to the view (transferring ownership)\n"
"\n"
"This method allows creating markers and transferring ownership to the view, hence making them persistent. "
"This means, when the variable with the marker object goes out of scope, the marker will still exist in the view.\n"
"\n"
"To create a persistent marker, use the following code:\n"
"\n"
"@code\n"
"marker = RBA::Marker::new\n"
"# ... configure marker ...\n"
"view.add_marker(marker)\n"
"@/code\n"
"\n"
"To remove all persistent markers owned by the view, use \\clear_markers.\n"
"\n"
"Persistent markers have been introduced in version 0.29.3\n"
) +
gsi::method_ext ("clear_markers", &clear_markers,
"@brief Clears all persistent markers from the view\n"
"See \\add_marker for details about persistent markers.\n"
"\n"
"Persistent markers have been introduced in version 0.29.3\n"
) +
gsi::method ("is_editable?", static_cast<bool (lay::LayoutViewBase::*) () const> (&lay::LayoutViewBase::is_editable),
"@brief Returns true if the view is in editable mode\n"
"\n"
@ -836,7 +877,7 @@ LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase ("lay", "LayoutVi
gsi::method ("active_cellview_index", static_cast<int (lay::LayoutViewBase::*) () const> (&lay::LayoutViewBase::active_cellview_index),
"@brief Gets the index of the active cellview (shown in hierarchy browser)\n"
) +
gsi::method ("active_setview_index=|#set_active_cellview_index", &lay::LayoutViewBase::set_active_cellview_index, gsi::arg ("index"),
gsi::method ("active_cellview_index=|#active_setview_index=|#set_active_cellview_index", &lay::LayoutViewBase::set_active_cellview_index, gsi::arg ("index"),
"@brief Makes the cellview with the given index the active one (shown in hierarchy browser)\n"
"See \\active_cellview_index.\n"
"\n"

View File

@ -29,43 +29,43 @@ namespace gsi
{
static
lay::DMarker *create_marker (lay::LayoutViewBase *view)
lay::ManagedDMarker *create_marker (lay::LayoutViewBase *view)
{
return new lay::DMarker (view);
return new lay::ManagedDMarker (view);
}
static
void reset_frame_color (lay::DMarker *marker)
void reset_frame_color (lay::ManagedDMarker *marker)
{
marker->set_frame_color (tl::Color ());
}
static
void set_frame_color (lay::DMarker *marker, unsigned int color)
void set_frame_color (lay::ManagedDMarker *marker, unsigned int color)
{
marker->set_frame_color (tl::Color (color));
}
static
unsigned int get_frame_color (const lay::DMarker *marker)
unsigned int get_frame_color (const lay::ManagedDMarker *marker)
{
return marker->get_frame_color ().rgb ();
}
static
bool has_frame_color (const lay::DMarker *marker)
bool has_frame_color (const lay::ManagedDMarker *marker)
{
return marker->get_frame_color ().is_valid ();
}
static
void reset_color (lay::DMarker *marker)
void reset_color (lay::ManagedDMarker *marker)
{
marker->set_color (tl::Color ());
}
static
void set_color (lay::DMarker *marker, unsigned int color)
void set_color (lay::ManagedDMarker *marker, unsigned int color)
{
marker->set_color (tl::Color (color));
}
@ -77,44 +77,48 @@ unsigned int get_color (const lay::DMarker *marker)
}
static
bool has_color (const lay::DMarker *marker)
bool has_color (const lay::ManagedDMarker *marker)
{
return marker->get_color ().is_valid ();
}
Class<lay::DMarker> decl_Marker ("lay", "Marker",
gsi::constructor ("new", &create_marker, gsi::arg ("view"),
Class<lay::ManagedDMarker> decl_Marker ("lay", "Marker",
gsi::constructor ("new", &create_marker, gsi::arg ("view", (lay::LayoutViewBase *) 0, "nil"),
"@brief Creates a marker\n"
"\n"
"A marker is always associated with a view, in which it is shown. The "
"view this marker is associated with must be passed to the constructor."
"view this marker is associated with must be passed to the constructor.\n"
"\n"
"See the class description about the options for attaching markers to a view.\n"
"\n"
"The 'view' argument is optional since version 0.29.3."
) +
gsi::method ("set|set_box", (void (lay::DMarker::*) (const db::DBox &)) &lay::DMarker::set, gsi::arg ("box"),
gsi::method ("set|set_box", (void (lay::ManagedDMarker::*) (const db::DBox &)) &lay::ManagedDMarker::set, gsi::arg ("box"),
"@brief Sets the box the marker is to display\n"
"\n"
"Makes the marker show a box. The box must be given in micron units.\n"
"If the box is empty, no marker is drawn.\n"
"The set method has been added in version 0.20.\n"
) +
gsi::method ("set|set_text", (void (lay::DMarker::*) (const db::DText &)) &lay::DMarker::set, gsi::arg ("text"),
gsi::method ("set|set_text", (void (lay::ManagedDMarker::*) (const db::DText &)) &lay::ManagedDMarker::set, gsi::arg ("text"),
"@brief Sets the text the marker is to display\n"
"\n"
"Makes the marker show a text. The text must be given in micron units.\n"
"The set method has been added in version 0.20.\n"
) +
gsi::method ("set|set_edge", (void (lay::DMarker::*) (const db::DEdge &)) &lay::DMarker::set, gsi::arg ("edge"),
gsi::method ("set|set_edge", (void (lay::ManagedDMarker::*) (const db::DEdge &)) &lay::ManagedDMarker::set, gsi::arg ("edge"),
"@brief Sets the edge the marker is to display\n"
"\n"
"Makes the marker show a edge. The edge must be given in micron units.\n"
"The set method has been added in version 0.20.\n"
) +
gsi::method ("set|set_path", (void (lay::DMarker::*) (const db::DPath &)) &lay::DMarker::set, gsi::arg ("path"),
gsi::method ("set|set_path", (void (lay::ManagedDMarker::*) (const db::DPath &)) &lay::ManagedDMarker::set, gsi::arg ("path"),
"@brief Sets the path the marker is to display\n"
"\n"
"Makes the marker show a path. The path must be given in micron units.\n"
"The set method has been added in version 0.20.\n"
) +
gsi::method ("set|set_polygon", (void (lay::DMarker::*) (const db::DPolygon &)) &lay::DMarker::set, gsi::arg ("polygon"),
gsi::method ("set|set_polygon", (void (lay::ManagedDMarker::*) (const db::DPolygon &)) &lay::ManagedDMarker::set, gsi::arg ("polygon"),
"@brief Sets the polygon the marker is to display\n"
"\n"
"Makes the marker show a polygon. The polygon must be given in micron units.\n"
@ -156,59 +160,59 @@ Class<lay::DMarker> decl_Marker ("lay", "Marker",
"@brief Returns a value indicating whether the marker has a specific frame color\n"
"The set method has been added in version 0.20.\n"
) +
gsi::method ("dismissable=", &lay::DMarker::set_dismissable, gsi::arg ("flag"),
gsi::method ("dismissable=", (void (lay::ManagedDMarker::*) (bool)) &lay::ManagedDMarker::set_dismissable, gsi::arg ("flag"),
"@brief Sets a value indicating whether the marker can be hidden\n"
"Dismissable markers can be hidden setting \"View/Show Markers\" to \"off\". "
"The default setting is \"false\" meaning the marker can't be hidden.\n"
"\n"
"This attribute has been introduced in version 0.25.4."
) +
gsi::method ("dismissable?", &lay::DMarker::get_dismissable,
gsi::method ("dismissable?", (bool (lay::ManagedDMarker::*) () const) &lay::ManagedDMarker::get_dismissable,
"@brief Gets a value indicating whether the marker can be hidden\n"
"See \\dismissable= for a description of this predicate."
) +
gsi::method ("line_width=", &lay::DMarker::set_line_width, gsi::arg ("width"),
gsi::method ("line_width=", (void (lay::ManagedDMarker::*) (int)) &lay::ManagedDMarker::set_line_width, gsi::arg ("width"),
"@brief Sets the line width of the marker\n"
"This is the width of the line drawn for the outline of the marker."
) +
gsi::method ("line_width", &lay::DMarker::get_line_width,
gsi::method ("line_width", (int (lay::ManagedDMarker::*) () const) &lay::ManagedDMarker::get_line_width,
"@brief Gets the line width of the marker\n"
"See \\line_width= for a description of the line width."
) +
gsi::method ("vertex_size=", &lay::DMarker::set_vertex_size, gsi::arg ("size"),
gsi::method ("vertex_size=", (void (lay::ManagedDMarker::*) (int)) &lay::ManagedDMarker::set_vertex_size, gsi::arg ("size"),
"@brief Sets the vertex size of the marker\n"
"This is the size of the rectangles drawn for the vertices object."
) +
gsi::method ("vertex_size", &lay::DMarker::get_vertex_size,
gsi::method ("vertex_size", (int (lay::ManagedDMarker::*) () const) &lay::ManagedDMarker::get_vertex_size,
"@brief Gets the vertex size of the marker\n"
"See \\vertex_size= for a description."
) +
gsi::method ("halo=", &lay::DMarker::set_halo, gsi::arg ("halo"),
gsi::method ("halo=", (void (lay::ManagedDMarker::*) (int)) &lay::ManagedDMarker::set_halo, gsi::arg ("halo"),
"@brief Sets the halo flag\n"
"The halo flag is either -1 (for taking the default), 0 to disable the halo or 1 to enable it. "
"If the halo is enabled, a pixel border with the background color is drawn around the marker, the "
"vertices and texts."
) +
gsi::method ("halo", &lay::DMarker::get_halo,
gsi::method ("halo", (int (lay::ManagedDMarker::*) () const) &lay::ManagedDMarker::get_halo,
"@brief Gets the halo flag\n"
"See \\halo= for a description of the halo flag."
) +
gsi::method ("dither_pattern=", &lay::DMarker::set_dither_pattern, gsi::arg ("index"),
gsi::method ("dither_pattern=", (void (lay::ManagedDMarker::*) (int)) &lay::ManagedDMarker::set_dither_pattern, gsi::arg ("index"),
"@brief Sets the stipple pattern index\n"
"A value of -1 or less than zero indicates that the marker is not filled. Otherwise, the "
"value indicates which pattern to use for filling the marker."
) +
gsi::method ("dither_pattern", &lay::DMarker::get_dither_pattern,
gsi::method ("dither_pattern", (int (lay::ManagedDMarker::*) () const) &lay::ManagedDMarker::get_dither_pattern,
"@brief Gets the stipple pattern index\n"
"See \\dither_pattern= for a description of the stipple pattern index."
) +
gsi::method ("line_style=", &lay::DMarker::set_line_style, gsi::arg ("index"),
gsi::method ("line_style=", (void (lay::ManagedDMarker::*) (int)) &lay::ManagedDMarker::set_line_style, gsi::arg ("index"),
"@brief Sets the line style\n"
"The line style is given by an index. 0 is solid, 1 is dashed and so forth.\n"
"\n"
"This method has been introduced in version 0.25."
) +
gsi::method ("line_style", &lay::DMarker::get_line_style,
gsi::method ("line_style", (int (lay::ManagedDMarker::*) () const) &lay::ManagedDMarker::get_line_style,
"@brief Get the line style\n"
"See \\line_style= for a description of the line style index."
"\n"
@ -219,6 +223,32 @@ Class<lay::DMarker> decl_Marker ("lay", "Marker",
"The marker is a visual object that \"marks\" (highlights) a \n"
"certain area of the layout, given by a database object. "
"This object accepts database objects with floating-point coordinates in micron values.\n"
"\n"
"Since version 0.29.3, markers can be attached to views in two ways: self-managed or persistent.\n"
"\n"
"Self-managed markers are created with a view argument. When the variable goes out of scope, the "
"and the Marker object is released, the marker vanishes. This was the only concept before 0.29.3:\n"
"\n"
"@code\n"
"view = ... # some LayoutView\n"
"marker = RBA::Marker::new(view)\n"
"@/code\n"
"\n"
"Persistent markers on the other hand are attached to the view and stay within the view. To create a "
"persistent marker, do not use a view argument to the constructor. Instead add them to the view using "
"\\LayoutView#add_marker. To remove persistent markers, "
"use \\LayoutView#clear_markers (removes all) or call \\_destroy on a specific marker:\n"
"\n"
"@code\n"
"view = ... # some LayoutView\n"
"marker = RBA::Marker::new\n"
"view.add_marker(marker)\n"
"...\n"
"view.clear_markers\n"
"@/code\n"
"\n"
"Persistent markers do not need to be held in separate variables to keep them visible. In some applications "
"this may be useful."
);
}

View File

@ -197,13 +197,23 @@ void render_cell_inst (const db::Layout &layout, const db::CellInstArray &inst,
// ------------------------------------------------------------------------
MarkerBase::MarkerBase (lay::LayoutViewBase *view)
: lay::ViewObject (view->canvas ()),
: lay::ViewObject (view ? view->canvas () : 0),
m_line_width (-1), m_vertex_size (-1), m_halo (-1), m_text_enabled (true), m_vertex_shape (lay::ViewOp::Rect), m_line_style (-1), m_dither_pattern (-1), m_frame_pattern (0), mp_view (view)
{
// .. nothing yet ..
}
void
void
MarkerBase::set_view (LayoutViewBase *view)
{
if (mp_view != view) {
mp_view = view;
mp_view->canvas ()->add_object (this);
redraw ();
}
}
void
MarkerBase::set_frame_color (tl::Color color)
{
if (color != m_frame_color) {
@ -381,7 +391,7 @@ MarkerBase::get_bitmaps (const Viewport & /*vp*/, ViewObjectCanvas &canvas, lay:
// ------------------------------------------------------------------------
GenericMarkerBase::GenericMarkerBase (lay::LayoutViewBase *view, unsigned int cv_index)
: MarkerBase (view), mp_trans_vector (0), mp_view (view), m_cv_index (cv_index)
: MarkerBase (view), mp_trans_vector (0), m_cv_index (cv_index)
{
// .. nothing yet ..
}
@ -463,7 +473,7 @@ GenericMarkerBase::set (const db::DCplxTrans &t1, const std::vector<db::DCplxTra
db::DBox
GenericMarkerBase::bbox () const
{
const lay::CellView &cv = mp_view->cellview (m_cv_index);
const lay::CellView &cv = view ()->cellview (m_cv_index);
if (! cv.is_valid ()) {
return db::DBox ();
}
@ -483,11 +493,11 @@ GenericMarkerBase::bbox () const
const db::Layout *
GenericMarkerBase::layout () const
{
if (m_cv_index >= (unsigned int) (mp_view->cellviews ())) {
if (m_cv_index >= (unsigned int) (view ()->cellviews ())) {
return 0;
}
const lay::CellView &cv = mp_view->cellview (m_cv_index);
const lay::CellView &cv = view ()->cellview (m_cv_index);
if (! cv.is_valid ()) {
return 0;
} else {
@ -1175,7 +1185,7 @@ Marker::render (const Viewport &vp, ViewObjectCanvas &canvas)
// ------------------------------------------------------------------------
DMarker::DMarker (LayoutViewBase *view)
: MarkerBase (view), mp_view (view)
: MarkerBase (view)
{
m_type = None;
m_object.any = 0;
@ -1304,9 +1314,9 @@ DMarker::render (const Viewport &vp, ViewObjectCanvas &canvas)
lay::Renderer &r = canvas.renderer ();
r.set_font (db::Font (mp_view->text_font ()));
r.apply_text_trans (mp_view->apply_text_trans ());
r.default_text_size (mp_view->default_text_size ());
r.set_font (db::Font (view ()->text_font ()));
r.apply_text_trans (view ()->apply_text_trans ());
r.default_text_size (view ()->default_text_size ());
r.set_precise (true);
db::DCplxTrans t = vp.trans ();

View File

@ -40,6 +40,7 @@
#include "dbEdgePair.h"
#include "dbArray.h"
#include "gsi.h"
#include "gsiObject.h"
namespace lay
{
@ -61,6 +62,11 @@ public:
*/
MarkerBase (lay::LayoutViewBase *view);
/**
* @brief Attaches to a new view
*/
void set_view (lay::LayoutViewBase *view);
/**
* @brief Get the color by which the marker is drawn
*
@ -231,6 +237,11 @@ protected:
return mp_view;
}
const lay::LayoutViewBase *view () const
{
return mp_view;
}
private:
tl::Color m_color;
tl::Color m_frame_color;
@ -324,14 +335,6 @@ public:
return m_cv_index;
}
/**
* @brief Gets the view object
*/
lay::LayoutViewBase *view () const
{
return mp_view;
}
/**
* @brief Gets the bounding box
*/
@ -350,7 +353,6 @@ public:
private:
db::CplxTrans m_trans;
std::vector<db::DCplxTrans> *mp_trans_vector;
lay::LayoutViewBase *mp_view;
unsigned int m_cv_index;
/**
@ -827,8 +829,21 @@ private:
db::DText *text;
void *any;
} m_object;
};
lay::LayoutViewBase *mp_view;
/**
* @brief A managed version of the marker class
*
* It uses gsi::ObjectBase as a base class and serves as
* proxy for GSI binding.
*/
class ManagedDMarker
: public lay::DMarker, public gsi::ObjectBase
{
public:
ManagedDMarker (lay::LayoutViewBase *view)
: lay::DMarker (view)
{ }
};
}

View File

@ -118,12 +118,9 @@ BackgroundViewObject::z_order (int z)
// ViewObject implementation
ViewObject::ViewObject (ViewObjectUI *widget, bool _static)
: mp_widget (widget), m_static (_static), m_visible (true), m_dismissable (false)
: mp_widget (0), m_static (_static), m_visible (true), m_dismissable (false)
{
if (widget) {
widget->m_objects.push_back (this);
redraw ();
}
set_widget (widget);
}
ViewObject::~ViewObject ()
@ -131,6 +128,19 @@ ViewObject::~ViewObject ()
redraw ();
}
void
ViewObject::set_widget (ViewObjectUI *widget)
{
if (mp_widget) {
mp_widget->m_objects.erase (this);
}
mp_widget = widget;
if (widget) {
widget->m_objects.push_back (this);
redraw ();
}
}
void
ViewObject::set_dismissable (bool dismissable)
{
@ -535,6 +545,20 @@ ViewObjectUI::init_ui (QWidget *parent)
}
#endif
void
ViewObjectUI::add_object (lay::ViewObject *object)
{
object->set_widget (this);
m_owned_objects.push_back (object);
m_objects.push_back (object);
}
void
ViewObjectUI::clear_objects ()
{
m_owned_objects.clear ();
}
void
ViewObjectUI::register_service (lay::ViewService *svc)
{

View File

@ -439,6 +439,13 @@ public:
*/
virtual ~ViewObject ();
/**
* @brief Attaches a view object to a widget
*
* This will register the object at the widget, but not transfer ownership.
*/
void set_widget (ViewObjectUI *widget);
/**
* @brief Render the object on the planes provided by the canvas.
*
@ -785,6 +792,16 @@ public:
return m_objects.end ();
}
/**
* @brief Adds an object, transferring ownership to the view
*/
void add_object (lay::ViewObject *object);
/**
* @brief Clears all objects owned by the view
*/
void clear_objects ();
/**
* @brief Remaining leave event handler
*
@ -1073,6 +1090,7 @@ private:
QWidget *mp_widget;
#endif
tl::weak_collection<lay::ViewObject> m_objects;
tl::shared_collection<lay::ViewObject> m_owned_objects;
tl::weak_collection<lay::BackgroundViewObject> m_background_objects;
std::list<lay::ViewService *> m_services;
std::list<ViewService *> m_grabbed;

View File

@ -77,6 +77,29 @@ class LAYMarkers_TestClass < TestBase
end
# persistent markers
def test_2
if !RBA.constants.member?(:Application)
return
end
app = RBA::Application.instance
mw = app.main_window
mw.create_layout(0)
cv = mw.current_view
m = RBA::Marker.new
m.set(RBA::DBox.new(1, 2, 3, 4))
m.vertex_size = 3
cv.add_marker(m)
cv.clear_markers
assert_equal(m.destroyed?, true)
end
end
load("test_epilogue.rb")