diff options
Diffstat (limited to 'gui/fpgaviewwidget.h')
-rw-r--r-- | gui/fpgaviewwidget.h | 170 |
1 files changed, 153 insertions, 17 deletions
diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 260ebf05..c35821d9 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -31,9 +31,12 @@ #include <QThread> #include <QTimer> #include <QWaitCondition> +#include <boost/optional.hpp> -#include "nextpnr.h" +#include "designwidget.h" #include "lineshader.h" +#include "nextpnr.h" +#include "quadtree.h" NEXTPNR_NAMESPACE_BEGIN @@ -105,10 +108,9 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions QSize minimumSizeHint() const override; QSize sizeHint() const override; - public Q_SLOTS: void newContext(Context *ctx); - void onSelectedArchItem(std::vector<DecalXY> decals); + void onSelectedArchItem(std::vector<DecalXY> decals, bool keep); void onHighlightGroupChanged(std::vector<DecalXY> decals, int group); void pokeRenderer(void); void zoomIn(); @@ -116,11 +118,103 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void zoomSelected(); void zoomOutbound(); + Q_SIGNALS: + void clickedBel(BelId bel, bool add); + void clickedWire(WireId wire, bool add); + void clickedPip(PipId pip, bool add); + private: - const float zoomNear_ = 1.0f; // do not zoom closer than this - const float zoomFar_ = 10000.0f; // do not zoom further than this - const float zoomLvl1_ = 100.0f; - const float zoomLvl2_ = 50.0f; + const float zoomNear_ = 0.1f; // do not zoom closer than this + const float zoomFar_ = 30.0f; // do not zoom further than this + const float zoomLvl1_ = 1.0f; + const float zoomLvl2_ = 5.0f; + + struct PickedElement + { + ElementType type; + + // These are not in an union (and thus this structure is very verbose + // and somewhat heavy) because the Id types are typedef'd to StringIds + // in the generic architecture. Once that changes (or we get an AnyId + // construct from Arches), this should go away. + BelId bel; + WireId wire; + PipId pip; + GroupId group; + + float x, y; // Decal X and Y + + PickedElement(ElementType type, float x, float y) : type(type), x(x), y(y) {} + + static PickedElement fromBel(BelId bel, float x, float y) + { + PickedElement e(ElementType::BEL, x, y); + e.bel = bel; + return e; + } + static PickedElement fromWire(WireId wire, float x, float y) + { + PickedElement e(ElementType::WIRE, x, y); + e.wire = wire; + return e; + } + static PickedElement fromPip(PipId pip, float x, float y) + { + PickedElement e(ElementType::PIP, x, y); + e.pip = pip; + return e; + } + static PickedElement fromGroup(GroupId group, float x, float y) + { + PickedElement e(ElementType::GROUP, x, y); + e.group = group; + return e; + } + + PickedElement(const PickedElement &other) : type(other.type) + { + switch (type) { + case ElementType::BEL: + bel = other.bel; + break; + case ElementType::WIRE: + wire = other.wire; + break; + case ElementType::PIP: + pip = other.pip; + break; + case ElementType::GROUP: + group = other.group; + break; + default: + NPNR_ASSERT_FALSE("Invalid ElementType"); + } + } + + DecalXY decal(Context *ctx) const + { + DecalXY decal; + switch (type) { + case ElementType::BEL: + decal = ctx->getBelDecal(bel); + break; + case ElementType::WIRE: + decal = ctx->getWireDecal(wire); + break; + case ElementType::PIP: + decal = ctx->getPipDecal(pip); + break; + case ElementType::GROUP: + decal = ctx->getGroupDecal(group); + break; + default: + NPNR_ASSERT_FALSE("Invalid ElementType"); + } + return decal; + } + float distance(Context *ctx, float wx, float wy) const; + }; + using PickQuadTree = QuadTree<float, PickedElement>; Context *ctx_; QTimer paintTimer_; @@ -140,33 +234,75 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions QColor inactive; QColor active; QColor selected; + QColor hovered; QColor highlight[8]; } colors_; - struct RendererData + // Flags that are passed through from renderer arguments to renderer data. + // These are used by the UI code to signal events that will only fire when + // the next frame gets rendered. + struct PassthroughFlags { - LineShaderData gfxByStyle[GraphicElement::STYLE_MAX]; - LineShaderData gfxSelected; - LineShaderData gfxHighlighted[8]; + bool zoomOutbound; + + PassthroughFlags() : zoomOutbound(false) {} + PassthroughFlags &operator=(const PassthroughFlags &other) noexcept + { + zoomOutbound = other.zoomOutbound; + return *this; + } + + void clear() { zoomOutbound = false; } }; - std::unique_ptr<RendererData> rendererData_; - QMutex rendererDataLock_; struct RendererArgs { + // Decals that he user selected. std::vector<DecalXY> selectedDecals; + // Decals that the user highlighted. std::vector<DecalXY> highlightedDecals[8]; - bool highlightedOrSelectedChanged; + // Decals that the user's mouse is hovering in. + DecalXY hoveredDecal; + // Whether to render the above three or skip it. + bool changed; + + // Flags to pass back into the RendererData. + PassthroughFlags flags; }; std::unique_ptr<RendererArgs> rendererArgs_; QMutex rendererArgsLock_; + struct RendererData + { + LineShaderData gfxByStyle[GraphicElement::STYLE_MAX]; + LineShaderData gfxSelected; + LineShaderData gfxHovered; + LineShaderData gfxHighlighted[8]; + // Global bounding box of data from Arch. + PickQuadTree::BoundingBox bbGlobal; + // Bounding box of selected items. + PickQuadTree::BoundingBox bbSelected; + // Quadtree for picking objects. + std::unique_ptr<PickQuadTree> qt; + // Flags from args. + PassthroughFlags flags; + }; + std::unique_ptr<RendererData> rendererData_; + QMutex rendererDataLock_; + + void clampZoom(); + void zoomToBB(const PickQuadTree::BoundingBox &bb, float margin); void zoom(int level); void renderLines(void); - void drawGraphicElement(LineShaderData &out, const GraphicElement &el, float x, float y); - void drawDecal(LineShaderData &out, const DecalXY &decal); - void drawArchDecal(LineShaderData out[GraphicElement::STYLE_MAX], const DecalXY &decal); + void renderGraphicElement(LineShaderData &out, PickQuadTree::BoundingBox &bb, const GraphicElement &el, float x, + float y); + void renderDecal(LineShaderData &out, PickQuadTree::BoundingBox &bb, const DecalXY &decal); + void renderArchDecal(LineShaderData out[GraphicElement::STYLE_MAX], PickQuadTree::BoundingBox &bb, + const DecalXY &decal); + void populateQuadTree(RendererData *data, const DecalXY &decal, const PickedElement &element); + boost::optional<PickedElement> pickElement(float worldx, float worldy); QVector4D mouseToWorldCoordinates(int x, int y); + QVector4D mouseToWorldDimensions(float x, float y); QMatrix4x4 getProjection(void); }; |