mirror of
https://github.com/KLayout/klayout.git
synced 2026-09-07 03:21:34 +02:00
Merge branch 'master' into issue-2224
This commit is contained in:
@@ -84,11 +84,15 @@ class ButtonStateNamespace { };
|
||||
static int const_ShiftButton() { return (int) lay::ShiftButton; }
|
||||
static int const_ControlButton() { return (int) lay::ControlButton; }
|
||||
static int const_AltButton() { return (int) lay::AltButton; }
|
||||
static int const_ModifierMask() { return (int) lay::ModifierMask; }
|
||||
static int const_LeftButton() { return (int) lay::LeftButton; }
|
||||
static int const_MidButton() { return (int) lay::MidButton; }
|
||||
static int const_RightButton() { return (int) lay::RightButton; }
|
||||
static int const_MouseButtonMask() { return (int) lay::MouseButtonMask; }
|
||||
|
||||
Class<gsi::ButtonStateNamespace> decl_ButtonState ("lay", "ButtonState",
|
||||
method ("ModifierMask", &const_ModifierMask, "@brief A bit mask that selects all keyboard modifiers in the button state mask\nThis constant has been introduced in version 0.30.6.") +
|
||||
method ("MouseButtonMask", &const_MouseButtonMask, "@brief A bit mask that selects all mouse buttons in the button state mask\nThis constant has been introduced in version 0.30.6.") +
|
||||
method ("ShiftKey", &const_ShiftButton, "@brief Indicates that the Shift key is pressed\nThis constant is combined with other constants within \\ButtonState") +
|
||||
method ("ControlKey", &const_ControlButton, "@brief Indicates that the Control key is pressed\nThis constant is combined with other constants within \\ButtonState") +
|
||||
method ("AltKey", &const_AltButton, "@brief Indicates that the Alt key is pressed\nThis constant is combined with other constants within \\ButtonState") +
|
||||
|
||||
@@ -125,58 +125,76 @@ static void drag_cancel_impl (lay::EditorServiceBase *p)
|
||||
|
||||
Class<lay::EditorServiceBase> decl_PluginBase ("lay", "PluginBase",
|
||||
gsi::method_ext ("tracking_position", &tracking_position_impl,
|
||||
"@brief Gets the tracking position (base class implementation)"
|
||||
"@brief Gets the tracking position (base class implementation)\n"
|
||||
"See \\Plugin#tracking_position for details."
|
||||
) +
|
||||
gsi::method_ext ("has_tracking_position", &has_tracking_position_impl,
|
||||
"@brief Gets a value indicating whether the plugin provides a tracking position (base class implementation)"
|
||||
"@brief Gets a value indicating whether the plugin provides a tracking position (base class implementation)\n"
|
||||
"See \\Plugin#has_tracking_position for details."
|
||||
) +
|
||||
gsi::method_ext ("menu_activated", &menu_activated_impl, gsi::arg ("symbol"),
|
||||
"@brief Gets called when a custom menu item is selected (base class implementation)"
|
||||
"@brief Gets called when a custom menu item is selected (base class implementation)\n"
|
||||
"See \\Plugin#menu_activated for details."
|
||||
) +
|
||||
gsi::method_ext ("configure", &configure_impl, gsi::arg ("name"), gsi::arg ("value"),
|
||||
"@brief Sends configuration requests to the plugin (base class implementation)"
|
||||
"@brief Sends configuration requests to the plugin (base class implementation)\n"
|
||||
"See \\Plugin#configure for details."
|
||||
) +
|
||||
gsi::method_ext ("config_finalize", &config_finalize_impl,
|
||||
"@brief Sends the post-configuration request to the plugin (base class implementation)"
|
||||
"@brief Sends the post-configuration request to the plugin (base class implementation)\n"
|
||||
"See \\Plugin#config_finalize for details."
|
||||
) +
|
||||
gsi::method_ext ("key_event", &key_event_impl, gsi::arg ("key"), gsi::arg ("buttons"),
|
||||
"@brief Handles the key pressed event (base class implementation)"
|
||||
"@brief Handles the key pressed event (base class implementation)\n"
|
||||
"See \\Plugin#key_event for details."
|
||||
) +
|
||||
gsi::method_ext ("mouse_button_pressed_event", &mouse_press_event_impl, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse button pressed event (base class implementation)"
|
||||
"@brief Handles the mouse button pressed event (base class implementation)\n"
|
||||
"See \\Plugin#mouse_button_pressed_event for details."
|
||||
) +
|
||||
gsi::method_ext ("mouse_click_event", &mouse_click_event_impl, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse button click event after the button has been released (base class implementation)"
|
||||
"@brief Handles the mouse button click event after the button has been released (base class implementation)\n"
|
||||
"See \\Plugin#mouse_click_event for details."
|
||||
) +
|
||||
gsi::method_ext ("mouse_double_click_event", &mouse_double_click_event_impl, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse button double-click event (base class implementation)"
|
||||
"@brief Handles the mouse button double-click event (base class implementation)\n"
|
||||
"See \\Plugin#mouse_double_click_event for details."
|
||||
) +
|
||||
gsi::method_ext ("leave_event", &leave_event_impl, gsi::arg ("prio"),
|
||||
"@brief Handles the leave event (base class implementation)"
|
||||
"@brief Handles the leave event (base class implementation)\n"
|
||||
"See \\Plugin#leave_event for details."
|
||||
) +
|
||||
gsi::method_ext ("enter_event", &enter_event_impl, gsi::arg ("prio"),
|
||||
"@brief Handles the enter event (base class implementation)"
|
||||
"@brief Handles the enter event (base class implementation)\n"
|
||||
"See \\Plugin#enter_event for details."
|
||||
) +
|
||||
gsi::method_ext ("mouse_moved_event", &mouse_move_event_impl, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse move event (base class implementation)"
|
||||
"@brief Handles the mouse move event (base class implementation)\n"
|
||||
"See \\Plugin#mouse_moved_event for details."
|
||||
) +
|
||||
gsi::method_ext ("mouse_button_released_event", &mouse_release_event_impl, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse button release event (base class implementation)"
|
||||
"@brief Handles the mouse button release event (base class implementation)\n"
|
||||
"See \\Plugin#mouse_button_released_event for details."
|
||||
) +
|
||||
gsi::method_ext ("wheel_event", &wheel_event_impl, gsi::arg ("delta"), gsi::arg ("horizontal"), gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse wheel event (base class implementation)"
|
||||
"@brief Handles the mouse wheel event (base class implementation)\n"
|
||||
"See \\Plugin#wheel_event for details."
|
||||
) +
|
||||
gsi::method_ext ("activated", &activated_impl,
|
||||
"@brief Gets called when the plugin is activated (base class implementation)"
|
||||
"@brief Gets called when the plugin is activated (base class implementation)\n"
|
||||
"See \\Plugin#activated for details."
|
||||
) +
|
||||
gsi::method_ext ("deactivated", &deactivated_impl,
|
||||
"@brief Gets called when the plugin is deactivated and another plugin is activated (base class implementation)"
|
||||
"@brief Gets called when the plugin is deactivated and another plugin is activated (base class implementation)\n"
|
||||
"See \\Plugin#deactivated for details."
|
||||
) +
|
||||
gsi::method_ext ("drag_cancel", &drag_cancel_impl,
|
||||
"@brief This method is called when some mouse dragging operation should be cancelled (base class implementation)"
|
||||
"@brief This method is called when some mouse dragging operation should be cancelled (base class implementation)\n"
|
||||
"See \\Plugin#drag_cancel for details."
|
||||
) +
|
||||
gsi::method_ext ("update", &update_impl,
|
||||
"@brief Gets called when the view has changed (base class implementation)"
|
||||
"@brief Gets called when the view has changed (base class implementation)\n"
|
||||
"See \\Plugin#update for details."
|
||||
),
|
||||
"@brief The plugin base class\n"
|
||||
"\n"
|
||||
@@ -735,36 +753,44 @@ Class<gsi::PluginImpl> decl_Plugin (decl_PluginBase, "lay", "Plugin",
|
||||
) +
|
||||
callback ("mouse_click_event", &gsi::PluginImpl::mouse_click_event_noref, &gsi::PluginImpl::f_mouse_click_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse button click event (after the button has been released)\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_press_event, except that it is called when the mouse button has been released without moving it.\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_button_pressed_event, except that it is called when the mouse button has been released without moving it.\n"
|
||||
"A mouse click is not defined by duration, but by releasing a button without moving the mouse after the button was pressed. "
|
||||
"As a consequence, a \\mouse_button_pressed_event is always issued at the beginning, but it is not followed by a \\mouse_button_released_event.\n"
|
||||
"Instead, the 'mouse_click_event' is issued.\n"
|
||||
"\n"
|
||||
"Starting with version 0.30.6, the button mask reflects the keyboard modifiers at the moment the mouse was released. Before, the keyboard modifiers were "
|
||||
"captured at the moment when the mouse was pressed."
|
||||
) +
|
||||
callback ("mouse_double_click_event", &gsi::PluginImpl::mouse_double_click_event_noref, &gsi::PluginImpl::f_mouse_double_click_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse button double-click event\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_press_event, except that it is called when the mouse button has been double-clicked.\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_button_pressed_event, except that it is called when the mouse button has been double-clicked.\n"
|
||||
) +
|
||||
callback ("leave_event", &gsi::PluginImpl::leave_event, &gsi::PluginImpl::f_leave_event, gsi::arg ("prio"),
|
||||
"@brief Handles the leave event (mouse leaves canvas area of view)\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_press_event, except that it is called when the mouse leaves the canvas area.\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_button_pressed_event, except that it is called when the mouse leaves the canvas area.\n"
|
||||
"This method does not have a position nor button flags.\n"
|
||||
) +
|
||||
callback ("enter_event", &gsi::PluginImpl::enter_event, &gsi::PluginImpl::f_enter_event, gsi::arg ("prio"),
|
||||
"@brief Handles the enter event (mouse enters canvas area of view)\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_press_event, except that it is called when the mouse enters the canvas area.\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_button_pressed_event, except that it is called when the mouse enters the canvas area.\n"
|
||||
"This method does not have a position nor button flags.\n"
|
||||
) +
|
||||
callback ("mouse_moved_event", &gsi::PluginImpl::mouse_move_event_noref, &gsi::PluginImpl::f_mouse_move_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse move event\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_press_event, except that it is called when the mouse is moved in the canvas area.\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_button_pressed_event, except that it is called when the mouse is moved in the canvas area.\n"
|
||||
"\n"
|
||||
"The mouse move event is important for a number of background jobs, such as coordinate display in the status bar.\n"
|
||||
"Hence, you should not consume the event - i.e. you should return 'false' from this method.\n"
|
||||
) +
|
||||
callback ("mouse_button_released_event", &gsi::PluginImpl::mouse_release_event_noref, &gsi::PluginImpl::f_mouse_release_event, gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse button release event\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_press_event, except that it is called when the mouse button is released.\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_button_pressed_event, except that it is called when the mouse button is released.\n"
|
||||
"Starting with version 0.30.6, the button mask reflects the keyboard modifiers at the moment the mouse was released. Before, the keyboard modifiers were "
|
||||
"captured at the moment when the mouse was pressed."
|
||||
) +
|
||||
callback ("wheel_event", &gsi::PluginImpl::wheel_event_noref, &gsi::PluginImpl::f_wheel_event, gsi::arg ("delta"), gsi::arg ("horizontal"), gsi::arg ("p"), gsi::arg ("buttons"), gsi::arg ("prio"),
|
||||
"@brief Handles the mouse wheel event\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_press_event, except that it is called when the mouse wheel is rotated.\n"
|
||||
"The behaviour of this callback is the same than for \\mouse_button_pressed_event, except that it is called when the mouse wheel is rotated.\n"
|
||||
"Additional parameters for this event are 'delta' (the rotation angle in units of 1/8th degree) and 'horizontal' which is true when the horizontal wheel was rotated and "
|
||||
"false if the vertical wheel was rotated.\n"
|
||||
) +
|
||||
|
||||
@@ -300,39 +300,11 @@ LayoutHandle::set_save_options (const db::SaveLayoutOptions &options, bool valid
|
||||
m_save_options_valid = valid;
|
||||
}
|
||||
|
||||
void
|
||||
LayoutHandle::update_save_options (db::SaveLayoutOptions &options)
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
|
||||
const lay::StreamWriterPluginDeclaration *decl = dynamic_cast <const lay::StreamWriterPluginDeclaration *> (&*cls);
|
||||
if (! decl || decl->options_alias ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_ptr<db::FormatSpecificWriterOptions> specific_options;
|
||||
if (options.get_options (decl->format_name ())) {
|
||||
specific_options.reset (options.get_options (decl->format_name ())->clone ());
|
||||
} else {
|
||||
specific_options.reset (decl->create_specific_options ());
|
||||
}
|
||||
|
||||
if (specific_options.get ()) {
|
||||
options.set_options (specific_options.release ());
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
LayoutHandle::save_as (const std::string &fn, tl::OutputStream::OutputStreamMode om, const db::SaveLayoutOptions &options, bool update, int keep_backups)
|
||||
{
|
||||
if (update) {
|
||||
|
||||
m_save_options = options;
|
||||
m_save_options_valid = true;
|
||||
// We must not load with the original options after we have saved the file - hence we reset the
|
||||
// reader options.
|
||||
m_load_options = db::LoadLayoutOptions ();
|
||||
|
||||
@@ -242,15 +242,6 @@ public:
|
||||
return m_save_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates the given save options with attributes from this cell view
|
||||
*
|
||||
* Some formats will initialize attributes from the cell view and the layout's
|
||||
* metadata (example: libname of GDS2). This method will update the options
|
||||
* if the layout provides attributes for initializing the latter.
|
||||
*/
|
||||
void update_save_options (db::SaveLayoutOptions &options);
|
||||
|
||||
/**
|
||||
* @brief Gets a flag indicating whether the save options are valid
|
||||
*
|
||||
|
||||
@@ -87,7 +87,7 @@ Finder::closer (double d)
|
||||
}
|
||||
|
||||
void
|
||||
Finder::start (lay::LayoutViewBase *view, unsigned int cv_index, const std::vector<db::DCplxTrans> &trans, const db::DBox ®ion, const db::DBox &scan_region, int min_level, int max_level, const std::vector<int> &layers)
|
||||
Finder::start (lay::LayoutViewBase *view, unsigned int cv_index, const std::vector<db::DCplxTrans> &trans, const db::DBox ®ion, const db::DBox &scan_region, int min_level, int max_level, const std::vector<unsigned int> &layers)
|
||||
{
|
||||
const lay::CellView &cv = view->cellview (cv_index);
|
||||
|
||||
@@ -100,8 +100,8 @@ Finder::start (lay::LayoutViewBase *view, unsigned int cv_index, const std::vect
|
||||
|
||||
if (layers.size () == 1) {
|
||||
|
||||
m_box_convert = db::box_convert <db::CellInst, false> (*mp_layout, (unsigned int) layers [0]);
|
||||
m_cell_box_convert = db::box_convert <db::Cell, false> ((unsigned int) layers [0]);
|
||||
m_box_convert = db::box_convert <db::CellInst, false> (*mp_layout, layers [0]);
|
||||
m_cell_box_convert = db::box_convert <db::Cell, false> (layers [0]);
|
||||
|
||||
} else {
|
||||
|
||||
@@ -202,7 +202,7 @@ Finder::do_find (const db::Cell &cell, int level, const db::DCplxTrans &vp, cons
|
||||
if (level <= m_max_level /*take level of cell itself*/
|
||||
&& cell.is_proxy ()
|
||||
&& m_layers.size () == 1
|
||||
&& (unsigned int) m_layers [0] == mp_layout->guiding_shape_layer ()) {
|
||||
&& m_layers [0] == mp_layout->guiding_shape_layer ()) {
|
||||
|
||||
// when looking at the guiding shape layer, we can visit this cell as well allowing to find the guiding shapes
|
||||
|
||||
@@ -339,7 +339,7 @@ ShapeFinder::find (LayoutViewBase *view, const db::DBox ®ion_mu)
|
||||
|
||||
std::sort (lprops.begin (), lprops.end (), LPContextCompareOp ());
|
||||
|
||||
std::vector<int> layers;
|
||||
std::vector<unsigned int> layers;
|
||||
for (std::vector<lay::LayerPropertiesConstIterator>::const_iterator llp = lprops.begin (); llp != lprops.end (); ) {
|
||||
|
||||
layers.clear ();
|
||||
@@ -347,7 +347,10 @@ ShapeFinder::find (LayoutViewBase *view, const db::DBox ®ion_mu)
|
||||
lay::LayerPropertiesConstIterator lp0 = *llp;
|
||||
LPContextEqualOp eq;
|
||||
do {
|
||||
layers.push_back ((*llp)->layer_index ());
|
||||
int li = (*llp)->layer_index ();
|
||||
if (li >= 0) {
|
||||
layers.push_back ((unsigned int) li);
|
||||
}
|
||||
++llp;
|
||||
} while (llp != lprops.end () && eq(lp0, *llp));
|
||||
|
||||
@@ -398,16 +401,19 @@ ShapeFinder::find (lay::LayoutViewBase *view, const lay::LayerProperties &lprops
|
||||
lay::TextInfo text_info (view);
|
||||
mp_text_info = (m_flags & db::ShapeIterator::Texts) != 0 ? &text_info : 0;
|
||||
|
||||
std::vector<int> layers;
|
||||
layers.push_back (lprops.layer_index ());
|
||||
std::vector<unsigned int> layers;
|
||||
int li = lprops.layer_index ();
|
||||
if (li >= 0) {
|
||||
layers.push_back ((unsigned int) li);
|
||||
}
|
||||
bool result = find_internal (view, lprops.cellview_index (), &lprops.prop_sel (), lprops.inverse_prop_sel (), lprops.hier_levels (), lprops.trans (), layers, region_mu);
|
||||
|
||||
mp_progress = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
ShapeFinder::find_internal (lay::LayoutViewBase *view, unsigned int cv_index, const std::set<db::properties_id_type> *prop_sel, bool inv_prop_sel, const lay::HierarchyLevelSelection &hier_sel, const std::vector<db::DCplxTrans> &trans_mu, const std::vector<int> &layers, const db::DBox ®ion_mu)
|
||||
bool
|
||||
ShapeFinder::find_internal (lay::LayoutViewBase *view, unsigned int cv_index, const std::set<db::properties_id_type> *prop_sel, bool inv_prop_sel, const lay::HierarchyLevelSelection &hier_sel, const std::vector<db::DCplxTrans> &trans_mu, const std::vector<unsigned int> &layers, const db::DBox ®ion_mu)
|
||||
{
|
||||
m_cv_index = cv_index;
|
||||
|
||||
@@ -511,13 +517,13 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
|
||||
|
||||
if (! point_mode ()) {
|
||||
|
||||
for (std::vector<int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) {
|
||||
for (std::vector<unsigned int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) {
|
||||
|
||||
if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox ((unsigned int) *l).touches (scan_box))) {
|
||||
if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox (*l).touches (scan_box))) {
|
||||
|
||||
checkpoint ();
|
||||
|
||||
const db::Shapes &shapes = cell.shapes ((unsigned int) *l);
|
||||
const db::Shapes &shapes = cell.shapes (*l);
|
||||
|
||||
db::ShapeIterator shape = shapes.begin_touching (scan_box, m_flags, mp_prop_sel, m_inv_prop_sel);
|
||||
while (! shape.at_end ()) {
|
||||
@@ -563,9 +569,9 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
|
||||
|
||||
} else {
|
||||
|
||||
for (std::vector<int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) {
|
||||
for (std::vector<unsigned int>::const_iterator l = layers ().begin (); l != layers ().end (); ++l) {
|
||||
|
||||
if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox ((unsigned int) *l).touches (scan_box))) {
|
||||
if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox (*l).touches (scan_box))) {
|
||||
|
||||
checkpoint ();
|
||||
|
||||
@@ -793,7 +799,7 @@ InstFinder::find_internal (LayoutViewBase *view, unsigned int cv_index, const db
|
||||
try {
|
||||
std::vector<db::DCplxTrans> tv;
|
||||
tv.push_back (trans_mu);
|
||||
start (view, cv_index, tv, region_mu, region_mu, view->get_min_hier_levels (), view->get_max_hier_levels (), std::vector<int> ());
|
||||
start (view, cv_index, tv, region_mu, region_mu, view->get_min_hier_levels (), view->get_max_hier_levels (), std::vector<unsigned int> ());
|
||||
} catch (StopException) {
|
||||
// ..
|
||||
}
|
||||
@@ -805,8 +811,12 @@ InstFinder::find_internal (LayoutViewBase *view, unsigned int cv_index, const db
|
||||
void
|
||||
InstFinder::checkpoint ()
|
||||
{
|
||||
if (--m_tries < 0) {
|
||||
throw StopException ();
|
||||
if (! point_mode ()) {
|
||||
++*mp_progress;
|
||||
} else {
|
||||
if (--m_tries < 0) {
|
||||
throw StopException ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -829,15 +839,13 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
|
||||
|
||||
if (! point_mode ()) {
|
||||
|
||||
++*mp_progress;
|
||||
|
||||
// look for instances to check here ..
|
||||
for (db::Cell::touching_iterator inst = cell.begin_touching (search_box); ! inst.at_end (); ++inst) {
|
||||
|
||||
const db::CellInstArray &cell_inst = inst->cell_inst ();
|
||||
const db::Cell &inst_cell = layout ().cell (cell_inst.object ().cell_index ());
|
||||
|
||||
++*mp_progress;
|
||||
checkpoint ();
|
||||
|
||||
if (! consider_cell (inst_cell)) {
|
||||
continue;
|
||||
@@ -851,7 +859,7 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
|
||||
db::box_convert <db::CellInst, false> bc (layout ());
|
||||
for (db::CellInstArray::iterator p = cell_inst.begin_touching (search_box, bc); ! p.at_end (); ++p) {
|
||||
|
||||
++*mp_progress;
|
||||
checkpoint ();
|
||||
|
||||
db::Box ibox;
|
||||
if (! m_visible_layers || level == mp_view->get_max_hier_levels () - 1 || inst_cell.is_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) {
|
||||
|
||||
@@ -132,7 +132,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
const std::vector<int> &layers () const
|
||||
const std::vector<unsigned int> &layers () const
|
||||
{
|
||||
return m_layers;
|
||||
}
|
||||
@@ -183,7 +183,7 @@ protected:
|
||||
* @param max_level The maximum hierarchy level to check
|
||||
* @param layers A set of layers to check
|
||||
*/
|
||||
void start (LayoutViewBase *view, unsigned int cv_index, const std::vector<db::DCplxTrans> &trans, const db::DBox ®ion, const db::DBox &scan_region, int min_level, int max_level, const std::vector<int> &layers = std::vector<int> ());
|
||||
void start (LayoutViewBase *view, unsigned int cv_index, const std::vector<db::DCplxTrans> &trans, const db::DBox ®ion, const db::DBox &scan_region, int min_level, int max_level, const std::vector<unsigned int> &layers = std::vector<unsigned int> ());
|
||||
|
||||
/**
|
||||
* @brief Provide a basic edge test facility
|
||||
@@ -232,7 +232,7 @@ private:
|
||||
unsigned int m_cv_index;
|
||||
db::Box m_region;
|
||||
db::Box m_scan_region;
|
||||
std::vector<int> m_layers;
|
||||
std::vector<unsigned int> m_layers;
|
||||
double m_distance;
|
||||
bool m_point_mode;
|
||||
bool m_catch_all;
|
||||
@@ -267,8 +267,8 @@ public:
|
||||
*/
|
||||
ShapeFinder (bool point_mode, bool top_level_sel, db::ShapeIterator::flags_type flags, const std::set<lay::ObjectInstPath> *excludes = 0, bool capture_all_shapes = false);
|
||||
|
||||
bool find (LayoutViewBase *view, const lay::LayerProperties &lprops, const db::DBox ®ion_mu);
|
||||
bool find (LayoutViewBase *view, const db::DBox ®ion_mu);
|
||||
bool find (lay::LayoutViewBase *view, const lay::LayerProperties &lprops, const db::DBox ®ion_mu);
|
||||
bool find (lay::LayoutViewBase *view, const db::DBox ®ion_mu);
|
||||
|
||||
iterator begin () const
|
||||
{
|
||||
@@ -327,7 +327,7 @@ private:
|
||||
bool inv_prop_sel,
|
||||
const lay::HierarchyLevelSelection &hier_sel,
|
||||
const std::vector<db::DCplxTrans> &trans_mu,
|
||||
const std::vector<int> &layers,
|
||||
const std::vector<unsigned int> &layers,
|
||||
const db::DBox ®ion_mu);
|
||||
|
||||
const std::set<lay::ObjectInstPath> *mp_excludes;
|
||||
|
||||
@@ -342,6 +342,7 @@ LayoutViewBase::init (db::Manager *mgr)
|
||||
m_box_text_transform = true;
|
||||
m_box_font = 0;
|
||||
m_min_size_for_label = 16;
|
||||
m_empty_cell_dimension = 4.0;
|
||||
m_cell_box_visible = true;
|
||||
m_ghost_cells_visible = true;
|
||||
m_text_visible = true;
|
||||
@@ -693,7 +694,7 @@ LayoutViewBase::set_synchronous (bool s)
|
||||
}
|
||||
|
||||
void
|
||||
LayoutViewBase::message (const std::string & /*s*/, int /*timeout*/)
|
||||
LayoutViewBase::message (const std::string & /*s*/, int /*timeout*/, int /*priority*/)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
@@ -944,6 +945,13 @@ LayoutViewBase::configure (const std::string &name, const std::string &value)
|
||||
min_inst_label_size (n);
|
||||
return true;
|
||||
|
||||
} else if (name == cfg_empty_cell_dimension) {
|
||||
|
||||
double n;
|
||||
tl::from_string (value, n);
|
||||
empty_cell_dimension (n);
|
||||
return true;
|
||||
|
||||
} else if (name == cfg_cell_box_text_font) {
|
||||
|
||||
int n;
|
||||
@@ -4156,7 +4164,7 @@ void
|
||||
LayoutViewBase::cancel_edits ()
|
||||
{
|
||||
// clear any messages
|
||||
message ();
|
||||
message (std::string (), 0, -1);
|
||||
|
||||
// the move service takes a special role here as it manages the
|
||||
// transaction for the collective move operation.
|
||||
@@ -5403,7 +5411,16 @@ LayoutViewBase::min_inst_label_size (int px)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
LayoutViewBase::empty_cell_dimension (double um)
|
||||
{
|
||||
if (m_empty_cell_dimension != um) {
|
||||
m_empty_cell_dimension = um;
|
||||
redraw ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayoutViewBase::text_visible (bool vis)
|
||||
{
|
||||
if (m_text_visible != vis) {
|
||||
|
||||
@@ -149,6 +149,70 @@ struct LAYBASIC_PUBLIC LayerDisplayProperties
|
||||
std::string name;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Descriptor for a notification inside the layout view
|
||||
*
|
||||
* Notifications are popups added at the top of the view to indicate need for reloading for example.
|
||||
* Notifications have a name, a title, optional actions (id, title) and a parameter (e.g. file path to reload).
|
||||
* Actions are mapped to QPushButtons.
|
||||
*/
|
||||
class LAYBASIC_PUBLIC LayoutViewNotification
|
||||
{
|
||||
public:
|
||||
LayoutViewNotification (const std::string &name, const std::string &title, const tl::Variant ¶meter = tl::Variant ())
|
||||
: m_name (name), m_title (title), m_parameter (parameter)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void add_action (const std::string &name, const std::string &title)
|
||||
{
|
||||
m_actions.push_back (std::make_pair (name, title));
|
||||
}
|
||||
|
||||
const std::vector<std::pair<std::string, std::string> > &actions () const
|
||||
{
|
||||
return m_actions;
|
||||
}
|
||||
|
||||
const std::string &name () const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const std::string &title () const
|
||||
{
|
||||
return m_title;
|
||||
}
|
||||
|
||||
const tl::Variant ¶meter () const
|
||||
{
|
||||
return m_parameter;
|
||||
}
|
||||
|
||||
bool operator<(const LayoutViewNotification &other) const
|
||||
{
|
||||
if (m_name != other.name ()) {
|
||||
return m_name < other.name ();
|
||||
}
|
||||
return m_parameter < other.parameter ();
|
||||
}
|
||||
|
||||
bool operator==(const LayoutViewNotification &other) const
|
||||
{
|
||||
if (m_name != other.name ()) {
|
||||
return false;
|
||||
}
|
||||
return m_parameter == other.parameter ();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::string m_title;
|
||||
tl::Variant m_parameter;
|
||||
std::vector<std::pair<std::string, std::string> > m_actions;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The layout view object
|
||||
*
|
||||
@@ -279,6 +343,14 @@ public:
|
||||
*/
|
||||
virtual void cut ();
|
||||
|
||||
/**
|
||||
* @brief Adds a notification
|
||||
*/
|
||||
virtual void add_notification (const LayoutViewNotification & /*notification*/)
|
||||
{
|
||||
// the base implementation does nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the explicit title string of the view
|
||||
*
|
||||
@@ -293,7 +365,7 @@ public:
|
||||
/**
|
||||
* @brief Display a status message
|
||||
*/
|
||||
virtual void message (const std::string &s = "", int timeout = 10);
|
||||
virtual void message (const std::string &s = "", int timeout = 10, int priority = 0);
|
||||
|
||||
/**
|
||||
* @brief Sets the keyboard focus to the view
|
||||
@@ -1149,7 +1221,20 @@ public:
|
||||
return m_min_size_for_label;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Empty cell dimension for the purpose of label generation setter
|
||||
*/
|
||||
void empty_cell_dimension (double um);
|
||||
|
||||
/**
|
||||
* @brief Empty cell dimension for the purpose of label generation getter
|
||||
*/
|
||||
int empty_cell_dimension () const
|
||||
{
|
||||
return m_empty_cell_dimension;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Visibility of text objects
|
||||
*/
|
||||
void text_visible (bool vis);
|
||||
@@ -2941,6 +3026,7 @@ private:
|
||||
bool m_box_text_transform;
|
||||
unsigned int m_box_font;
|
||||
int m_min_size_for_label;
|
||||
double m_empty_cell_dimension;
|
||||
bool m_cell_box_visible;
|
||||
bool m_ghost_cells_visible;
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_current_lib_view, ""));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_hide_empty_layers, "false"));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_min_inst_label_size, "16"));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_empty_cell_dimension, "4"));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_cell_box_text_font, "0"));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_cell_box_text_transform, "true"));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_cell_box_color, "auto"));
|
||||
|
||||
@@ -40,6 +40,90 @@ static inline db::Box safe_transformed_box (const db::Box &box, const db::ICplxT
|
||||
return db::Box (db);
|
||||
}
|
||||
|
||||
static bool
|
||||
has_zero_bit (const lay::Bitmap *bitmap, unsigned int ixmin, unsigned int iymin, unsigned int ixmax, unsigned int iymax)
|
||||
{
|
||||
uint32_t imin = ixmin / 32;
|
||||
uint32_t imax = ixmax / 32;
|
||||
|
||||
if (imin == imax) {
|
||||
|
||||
uint32_t m = ((unsigned int) 0xffffffff << (ixmin % 32)) & ((unsigned int) 0xffffffff >> (31 - (ixmax % 32)));
|
||||
|
||||
for (unsigned int y = iymin; y <= iymax; ++y) {
|
||||
|
||||
if (bitmap->is_scanline_empty (y)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((bitmap->scanline (y) [imin] & m) != m) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
uint32_t m1 = ((unsigned int) 0xffffffff << (ixmin % 32));
|
||||
uint32_t m2 = ((unsigned int) 0xffffffff >> (31 - (ixmax % 32)));
|
||||
|
||||
for (unsigned int y = iymin; y <= iymax; ++y) {
|
||||
|
||||
if (bitmap->is_scanline_empty (y)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((bitmap->scanline (y) [imin] & m1) != m1) {
|
||||
return true;
|
||||
}
|
||||
for (unsigned int i = imin + 1; i < imax; ++i) {
|
||||
if (bitmap->scanline (y) [i] != 0xffffffff) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ((bitmap->scanline (y) [imax] & m2) != m2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
skip_quad (const db::Box &qb, const lay::Bitmap *vertex_bitmap, const db::CplxTrans &trans)
|
||||
{
|
||||
double threshold = 32 / trans.mag (); // only check cells below 32x32 pixels
|
||||
if (qb.empty () || qb.width () > threshold || qb.height () > threshold || !vertex_bitmap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
db::DBox qb_trans = (trans * qb) & db::DBox (0, 0, vertex_bitmap->width () - 1.0 - 1e-6, vertex_bitmap->height () - 1.0 - 1e-6);
|
||||
if (qb_trans.empty ()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int ixmin = (unsigned int)(qb_trans.left () + 0.5);
|
||||
int ixmax = (unsigned int)(qb_trans.right () + 0.5);
|
||||
int iymin = (unsigned int)(qb_trans.bottom () + 0.5);
|
||||
int iymax = (unsigned int)(qb_trans.top () + 0.5);
|
||||
if (! has_zero_bit (vertex_bitmap, ixmin, iymin, ixmax, iymax)) {
|
||||
return true; // skip
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
copy_bitmap (const lay::Bitmap *from, lay::Bitmap *to, int dx, int dy)
|
||||
{
|
||||
if (to) {
|
||||
to->merge (from, dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// RedrawThreadWorker implementation
|
||||
|
||||
@@ -61,6 +145,7 @@ RedrawThreadWorker::RedrawThreadWorker (RedrawThread *redraw_thread)
|
||||
m_box_text_transform = false;
|
||||
m_box_font = 0;
|
||||
m_min_size_for_label = 1;
|
||||
m_empty_cell_dimension = 1.0;
|
||||
m_text_font = 0;
|
||||
m_text_visible = false;
|
||||
m_text_lazy_rendering = false;
|
||||
@@ -600,6 +685,7 @@ RedrawThreadWorker::setup (LayoutViewBase *view, RedrawThreadCanvas *canvas, con
|
||||
m_from_level_default = view->get_hier_levels ().first;
|
||||
m_to_level_default = view->get_hier_levels ().second;
|
||||
m_min_size_for_label = view->min_inst_label_size ();
|
||||
m_empty_cell_dimension = view->empty_cell_dimension ();
|
||||
m_box_text_transform = view->cell_box_text_transform ();
|
||||
m_box_font = view->cell_box_text_font ();
|
||||
m_text_font = view->text_font ();
|
||||
@@ -680,7 +766,7 @@ RedrawThreadWorker::test_snapshot (const UpdateSnapshotCallback *update_snapshot
|
||||
}
|
||||
|
||||
void
|
||||
RedrawThreadWorker::draw_cell (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, bool empty_cell, const std::string &txt)
|
||||
RedrawThreadWorker::draw_cell (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, const db::Box &box_for_label, bool empty_cell, const std::string &txt, lay::Bitmap *opt_bitmap)
|
||||
{
|
||||
lay::Renderer &r = *mp_renderer;
|
||||
|
||||
@@ -699,13 +785,17 @@ RedrawThreadWorker::draw_cell (bool drawing_context, int level, const db::CplxTr
|
||||
|
||||
if (empty_cell) {
|
||||
r.draw (dbox, 0, contour, vertices, 0);
|
||||
if (opt_bitmap) {
|
||||
r.draw (dbox, 0, 0, opt_bitmap, 0);
|
||||
}
|
||||
} else {
|
||||
r.draw (dbox, fill, contour, 0, 0);
|
||||
}
|
||||
|
||||
if (! txt.empty () && (empty_cell || (dbox.width () > m_min_size_for_label && dbox.height () > m_min_size_for_label))) {
|
||||
db::DBox dbox_for_label = trans * box_for_label;
|
||||
if (! txt.empty () && (empty_cell || (dbox_for_label.width () > m_min_size_for_label && dbox_for_label.height () > m_min_size_for_label))) {
|
||||
// Hint: we render to contour because the texts plane is reserved for properties
|
||||
r.draw (dbox, txt,
|
||||
r.draw (dbox_for_label, txt,
|
||||
db::Font (m_box_font),
|
||||
db::HAlignCenter,
|
||||
db::VAlignCenter,
|
||||
@@ -817,34 +907,58 @@ RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type c
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<lay::Bitmap> opt_bitmap;
|
||||
|
||||
unsigned int plane_group = 2;
|
||||
if (drawing_context) {
|
||||
plane_group = 0;
|
||||
} else if (m_child_context_enabled && level + 1 > 0) {
|
||||
plane_group = 1;
|
||||
}
|
||||
|
||||
lay::CanvasPlane *vertex = m_planes[3 + plane_group * (planes_per_layer / 3)];
|
||||
lay::Bitmap *vertex_bitmap = dynamic_cast<lay::Bitmap *> (vertex);
|
||||
if (vertex_bitmap) {
|
||||
opt_bitmap.reset (new lay::Bitmap (vertex_bitmap->width (), vertex_bitmap->height (), vertex_bitmap->resolution (), vertex_bitmap->font_resolution ()));
|
||||
}
|
||||
|
||||
for (std::vector<db::Box>::const_iterator b = redraw_regions.begin (); b != redraw_regions.end (); ++b) {
|
||||
draw_boxes_impl (drawing_context, ci, trans, *b, level, for_ghosts);
|
||||
draw_boxes_impl (drawing_context, ci, trans, *b, level, for_ghosts, opt_bitmap.get ());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level, bool for_ghosts)
|
||||
RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level, bool for_ghosts, lay::Bitmap *opt_bitmap)
|
||||
{
|
||||
lay::Renderer &r = *mp_renderer;
|
||||
const db::Cell &cell = mp_layout->cell (ci);
|
||||
|
||||
// small cells are dropped
|
||||
if (m_drop_small_cells && drop_cell (cell, trans)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For small bboxes, the cell outline can be reduced ..
|
||||
db::Box bbox = cell.bbox_with_empty ();
|
||||
bool empty_cell = cell.bbox ().empty ();
|
||||
|
||||
if (m_drop_small_cells && drop_cell (cell, trans)) {
|
||||
db::Box bbox_for_label;
|
||||
if (empty_cell) {
|
||||
db::Coord d = db::coord_traits<db::Coord>::rounded (0.5 * m_empty_cell_dimension / mp_layout->dbu ());
|
||||
bbox_for_label = bbox.enlarged (db::Vector (d, d));
|
||||
} else {
|
||||
bbox_for_label = bbox;
|
||||
}
|
||||
|
||||
// small cell dropped
|
||||
|
||||
} else if (for_ghosts && cell.is_ghost_cell ()) {
|
||||
if (for_ghosts && cell.is_ghost_cell ()) {
|
||||
|
||||
// paint the box on this level
|
||||
draw_cell (drawing_context, level, trans, bbox, empty_cell, mp_layout->display_name (ci));
|
||||
draw_cell (drawing_context, level, trans, bbox, bbox_for_label, empty_cell, mp_layout->display_name (ci), opt_bitmap);
|
||||
|
||||
} else if (! for_ghosts && ! cell.is_ghost_cell () && (level == m_to_level || (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ()))) {
|
||||
|
||||
// paint the box on this level
|
||||
draw_cell (drawing_context, level, trans, bbox, empty_cell, mp_layout->display_name (ci));
|
||||
draw_cell (drawing_context, level, trans, bbox, bbox_for_label, empty_cell, mp_layout->display_name (ci), opt_bitmap);
|
||||
|
||||
} else if (level < m_to_level) {
|
||||
|
||||
@@ -855,7 +969,7 @@ RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type c
|
||||
// the cell is a very small box and we know there must be
|
||||
// some level at which to draw the boundary: just draw it
|
||||
// here and stop looking further down ..
|
||||
draw_cell (drawing_context, level, trans, bbox, empty_cell, std::string ());
|
||||
draw_cell (drawing_context, level, trans, bbox, bbox_for_label, empty_cell, std::string (), opt_bitmap);
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -884,6 +998,8 @@ RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type c
|
||||
bool anything = false;
|
||||
db::cell_index_type last_ci = std::numeric_limits<db::cell_index_type>::max ();
|
||||
|
||||
size_t current_quad_id = 0;
|
||||
|
||||
db::Cell::touching_iterator inst = cell.begin_touching (*v);
|
||||
while (! inst.at_end ()) {
|
||||
|
||||
@@ -893,6 +1009,20 @@ RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type c
|
||||
db::Box new_cell_box = cell_inst.bbox (bc);
|
||||
bool empty_inst_cell = mp_layout->cell (new_ci).bbox ().empty ();
|
||||
|
||||
// skip this quad if we have drawn something here already
|
||||
size_t qid = inst.quad_id ();
|
||||
bool skip = false;
|
||||
if (empty_inst_cell && qid != current_quad_id) {
|
||||
current_quad_id = qid;
|
||||
skip = opt_bitmap && skip_quad (inst.quad_box () & bbox, opt_bitmap, trans);
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
// move on to the next quad
|
||||
inst.skip_quad ();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (last_ci != new_ci) {
|
||||
// Hint: don't use any_cell_box on partially visible cells because that will degrade performance
|
||||
if (new_cell_box.inside (*v)) {
|
||||
@@ -940,6 +1070,9 @@ RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type c
|
||||
if (empty_inst_cell) {
|
||||
lay::CanvasPlane *vertices = m_planes[3 + plane_group * (planes_per_layer / 3)];
|
||||
r.draw (cell_inst.bbox (bc), trans, 0, 0, vertices, 0);
|
||||
if (opt_bitmap) {
|
||||
r.draw (cell_inst.bbox (bc), trans, opt_bitmap, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
lay::CanvasPlane *contour = m_planes[1 + plane_group * (planes_per_layer / 3)];
|
||||
@@ -955,9 +1088,10 @@ RedrawThreadWorker::draw_boxes_impl (bool drawing_context, db::cell_index_type c
|
||||
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ) {
|
||||
|
||||
test_snapshot (0);
|
||||
|
||||
db::ICplxTrans t (cell_inst.complex_trans (*p));
|
||||
db::Box new_vp = safe_transformed_box (*v, t.inverted ());
|
||||
draw_boxes_impl (drawing_context, new_ci, trans * t, new_vp, level + 1, for_ghosts);
|
||||
draw_boxes_impl (drawing_context, new_ci, trans * t, new_vp, level + 1, for_ghosts, opt_bitmap);
|
||||
|
||||
if (p.quad_id () > 0 && p.quad_id () != qid) {
|
||||
|
||||
@@ -1292,91 +1426,7 @@ RedrawThreadWorker::any_text_shapes (db::cell_index_type cell_index, unsigned in
|
||||
return c->second;
|
||||
}
|
||||
|
||||
static bool
|
||||
has_zero_bit (const lay::Bitmap *bitmap, unsigned int ixmin, unsigned int iymin, unsigned int ixmax, unsigned int iymax)
|
||||
{
|
||||
uint32_t imin = ixmin / 32;
|
||||
uint32_t imax = ixmax / 32;
|
||||
|
||||
if (imin == imax) {
|
||||
|
||||
uint32_t m = ((unsigned int) 0xffffffff << (ixmin % 32)) & ((unsigned int) 0xffffffff >> (31 - (ixmax % 32)));
|
||||
|
||||
for (unsigned int y = iymin; y <= iymax; ++y) {
|
||||
|
||||
if (bitmap->is_scanline_empty (y)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((bitmap->scanline (y) [imin] & m) != m) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
uint32_t m1 = ((unsigned int) 0xffffffff << (ixmin % 32));
|
||||
uint32_t m2 = ((unsigned int) 0xffffffff >> (31 - (ixmax % 32)));
|
||||
|
||||
for (unsigned int y = iymin; y <= iymax; ++y) {
|
||||
|
||||
if (bitmap->is_scanline_empty (y)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((bitmap->scanline (y) [imin] & m1) != m1) {
|
||||
return true;
|
||||
}
|
||||
for (unsigned int i = imin + 1; i < imax; ++i) {
|
||||
if (bitmap->scanline (y) [i] != 0xffffffff) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ((bitmap->scanline (y) [imax] & m2) != m2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
skip_quad (const db::Box &qb, const lay::Bitmap *vertex_bitmap, const db::CplxTrans &trans)
|
||||
{
|
||||
double threshold = 32 / trans.mag (); // don't check cells below 32x32 pixels
|
||||
if (qb.empty () || qb.width () > threshold || qb.height () > threshold || !vertex_bitmap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
db::DBox qb_trans = (trans * qb) & db::DBox (0, 0, vertex_bitmap->width () - 1.0 - 1e-6, vertex_bitmap->height () - 1.0 - 1e-6);
|
||||
if (qb_trans.empty ()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int ixmin = (unsigned int)(qb_trans.left () + 0.5);
|
||||
int ixmax = (unsigned int)(qb_trans.right () + 0.5);
|
||||
int iymin = (unsigned int)(qb_trans.bottom () + 0.5);
|
||||
int iymax = (unsigned int)(qb_trans.top () + 0.5);
|
||||
if (! has_zero_bit (vertex_bitmap, ixmin, iymin, ixmax, iymax)) {
|
||||
return true; // skip
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
copy_bitmap (const lay::Bitmap *from, lay::Bitmap *to, int dx, int dy)
|
||||
{
|
||||
if (to) {
|
||||
to->merge (from, dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<db::Box>
|
||||
std::vector<db::Box>
|
||||
RedrawThreadWorker::search_regions (const db::Box &cell_bbox, const db::Box &vp, int level)
|
||||
{
|
||||
std::vector<db::Box> vv;
|
||||
|
||||
@@ -185,13 +185,13 @@ private:
|
||||
void draw_boxes_for_ghosts (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
|
||||
void draw_boxes (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
|
||||
void draw_boxes_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level, bool for_ghosts);
|
||||
void draw_boxes_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_region, int level, bool for_ghosts);
|
||||
void draw_boxes_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_region, int level, bool for_ghosts, Bitmap *opt_bitmap);
|
||||
void draw_box_properties_for_ghosts (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
|
||||
void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
|
||||
void draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level, bool for_ghosts);
|
||||
void draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level, db::properties_id_type prop_id, bool for_ghosts);
|
||||
void draw_box_properties_impl (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level, db::properties_id_type prop_id, bool for_ghosts);
|
||||
void draw_cell (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, bool empty_cell, const std::string &txt);
|
||||
void draw_cell (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, const db::Box &box_for_label, bool empty_cell, const std::string &txt, Bitmap *opt_bitmap);
|
||||
void draw_cell_properties (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, db::properties_id_type prop_id);
|
||||
void draw_cell_shapes (const db::CplxTrans &trans, const db::Cell &cell, const db::Box &vp, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text);
|
||||
void test_snapshot (const UpdateSnapshotCallback *update_snapshot);
|
||||
@@ -216,6 +216,7 @@ private:
|
||||
int m_from_level, m_to_level;
|
||||
int m_from_level_default, m_to_level_default;
|
||||
int m_min_size_for_label;
|
||||
double m_empty_cell_dimension;
|
||||
bool m_box_text_transform;
|
||||
unsigned int m_box_font;
|
||||
unsigned int m_text_font;
|
||||
|
||||
@@ -47,7 +47,6 @@ SelectionService::SelectionService (lay::LayoutViewBase *view) :
|
||||
mp_view (view),
|
||||
mp_box (0),
|
||||
m_color (0),
|
||||
m_buttons (0),
|
||||
m_hover (false),
|
||||
m_hover_wait (false),
|
||||
m_mouse_in_window (false)
|
||||
@@ -204,7 +203,6 @@ SelectionService::mouse_press_event (const db::DPoint &p, unsigned int buttons,
|
||||
|
||||
if ((buttons & lay::LeftButton) != 0) {
|
||||
mp_view->stop_redraw (); // TODO: how to restart if selection is aborted?
|
||||
m_buttons = buttons;
|
||||
begin (p);
|
||||
return true;
|
||||
}
|
||||
@@ -263,7 +261,7 @@ SelectionService::mouse_click_event (const db::DPoint &p, unsigned int buttons,
|
||||
}
|
||||
|
||||
bool
|
||||
SelectionService::mouse_release_event (const db::DPoint & /*p*/, unsigned int /*buttons*/, bool prio)
|
||||
SelectionService::mouse_release_event (const db::DPoint & /*p*/, unsigned int buttons, bool prio)
|
||||
{
|
||||
hover_reset ();
|
||||
|
||||
@@ -274,8 +272,8 @@ SelectionService::mouse_release_event (const db::DPoint & /*p*/, unsigned int /*
|
||||
if (mp_view) {
|
||||
|
||||
lay::Editable::SelectionMode mode = lay::Editable::Replace;
|
||||
bool shift = ((m_buttons & lay::ShiftButton) != 0);
|
||||
bool ctrl = ((m_buttons & lay::ControlButton) != 0);
|
||||
bool shift = ((buttons & lay::ShiftButton) != 0);
|
||||
bool ctrl = ((buttons & lay::ControlButton) != 0);
|
||||
if (shift && ctrl) {
|
||||
mode = lay::Editable::Invert;
|
||||
} else if (shift) {
|
||||
|
||||
@@ -91,7 +91,6 @@ private:
|
||||
lay::LayoutViewBase *mp_view;
|
||||
lay::RubberBox *mp_box;
|
||||
unsigned int m_color;
|
||||
unsigned int m_buttons;
|
||||
bool m_hover;
|
||||
bool m_hover_wait;
|
||||
db::DPoint m_hover_point;
|
||||
|
||||
@@ -907,7 +907,7 @@ ViewObjectUI::send_mouse_double_clicked_event (const db::DPoint &pt, unsigned in
|
||||
}
|
||||
|
||||
void
|
||||
ViewObjectUI::send_mouse_release_event (const db::DPoint &pt, unsigned int /*buttons*/)
|
||||
ViewObjectUI::send_mouse_release_event (const db::DPoint &pt, unsigned int buttons)
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -916,23 +916,27 @@ ViewObjectUI::send_mouse_release_event (const db::DPoint &pt, unsigned int /*but
|
||||
|
||||
bool done = false;
|
||||
|
||||
// Qt does not include the released button in the mask, so we take the mouse buttons that we stored
|
||||
// on "press", but use the current modifiers (issue #2214)
|
||||
unsigned int effective_buttons = (m_mouse_buttons & lay::MouseButtonMask) | (buttons & lay::ModifierMask);
|
||||
|
||||
m_mouse_pos = pt;
|
||||
db::DPoint p = pixel_to_um (m_mouse_pos);
|
||||
|
||||
auto grabbed = m_grabbed;
|
||||
for (auto g = grabbed.begin (); !done && g != grabbed.end (); ++g) {
|
||||
if (m_mouse_pressed_state) {
|
||||
done = (*g)->enabled () && (*g)->mouse_click_event (p, m_mouse_buttons, true);
|
||||
done = (*g)->enabled () && (*g)->mouse_click_event (p, effective_buttons, true);
|
||||
} else {
|
||||
done = (*g)->enabled () && (*g)->mouse_release_event (p, m_mouse_buttons, true);
|
||||
done = (*g)->enabled () && (*g)->mouse_release_event (p, effective_buttons, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (! done && mp_active_service && mp_active_service->enabled ()) {
|
||||
if (m_mouse_pressed_state) {
|
||||
done = mp_active_service->mouse_click_event (p, m_mouse_buttons, true);
|
||||
done = mp_active_service->mouse_click_event (p, effective_buttons, true);
|
||||
} else {
|
||||
done = mp_active_service->mouse_release_event (p, m_mouse_buttons, true);
|
||||
done = mp_active_service->mouse_release_event (p, effective_buttons, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -942,9 +946,9 @@ ViewObjectUI::send_mouse_release_event (const db::DPoint &pt, unsigned int /*but
|
||||
++next;
|
||||
if ((*svc)->enabled ()) {
|
||||
if (m_mouse_pressed_state) {
|
||||
done = (*svc)->mouse_click_event (p, m_mouse_buttons, false);
|
||||
done = (*svc)->mouse_click_event (p, effective_buttons, false);
|
||||
} else {
|
||||
done = (*svc)->mouse_release_event (p, m_mouse_buttons, false);
|
||||
done = (*svc)->mouse_release_event (p, effective_buttons, false);
|
||||
}
|
||||
}
|
||||
svc = next;
|
||||
@@ -952,9 +956,9 @@ ViewObjectUI::send_mouse_release_event (const db::DPoint &pt, unsigned int /*but
|
||||
|
||||
if (! done) {
|
||||
if (m_mouse_pressed_state) {
|
||||
mouse_click_event (p, m_mouse_buttons);
|
||||
mouse_click_event (p, effective_buttons);
|
||||
} else {
|
||||
mouse_release_event (p, m_mouse_buttons);
|
||||
mouse_release_event (p, effective_buttons);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -548,12 +548,14 @@ private:
|
||||
* @brief Describes the button state (supposed to be ored)
|
||||
*/
|
||||
enum ButtonState {
|
||||
ShiftButton = 1,
|
||||
ControlButton = 2,
|
||||
AltButton = 4,
|
||||
LeftButton = 8,
|
||||
MidButton = 16,
|
||||
RightButton = 32
|
||||
ShiftButton = 0x01,
|
||||
ControlButton = 0x02,
|
||||
AltButton = 0x04,
|
||||
ModifierMask = 0x07, // all keyboard modifiers
|
||||
LeftButton = 0x08,
|
||||
MidButton = 0x10,
|
||||
RightButton = 0x20,
|
||||
MouseButtonMask = 0x38 // all mouse buttons
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -91,6 +91,7 @@ static const std::string cfg_crosshair_cursor_enabled ("crosshair-cursor-enabled
|
||||
static const std::string cfg_markers_visible ("markers-visible");
|
||||
|
||||
static const std::string cfg_min_inst_label_size ("min-inst-label-size");
|
||||
static const std::string cfg_empty_cell_dimension ("empty-cell-dimension");
|
||||
static const std::string cfg_cell_box_text_font ("inst-label-font");
|
||||
static const std::string cfg_cell_box_text_transform ("inst-label-transform");
|
||||
static const std::string cfg_cell_box_color ("inst-color");
|
||||
|
||||
Reference in New Issue
Block a user