aboutsummaryrefslogtreecommitdiffstats
path: root/gui
diff options
context:
space:
mode:
authorSergiusz Bazanski <q3k@q3k.org>2018-07-26 16:22:19 +0100
committerSergiusz Bazanski <q3k@q3k.org>2018-07-26 16:22:19 +0100
commit4a21436dfa98caa458a8e6e130cf1f6305968650 (patch)
tree4e1dd3f04e5b671acf958eba6f7dc930ae4d1547 /gui
parentc897c0ca9afab1d758f5c1b77312e77057a4c814 (diff)
parent03f92948d1504c32049da065c0e73e01f96d8033 (diff)
downloadnextpnr-4a21436dfa98caa458a8e6e130cf1f6305968650.tar.gz
nextpnr-4a21436dfa98caa458a8e6e130cf1f6305968650.tar.bz2
nextpnr-4a21436dfa98caa458a8e6e130cf1f6305968650.zip
Merge branch 'master' of gitlab.com:SymbioticEDA/nextpnr
Diffstat (limited to 'gui')
-rw-r--r--gui/base.qrc4
-rw-r--r--gui/basewindow.cc29
-rw-r--r--gui/basewindow.h4
-rw-r--r--gui/designwidget.cc130
-rw-r--r--gui/designwidget.h3
-rw-r--r--gui/fpgaviewwidget.cc39
-rw-r--r--gui/fpgaviewwidget.h6
-rw-r--r--gui/ice40/mainwindow.cc2
-rw-r--r--gui/resources/shape_handles.pngbin0 -> 538 bytes
-rw-r--r--gui/resources/shape_square.pngbin0 -> 353 bytes
-rw-r--r--gui/resources/zoom_in.pngbin0 -> 725 bytes
-rw-r--r--gui/resources/zoom_out.pngbin0 -> 708 bytes
12 files changed, 145 insertions, 72 deletions
diff --git a/gui/base.qrc b/gui/base.qrc
index 1a848f54..7b3fa55c 100644
--- a/gui/base.qrc
+++ b/gui/base.qrc
@@ -10,5 +10,9 @@
<file>resources/resultset_next.png</file>
<file>resources/resultset_last.png</file>
<file>resources/cross.png</file>
+ <file>resources/zoom_in.png</file>
+ <file>resources/zoom_out.png</file>
+ <file>resources/shape_handles.png</file>
+ <file>resources/shape_square.png</file>
</qresource>
</RCC>
diff --git a/gui/basewindow.cc b/gui/basewindow.cc
index 3cb2cc96..d44bd0f7 100644
--- a/gui/basewindow.cc
+++ b/gui/basewindow.cc
@@ -25,7 +25,6 @@
#include <QSplitter>
#include "designwidget.h"
#include "fpgaviewwidget.h"
-#include "jsonparse.h"
#include "log.h"
#include "mainwindow.h"
#include "pythontab.h"
@@ -76,7 +75,7 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> context, QWidget *parent
centralTabWidget->setTabsClosable(true);
connect(centralTabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
- FPGAViewWidget *fpgaView = new FPGAViewWidget();
+ fpgaView = new FPGAViewWidget();
centralTabWidget->addTab(fpgaView, "Graphics");
centralTabWidget->tabBar()->tabButton(0, QTabBar::RightSide)->resize(0, 0);
@@ -164,4 +163,30 @@ void BaseMainWindow::createMenusAndBars()
mainToolBar->addAction(actionSave);
}
+void BaseMainWindow::createGraphicsBar()
+{
+ QAction *actionZoomIn = new QAction("Zoom In", this);
+ actionZoomIn->setIcon(QIcon(":/icons/resources/zoom_in.png"));
+ connect(actionZoomIn, SIGNAL(triggered()), fpgaView, SLOT(zoom_in()));
+
+ QAction *actionZoomOut = new QAction("Zoom Out", this);
+ actionZoomOut->setIcon(QIcon(":/icons/resources/zoom_out.png"));
+ connect(actionZoomOut, SIGNAL(triggered()), fpgaView, SLOT(zoom_out()));
+
+ QAction *actionZoomSelected = new QAction("Zoom Selected", this);
+ actionZoomSelected->setIcon(QIcon(":/icons/resources/shape_handles.png"));
+ connect(actionZoomSelected, SIGNAL(triggered()), fpgaView, SLOT(zoom_selected()));
+
+ QAction *actionZoomOutbound = new QAction("Zoom Outbound", this);
+ actionZoomOutbound->setIcon(QIcon(":/icons/resources/shape_square.png"));
+ connect(actionZoomOutbound, SIGNAL(triggered()), fpgaView, SLOT(zoom_outbound()));
+
+ graphicsToolBar = new QToolBar();
+ addToolBar(Qt::TopToolBarArea, graphicsToolBar);
+ graphicsToolBar->addAction(actionZoomIn);
+ graphicsToolBar->addAction(actionZoomOut);
+ graphicsToolBar->addAction(actionZoomSelected);
+ graphicsToolBar->addAction(actionZoomOutbound);
+}
+
NEXTPNR_NAMESPACE_END
diff --git a/gui/basewindow.h b/gui/basewindow.h
index 1184fa80..a25a2854 100644
--- a/gui/basewindow.h
+++ b/gui/basewindow.h
@@ -37,6 +37,7 @@ NEXTPNR_NAMESPACE_BEGIN
class PythonTab;
class DesignWidget;
+class FPGAViewWidget;
class BaseMainWindow : public QMainWindow
{
@@ -49,6 +50,7 @@ class BaseMainWindow : public QMainWindow
protected:
void createMenusAndBars();
+ void createGraphicsBar();
protected Q_SLOTS:
void writeInfo(std::string text);
@@ -70,12 +72,14 @@ class BaseMainWindow : public QMainWindow
QMenuBar *menuBar;
QToolBar *mainToolBar;
+ QToolBar *graphicsToolBar;
QStatusBar *statusBar;
QAction *actionNew;
QAction *actionOpen;
QAction *actionSave;
QProgressBar *progressBar;
DesignWidget *designview;
+ FPGAViewWidget *fpgaView;
};
NEXTPNR_NAMESPACE_END
diff --git a/gui/designwidget.cc b/gui/designwidget.cc
index 6d2a6d3d..989b55fe 100644
--- a/gui/designwidget.cc
+++ b/gui/designwidget.cc
@@ -35,6 +35,7 @@ class ElementTreeItem : public QTreeWidgetItem
ElementTreeItem(ElementType t, QString str, QTreeWidgetItem *parent)
: QTreeWidgetItem(parent, QStringList(str)), type(t)
{
+ this->setFlags(this->flags() & ~Qt::ItemIsSelectable);
}
virtual ~ElementTreeItem(){};
@@ -49,6 +50,7 @@ class IdStringTreeItem : public ElementTreeItem
public:
IdStringTreeItem(IdString d, ElementType t, QString str, QTreeWidgetItem *parent) : ElementTreeItem(t, str, parent)
{
+ this->setFlags(this->flags() | Qt::ItemIsSelectable);
this->data = d;
}
virtual ~IdStringTreeItem(){};
@@ -68,6 +70,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net
treeWidget->setColumnCount(1);
treeWidget->setHeaderLabel("Items");
treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+ treeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
// Add property view
variantManager = new QtVariantPropertyManager(this);
@@ -79,6 +82,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), net
propertyEditor->setPropertiesWithoutValueMarked(true);
propertyEditor->show();
propertyEditor->treeWidget()->setContextMenuPolicy(Qt::CustomContextMenu);
+ propertyEditor->treeWidget()->setSelectionMode(QAbstractItemView::ExtendedSelection);
QLineEdit *lineEdit = new QLineEdit();
lineEdit->setClearButtonEnabled(true);
@@ -248,6 +252,7 @@ void DesignWidget::newContext(Context *ctx)
QTreeWidgetItem *bel_root = new QTreeWidgetItem(treeWidget);
QMap<QString, QTreeWidgetItem *> bel_items;
bel_root->setText(0, "Bels");
+ bel_root->setFlags(bel_root->flags() & ~Qt::ItemIsSelectable);
treeWidget->insertTopLevelItem(0, bel_root);
if (ctx) {
for (auto bel : ctx->getBels()) {
@@ -280,6 +285,7 @@ void DesignWidget::newContext(Context *ctx)
QTreeWidgetItem *wire_root = new QTreeWidgetItem(treeWidget);
QMap<QString, QTreeWidgetItem *> wire_items;
wire_root->setText(0, "Wires");
+ wire_root->setFlags(wire_root->flags() & ~Qt::ItemIsSelectable);
treeWidget->insertTopLevelItem(0, wire_root);
if (ctx) {
for (auto wire : ctx->getWires()) {
@@ -311,8 +317,9 @@ void DesignWidget::newContext(Context *ctx)
QTreeWidgetItem *pip_root = new QTreeWidgetItem(treeWidget);
QMap<QString, QTreeWidgetItem *> pip_items;
pip_root->setText(0, "Pips");
+ pip_root->setFlags(pip_root->flags() & ~Qt::ItemIsSelectable);
treeWidget->insertTopLevelItem(0, pip_root);
-#ifndef ARCH_ECP5
+#ifndef ARCH_ECP5
if (ctx) {
for (auto pip : ctx->getPips()) {
auto id = ctx->getPipName(pip);
@@ -339,14 +346,16 @@ void DesignWidget::newContext(Context *ctx)
for (auto pip : nameToItem[2].toStdMap()) {
pip_root->addChild(pip.second);
}
-#endif
+#endif
nets_root = new QTreeWidgetItem(treeWidget);
nets_root->setText(0, "Nets");
+ nets_root->setFlags(nets_root->flags() & ~Qt::ItemIsSelectable);
treeWidget->insertTopLevelItem(0, nets_root);
cells_root = new QTreeWidgetItem(treeWidget);
cells_root->setText(0, "Cells");
+ cells_root->setFlags(cells_root->flags() & ~Qt::ItemIsSelectable);
treeWidget->insertTopLevelItem(0, cells_root);
updateTree();
@@ -418,6 +427,7 @@ QtProperty *DesignWidget::addTopLevelProperty(const QString &id)
QtProperty *topItem = groupManager->addProperty(id);
propertyToId[topItem] = id;
idToProperty[id] = topItem;
+ topItem->setSelectable(false);
propertyEditor->addProperty(topItem);
return topItem;
}
@@ -485,12 +495,14 @@ void DesignWidget::addProperty(QtProperty *topItem, int propertyType, const QStr
QtVariantProperty *item = readOnlyManager->addProperty(propertyType, name);
item->setValue(value);
item->setPropertyId(getElementTypeName(type));
+ item->setSelectable(type != ElementType::NONE);
topItem->addSubProperty(item);
}
QtProperty *DesignWidget::addSubGroup(QtProperty *topItem, const QString &name)
{
QtProperty *item = groupManager->addProperty(name);
+ item->setSelectable(false);
topItem->addSubProperty(item);
return item;
}
@@ -507,6 +519,18 @@ void DesignWidget::onItemSelectionChanged()
if (treeWidget->selectedItems().size() == 0)
return;
+ if (treeWidget->selectedItems().size() > 1) {
+ std::vector<DecalXY> decals;
+ for (auto clickItem : treeWidget->selectedItems()) {
+ IdString value = static_cast<IdStringTreeItem *>(clickItem)->getData();
+ ElementType type = static_cast<ElementTreeItem *>(clickItem)->getType();
+ std::vector<DecalXY> d = getDecals(type, value);
+ std::move(d.begin(), d.end(), std::back_inserter(decals));
+ }
+ Q_EMIT selected(decals);
+ return;
+ }
+
QTreeWidgetItem *clickItem = treeWidget->selectedItems().at(0);
if (!clickItem->parent())
@@ -550,6 +574,7 @@ void DesignWidget::onItemSelectionChanged()
QtProperty *topItem = addTopLevelProperty("Wire");
addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
+ addProperty(topItem, QVariant::String, "Type", ctx->getWireType(wire).c_str(ctx));
addProperty(topItem, QVariant::Bool, "Available", ctx->checkWireAvail(wire));
addProperty(topItem, QVariant::String, "Bound Net", ctx->getBoundWireNet(wire).c_str(ctx), ElementType::NET);
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->getConflictingWireNet(wire).c_str(ctx),
@@ -601,6 +626,7 @@ void DesignWidget::onItemSelectionChanged()
QtProperty *topItem = addTopLevelProperty("Pip");
addProperty(topItem, QVariant::String, "Name", c.c_str(ctx));
+ addProperty(topItem, QVariant::String, "Type", ctx->getPipType(pip).c_str(ctx));
addProperty(topItem, QVariant::Bool, "Available", ctx->checkPipAvail(pip));
addProperty(topItem, QVariant::String, "Bound Net", ctx->getBoundPipNet(pip).c_str(ctx), ElementType::NET);
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->getConflictingPipNet(pip).c_str(ctx),
@@ -758,54 +784,53 @@ std::vector<DecalXY> DesignWidget::getDecals(ElementType type, IdString value)
return decals;
}
-void DesignWidget::updateHighlightGroup(QTreeWidgetItem *item, int group)
+void DesignWidget::updateHighlightGroup(QList<QTreeWidgetItem *> items, int group)
{
- if (highlightSelected.contains(item)) {
- if (highlightSelected[item] == group) {
- highlightSelected.remove(item);
+ const bool shouldClear = items.size() == 1;
+ for (auto item : items) {
+ if (highlightSelected.contains(item)) {
+ if (shouldClear && highlightSelected[item] == group) {
+ highlightSelected.remove(item);
+ } else
+ highlightSelected[item] = group;
} else
- highlightSelected[item] = group;
- } else
- highlightSelected.insert(item, group);
-
- std::vector<DecalXY> decals;
+ highlightSelected.insert(item, group);
+ }
+ std::vector<DecalXY> decals[8];
for (auto it : highlightSelected.toStdMap()) {
- if (it.second == group) {
- ElementType type = static_cast<ElementTreeItem *>(it.first)->getType();
- IdString value = static_cast<IdStringTreeItem *>(it.first)->getData();
- std::vector<DecalXY> d = getDecals(type, value);
- std::move(d.begin(), d.end(), std::back_inserter(decals));
- }
+ ElementType type = static_cast<ElementTreeItem *>(it.first)->getType();
+ IdString value = static_cast<IdStringTreeItem *>(it.first)->getData();
+ std::vector<DecalXY> d = getDecals(type, value);
+ std::move(d.begin(), d.end(), std::back_inserter(decals[it.second]));
}
-
- Q_EMIT highlight(decals, group);
+ for (int i = 0; i < 8; i++)
+ Q_EMIT highlight(decals[i], i);
}
void DesignWidget::prepareMenuProperty(const QPoint &pos)
{
QTreeWidget *tree = propertyEditor->treeWidget();
-
- itemContextMenu = tree->itemAt(pos);
- if (itemContextMenu->parent() == nullptr)
- return;
-
- QtBrowserItem *browserItem = propertyEditor->itemToBrowserItem(itemContextMenu);
- if (!browserItem)
- return;
- QtProperty *selectedProperty = browserItem->property();
- ElementType type = getElementTypeByName(selectedProperty->propertyId());
- if (type == ElementType::NONE)
- return;
- IdString value = ctx->id(selectedProperty->valueText().toStdString());
-
- QTreeWidgetItem *item = nameToItem[getElementIndex(type)].value(value.c_str(ctx));
+ QList<QTreeWidgetItem *> items;
+ for (auto itemContextMenu : tree->selectedItems()) {
+ QtBrowserItem *browserItem = propertyEditor->itemToBrowserItem(itemContextMenu);
+ if (!browserItem)
+ continue;
+ QtProperty *selectedProperty = browserItem->property();
+ ElementType type = getElementTypeByName(selectedProperty->propertyId());
+ if (type == ElementType::NONE)
+ continue;
+ IdString value = ctx->id(selectedProperty->valueText().toStdString());
+ items.append(nameToItem[getElementIndex(type)].value(value.c_str(ctx)));
+ }
+ int selectedIndex = -1;
+ if (items.size() == 1) {
+ QTreeWidgetItem *item = items.at(0);
+ if (highlightSelected.contains(item))
+ selectedIndex = highlightSelected[item];
+ }
QMenu menu(this);
- QAction *selectAction = new QAction("&Select", this);
- connect(selectAction, &QAction::triggered, this, [this, type, value] { Q_EMIT selected(getDecals(type, value)); });
- menu.addAction(selectAction);
-
QMenu *subMenu = menu.addMenu("Highlight");
QActionGroup *group = new QActionGroup(this);
group->setExclusive(true);
@@ -816,27 +841,24 @@ void DesignWidget::prepareMenuProperty(const QPoint &pos)
action->setCheckable(true);
subMenu->addAction(action);
group->addAction(action);
- if (highlightSelected.contains(item) && highlightSelected[item] == i)
+ if (selectedIndex == i)
action->setChecked(true);
- connect(action, &QAction::triggered, this, [this, i, item] { updateHighlightGroup(item, i); });
+ connect(action, &QAction::triggered, this, [this, i, items] { updateHighlightGroup(items, i); });
}
menu.exec(tree->mapToGlobal(pos));
}
void DesignWidget::prepareMenuTree(const QPoint &pos)
{
- QTreeWidget *tree = treeWidget;
-
- itemContextMenu = tree->itemAt(pos);
-
- ElementType type = static_cast<ElementTreeItem *>(itemContextMenu)->getType();
- IdString value = static_cast<IdStringTreeItem *>(itemContextMenu)->getData();
-
- if (type == ElementType::NONE)
+ if (treeWidget->selectedItems().size() == 0)
return;
-
- QTreeWidgetItem *item = nameToItem[getElementIndex(type)].value(value.c_str(ctx));
-
+ int selectedIndex = -1;
+ QList<QTreeWidgetItem *> items = treeWidget->selectedItems();
+ if (treeWidget->selectedItems().size() == 1) {
+ QTreeWidgetItem *item = treeWidget->selectedItems().at(0);
+ if (highlightSelected.contains(item))
+ selectedIndex = highlightSelected[item];
+ }
QMenu menu(this);
QMenu *subMenu = menu.addMenu("Highlight");
QActionGroup *group = new QActionGroup(this);
@@ -848,11 +870,11 @@ void DesignWidget::prepareMenuTree(const QPoint &pos)
action->setCheckable(true);
subMenu->addAction(action);
group->addAction(action);
- if (highlightSelected.contains(item) && highlightSelected[item] == i)
+ if (selectedIndex == i)
action->setChecked(true);
- connect(action, &QAction::triggered, this, [this, i, item] { updateHighlightGroup(item, i); });
+ connect(action, &QAction::triggered, this, [this, i, items] { updateHighlightGroup(items, i); });
}
- menu.exec(tree->mapToGlobal(pos));
+ menu.exec(treeWidget->mapToGlobal(pos));
}
void DesignWidget::onItemDoubleClicked(QTreeWidgetItem *item, int column)
diff --git a/gui/designwidget.h b/gui/designwidget.h
index 61681541..85c326d0 100644
--- a/gui/designwidget.h
+++ b/gui/designwidget.h
@@ -60,7 +60,7 @@ class DesignWidget : public QWidget
void updateButtons();
void addToHistory(QTreeWidgetItem *item);
std::vector<DecalXY> getDecals(ElementType type, IdString value);
- void updateHighlightGroup(QTreeWidgetItem *item, int group);
+ void updateHighlightGroup(QList<QTreeWidgetItem *> item, int group);
Q_SIGNALS:
void info(std::string text);
void selected(std::vector<DecalXY> decal);
@@ -86,7 +86,6 @@ class DesignWidget : public QWidget
QtGroupPropertyManager *groupManager;
QtVariantEditorFactory *variantFactory;
QtTreePropertyBrowser *propertyEditor;
- QTreeWidgetItem *itemContextMenu;
QMap<QtProperty *, QString> propertyToId;
QMap<QString, QtProperty *> idToProperty;
diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc
index b9e05a04..e81fe3bd 100644
--- a/gui/fpgaviewwidget.cc
+++ b/gui/fpgaviewwidget.cc
@@ -624,21 +624,32 @@ void FPGAViewWidget::wheelEvent(QWheelEvent *event)
{
QPoint degree = event->angleDelta() / 8;
- if (!degree.isNull()) {
-
- if (zoom_ < zoomNear_) {
- zoom_ = zoomNear_;
- } else if (zoom_ < zoomLvl1_) {
- zoom_ -= degree.y() / 10.0;
- } else if (zoom_ < zoomLvl2_) {
- zoom_ -= degree.y() / 5.0;
- } else if (zoom_ < zoomFar_) {
- zoom_ -= degree.y();
- } else {
- zoom_ = zoomFar_;
- }
- update();
+ if (!degree.isNull())
+ zoom(degree.y());
+}
+
+void FPGAViewWidget::zoom(int level)
+{
+ if (zoom_ < zoomNear_) {
+ zoom_ = zoomNear_;
+ } else if (zoom_ < zoomLvl1_) {
+ zoom_ -= level / 10.0;
+ } else if (zoom_ < zoomLvl2_) {
+ zoom_ -= level / 5.0;
+ } else if (zoom_ < zoomFar_) {
+ zoom_ -= level;
+ } else {
+ zoom_ = zoomFar_;
}
+ update();
}
+void FPGAViewWidget::zoom_in() { zoom(10); }
+
+void FPGAViewWidget::zoom_out() { zoom(-10); }
+
+void FPGAViewWidget::zoom_selected() {}
+
+void FPGAViewWidget::zoom_outbound() {}
+
NEXTPNR_NAMESPACE_END
diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h
index f69fa786..cc79cd03 100644
--- a/gui/fpgaviewwidget.h
+++ b/gui/fpgaviewwidget.h
@@ -293,11 +293,17 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
void onSelectedArchItem(std::vector<DecalXY> decals);
void onHighlightGroupChanged(std::vector<DecalXY> decals, int group);
void pokeRenderer(void);
+ void zoom_in();
+ void zoom_out();
+ void zoom_selected();
+ void zoom_outbound();
+
Q_SIGNALS:
void clickedBel(BelId bel);
private:
void renderLines(void);
+ void zoom(int level);
QPoint lastPos_;
LineShader lineShader_;
diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc
index 810a98ae..f06971b6 100644
--- a/gui/ice40/mainwindow.cc
+++ b/gui/ice40/mainwindow.cc
@@ -159,6 +159,8 @@ void MainWindow::createMenu()
taskToolBar->addAction(actionPlay);
taskToolBar->addAction(actionPause);
taskToolBar->addAction(actionStop);
+
+ createGraphicsBar();
}
#if defined(_MSC_VER)
diff --git a/gui/resources/shape_handles.png b/gui/resources/shape_handles.png
new file mode 100644
index 00000000..ce27fe3a
--- /dev/null
+++ b/gui/resources/shape_handles.png
Binary files differ
diff --git a/gui/resources/shape_square.png b/gui/resources/shape_square.png
new file mode 100644
index 00000000..33af0460
--- /dev/null
+++ b/gui/resources/shape_square.png
Binary files differ
diff --git a/gui/resources/zoom_in.png b/gui/resources/zoom_in.png
new file mode 100644
index 00000000..cdf0a52f
--- /dev/null
+++ b/gui/resources/zoom_in.png
Binary files differ
diff --git a/gui/resources/zoom_out.png b/gui/resources/zoom_out.png
new file mode 100644
index 00000000..07bf98a7
--- /dev/null
+++ b/gui/resources/zoom_out.png
Binary files differ