aboutsummaryrefslogtreecommitdiffstats
path: root/gui
diff options
context:
space:
mode:
authorSergiusz Bazanski <q3k@q3k.org>2018-07-26 16:20:58 +0100
committerSergiusz Bazanski <q3k@q3k.org>2018-07-26 16:20:58 +0100
commitc897c0ca9afab1d758f5c1b77312e77057a4c814 (patch)
tree97aa0945f08ce5b26117242b017f39a73a214a7a /gui
parent30d481e3215f33eff80e73c1ee0ed9cc3a8834f0 (diff)
downloadnextpnr-c897c0ca9afab1d758f5c1b77312e77057a4c814.tar.gz
nextpnr-c897c0ca9afab1d758f5c1b77312e77057a4c814.tar.bz2
nextpnr-c897c0ca9afab1d758f5c1b77312e77057a4c814.zip
gui: clickable bels, WIP
Diffstat (limited to 'gui')
-rw-r--r--gui/basewindow.cc1
-rw-r--r--gui/designwidget.cc7
-rw-r--r--gui/designwidget.h1
-rw-r--r--gui/fpgaviewwidget.cc74
-rw-r--r--gui/fpgaviewwidget.h20
5 files changed, 88 insertions, 15 deletions
diff --git a/gui/basewindow.cc b/gui/basewindow.cc
index 78c2fe3a..3cb2cc96 100644
--- a/gui/basewindow.cc
+++ b/gui/basewindow.cc
@@ -83,6 +83,7 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
connect(this, SIGNAL(contextChanged(Context *)), fpgaView, SLOT(newContext(Context *)));
connect(designview, SIGNAL(selected(std::vector<DecalXY>)), fpgaView,
SLOT(onSelectedArchItem(std::vector<DecalXY>)));
+ connect(fpgaView, SIGNAL(clickedBel(BelId)), designview, SLOT(onClickedBel(BelId)));
connect(designview, SIGNAL(highlight(std::vector<DecalXY>, int)), fpgaView,
SLOT(onHighlightGroupChanged(std::vector<DecalXY>, int)));
diff --git a/gui/designwidget.cc b/gui/designwidget.cc
index 7e8e2840..6d2a6d3d 100644
--- a/gui/designwidget.cc
+++ b/gui/designwidget.cc
@@ -495,6 +495,13 @@ QtProperty *DesignWidget::addSubGroup(QtProperty *topItem, const QString &name)
return item;
}
+void DesignWidget::onClickedBel(BelId bel)
+{
+ QTreeWidgetItem *item = nameToItem[getElementIndex(ElementType::BEL)].value(ctx->getBelName(bel).c_str(ctx));
+ treeWidget->setCurrentItem(item);
+ Q_EMIT selected(getDecals(ElementType::BEL, ctx->getBelName(bel)));
+}
+
void DesignWidget::onItemSelectionChanged()
{
if (treeWidget->selectedItems().size() == 0)
diff --git a/gui/designwidget.h b/gui/designwidget.h
index b5877f60..61681541 100644
--- a/gui/designwidget.h
+++ b/gui/designwidget.h
@@ -74,6 +74,7 @@ class DesignWidget : public QWidget
public Q_SLOTS:
void newContext(Context *ctx);
void updateTree();
+ void onClickedBel(BelId bel);
private:
Context *ctx;
diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc
index 15f37ce0..b9e05a04 100644
--- a/gui/fpgaviewwidget.cc
+++ b/gui/fpgaviewwidget.cc
@@ -314,11 +314,10 @@ void FPGAViewWidget::initializeGL()
void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal)
{
const float scale = 1.0;
- float offsetX = 0.0, offsetY = 0.0;
+ float offsetX = decal.x;
+ float offsetY = decal.y;
for (auto &el : ctx_->getDecalGraphics(decal.decal)) {
- offsetX = decal.x;
- offsetY = decal.y;
if (el.type == GraphicElement::G_BOX) {
auto line = PolyLine(true);
@@ -400,8 +399,8 @@ void FPGAViewWidget::paintGL()
matrix *= viewMove_;
// Calculate world thickness to achieve a screen 1px/1.1px line.
- float thick1Px = mouseToWorldCoordinates(1, 0).x();
- float thick11Px = mouseToWorldCoordinates(1.1, 0).x();
+ float thick1Px = mouseToWorldDimensions(1, 0).x();
+ float thick11Px = mouseToWorldDimensions(1.1, 0).x();
// Draw grid.
auto grid = LineShaderData();
@@ -462,13 +461,14 @@ void FPGAViewWidget::renderLines(void)
}
// Local copy of decals, taken as fast as possible to not block the P&R.
- std::vector<DecalXY> belDecals;
+ std::vector<std::pair<BelId, DecalXY>> belDecals;
std::vector<DecalXY> wireDecals;
std::vector<DecalXY> pipDecals;
std::vector<DecalXY> groupDecals;
+
if (decalsChanged) {
for (auto bel : ctx_->getBels()) {
- belDecals.push_back(ctx_->getBelDecal(bel));
+ belDecals.push_back(std::pair<BelId, DecalXY>(bel, ctx_->getBelDecal(bel)));
}
for (auto wire : ctx_->getWires()) {
wireDecals.push_back(ctx_->getWireDecal(wire));
@@ -489,11 +489,15 @@ void FPGAViewWidget::renderLines(void)
rendererArgs_->highlightedOrSelectedChanged = false;
rendererArgsLock_.unlock();
+ QuadTreeBels::BoundingBox globalBB = QuadTreeBels::BoundingBox(-1000, -1000, 1000, 1000);
+
if (decalsChanged) {
auto data = std::unique_ptr<FPGAViewWidget::RendererData>(new FPGAViewWidget::RendererData);
// Draw Bels.
+ data->qtBels = std::unique_ptr<QuadTreeBels>(new QuadTreeBels(globalBB));
for (auto const &decal : belDecals) {
- drawDecal(data->decals, decal);
+ drawDecal(data->decals, decal.second);
+ commitToQuadtree(data->qtBels.get(), decal.second, decal.first);
}
// Draw Wires.
for (auto const &decal : wireDecals) {
@@ -550,12 +554,50 @@ void FPGAViewWidget::onHighlightGroupChanged(std::vector<DecalXY> decals, int gr
void FPGAViewWidget::resizeGL(int width, int height) {}
-void FPGAViewWidget::mousePressEvent(QMouseEvent *event) { lastPos_ = event->pos(); }
+void FPGAViewWidget::mousePressEvent(QMouseEvent *event)
+{
+ if (event->buttons() & Qt::RightButton || event->buttons() & Qt::MidButton) {
+ lastPos_ = event->pos();
+ }
+ if (event->buttons() & Qt::LeftButton) {
+ int x = event->x();
+ int y = event->y();
+ auto world = mouseToWorldCoordinates(x, y);
+ rendererDataLock_.lock();
+ if (rendererData_->qtBels != nullptr) {
+ auto elems = rendererData_->qtBels->get(world.x(), world.y());
+ if (elems.size() > 0) {
+ clickedBel(elems[0]);
+ }
+ }
+ rendererDataLock_.unlock();
+ }
+}
// Invert the projection matrix to calculate screen/mouse to world/grid
// coordinates.
QVector4D FPGAViewWidget::mouseToWorldCoordinates(int x, int y)
{
+ const qreal retinaScale = devicePixelRatio();
+
+ auto projection = getProjection();
+
+ QMatrix4x4 vp;
+ vp.viewport(0, 0, width() * retinaScale, height() * retinaScale);
+
+ QVector4D vec(x, y, 0, 1);
+ vec = vp.inverted() * vec;
+ vec = projection.inverted() * vec;
+
+ auto ray = vec.toVector3DAffine();
+ auto world = QVector4D(ray.x()*ray.z(), -ray.y()*ray.z(), 0, 1);
+ world = viewMove_.inverted() * world;
+
+ return world;
+}
+
+QVector4D FPGAViewWidget::mouseToWorldDimensions(int x, int y)
+{
QMatrix4x4 p = getProjection();
QVector2D unit = p.map(QVector4D(1, 1, 0, 1)).toVector2DAffine();
@@ -566,14 +608,16 @@ QVector4D FPGAViewWidget::mouseToWorldCoordinates(int x, int y)
void FPGAViewWidget::mouseMoveEvent(QMouseEvent *event)
{
- const int dx = event->x() - lastPos_.x();
- const int dy = event->y() - lastPos_.y();
- lastPos_ = event->pos();
+ if (event->buttons() & Qt::RightButton || event->buttons() & Qt::MidButton) {
+ const int dx = event->x() - lastPos_.x();
+ const int dy = event->y() - lastPos_.y();
+ lastPos_ = event->pos();
- auto world = mouseToWorldCoordinates(dx, dy);
- viewMove_.translate(world.x(), -world.y());
+ auto world = mouseToWorldDimensions(dx, dy);
+ viewMove_.translate(world.x(), -world.y());
- update();
+ update();
+ }
}
void FPGAViewWidget::wheelEvent(QWheelEvent *event)
diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h
index b87c5d0a..f69fa786 100644
--- a/gui/fpgaviewwidget.h
+++ b/gui/fpgaviewwidget.h
@@ -33,6 +33,7 @@
#include <QWaitCondition>
#include "nextpnr.h"
+#include "quadtree.h"
NEXTPNR_NAMESPACE_BEGIN
@@ -292,6 +293,8 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
void onSelectedArchItem(std::vector<DecalXY> decals);
void onHighlightGroupChanged(std::vector<DecalXY> decals, int group);
void pokeRenderer(void);
+ Q_SIGNALS:
+ void clickedBel(BelId bel);
private:
void renderLines(void);
@@ -302,6 +305,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
float zoom_;
QMatrix4x4 getProjection(void);
QVector4D mouseToWorldCoordinates(int x, int y);
+ QVector4D mouseToWorldDimensions(int x, int y);
const float zoomNear_ = 1.0f; // do not zoom closer than this
const float zoomFar_ = 10000.0f; // do not zoom further than this
@@ -314,6 +318,21 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
std::unique_ptr<PeriodicRunner> renderRunner_;
+ using QuadTreeBels = QuadTree<float, BelId>;
+
+ template <typename T>
+ void commitToQuadtree(T *tree, const DecalXY &decal, BelId bel)
+ {
+ float offsetX = decal.x;
+ float offsetY = decal.y;
+
+ for (auto &el : ctx_->getDecalGraphics(decal.decal)) {
+ if (el.type == GraphicElement::G_BOX) {
+ tree->insert(typename T::BoundingBox(offsetX + el.x1, offsetY + el.y1, offsetX + el.x2, offsetY + el.y2), bel);
+ }
+ }
+ }
+
struct
{
QColor background;
@@ -331,6 +350,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
LineShaderData decals[4];
LineShaderData selected;
LineShaderData highlighted[8];
+ std::unique_ptr<QuadTreeBels> qtBels;
};
struct RendererArgs