diff --git a/src/gui/include/gui/gui.h b/src/gui/include/gui/gui.h index 1303654923b..9e29d22429d 100644 --- a/src/gui/include/gui/gui.h +++ b/src/gui/include/gui/gui.h @@ -744,6 +744,8 @@ class Gui // Zoom to the given rectangle void zoomTo(const odb::Rect& rect_dbu); + // zoom to the specified point + void zoomTo(const odb::Point& focus, int diameter); void zoomIn(); void zoomIn(const odb::Point& focus_dbu); void zoomOut(); diff --git a/src/gui/src/gotoDialog.cpp b/src/gui/src/gotoDialog.cpp index 74848c86730..c547e499046 100644 --- a/src/gui/src/gotoDialog.cpp +++ b/src/gui/src/gotoDialog.cpp @@ -16,65 +16,50 @@ GotoLocationDialog::GotoLocationDialog(QWidget* parent, LayoutTabs* viewers) : QDialog(parent), viewers_(viewers) { setupUi(this); -} - -void GotoLocationDialog::updateUnits(int dbu_per_micron, bool use_dbu) -{ - if (use_dbu) { - xEdit->setText(QString::number(xEdit->text().toDouble() * dbu_per_micron)); - yEdit->setText(QString::number(yEdit->text().toDouble() * dbu_per_micron)); - sEdit->setText(QString::number(sEdit->text().toDouble() * dbu_per_micron)); - } else { - xEdit->setText(QString::number(xEdit->text().toDouble() / dbu_per_micron)); - yEdit->setText(QString::number(yEdit->text().toDouble() / dbu_per_micron)); - sEdit->setText(QString::number(sEdit->text().toDouble() / dbu_per_micron)); - } + connect(gotoBtn, &QPushButton::clicked, this, &GotoLocationDialog::goTo); } // NOLINTNEXTLINE(readability-non-const-parameter) -void GotoLocationDialog::updateLocation(QLineEdit* x_edit, QLineEdit* y_edit) +void GotoLocationDialog::updateLocation() { auto viewer = viewers_->getCurrent(); + if (!viewer) { + return; + } x_edit->setText(QString::fromStdString(Descriptor::Property::convert_dbu( viewer->getVisibleCenter().x(), false))); y_edit->setText(QString::fromStdString(Descriptor::Property::convert_dbu( viewer->getVisibleCenter().y(), false))); + int box_size = viewer->getVisibleDiameter(); + s_edit->setText(QString::fromStdString( + Descriptor::Property::convert_dbu(box_size, false))); } -void GotoLocationDialog::show_init() +void GotoLocationDialog::showInit() { - auto viewer = viewers_->getCurrent(); - GotoLocationDialog::updateLocation(xEdit, yEdit); - int box_size = sqrt(pow((viewer->getVisibleBounds().lr().x() - - viewer->getVisibleBounds().ll().x()), - 2) - + pow((viewer->getVisibleBounds().ul().y() - - viewer->getVisibleBounds().ll().y()), - 2)) - / 2; - sEdit->setText(QString::fromStdString( - Descriptor::Property::convert_dbu(box_size, false))); + updateLocation(); show(); } -void GotoLocationDialog::accept() +void GotoLocationDialog::goTo() { auto gui = gui::Gui::get(); bool convert_x_ok; bool convert_y_ok; bool convert_s_ok; int x_coord = Descriptor::Property::convert_string( - xEdit->text().toStdString(), &convert_x_ok); + x_edit->text().toStdString(), &convert_x_ok); int y_coord = Descriptor::Property::convert_string( - yEdit->text().toStdString(), &convert_y_ok); - int box_size = Descriptor::Property::convert_string( - sEdit->text().toStdString(), &convert_s_ok); + y_edit->text().toStdString(), &convert_y_ok); + int diameter = Descriptor::Property::convert_string( + s_edit->text().toStdString(), &convert_s_ok); if (convert_x_ok && convert_y_ok && convert_s_ok) { - gui->zoomTo(odb::Rect(x_coord - box_size, - y_coord - box_size, - x_coord + box_size, - y_coord + box_size)); + gui->zoomTo(odb::Point(x_coord, y_coord), diameter); } - GotoLocationDialog::updateLocation(xEdit, yEdit); + updateLocation(); +} + +void GotoLocationDialog::accept() +{ } } // namespace gui diff --git a/src/gui/src/gotoDialog.h b/src/gui/src/gotoDialog.h index 1d243deff5e..17c010c6ef7 100644 --- a/src/gui/src/gotoDialog.h +++ b/src/gui/src/gotoDialog.h @@ -19,9 +19,9 @@ class GotoLocationDialog : public QDialog, public Ui::GotoLocDialog public: GotoLocationDialog(QWidget* parent = nullptr, LayoutTabs* viewers = nullptr); public slots: - void updateLocation(QLineEdit* x_edit, QLineEdit* y_edit); - void updateUnits(int dbu_per_micron, bool use_dbu); - void show_init(); + void updateLocation(); + void showInit(); + void goTo(); void accept() override; }; } // namespace gui diff --git a/src/gui/src/gui.cpp b/src/gui/src/gui.cpp index a8f8fb485a9..dd8c1873d49 100644 --- a/src/gui/src/gui.cpp +++ b/src/gui/src/gui.cpp @@ -707,6 +707,11 @@ void Gui::zoomTo(const odb::Rect& rect_dbu) main_window->zoomTo(rect_dbu); } +void Gui::zoomTo(const odb::Point& focus, int diameter) +{ + main_window->zoomTo(focus, diameter); +} + void Gui::zoomIn() { main_window->getLayoutViewer()->zoomIn(); diff --git a/src/gui/src/layoutTabs.cpp b/src/gui/src/layoutTabs.cpp index 2f23540a792..f49578251d3 100644 --- a/src/gui/src/layoutTabs.cpp +++ b/src/gui/src/layoutTabs.cpp @@ -124,6 +124,7 @@ void LayoutTabs::chipLoaded(odb::dbChip* chip) &LayoutViewer::focusNetsChanged, this, &LayoutTabs::focusNetsChanged); + connect(viewer, &LayoutViewer::viewUpdated, this, &LayoutTabs::viewUpdated); emit newViewer(viewer); } @@ -177,6 +178,13 @@ void LayoutTabs::zoomTo(const odb::Rect& rect_dbu) } } +void LayoutTabs::zoomTo(const odb::Point& focus, int diameter) +{ + if (current_viewer_) { + current_viewer_->zoomTo(focus, diameter); + } +} + void LayoutTabs::fit() { if (current_viewer_) { diff --git a/src/gui/src/layoutTabs.h b/src/gui/src/layoutTabs.h index 4e81c381c25..a0422f29227 100644 --- a/src/gui/src/layoutTabs.h +++ b/src/gui/src/layoutTabs.h @@ -85,6 +85,7 @@ class LayoutTabs : public QTabWidget void focusNetsChanged(); void routeGuidesChanged(); void netTracksChanged(); + void viewUpdated(); public slots: void tabChange(int index); @@ -95,6 +96,7 @@ class LayoutTabs : public QTabWidget void zoomIn(); void zoomOut(); void zoomTo(const odb::Rect& rect_dbu); + void zoomTo(const odb::Point& focus, int diameter); void chipLoaded(odb::dbChip* chip); void fit(); void fullRepaint(); diff --git a/src/gui/src/layoutViewer.cpp b/src/gui/src/layoutViewer.cpp index 537b8345138..442d3a66fe3 100644 --- a/src/gui/src/layoutViewer.cpp +++ b/src/gui/src/layoutViewer.cpp @@ -251,7 +251,7 @@ qreal LayoutViewer::computePixelsPerDBU(const QSize& size, const Rect& dbu_rect) size.height() / (double) dbu_rect.dy()); } -void LayoutViewer::setPixelsPerDBU(qreal pixels_per_dbu) +void LayoutViewer::setPixelsPerDBU(qreal target_pixels_per_dbu) { if (!hasDesign()) { return; @@ -259,31 +259,27 @@ void LayoutViewer::setPixelsPerDBU(qreal pixels_per_dbu) bool scroll_bars_visible = scroller_->horizontalScrollBar()->isVisible() || scroller_->verticalScrollBar()->isVisible(); - bool zoomed_out = pixels_per_dbu_ /*old*/ > pixels_per_dbu /*new*/; + bool zoomed_out = pixels_per_dbu_ /*old*/ > target_pixels_per_dbu /*new*/; if (!scroll_bars_visible && zoomed_out) { return; } - const Rect current_viewer(0, - 0, - this->size().width() / pixels_per_dbu_, - this->size().height() / pixels_per_dbu_); + qreal current_viewer_x = this->size().width() / pixels_per_dbu_; + qreal current_viewer_y = this->size().height() / pixels_per_dbu_; // ensure max size is not exceeded qreal maximum_pixels_per_dbu = 0.98 * computePixelsPerDBU(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX), - current_viewer); - qreal target_pixels_per_dbu - = std::min(pixels_per_dbu, maximum_pixels_per_dbu); + Rect(0, 0, current_viewer_x, current_viewer_y)); - if (target_pixels_per_dbu == maximum_pixels_per_dbu) { + if (target_pixels_per_dbu >= maximum_pixels_per_dbu) { return; } - const QSize new_size(ceil(current_viewer.dx() * target_pixels_per_dbu), - ceil(current_viewer.dy() * target_pixels_per_dbu)); + const QSize new_size(ceil(current_viewer_x * target_pixels_per_dbu), + ceil(current_viewer_y * target_pixels_per_dbu)); resize(new_size); } @@ -421,17 +417,46 @@ void LayoutViewer::zoom(const odb::Point& focus, void LayoutViewer::zoomTo(const Rect& rect_dbu) { - const Rect padded_rect = getPaddedRect(rect_dbu); - - // set resolution required to view the whole padded rect - setPixelsPerDBU( - computePixelsPerDBU(scroller_->maximumViewportSize(), padded_rect)); + qreal pixels_per_DBU + = computePixelsPerDBU(scroller_->maximumViewportSize(), rect_dbu); + qreal pixels_per_DBU_with_margins + = pixels_per_DBU / (1 + 2 * defaultZoomMargin); + setPixelsPerDBU(pixels_per_DBU_with_margins); // center the layout at the middle of the rect centerAt(Point(rect_dbu.xMin() + rect_dbu.dx() / 2, rect_dbu.yMin() + rect_dbu.dy() / 2)); } +void LayoutViewer::zoomTo(const odb::Point& focus, int diameter) +{ + odb::Point ref + = odb::Point(focus.x() - (diameter / 2), focus.y() - (diameter / 2)); + zoomTo(odb::Rect(ref.x(), ref.y(), ref.x() + diameter, ref.y() + diameter)); +} + +int LayoutViewer::getVisibleDiameter() +{ + odb::Rect bounds = getVisibleBounds(); + // scrollbar + int scrollBarWidth + = std::ceil((qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent)) + / pixels_per_dbu_); + if (scroller_->verticalScrollBar()->isVisible()) { + bounds.set_xhi(bounds.xMax() + scrollBarWidth); + } + if (scroller_->horizontalScrollBar()->isVisible()) { + bounds.set_yhi(bounds.yMax() + scrollBarWidth); + } + + // undo the margin + const int smaller_side = std::min(bounds.dx(), bounds.dy()); + const int margin = std::ceil(smaller_side * 2 * defaultZoomMargin + / (1 + 2 * defaultZoomMargin)); + + return std::min(bounds.dx(), bounds.dy()) - margin; +} + int LayoutViewer::edgeToPointDistance(const odb::Point& pt, const Edge& edge) const { @@ -1986,6 +2011,8 @@ void LayoutViewer::fullRepaint() setLoadingState(); viewer_thread_.render(rect, selected_, highlighted_, rulers_, labels_); } + + emit(viewUpdated()); } void LayoutViewer::fit() diff --git a/src/gui/src/layoutViewer.h b/src/gui/src/layoutViewer.h index d42cb583f36..37ea60e46da 100644 --- a/src/gui/src/layoutViewer.h +++ b/src/gui/src/layoutViewer.h @@ -167,6 +167,9 @@ class LayoutViewer : public QWidget bool isCursorInsideViewport(); void updateCursorCoordinates(); + // gets the size of the diameter of the biggest circle that fits the view + int getVisibleDiameter(); + signals: // indicates the current location of the mouse void location(int x, int y); @@ -183,6 +186,8 @@ class LayoutViewer : public QWidget void focusNetsChanged(); + void viewUpdated(); + public slots: // zoom in the layout, keeping the current center_ void zoomIn(); @@ -205,6 +210,9 @@ class LayoutViewer : public QWidget // zoom to the specified rect void zoomTo(const odb::Rect& rect_dbu); + // zoom to the specified point + void zoomTo(const odb::Point& focus, int diameter); + // indicates a chip has been loaded void chipLoaded(odb::dbChip* chip); @@ -291,7 +299,8 @@ class LayoutViewer : public QWidget qreal computePixelsPerDBU(const QSize& size, const odb::Rect& dbu_rect); odb::Rect getBounds() const; - odb::Rect getPaddedRect(const odb::Rect& rect, double factor = 0.05); + odb::Rect getPaddedRect(const odb::Rect& rect, + double factor = defaultZoomMargin); bool hasDesign() const; int getDbuPerMicron() const; @@ -435,6 +444,7 @@ class LayoutViewer : public QWidget std::string loading_indicator_; static constexpr qreal kZoomScaleFactor = 1.2; + static constexpr double defaultZoomMargin = 0.05; // parameters used to animate the selection of objects static constexpr int kAnimationRepeats = 6; diff --git a/src/gui/src/mainWindow.cpp b/src/gui/src/mainWindow.cpp index 591ce031839..e6c238e11e7 100644 --- a/src/gui/src/mainWindow.cpp +++ b/src/gui/src/mainWindow.cpp @@ -45,6 +45,7 @@ #include "displayControls.h" #include "drcWidget.h" #include "globalConnectDialog.h" +#include "gotoDialog.h" #include "gui/gui.h" #include "gui/heatMap.h" #include "helpWidget.h" @@ -395,10 +396,10 @@ MainWindow::MainWindow(bool load_settings, QWidget* parent) drc_viewer_->updateSelection(*selected_.begin()); } }); - connect(this, - &MainWindow::displayUnitsChanged, + connect(viewers_, + &LayoutTabs::viewUpdated, goto_dialog_, - &GotoLocationDialog::updateUnits); + &GotoLocationDialog::updateLocation); connect(selection_timer_.get(), &QTimer::timeout, [this]() { emit selectionChanged(); }); @@ -1431,6 +1432,11 @@ void MainWindow::zoomTo(const odb::Rect& rect_dbu) viewers_->zoomTo(rect_dbu); } +void MainWindow::zoomTo(const odb::Point& focus, int diameter) +{ + viewers_->zoomTo(focus, diameter); +} + void MainWindow::zoomInToItems(const QList& items) { if (items.empty()) { @@ -1471,7 +1477,7 @@ void MainWindow::showGotoDialog() return; } - goto_dialog_->show_init(); + goto_dialog_->showInit(); } void MainWindow::showHelp() diff --git a/src/gui/src/mainWindow.h b/src/gui/src/mainWindow.h index 5a76d7df547..06a730da35e 100644 --- a/src/gui/src/mainWindow.h +++ b/src/gui/src/mainWindow.h @@ -227,6 +227,9 @@ class MainWindow : public QMainWindow, public odb::dbDatabaseObserver // Zoom to the given rectangle void zoomTo(const odb::Rect& rect_dbu); + // zoom to the specified point + void zoomTo(const odb::Point& focus, int diameter); + // Zoom In To Items such that its bbox is in visible Area void zoomInToItems(const QList& items); diff --git a/src/gui/ui/gotoDlg.ui b/src/gui/ui/gotoDlg.ui index e8f73771aae..11d48f97596 100644 --- a/src/gui/ui/gotoDlg.ui +++ b/src/gui/ui/gotoDlg.ui @@ -13,7 +13,7 @@ 0 0 150 - 100 + 120 @@ -69,7 +69,7 @@ 3 - + 3 @@ -105,12 +105,12 @@ - + X - xEdit + x_edit @@ -119,7 +119,7 @@ - + Qt::ImhDigitsOnly @@ -149,12 +149,12 @@ - + Y - yEdit + y_edit @@ -163,7 +163,7 @@ - + Qt::ImhDigitsOnly @@ -205,7 +205,7 @@ 0 - + Qt::LeftToRight @@ -219,7 +219,7 @@ Qt::AlignCenter - sEdit + s_edit @@ -240,12 +240,23 @@ 0 - + + + Qt::ImhDigitsOnly + + + + + + Go to + + + @@ -253,7 +264,7 @@ - xEdit + x_edit textEdited(QString) GotoLocDialog accept() @@ -269,7 +280,7 @@ - yEdit + y_edit textEdited(QString) GotoLocDialog accept() @@ -287,7 +298,7 @@ GotoLocDialog objectNameChanged(QString) - xEdit + x_edit setText(QString) @@ -303,7 +314,7 @@ GotoLocDialog objectNameChanged(QString) - yEdit + y_edit setText(QString) @@ -317,7 +328,7 @@ - sEdit + s_edit textEdited(QString) GotoLocDialog accept() @@ -335,7 +346,7 @@ GotoLocDialog objectNameChanged(QString) - sEdit + s_edit setText(QString)