gui: clickable bels, WIP
This commit is contained in:
parent
30d481e321
commit
c897c0ca9a
@ -83,6 +83,7 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
|
|||||||
connect(this, SIGNAL(contextChanged(Context *)), fpgaView, SLOT(newContext(Context *)));
|
connect(this, SIGNAL(contextChanged(Context *)), fpgaView, SLOT(newContext(Context *)));
|
||||||
connect(designview, SIGNAL(selected(std::vector<DecalXY>)), fpgaView,
|
connect(designview, SIGNAL(selected(std::vector<DecalXY>)), fpgaView,
|
||||||
SLOT(onSelectedArchItem(std::vector<DecalXY>)));
|
SLOT(onSelectedArchItem(std::vector<DecalXY>)));
|
||||||
|
connect(fpgaView, SIGNAL(clickedBel(BelId)), designview, SLOT(onClickedBel(BelId)));
|
||||||
|
|
||||||
connect(designview, SIGNAL(highlight(std::vector<DecalXY>, int)), fpgaView,
|
connect(designview, SIGNAL(highlight(std::vector<DecalXY>, int)), fpgaView,
|
||||||
SLOT(onHighlightGroupChanged(std::vector<DecalXY>, int)));
|
SLOT(onHighlightGroupChanged(std::vector<DecalXY>, int)));
|
||||||
|
@ -495,6 +495,13 @@ QtProperty *DesignWidget::addSubGroup(QtProperty *topItem, const QString &name)
|
|||||||
return item;
|
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()
|
void DesignWidget::onItemSelectionChanged()
|
||||||
{
|
{
|
||||||
if (treeWidget->selectedItems().size() == 0)
|
if (treeWidget->selectedItems().size() == 0)
|
||||||
|
@ -74,6 +74,7 @@ class DesignWidget : public QWidget
|
|||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void newContext(Context *ctx);
|
void newContext(Context *ctx);
|
||||||
void updateTree();
|
void updateTree();
|
||||||
|
void onClickedBel(BelId bel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Context *ctx;
|
Context *ctx;
|
||||||
|
@ -314,11 +314,10 @@ void FPGAViewWidget::initializeGL()
|
|||||||
void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal)
|
void FPGAViewWidget::drawDecal(LineShaderData &out, const DecalXY &decal)
|
||||||
{
|
{
|
||||||
const float scale = 1.0;
|
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)) {
|
for (auto &el : ctx_->getDecalGraphics(decal.decal)) {
|
||||||
offsetX = decal.x;
|
|
||||||
offsetY = decal.y;
|
|
||||||
|
|
||||||
if (el.type == GraphicElement::G_BOX) {
|
if (el.type == GraphicElement::G_BOX) {
|
||||||
auto line = PolyLine(true);
|
auto line = PolyLine(true);
|
||||||
@ -400,8 +399,8 @@ void FPGAViewWidget::paintGL()
|
|||||||
matrix *= viewMove_;
|
matrix *= viewMove_;
|
||||||
|
|
||||||
// Calculate world thickness to achieve a screen 1px/1.1px line.
|
// Calculate world thickness to achieve a screen 1px/1.1px line.
|
||||||
float thick1Px = mouseToWorldCoordinates(1, 0).x();
|
float thick1Px = mouseToWorldDimensions(1, 0).x();
|
||||||
float thick11Px = mouseToWorldCoordinates(1.1, 0).x();
|
float thick11Px = mouseToWorldDimensions(1.1, 0).x();
|
||||||
|
|
||||||
// Draw grid.
|
// Draw grid.
|
||||||
auto grid = LineShaderData();
|
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.
|
// 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> wireDecals;
|
||||||
std::vector<DecalXY> pipDecals;
|
std::vector<DecalXY> pipDecals;
|
||||||
std::vector<DecalXY> groupDecals;
|
std::vector<DecalXY> groupDecals;
|
||||||
|
|
||||||
if (decalsChanged) {
|
if (decalsChanged) {
|
||||||
for (auto bel : ctx_->getBels()) {
|
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()) {
|
for (auto wire : ctx_->getWires()) {
|
||||||
wireDecals.push_back(ctx_->getWireDecal(wire));
|
wireDecals.push_back(ctx_->getWireDecal(wire));
|
||||||
@ -489,11 +489,15 @@ void FPGAViewWidget::renderLines(void)
|
|||||||
rendererArgs_->highlightedOrSelectedChanged = false;
|
rendererArgs_->highlightedOrSelectedChanged = false;
|
||||||
rendererArgsLock_.unlock();
|
rendererArgsLock_.unlock();
|
||||||
|
|
||||||
|
QuadTreeBels::BoundingBox globalBB = QuadTreeBels::BoundingBox(-1000, -1000, 1000, 1000);
|
||||||
|
|
||||||
if (decalsChanged) {
|
if (decalsChanged) {
|
||||||
auto data = std::unique_ptr<FPGAViewWidget::RendererData>(new FPGAViewWidget::RendererData);
|
auto data = std::unique_ptr<FPGAViewWidget::RendererData>(new FPGAViewWidget::RendererData);
|
||||||
// Draw Bels.
|
// Draw Bels.
|
||||||
|
data->qtBels = std::unique_ptr<QuadTreeBels>(new QuadTreeBels(globalBB));
|
||||||
for (auto const &decal : belDecals) {
|
for (auto const &decal : belDecals) {
|
||||||
drawDecal(data->decals, decal);
|
drawDecal(data->decals, decal.second);
|
||||||
|
commitToQuadtree(data->qtBels.get(), decal.second, decal.first);
|
||||||
}
|
}
|
||||||
// Draw Wires.
|
// Draw Wires.
|
||||||
for (auto const &decal : wireDecals) {
|
for (auto const &decal : wireDecals) {
|
||||||
@ -550,11 +554,49 @@ void FPGAViewWidget::onHighlightGroupChanged(std::vector<DecalXY> decals, int gr
|
|||||||
|
|
||||||
void FPGAViewWidget::resizeGL(int width, int height) {}
|
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
|
// Invert the projection matrix to calculate screen/mouse to world/grid
|
||||||
// coordinates.
|
// coordinates.
|
||||||
QVector4D FPGAViewWidget::mouseToWorldCoordinates(int x, int y)
|
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();
|
QMatrix4x4 p = getProjection();
|
||||||
QVector2D unit = p.map(QVector4D(1, 1, 0, 1)).toVector2DAffine();
|
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)
|
void FPGAViewWidget::mouseMoveEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
const int dx = event->x() - lastPos_.x();
|
if (event->buttons() & Qt::RightButton || event->buttons() & Qt::MidButton) {
|
||||||
const int dy = event->y() - lastPos_.y();
|
const int dx = event->x() - lastPos_.x();
|
||||||
lastPos_ = event->pos();
|
const int dy = event->y() - lastPos_.y();
|
||||||
|
lastPos_ = event->pos();
|
||||||
|
|
||||||
auto world = mouseToWorldCoordinates(dx, dy);
|
auto world = mouseToWorldDimensions(dx, dy);
|
||||||
viewMove_.translate(world.x(), -world.y());
|
viewMove_.translate(world.x(), -world.y());
|
||||||
|
|
||||||
update();
|
update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FPGAViewWidget::wheelEvent(QWheelEvent *event)
|
void FPGAViewWidget::wheelEvent(QWheelEvent *event)
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include <QWaitCondition>
|
#include <QWaitCondition>
|
||||||
|
|
||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
|
#include "quadtree.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -292,6 +293,8 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
|||||||
void onSelectedArchItem(std::vector<DecalXY> decals);
|
void onSelectedArchItem(std::vector<DecalXY> decals);
|
||||||
void onHighlightGroupChanged(std::vector<DecalXY> decals, int group);
|
void onHighlightGroupChanged(std::vector<DecalXY> decals, int group);
|
||||||
void pokeRenderer(void);
|
void pokeRenderer(void);
|
||||||
|
Q_SIGNALS:
|
||||||
|
void clickedBel(BelId bel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void renderLines(void);
|
void renderLines(void);
|
||||||
@ -302,6 +305,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
|||||||
float zoom_;
|
float zoom_;
|
||||||
QMatrix4x4 getProjection(void);
|
QMatrix4x4 getProjection(void);
|
||||||
QVector4D mouseToWorldCoordinates(int x, int y);
|
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 zoomNear_ = 1.0f; // do not zoom closer than this
|
||||||
const float zoomFar_ = 10000.0f; // do not zoom further 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_;
|
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
|
struct
|
||||||
{
|
{
|
||||||
QColor background;
|
QColor background;
|
||||||
@ -331,6 +350,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
|||||||
LineShaderData decals[4];
|
LineShaderData decals[4];
|
||||||
LineShaderData selected;
|
LineShaderData selected;
|
||||||
LineShaderData highlighted[8];
|
LineShaderData highlighted[8];
|
||||||
|
std::unique_ptr<QuadTreeBels> qtBels;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RendererArgs
|
struct RendererArgs
|
||||||
|
Loading…
Reference in New Issue
Block a user