mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into issue-2224
This commit is contained in:
commit
1e8321d8fb
|
|
@ -49,7 +49,7 @@ jobs:
|
|||
- uses: hmarr/debug-action@v3
|
||||
- name: Cancel Workflow Action
|
||||
uses: styfle/cancel-workflow-action@0.12.1
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- name: ccache
|
||||
if: matrix.os != 'ubuntu-24.04-arm'
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
|
@ -66,7 +66,7 @@ jobs:
|
|||
mkdir -p $HOST_CCACHE_DIR
|
||||
- name: Build wheels (ARM)
|
||||
if: matrix.os == 'ubuntu-24.04-arm'
|
||||
uses: pypa/cibuildwheel@v3.2.1
|
||||
uses: pypa/cibuildwheel@v3.3.0
|
||||
env:
|
||||
# override the default CentOS “yum install … ccache” and drop ccache
|
||||
CIBW_BEFORE_ALL_LINUX: |
|
||||
|
|
@ -81,7 +81,7 @@ jobs:
|
|||
|
||||
- name: Build wheels (all other platforms)
|
||||
if: matrix.os != 'ubuntu-24.04-arm'
|
||||
uses: pypa/cibuildwheel@v3.2.1
|
||||
uses: pypa/cibuildwheel@v3.3.0
|
||||
env:
|
||||
CIBW_BUILD: ${{ matrix.cibuild }}
|
||||
CIBW_ARCHS_MACOS: ${{ matrix.macos-arch }}
|
||||
|
|
@ -98,7 +98,7 @@ jobs:
|
|||
mv ./wheelhouse/.ccache $HOST_CCACHE_DIR
|
||||
ls -la $HOST_CCACHE_DIR
|
||||
ccache -s
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: artifact-${{ matrix.os }}-${{ matrix.cibw_arch }}-${{ strategy.job-index }}
|
||||
path: ./wheelhouse/*.whl
|
||||
|
|
@ -108,12 +108,12 @@ jobs:
|
|||
name: Make SDist
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Build SDist
|
||||
run: pipx run build --sdist
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: artifact-sdist
|
||||
path: dist/*.tar.gz
|
||||
|
|
@ -122,7 +122,7 @@ jobs:
|
|||
needs: [build, make_sdist]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/download-artifact@v5
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
merge-multiple: true
|
||||
path: dist
|
||||
|
|
@ -139,7 +139,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'release' && github.event.action == 'published'
|
||||
steps:
|
||||
- uses: actions/download-artifact@v5
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
merge-multiple: true
|
||||
path: dist
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Cleanup
|
||||
run: |
|
||||
|
|
|
|||
15
COPYRIGHT
15
COPYRIGHT
|
|
@ -7,18 +7,19 @@ Authors:
|
|||
Copyright:
|
||||
Copyright (C) 2006-2025 by Matthias Köfferlein.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 or 3 of the License.
|
||||
This program is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this package; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
along with this program. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
On Debian GNU/Linux systems, the complete text of the GNU General
|
||||
Public License can be found in `/usr/share/common-licenses/GPL'.
|
||||
|
|
|
|||
|
|
@ -762,9 +762,9 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, co
|
|||
{
|
||||
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 ();
|
||||
|
||||
|
|
@ -897,9 +897,9 @@ PartialShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, co
|
|||
|
||||
} 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 (hit_box))) {
|
||||
if (layers ().size () == 1 || (layers ().size () > 1 && cell.bbox (*l).touches (hit_box))) {
|
||||
|
||||
checkpoint ();
|
||||
|
||||
|
|
@ -2315,8 +2315,8 @@ PartialService::mouse_release_event (const db::DPoint &p, unsigned int buttons,
|
|||
if (ui ()->mouse_event_viewport ().contains (p)) {
|
||||
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -328,6 +328,12 @@ set_menu_items_hidden (lay::MainWindow *mw, const std::map<std::string, bool> &h
|
|||
mw->dispatcher ()->config_set (lay::cfg_menu_items_hidden, lay::pack_menu_items_hidden (hv));
|
||||
}
|
||||
|
||||
static void
|
||||
clear_message (lay::MainWindow *mw, int priority)
|
||||
{
|
||||
mw->message (std::string (), 0, priority);
|
||||
}
|
||||
|
||||
Class<lay::MainWindow> decl_MainWindow (QT_EXTERNAL_BASE (QMainWindow) "lay", "MainWindow",
|
||||
|
||||
// Dispatcher interface and convenience functions
|
||||
|
|
@ -475,15 +481,36 @@ Class<lay::MainWindow> decl_MainWindow (QT_EXTERNAL_BASE (QMainWindow) "lay", "M
|
|||
"\n"
|
||||
"This method has been added in version 0.24."
|
||||
) +
|
||||
gsi::method ("message", &lay::MainWindow::message, gsi::arg ("message"), gsi::arg ("time", -1, "infinite"),
|
||||
gsi::method_ext ("clear_message", &clear_message, gsi::arg ("priority", -1, "all priorities"),
|
||||
"@brief Clears the message\n"
|
||||
"When calling this method with a priority, it will clear the message in the given priority slot, thus "
|
||||
"unhiding the messages with lower priority. This is equivalent to calling \\message with an empty string.\n"
|
||||
"\n"
|
||||
"When calling without a priority, all messages in all priority slots will be cleared.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.30.6."
|
||||
) +
|
||||
gsi::method ("message", &lay::MainWindow::message, gsi::arg ("message"), gsi::arg ("time", -1, "infinite"), gsi::arg ("priority", 0),
|
||||
"@brief Displays a message in the status bar\n"
|
||||
"\n"
|
||||
"@param message The message to display\n"
|
||||
"@param time The time how long to display the message in ms. A negative value means 'infinitely'.\n"
|
||||
"@param priority The priority of the message. Higher-priority messages have precendence over lower-priority ones.\n"
|
||||
"\n"
|
||||
"This given message is shown in the status bar for the given time.\n"
|
||||
"If a priority is given, higher-priority messages have precedence over lower-priority ones.\n"
|
||||
"Placing an empty message clears a message with a given priority and unhides messages with lower "
|
||||
"priority. Standard messages like selection descriptions have priority 0, which is the lowest priority.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.18. The 'time' parameter was made optional in version 0.28.10."
|
||||
"Messages generated during modal actions (e.g. 'Click on first point') by convention should have priority 10 "
|
||||
"and should be tied to the active state of a plugin. This ensures there is only one such message.\n"
|
||||
"Higher-priority messages must be cleared (set to empty string) explicitly to unhide lower-priority messages "
|
||||
"when the indicated action is finished.\n"
|
||||
"\n"
|
||||
"\\clear_message is a convenience method that will clear messages.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.18. The 'time' parameter was made optional in version 0.28.10.\n"
|
||||
"The 'priority' argument has been added in version 0.30.6."
|
||||
) +
|
||||
gsi::method ("resize", (void (lay::MainWindow::*)(int, int)) &lay::MainWindow::resize, gsi::arg ("width"), gsi::arg ("height"),
|
||||
"@brief Resizes the window\n"
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ MainWindow::MainWindow (QApplication *app, const char *name, bool undo_enabled)
|
|||
m_synchronous (false),
|
||||
m_busy (false),
|
||||
mp_app (app),
|
||||
m_message_timer_priority (-1),
|
||||
m_manager (undo_enabled)
|
||||
{
|
||||
setAnimated (false);
|
||||
|
|
@ -823,10 +824,15 @@ static int fm_width (const QFontMetrics &fm, const QString &s)
|
|||
void
|
||||
MainWindow::format_message ()
|
||||
{
|
||||
std::string msg;
|
||||
if (! m_messages.empty ()) {
|
||||
msg = (--m_messages.end ())->second;
|
||||
}
|
||||
|
||||
QFontMetrics fm (mp_msg_label->font ());
|
||||
|
||||
std::string full_message;
|
||||
for (const char *c = m_message.c_str (); *c; ++c) {
|
||||
for (const char *c = msg.c_str (); *c; ++c) {
|
||||
if (*c == '\\' && (c[1] == '(' || c[1] == ')')) {
|
||||
++c;
|
||||
} else {
|
||||
|
|
@ -847,7 +853,7 @@ MainWindow::format_message ()
|
|||
|
||||
short_message.clear ();
|
||||
|
||||
for (const char *c = m_message.c_str (); *c; ++c) {
|
||||
for (const char *c = msg.c_str (); *c; ++c) {
|
||||
if (*c == '\\' && c[1] == '(') {
|
||||
if (nsection++ < ndrop) {
|
||||
in_drop = true;
|
||||
|
|
@ -875,24 +881,53 @@ MainWindow::format_message ()
|
|||
}
|
||||
|
||||
void
|
||||
MainWindow::message (const std::string &s, int ms)
|
||||
MainWindow::message (const std::string &s, int ms, int priority)
|
||||
{
|
||||
m_message = s;
|
||||
if (s.empty () && priority < 0) {
|
||||
|
||||
m_messages.clear ();
|
||||
|
||||
} else if (s.empty ()) {
|
||||
|
||||
m_messages.erase (priority);
|
||||
|
||||
} else {
|
||||
|
||||
// simulate timeout of previous message timer
|
||||
if (m_message_timer_priority >= 0) {
|
||||
m_messages.erase (m_message_timer_priority);
|
||||
}
|
||||
|
||||
m_messages[priority] = s;
|
||||
|
||||
if (ms >= 0) {
|
||||
m_message_timer_priority = priority;
|
||||
m_message_timer.start (ms);
|
||||
} else {
|
||||
m_message_timer_priority = -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
format_message ();
|
||||
m_message_timer.start (ms);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::clear_message ()
|
||||
MainWindow::clear_messages ()
|
||||
{
|
||||
m_message.clear ();
|
||||
m_message_timer.start (0);
|
||||
m_message_timer.stop ();
|
||||
m_message_timer_priority = -1;
|
||||
m_messages.clear ();
|
||||
format_message ();
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::message_timer ()
|
||||
{
|
||||
m_message.clear ();
|
||||
if (m_message_timer_priority >= 0) {
|
||||
m_messages.erase (m_message_timer_priority);
|
||||
}
|
||||
m_message_timer_priority = -1;
|
||||
format_message ();
|
||||
}
|
||||
|
||||
|
|
@ -2277,6 +2312,29 @@ MainWindow::cm_save_as ()
|
|||
do_save (true);
|
||||
}
|
||||
|
||||
static db::SaveLayoutOptions
|
||||
get_save_options_from_cv (const lay::CellView &cv)
|
||||
{
|
||||
db::SaveLayoutOptions options = cv->save_options ();
|
||||
if (!cv->save_options_valid () && cv->technology ()) {
|
||||
options = cv->technology ()->save_layout_options ();
|
||||
options.set_format (cv->save_options ().format ());
|
||||
}
|
||||
|
||||
// preconfigure options with current values
|
||||
|
||||
options.set_dbu (cv->layout ().dbu ());
|
||||
|
||||
if (cv->layout ().has_meta_info ("libname")) {
|
||||
tl::Variant libname = cv->layout ().meta_info ("libname").value;
|
||||
if (libname.is_a_string ()) {
|
||||
options.set_libname (libname.to_stdstring ());
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::do_save (bool as)
|
||||
{
|
||||
|
|
@ -2309,22 +2367,7 @@ MainWindow::do_save (bool as)
|
|||
// - if the layout's save options are valid we take the options from there, otherwise we take the options from the technology
|
||||
// - on "save as" we let the user edit the options
|
||||
|
||||
db::SaveLayoutOptions options = cv->save_options ();
|
||||
if (!cv->save_options_valid () && cv->technology ()) {
|
||||
options = cv->technology ()->save_layout_options ();
|
||||
options.set_format (cv->save_options ().format ());
|
||||
}
|
||||
|
||||
// preconfigure options with current values
|
||||
|
||||
options.set_dbu (cv->layout ().dbu ());
|
||||
|
||||
if (cv->layout ().has_meta_info ("libname")) {
|
||||
tl::Variant libname = cv->layout ().meta_info ("libname").value;
|
||||
if (libname.is_a_string ()) {
|
||||
options.set_libname (libname.to_stdstring ());
|
||||
}
|
||||
}
|
||||
db::SaveLayoutOptions options = get_save_options_from_cv (cv);
|
||||
|
||||
if (as || options.format ().empty ()) {
|
||||
options.set_format_from_filename (fn);
|
||||
|
|
@ -2337,7 +2380,18 @@ MainWindow::do_save (bool as)
|
|||
}
|
||||
|
||||
current_view ()->save_as ((unsigned int) cv_index, fn, om, options, true, m_keep_backups);
|
||||
add_mru (fn, current_view ()->cellview (cv_index)->tech_name ());
|
||||
add_mru (fn, cv->tech_name ());
|
||||
|
||||
if (as) {
|
||||
|
||||
lay::LayoutViewNotification n ("reload", tl::to_string (tr ("The next 'save' operations will use the writer options you have picked, instead of the application-wide ones.")));
|
||||
current_view ()->add_notification (n);
|
||||
|
||||
// freeze writer options in the 'save_as' case, so we can do another "save" and get the
|
||||
// selected options again
|
||||
cv->set_save_options (options, true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -2362,8 +2416,7 @@ MainWindow::cm_save_all ()
|
|||
|
||||
if (! fn.empty () || mp_layout_fdia->get_save (fn, tl::to_string (tr ("Save Layout '%1'").arg (tl::to_qstring (cv->name ()))))) {
|
||||
|
||||
db::SaveLayoutOptions options (cv->save_options ());
|
||||
options.set_dbu (cv->layout ().dbu ());
|
||||
db::SaveLayoutOptions options = get_save_options_from_cv (cv);
|
||||
|
||||
if (options.format ().empty ()) {
|
||||
options.set_format_from_filename (fn);
|
||||
|
|
@ -2371,14 +2424,6 @@ MainWindow::cm_save_all ()
|
|||
|
||||
tl::OutputStream::OutputStreamMode om = tl::OutputStream::OM_Auto;
|
||||
|
||||
// initialize the specific options from the configuration if required
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
const StreamWriterPluginDeclaration *decl = dynamic_cast <const StreamWriterPluginDeclaration *> (&*cls);
|
||||
if (decl) {
|
||||
options.set_options (decl->create_specific_options ());
|
||||
}
|
||||
}
|
||||
|
||||
view (view_index)->save_as (cv_index, fn, om, options, true, m_keep_backups);
|
||||
add_mru (fn, cv->tech_name ());
|
||||
|
||||
|
|
@ -2457,7 +2502,7 @@ MainWindow::select_view (int index)
|
|||
update_editor_options_dock ();
|
||||
clear_current_pos ();
|
||||
edits_enabled_changed ();
|
||||
clear_message ();
|
||||
clear_messages ();
|
||||
menu_needs_update ();
|
||||
|
||||
m_disable_tab_selected = dis;
|
||||
|
|
@ -2984,7 +3029,7 @@ MainWindow::close_view (int index)
|
|||
clear_current_pos ();
|
||||
edits_enabled_changed ();
|
||||
menu_needs_update ();
|
||||
clear_message ();
|
||||
clear_messages ();
|
||||
|
||||
update_dock_widget_state ();
|
||||
|
||||
|
|
@ -3469,7 +3514,7 @@ MainWindow::add_view (lay::LayoutViewWidget *view)
|
|||
connect (view, SIGNAL (dirty_changed (lay::LayoutView *)), this, SLOT (view_title_changed (lay::LayoutView *)));
|
||||
connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ()));
|
||||
connect (view, SIGNAL (menu_needs_update ()), this, SLOT (menu_needs_update ()));
|
||||
connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int)));
|
||||
connect (view, SIGNAL (show_message (const std::string &, int, int)), this, SLOT (message (const std::string &, int, int)));
|
||||
connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool)));
|
||||
connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ()));
|
||||
connect (view, SIGNAL (mode_change (int)), this, SLOT (select_mode (int)));
|
||||
|
|
|
|||
|
|
@ -649,12 +649,12 @@ public slots:
|
|||
/**
|
||||
* @brief Displays a status message next to the coordinates
|
||||
*/
|
||||
void message (const std::string &s, int ms);
|
||||
void message (const std::string &s, int ms, int);
|
||||
|
||||
/**
|
||||
* @brief Clears the current message
|
||||
*/
|
||||
void clear_message ();
|
||||
void clear_messages ();
|
||||
|
||||
/**
|
||||
* @brief Selects the given mode
|
||||
|
|
@ -789,7 +789,8 @@ private:
|
|||
QApplication *mp_app;
|
||||
lay::HelpDialog *mp_assistant;
|
||||
std::string m_current_session;
|
||||
std::string m_message;
|
||||
int m_message_timer_priority;
|
||||
std::map<int, std::string> m_messages;
|
||||
std::unique_ptr<QPrinter> mp_printer;
|
||||
std::vector<QString> m_changed_files;
|
||||
std::string m_title;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>656</width>
|
||||
<height>397</height>
|
||||
<height>451</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -49,85 +49,14 @@
|
|||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QFrame" name="frame_3">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="textLabel1_3">
|
||||
<property name="text">
|
||||
<string>Label font</string>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cell_font_cb"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>141</width>
|
||||
<height>21</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="lay::ColorButton" name="cell_box_color_pb">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
|
|
@ -190,6 +119,20 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="textLabel3">
|
||||
<property name="text">
|
||||
<string>Cell box color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="cell_xform_text_cbx">
|
||||
<property name="text">
|
||||
<string>Transform text with cell instance (not available for "Default" font)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="textLabel1_2_2">
|
||||
<property name="text">
|
||||
|
|
@ -197,21 +140,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="textLabel1_3">
|
||||
<property name="text">
|
||||
<string>Label font</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="textLabel3">
|
||||
<property name="text">
|
||||
<string>Cell box color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<item row="4" column="0" colspan="2">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
|
@ -227,10 +156,139 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="cell_xform_text_cbx">
|
||||
<item row="3" column="1">
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="lay::ColorButton" name="cell_box_color_pb">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QFrame" name="frame_3">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cell_font_cb"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>141</width>
|
||||
<height>21</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QFrame" name="frame_4">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="empty_cell_dimension">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>µm (for label scaling)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>159</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Transform text with cell instance (not available for "Default" font)</string>
|
||||
<string>Empty cell virtual size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -227,6 +227,10 @@ LayoutViewConfigPage2a::setup (lay::Dispatcher *root)
|
|||
root->config_get (cfg_min_inst_label_size, n);
|
||||
mp_ui->cell_min_size_for_label_edit->setText (tl::to_qstring (tl::to_string (n)));
|
||||
|
||||
double ecd = 0;
|
||||
root->config_get (cfg_empty_cell_dimension, ecd);
|
||||
mp_ui->empty_cell_dimension->setText (tl::to_qstring (tl::to_string (ecd)));
|
||||
|
||||
bool gs_visible = true;
|
||||
root->config_get (cfg_guiding_shape_visible, gs_visible);
|
||||
mp_ui->pcell_gs_group->setChecked (gs_visible);
|
||||
|
|
@ -263,6 +267,12 @@ LayoutViewConfigPage2a::commit (lay::Dispatcher *root)
|
|||
tl::from_string_ext (tl::to_string (mp_ui->cell_min_size_for_label_edit->text ()), n);
|
||||
root->config_set (cfg_min_inst_label_size, n);
|
||||
} catch (...) { }
|
||||
|
||||
try {
|
||||
double ecd;
|
||||
tl::from_string_ext (tl::to_string (mp_ui->empty_cell_dimension->text ()), ecd);
|
||||
root->config_set (cfg_empty_cell_dimension, ecd);
|
||||
} catch (...) { }
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -453,6 +453,14 @@ LayoutView::LayoutView (lay::LayoutView *source, db::Manager *manager, bool edit
|
|||
LayoutView::set_active_cellview_index (source->active_cellview_index ());
|
||||
}
|
||||
|
||||
void
|
||||
LayoutView::add_notification (const LayoutViewNotification ¬ification)
|
||||
{
|
||||
if (mp_widget) {
|
||||
mp_widget->add_notification (notification);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
LayoutView::event_filter (QObject *obj, QEvent *event, bool &taken)
|
||||
{
|
||||
|
|
@ -1577,10 +1585,10 @@ LayoutView::signal_selection_changed ()
|
|||
}
|
||||
|
||||
void
|
||||
LayoutView::message (const std::string &s, int timeout)
|
||||
LayoutView::message (const std::string &s, int timeout, int priority)
|
||||
{
|
||||
if (mp_widget) {
|
||||
mp_widget->emit_show_message (s, timeout * 1000);
|
||||
mp_widget->emit_show_message (s, timeout * 1000, priority);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
#
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
|
|
@ -149,6 +149,11 @@ public:
|
|||
*/
|
||||
~LayoutView ();
|
||||
|
||||
/**
|
||||
* @brief Adds a notification
|
||||
*/
|
||||
virtual void add_notification (const LayoutViewNotification ¬ification);
|
||||
|
||||
/**
|
||||
* @brief Gets the widget object that view is embedded in
|
||||
*/
|
||||
|
|
@ -182,7 +187,7 @@ public:
|
|||
/**
|
||||
* @brief Displays a status message
|
||||
*/
|
||||
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
|
||||
|
|
@ -695,70 +700,6 @@ private:
|
|||
void activate_editor_option_pages ();
|
||||
};
|
||||
|
||||
/**
|
||||
* @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 LAYVIEW_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 A widget representing a notification
|
||||
*/
|
||||
|
|
@ -810,12 +751,12 @@ public:
|
|||
/**
|
||||
* @brief Adds a notification
|
||||
*/
|
||||
void add_notification (const LayoutViewNotification ¬ificaton);
|
||||
void add_notification (const LayoutViewNotification ¬ification);
|
||||
|
||||
/**
|
||||
* @brief Removes a notification
|
||||
*/
|
||||
void remove_notification (const LayoutViewNotification ¬ificaton);
|
||||
void remove_notification (const LayoutViewNotification ¬ification);
|
||||
|
||||
/**
|
||||
* @brief Gets the LayoutView embedded into this widget
|
||||
|
|
@ -832,7 +773,7 @@ public:
|
|||
|
||||
void emit_title_changed (lay::LayoutView *view) { emit title_changed (view); }
|
||||
void emit_dirty_changed (lay::LayoutView *view) { emit dirty_changed (view); }
|
||||
void emit_show_message (const std::string &s, int ms) { emit show_message (s, ms); }
|
||||
void emit_show_message (const std::string &s, int ms, int priority) { emit show_message (s, ms, priority); }
|
||||
void emit_current_pos_changed (double x, double y, bool dbu_units) { emit current_pos_changed (x, y, dbu_units); }
|
||||
void emit_clear_current_pos () { emit clear_current_pos (); }
|
||||
void emit_edits_enabled_changed () { emit edits_enabled_changed (); }
|
||||
|
|
@ -885,7 +826,7 @@ signals:
|
|||
/**
|
||||
* @brief This signal is emitted when the view wants to show a message for the given time (of infinitely for ms == 0)
|
||||
*/
|
||||
void show_message (const std::string &s, int ms);
|
||||
void show_message (const std::string &s, int ms, int priority);
|
||||
|
||||
/**
|
||||
* @brief This signal is emitted when the view wants to indicate a mouse position change
|
||||
|
|
|
|||
|
|
@ -337,6 +337,16 @@ NetTracerData::requires_booleans (unsigned int from_layer) const
|
|||
return r->second;
|
||||
}
|
||||
|
||||
std::set<unsigned int>
|
||||
NetTracerData::original_layers () const
|
||||
{
|
||||
std::set<unsigned int> ol;
|
||||
for (std::map <unsigned int, std::set <unsigned int> >::const_iterator g = m_original_layers.begin (); g != m_original_layers.end (); ++g) {
|
||||
ol.insert (g->second.begin (), g->second.end ());
|
||||
}
|
||||
return ol;
|
||||
}
|
||||
|
||||
void
|
||||
NetTracerData::clean_l2n_regions ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -626,6 +626,13 @@ public:
|
|||
*/
|
||||
void configure_l2n (db::LayoutToNetlist &l2n);
|
||||
|
||||
/**
|
||||
* @brief Gets the original layers
|
||||
*
|
||||
* These are the layer indexes used for computing the net tracer functions
|
||||
*/
|
||||
std::set<unsigned int> original_layers () const;
|
||||
|
||||
private:
|
||||
unsigned int m_next_log_layer;
|
||||
std::vector <NetTracerConnection> m_connections;
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ NetTracerDialog::drag_cancel ()
|
|||
{
|
||||
if (m_mouse_state > 0) {
|
||||
|
||||
view ()->message ();
|
||||
view ()->message (std::string (), 0, 10);
|
||||
ui ()->ungrab_mouse (this);
|
||||
set_cursor (lay::Cursor::none);
|
||||
|
||||
|
|
@ -241,7 +241,7 @@ NetTracerDialog::mouse_click_event (const db::DPoint &p, unsigned int buttons, b
|
|||
m_mouse_first_point = p;
|
||||
m_mouse_state = 3;
|
||||
|
||||
view ()->message (tl::to_string (QObject::tr ("Click on the second point in the net")));
|
||||
view ()->message (tl::to_string (QObject::tr ("Click on the second point in the net")), -1 /*infinitely*/, 10);
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -414,9 +414,24 @@ NetTracerDialog::get_net_tracer_setup (const lay::CellView &cv, db::NetTracerDat
|
|||
db::NetTracerNet *
|
||||
NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &stop_search_box, bool trace_path)
|
||||
{
|
||||
// determine the cellview
|
||||
lay::CellView cv = view ()->cellview (m_cv_index);
|
||||
if (! cv.is_valid ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set up the net tracer environment
|
||||
db::NetTracerData tracer_data;
|
||||
if (! get_net_tracer_setup (cv, tracer_data)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::set<unsigned int> original_layers = tracer_data.original_layers ();
|
||||
|
||||
unsigned int start_layer = 0;
|
||||
db::Point start_point;
|
||||
db::Shape start_shape;
|
||||
db::ICplxTrans start_trans;
|
||||
|
||||
// locate the seed
|
||||
{
|
||||
|
|
@ -426,7 +441,7 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
|
|||
|
||||
// go through all visible layers of all cellviews and find a seed shape
|
||||
for (lay::LayerPropertiesConstIterator lprop = view ()->begin_layers (); ! lprop.at_end (); ++lprop) {
|
||||
if (lprop->is_visual ()) {
|
||||
if (lprop->is_visual () && lprop->cellview_index () == m_cv_index && original_layers.find ((unsigned int) lprop->layer_index ()) != original_layers.end ()) {
|
||||
finder.find (view (), *lprop, start_search_box);
|
||||
}
|
||||
}
|
||||
|
|
@ -440,15 +455,10 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
|
|||
m_cv_index = r->cv_index ();
|
||||
start_shape = r->shape ();
|
||||
start_layer = r->layer ();
|
||||
start_trans = r->trans ();
|
||||
|
||||
}
|
||||
|
||||
// determine the cellview
|
||||
lay::CellView cv = view ()->cellview (m_cv_index);
|
||||
if (! cv.is_valid ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// determine the start point
|
||||
{
|
||||
|
||||
|
|
@ -463,20 +473,15 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
|
|||
|
||||
// stop if the center start point is not inside the start polygon
|
||||
db::Polygon poly;
|
||||
if (start_shape.polygon (poly) && db::inside_poly (poly.begin_edge (), start_point) < 0) {
|
||||
if (start_shape.polygon (poly) && db::inside_poly (poly.begin_edge (), start_trans.inverted () * start_point) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Set up the net tracer environment
|
||||
db::NetTracerData tracer_data;
|
||||
if (! get_net_tracer_setup (cv, tracer_data)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int stop_layer = 0;
|
||||
db::Point stop_point;
|
||||
db::ICplxTrans stop_trans;
|
||||
|
||||
// locate the stop shape (the second mouse click)
|
||||
if (trace_path) {
|
||||
|
|
@ -486,7 +491,7 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
|
|||
|
||||
// go through all visible layers of all cellviews and find a seed shape
|
||||
for (lay::LayerPropertiesConstIterator lprop = view ()->begin_layers (); ! lprop.at_end (); ++lprop) {
|
||||
if (lprop->is_visual ()) {
|
||||
if (lprop->is_visual () && lprop->cellview_index () == m_cv_index && original_layers.find ((unsigned int) lprop->layer_index ()) != original_layers.end ()) {
|
||||
finder.find (view (), *lprop, stop_search_box);
|
||||
}
|
||||
}
|
||||
|
|
@ -510,10 +515,11 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
|
|||
|
||||
stop_point = tt.inverted ().trans (stop_search_box.center ());
|
||||
stop_layer = r->layer ();
|
||||
stop_trans = r->trans ();
|
||||
|
||||
// stop if the center stop point is not inside the stop polygon
|
||||
db::Polygon poly;
|
||||
if (r->shape ().polygon (poly) && db::inside_poly (poly.begin_edge (), stop_point) < 0) {
|
||||
if (r->shape ().polygon (poly) && db::inside_poly (poly.begin_edge (), stop_trans.inverted () * stop_point) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1258,7 +1264,7 @@ BEGIN_PROTECTED
|
|||
commit ();
|
||||
net_list->setCurrentItem (0);
|
||||
m_mouse_state = 2;
|
||||
view ()->message (tl::to_string (QObject::tr ("Click on the first point in the net")));
|
||||
view ()->message (tl::to_string (QObject::tr ("Click on the first point in the net")), -1 /*infinitely*/, 10);
|
||||
ui ()->grab_mouse (this, false);
|
||||
END_PROTECTED
|
||||
}
|
||||
|
|
@ -1270,7 +1276,7 @@ BEGIN_PROTECTED
|
|||
commit ();
|
||||
net_list->setCurrentItem (0);
|
||||
m_mouse_state = 1;
|
||||
view ()->message (tl::to_string (QObject::tr ("Click on a point in the net")));
|
||||
view ()->message (tl::to_string (QObject::tr ("Click on a point in the net")), -1 /*infinitely*/, 10);
|
||||
ui ()->grab_mouse (this, false);
|
||||
END_PROTECTED
|
||||
}
|
||||
|
|
@ -1293,7 +1299,7 @@ NetTracerDialog::release_mouse ()
|
|||
add_pb->setChecked (false);
|
||||
add2_pb->setChecked (false);
|
||||
m_mouse_state = 0;
|
||||
view ()->message ();
|
||||
view ()->message (std::string (), 0, 10);
|
||||
ui ()->ungrab_mouse (this);
|
||||
set_cursor (lay::Cursor::none);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue