Merge branch 'master' into issue-2224

This commit is contained in:
Matthias Koefferlein
2025-12-07 22:30:37 +01:00
30 changed files with 743 additions and 469 deletions
+4
View File
@@ -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") +
+51 -25
View File
@@ -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"
) +
-28
View File
@@ -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 ();
-9
View File
@@ -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
*
+30 -22
View File
@@ -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 &region, 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 &region, 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 &region_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 &region_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 &region_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 &region_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)) {
+6 -6
View File
@@ -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 &region, 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 &region, 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 &region_mu);
bool find (LayoutViewBase *view, const db::DBox &region_mu);
bool find (lay::LayoutViewBase *view, const lay::LayerProperties &lprops, const db::DBox &region_mu);
bool find (lay::LayoutViewBase *view, const db::DBox &region_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 &region_mu);
const std::set<lay::ObjectInstPath> *mp_excludes;
+20 -3
View File
@@ -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) {
+88 -2
View File
@@ -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 &parameter = 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 &parameter () 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"));
+148 -98
View File
@@ -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;
+3 -5
View File
@@ -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) {
-1
View File
@@ -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;
+13 -9
View File
@@ -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);
}
}
+8 -6
View File
@@ -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
};
/**
+1
View File
@@ -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");