CRLF -> LF eol
This commit is contained in:
parent
ec60542ffd
commit
e3f4578b3b
1094
gui/basewindow.cc
1094
gui/basewindow.cc
File diff suppressed because it is too large
Load Diff
284
gui/basewindow.h
284
gui/basewindow.h
@ -1,142 +1,142 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BASEMAINWINDOW_H
|
||||
#define BASEMAINWINDOW_H
|
||||
|
||||
#include "command.h"
|
||||
#include "nextpnr.h"
|
||||
#include "worker.h"
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
#include <QProgressBar>
|
||||
#include <QStatusBar>
|
||||
#include <QTabWidget>
|
||||
#include <QToolBar>
|
||||
|
||||
Q_DECLARE_METATYPE(std::string)
|
||||
Q_DECLARE_METATYPE(NEXTPNR_NAMESPACE_PREFIX DecalXY)
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class PythonTab;
|
||||
class DesignWidget;
|
||||
class FPGAViewWidget;
|
||||
|
||||
class BaseMainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BaseMainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent = 0);
|
||||
virtual ~BaseMainWindow();
|
||||
Context *getContext() { return ctx.get(); }
|
||||
void updateActions();
|
||||
|
||||
void notifyChangeContext();
|
||||
|
||||
protected:
|
||||
void createMenusAndBars();
|
||||
void disableActions();
|
||||
void enableDisableDecals();
|
||||
|
||||
virtual void onDisableActions(){};
|
||||
virtual void onUpdateActions(){};
|
||||
|
||||
protected Q_SLOTS:
|
||||
void writeInfo(std::string text);
|
||||
void closeTab(int index);
|
||||
|
||||
virtual void new_proj() = 0;
|
||||
|
||||
void open_json();
|
||||
void save_json();
|
||||
void place();
|
||||
|
||||
void execute_python();
|
||||
|
||||
void pack_finished(bool status);
|
||||
void place_finished(bool status);
|
||||
void route_finished(bool status);
|
||||
|
||||
void taskCanceled();
|
||||
void taskStarted();
|
||||
void taskPaused();
|
||||
|
||||
void screenshot();
|
||||
void saveMovie();
|
||||
void saveSVG();
|
||||
|
||||
void about();
|
||||
|
||||
Q_SIGNALS:
|
||||
void contextChanged(Context *ctx);
|
||||
void updateTreeView();
|
||||
|
||||
protected:
|
||||
// state variables
|
||||
CommandHandler *handler;
|
||||
std::unique_ptr<Context> ctx;
|
||||
TaskManager *task;
|
||||
bool timing_driven;
|
||||
std::string currentProj;
|
||||
|
||||
// main widgets
|
||||
QTabWidget *tabWidget;
|
||||
QTabWidget *centralTabWidget;
|
||||
PythonTab *console;
|
||||
DesignWidget *designview;
|
||||
FPGAViewWidget *fpgaView;
|
||||
|
||||
// Menus, bars and actions
|
||||
QMenuBar *menuBar;
|
||||
QMenu *menuDesign;
|
||||
QStatusBar *statusBar;
|
||||
QToolBar *mainActionBar;
|
||||
QProgressBar *progressBar;
|
||||
|
||||
QAction *actionNew;
|
||||
QAction *actionLoadJSON;
|
||||
QAction *actionSaveJSON;
|
||||
|
||||
QAction *actionPack;
|
||||
QAction *actionPlace;
|
||||
QAction *actionRoute;
|
||||
|
||||
QAction *actionExecutePy;
|
||||
|
||||
QAction *actionPlay;
|
||||
QAction *actionPause;
|
||||
QAction *actionStop;
|
||||
|
||||
QAction *actionDisplayBel;
|
||||
QAction *actionDisplayWire;
|
||||
QAction *actionDisplayPip;
|
||||
QAction *actionDisplayGroups;
|
||||
|
||||
QAction *actionScreenshot;
|
||||
QAction *actionMovie;
|
||||
QAction *actionSaveSVG;
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // BASEMAINWINDOW_H
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BASEMAINWINDOW_H
|
||||
#define BASEMAINWINDOW_H
|
||||
|
||||
#include "command.h"
|
||||
#include "nextpnr.h"
|
||||
#include "worker.h"
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
#include <QProgressBar>
|
||||
#include <QStatusBar>
|
||||
#include <QTabWidget>
|
||||
#include <QToolBar>
|
||||
|
||||
Q_DECLARE_METATYPE(std::string)
|
||||
Q_DECLARE_METATYPE(NEXTPNR_NAMESPACE_PREFIX DecalXY)
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class PythonTab;
|
||||
class DesignWidget;
|
||||
class FPGAViewWidget;
|
||||
|
||||
class BaseMainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BaseMainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent = 0);
|
||||
virtual ~BaseMainWindow();
|
||||
Context *getContext() { return ctx.get(); }
|
||||
void updateActions();
|
||||
|
||||
void notifyChangeContext();
|
||||
|
||||
protected:
|
||||
void createMenusAndBars();
|
||||
void disableActions();
|
||||
void enableDisableDecals();
|
||||
|
||||
virtual void onDisableActions(){};
|
||||
virtual void onUpdateActions(){};
|
||||
|
||||
protected Q_SLOTS:
|
||||
void writeInfo(std::string text);
|
||||
void closeTab(int index);
|
||||
|
||||
virtual void new_proj() = 0;
|
||||
|
||||
void open_json();
|
||||
void save_json();
|
||||
void place();
|
||||
|
||||
void execute_python();
|
||||
|
||||
void pack_finished(bool status);
|
||||
void place_finished(bool status);
|
||||
void route_finished(bool status);
|
||||
|
||||
void taskCanceled();
|
||||
void taskStarted();
|
||||
void taskPaused();
|
||||
|
||||
void screenshot();
|
||||
void saveMovie();
|
||||
void saveSVG();
|
||||
|
||||
void about();
|
||||
|
||||
Q_SIGNALS:
|
||||
void contextChanged(Context *ctx);
|
||||
void updateTreeView();
|
||||
|
||||
protected:
|
||||
// state variables
|
||||
CommandHandler *handler;
|
||||
std::unique_ptr<Context> ctx;
|
||||
TaskManager *task;
|
||||
bool timing_driven;
|
||||
std::string currentProj;
|
||||
|
||||
// main widgets
|
||||
QTabWidget *tabWidget;
|
||||
QTabWidget *centralTabWidget;
|
||||
PythonTab *console;
|
||||
DesignWidget *designview;
|
||||
FPGAViewWidget *fpgaView;
|
||||
|
||||
// Menus, bars and actions
|
||||
QMenuBar *menuBar;
|
||||
QMenu *menuDesign;
|
||||
QStatusBar *statusBar;
|
||||
QToolBar *mainActionBar;
|
||||
QProgressBar *progressBar;
|
||||
|
||||
QAction *actionNew;
|
||||
QAction *actionLoadJSON;
|
||||
QAction *actionSaveJSON;
|
||||
|
||||
QAction *actionPack;
|
||||
QAction *actionPlace;
|
||||
QAction *actionRoute;
|
||||
|
||||
QAction *actionExecutePy;
|
||||
|
||||
QAction *actionPlay;
|
||||
QAction *actionPause;
|
||||
QAction *actionStop;
|
||||
|
||||
QAction *actionDisplayBel;
|
||||
QAction *actionDisplayWire;
|
||||
QAction *actionDisplayPip;
|
||||
QAction *actionDisplayGroups;
|
||||
|
||||
QAction *actionScreenshot;
|
||||
QAction *actionMovie;
|
||||
QAction *actionSaveSVG;
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // BASEMAINWINDOW_H
|
||||
|
2144
gui/designwidget.cc
2144
gui/designwidget.cc
File diff suppressed because it is too large
Load Diff
@ -1,138 +1,138 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DESIGNWIDGET_H
|
||||
#define DESIGNWIDGET_H
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QTabWidget>
|
||||
#include <QTreeView>
|
||||
#include <QVariant>
|
||||
#include "nextpnr.h"
|
||||
#include "qtgroupboxpropertybrowser.h"
|
||||
#include "qtpropertymanager.h"
|
||||
#include "qttreepropertybrowser.h"
|
||||
#include "qtvariantproperty.h"
|
||||
#include "treemodel.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class TreeView : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TreeView(QWidget *parent = 0);
|
||||
~TreeView();
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void hoverIndexChanged(QModelIndex index);
|
||||
|
||||
private:
|
||||
QModelIndex current;
|
||||
};
|
||||
|
||||
class DesignWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DesignWidget(QWidget *parent = 0);
|
||||
~DesignWidget();
|
||||
|
||||
private:
|
||||
void clearProperties();
|
||||
QtProperty *addTopLevelProperty(const QString &id);
|
||||
QtProperty *addSubGroup(QtProperty *topItem, const QString &name);
|
||||
void addProperty(QtProperty *topItem, int propertyType, const QString &name, QVariant value,
|
||||
const ElementType &type = ElementType::NONE);
|
||||
QString getElementTypeName(ElementType type);
|
||||
ElementType getElementTypeByName(QString type);
|
||||
TreeModel::Model *getTreeByElementType(ElementType type);
|
||||
int getIndexByElementType(ElementType type);
|
||||
int getElementIndex(ElementType type);
|
||||
void updateButtons();
|
||||
void addToHistory(int tab, QModelIndex item);
|
||||
std::vector<DecalXY> getDecals(ElementType type, IdStringList value);
|
||||
void updateHighlightGroup(QList<TreeModel::Item *> item, int group);
|
||||
void clearAllSelectionModels();
|
||||
Q_SIGNALS:
|
||||
void selected(std::vector<DecalXY> decal, bool keep);
|
||||
void highlight(std::vector<DecalXY> decal, int group);
|
||||
void hover(DecalXY decal);
|
||||
void zoomSelected();
|
||||
|
||||
private Q_SLOTS:
|
||||
void prepareMenuProperty(const QPoint &pos);
|
||||
void prepareMenuTree(int num, const QPoint &pos);
|
||||
void onSelectionChanged(int num, const QItemSelection &selected, const QItemSelection &deselected);
|
||||
void onItemDoubleClicked(QTreeWidgetItem *item, int column);
|
||||
void onDoubleClicked(const QModelIndex &index);
|
||||
void onSearchInserted();
|
||||
void onHoverIndexChanged(int num, QModelIndex index);
|
||||
void onHoverPropertyChanged(QtBrowserItem *item);
|
||||
public Q_SLOTS:
|
||||
void newContext(Context *ctx);
|
||||
void updateTree();
|
||||
void onClickedBel(BelId bel, bool keep);
|
||||
void onClickedWire(WireId wire, bool keep);
|
||||
void onClickedPip(PipId pip, bool keep);
|
||||
|
||||
private:
|
||||
Context *ctx;
|
||||
|
||||
QTabWidget *tabWidget;
|
||||
|
||||
TreeView *treeView[6];
|
||||
QItemSelectionModel *selectionModel[6];
|
||||
TreeModel::Model *treeModel[6];
|
||||
QLineEdit *searchEdit;
|
||||
QtVariantPropertyManager *variantManager;
|
||||
QtVariantPropertyManager *readOnlyManager;
|
||||
QtGroupPropertyManager *groupManager;
|
||||
QtVariantEditorFactory *variantFactory;
|
||||
QtTreePropertyBrowser *propertyEditor;
|
||||
|
||||
QMap<QtProperty *, QString> propertyToId;
|
||||
QMap<QString, QtProperty *> idToProperty;
|
||||
|
||||
std::vector<std::pair<int, QModelIndex>> history;
|
||||
int history_index;
|
||||
bool history_ignore;
|
||||
|
||||
QAction *actionFirst;
|
||||
QAction *actionPrev;
|
||||
QAction *actionNext;
|
||||
QAction *actionLast;
|
||||
QAction *actionClear;
|
||||
|
||||
QColor highlightColors[8];
|
||||
QMap<TreeModel::Item *, int> highlightSelected;
|
||||
|
||||
QString currentSearch;
|
||||
QList<QModelIndex> currentSearchIndexes;
|
||||
int currentIndex;
|
||||
int currentIndexTab;
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // DESIGNWIDGET_H
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DESIGNWIDGET_H
|
||||
#define DESIGNWIDGET_H
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QTabWidget>
|
||||
#include <QTreeView>
|
||||
#include <QVariant>
|
||||
#include "nextpnr.h"
|
||||
#include "qtgroupboxpropertybrowser.h"
|
||||
#include "qtpropertymanager.h"
|
||||
#include "qttreepropertybrowser.h"
|
||||
#include "qtvariantproperty.h"
|
||||
#include "treemodel.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class TreeView : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TreeView(QWidget *parent = 0);
|
||||
~TreeView();
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void hoverIndexChanged(QModelIndex index);
|
||||
|
||||
private:
|
||||
QModelIndex current;
|
||||
};
|
||||
|
||||
class DesignWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DesignWidget(QWidget *parent = 0);
|
||||
~DesignWidget();
|
||||
|
||||
private:
|
||||
void clearProperties();
|
||||
QtProperty *addTopLevelProperty(const QString &id);
|
||||
QtProperty *addSubGroup(QtProperty *topItem, const QString &name);
|
||||
void addProperty(QtProperty *topItem, int propertyType, const QString &name, QVariant value,
|
||||
const ElementType &type = ElementType::NONE);
|
||||
QString getElementTypeName(ElementType type);
|
||||
ElementType getElementTypeByName(QString type);
|
||||
TreeModel::Model *getTreeByElementType(ElementType type);
|
||||
int getIndexByElementType(ElementType type);
|
||||
int getElementIndex(ElementType type);
|
||||
void updateButtons();
|
||||
void addToHistory(int tab, QModelIndex item);
|
||||
std::vector<DecalXY> getDecals(ElementType type, IdStringList value);
|
||||
void updateHighlightGroup(QList<TreeModel::Item *> item, int group);
|
||||
void clearAllSelectionModels();
|
||||
Q_SIGNALS:
|
||||
void selected(std::vector<DecalXY> decal, bool keep);
|
||||
void highlight(std::vector<DecalXY> decal, int group);
|
||||
void hover(DecalXY decal);
|
||||
void zoomSelected();
|
||||
|
||||
private Q_SLOTS:
|
||||
void prepareMenuProperty(const QPoint &pos);
|
||||
void prepareMenuTree(int num, const QPoint &pos);
|
||||
void onSelectionChanged(int num, const QItemSelection &selected, const QItemSelection &deselected);
|
||||
void onItemDoubleClicked(QTreeWidgetItem *item, int column);
|
||||
void onDoubleClicked(const QModelIndex &index);
|
||||
void onSearchInserted();
|
||||
void onHoverIndexChanged(int num, QModelIndex index);
|
||||
void onHoverPropertyChanged(QtBrowserItem *item);
|
||||
public Q_SLOTS:
|
||||
void newContext(Context *ctx);
|
||||
void updateTree();
|
||||
void onClickedBel(BelId bel, bool keep);
|
||||
void onClickedWire(WireId wire, bool keep);
|
||||
void onClickedPip(PipId pip, bool keep);
|
||||
|
||||
private:
|
||||
Context *ctx;
|
||||
|
||||
QTabWidget *tabWidget;
|
||||
|
||||
TreeView *treeView[6];
|
||||
QItemSelectionModel *selectionModel[6];
|
||||
TreeModel::Model *treeModel[6];
|
||||
QLineEdit *searchEdit;
|
||||
QtVariantPropertyManager *variantManager;
|
||||
QtVariantPropertyManager *readOnlyManager;
|
||||
QtGroupPropertyManager *groupManager;
|
||||
QtVariantEditorFactory *variantFactory;
|
||||
QtTreePropertyBrowser *propertyEditor;
|
||||
|
||||
QMap<QtProperty *, QString> propertyToId;
|
||||
QMap<QString, QtProperty *> idToProperty;
|
||||
|
||||
std::vector<std::pair<int, QModelIndex>> history;
|
||||
int history_index;
|
||||
bool history_ignore;
|
||||
|
||||
QAction *actionFirst;
|
||||
QAction *actionPrev;
|
||||
QAction *actionNext;
|
||||
QAction *actionLast;
|
||||
QAction *actionClear;
|
||||
|
||||
QColor highlightColors[8];
|
||||
QMap<TreeModel::Item *, int> highlightSelected;
|
||||
|
||||
QString currentSearch;
|
||||
QList<QModelIndex> currentSearchIndexes;
|
||||
int currentIndex;
|
||||
int currentIndexTab;
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // DESIGNWIDGET_H
|
||||
|
@ -1,166 +1,166 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include <fstream>
|
||||
#include "bitstream.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QLineEdit>
|
||||
|
||||
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent)
|
||||
: BaseMainWindow(std::move(context), handler, parent)
|
||||
{
|
||||
initMainResource();
|
||||
|
||||
std::string title = "nextpnr-ecp5 - [EMPTY]";
|
||||
setWindowTitle(title.c_str());
|
||||
|
||||
connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
|
||||
|
||||
createMenu();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {}
|
||||
|
||||
void MainWindow::newContext(Context *ctx)
|
||||
{
|
||||
std::string title = "nextpnr-ecp5 - " + ctx->getChipName() + " ( " + ctx->archArgs().package + " )";
|
||||
setWindowTitle(title.c_str());
|
||||
}
|
||||
|
||||
void MainWindow::createMenu()
|
||||
{
|
||||
// Add arch specific actions
|
||||
actionLoadLPF = new QAction("Open LPF", this);
|
||||
actionLoadLPF->setIcon(QIcon(":/icons/resources/open_lpf.png"));
|
||||
actionLoadLPF->setStatusTip("Open LPF file");
|
||||
actionLoadLPF->setEnabled(false);
|
||||
connect(actionLoadLPF, &QAction::triggered, this, &MainWindow::open_lpf);
|
||||
|
||||
actionSaveConfig = new QAction("Save Bitstream", this);
|
||||
actionSaveConfig->setIcon(QIcon(":/icons/resources/save_config.png"));
|
||||
actionSaveConfig->setStatusTip("Save Bitstream config file");
|
||||
actionSaveConfig->setEnabled(false);
|
||||
connect(actionSaveConfig, &QAction::triggered, this, &MainWindow::save_config);
|
||||
|
||||
// Add actions in menus
|
||||
mainActionBar->addSeparator();
|
||||
mainActionBar->addAction(actionLoadLPF);
|
||||
mainActionBar->addAction(actionSaveConfig);
|
||||
|
||||
menuDesign->addSeparator();
|
||||
menuDesign->addAction(actionLoadLPF);
|
||||
menuDesign->addAction(actionSaveConfig);
|
||||
}
|
||||
|
||||
void MainWindow::new_proj()
|
||||
{
|
||||
QMap<QString, int> arch;
|
||||
if (Arch::is_available(ArchArgs::LFE5U_25F))
|
||||
arch.insert("Lattice ECP5 LFE5U-25F", ArchArgs::LFE5U_25F);
|
||||
if (Arch::is_available(ArchArgs::LFE5U_45F))
|
||||
arch.insert("Lattice ECP5 LFE5U-45F", ArchArgs::LFE5U_45F);
|
||||
if (Arch::is_available(ArchArgs::LFE5U_85F))
|
||||
arch.insert("Lattice ECP5 LFE5U-85F", ArchArgs::LFE5U_85F);
|
||||
if (Arch::is_available(ArchArgs::LFE5UM_25F))
|
||||
arch.insert("Lattice ECP5 LFE5UM-25F", ArchArgs::LFE5UM_25F);
|
||||
if (Arch::is_available(ArchArgs::LFE5UM_45F))
|
||||
arch.insert("Lattice ECP5 LFE5UM-45F", ArchArgs::LFE5UM_45F);
|
||||
if (Arch::is_available(ArchArgs::LFE5UM_85F))
|
||||
arch.insert("Lattice ECP5 LFE5UM-85F", ArchArgs::LFE5UM_85F);
|
||||
if (Arch::is_available(ArchArgs::LFE5UM5G_25F))
|
||||
arch.insert("Lattice ECP5 LFE5UM5G-25F", ArchArgs::LFE5UM5G_25F);
|
||||
if (Arch::is_available(ArchArgs::LFE5UM5G_45F))
|
||||
arch.insert("Lattice ECP5 LFE5UM5G-45F", ArchArgs::LFE5UM5G_45F);
|
||||
if (Arch::is_available(ArchArgs::LFE5UM5G_85F))
|
||||
arch.insert("Lattice ECP5 LFE5UM5G-85F", ArchArgs::LFE5UM5G_85F);
|
||||
|
||||
bool ok;
|
||||
QString item = QInputDialog::getItem(this, "Select new context", "Chip:", arch.keys(), 0, false, &ok);
|
||||
if (ok && !item.isEmpty()) {
|
||||
ArchArgs chipArgs;
|
||||
chipArgs.type = (ArchArgs::ArchArgsTypes)arch.value(item);
|
||||
|
||||
QStringList packages;
|
||||
for (auto package : Arch::get_supported_packages(chipArgs.type))
|
||||
packages.append(QLatin1String(package.data(), package.size()));
|
||||
QString package = QInputDialog::getItem(this, "Select package", "Package:", packages, 0, false, &ok);
|
||||
|
||||
if (ok && !item.isEmpty()) {
|
||||
handler->clear();
|
||||
currentProj = "";
|
||||
disableActions();
|
||||
chipArgs.package = package.toStdString().c_str();
|
||||
ctx = std::unique_ptr<Context>(new Context(chipArgs));
|
||||
actionLoadJSON->setEnabled(true);
|
||||
|
||||
Q_EMIT contextChanged(ctx.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::open_lpf()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, QString("Open LPF"), QString(), QString("*.lpf"));
|
||||
if (!fileName.isEmpty()) {
|
||||
std::ifstream in(fileName.toStdString());
|
||||
if (ctx->apply_lpf(fileName.toStdString(), in)) {
|
||||
log("Loading LPF successful.\n");
|
||||
actionPack->setEnabled(true);
|
||||
actionLoadLPF->setEnabled(false);
|
||||
} else {
|
||||
actionLoadLPF->setEnabled(true);
|
||||
log("Loading LPF failed.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::save_config()
|
||||
{
|
||||
QString fileName = QFileDialog::getSaveFileName(this, QString("Save Bitstream"), QString(), QString("*.config"));
|
||||
if (!fileName.isEmpty()) {
|
||||
std::string fn = fileName.toStdString();
|
||||
disableActions();
|
||||
write_bitstream(ctx.get(), "", fileName.toStdString());
|
||||
log("Saving Bitstream successful.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onDisableActions()
|
||||
{
|
||||
actionLoadLPF->setEnabled(false);
|
||||
actionSaveConfig->setEnabled(false);
|
||||
}
|
||||
|
||||
void MainWindow::onUpdateActions()
|
||||
{
|
||||
if (ctx->settings.find(ctx->id("pack")) == ctx->settings.end())
|
||||
actionLoadLPF->setEnabled(true);
|
||||
if (ctx->settings.find(ctx->id("route")) != ctx->settings.end())
|
||||
actionSaveConfig->setEnabled(true);
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include <fstream>
|
||||
#include "bitstream.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QLineEdit>
|
||||
|
||||
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent)
|
||||
: BaseMainWindow(std::move(context), handler, parent)
|
||||
{
|
||||
initMainResource();
|
||||
|
||||
std::string title = "nextpnr-ecp5 - [EMPTY]";
|
||||
setWindowTitle(title.c_str());
|
||||
|
||||
connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
|
||||
|
||||
createMenu();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {}
|
||||
|
||||
void MainWindow::newContext(Context *ctx)
|
||||
{
|
||||
std::string title = "nextpnr-ecp5 - " + ctx->getChipName() + " ( " + ctx->archArgs().package + " )";
|
||||
setWindowTitle(title.c_str());
|
||||
}
|
||||
|
||||
void MainWindow::createMenu()
|
||||
{
|
||||
// Add arch specific actions
|
||||
actionLoadLPF = new QAction("Open LPF", this);
|
||||
actionLoadLPF->setIcon(QIcon(":/icons/resources/open_lpf.png"));
|
||||
actionLoadLPF->setStatusTip("Open LPF file");
|
||||
actionLoadLPF->setEnabled(false);
|
||||
connect(actionLoadLPF, &QAction::triggered, this, &MainWindow::open_lpf);
|
||||
|
||||
actionSaveConfig = new QAction("Save Bitstream", this);
|
||||
actionSaveConfig->setIcon(QIcon(":/icons/resources/save_config.png"));
|
||||
actionSaveConfig->setStatusTip("Save Bitstream config file");
|
||||
actionSaveConfig->setEnabled(false);
|
||||
connect(actionSaveConfig, &QAction::triggered, this, &MainWindow::save_config);
|
||||
|
||||
// Add actions in menus
|
||||
mainActionBar->addSeparator();
|
||||
mainActionBar->addAction(actionLoadLPF);
|
||||
mainActionBar->addAction(actionSaveConfig);
|
||||
|
||||
menuDesign->addSeparator();
|
||||
menuDesign->addAction(actionLoadLPF);
|
||||
menuDesign->addAction(actionSaveConfig);
|
||||
}
|
||||
|
||||
void MainWindow::new_proj()
|
||||
{
|
||||
QMap<QString, int> arch;
|
||||
if (Arch::is_available(ArchArgs::LFE5U_25F))
|
||||
arch.insert("Lattice ECP5 LFE5U-25F", ArchArgs::LFE5U_25F);
|
||||
if (Arch::is_available(ArchArgs::LFE5U_45F))
|
||||
arch.insert("Lattice ECP5 LFE5U-45F", ArchArgs::LFE5U_45F);
|
||||
if (Arch::is_available(ArchArgs::LFE5U_85F))
|
||||
arch.insert("Lattice ECP5 LFE5U-85F", ArchArgs::LFE5U_85F);
|
||||
if (Arch::is_available(ArchArgs::LFE5UM_25F))
|
||||
arch.insert("Lattice ECP5 LFE5UM-25F", ArchArgs::LFE5UM_25F);
|
||||
if (Arch::is_available(ArchArgs::LFE5UM_45F))
|
||||
arch.insert("Lattice ECP5 LFE5UM-45F", ArchArgs::LFE5UM_45F);
|
||||
if (Arch::is_available(ArchArgs::LFE5UM_85F))
|
||||
arch.insert("Lattice ECP5 LFE5UM-85F", ArchArgs::LFE5UM_85F);
|
||||
if (Arch::is_available(ArchArgs::LFE5UM5G_25F))
|
||||
arch.insert("Lattice ECP5 LFE5UM5G-25F", ArchArgs::LFE5UM5G_25F);
|
||||
if (Arch::is_available(ArchArgs::LFE5UM5G_45F))
|
||||
arch.insert("Lattice ECP5 LFE5UM5G-45F", ArchArgs::LFE5UM5G_45F);
|
||||
if (Arch::is_available(ArchArgs::LFE5UM5G_85F))
|
||||
arch.insert("Lattice ECP5 LFE5UM5G-85F", ArchArgs::LFE5UM5G_85F);
|
||||
|
||||
bool ok;
|
||||
QString item = QInputDialog::getItem(this, "Select new context", "Chip:", arch.keys(), 0, false, &ok);
|
||||
if (ok && !item.isEmpty()) {
|
||||
ArchArgs chipArgs;
|
||||
chipArgs.type = (ArchArgs::ArchArgsTypes)arch.value(item);
|
||||
|
||||
QStringList packages;
|
||||
for (auto package : Arch::get_supported_packages(chipArgs.type))
|
||||
packages.append(QLatin1String(package.data(), package.size()));
|
||||
QString package = QInputDialog::getItem(this, "Select package", "Package:", packages, 0, false, &ok);
|
||||
|
||||
if (ok && !item.isEmpty()) {
|
||||
handler->clear();
|
||||
currentProj = "";
|
||||
disableActions();
|
||||
chipArgs.package = package.toStdString().c_str();
|
||||
ctx = std::unique_ptr<Context>(new Context(chipArgs));
|
||||
actionLoadJSON->setEnabled(true);
|
||||
|
||||
Q_EMIT contextChanged(ctx.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::open_lpf()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, QString("Open LPF"), QString(), QString("*.lpf"));
|
||||
if (!fileName.isEmpty()) {
|
||||
std::ifstream in(fileName.toStdString());
|
||||
if (ctx->apply_lpf(fileName.toStdString(), in)) {
|
||||
log("Loading LPF successful.\n");
|
||||
actionPack->setEnabled(true);
|
||||
actionLoadLPF->setEnabled(false);
|
||||
} else {
|
||||
actionLoadLPF->setEnabled(true);
|
||||
log("Loading LPF failed.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::save_config()
|
||||
{
|
||||
QString fileName = QFileDialog::getSaveFileName(this, QString("Save Bitstream"), QString(), QString("*.config"));
|
||||
if (!fileName.isEmpty()) {
|
||||
std::string fn = fileName.toStdString();
|
||||
disableActions();
|
||||
write_bitstream(ctx.get(), "", fileName.toStdString());
|
||||
log("Saving Bitstream successful.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onDisableActions()
|
||||
{
|
||||
actionLoadLPF->setEnabled(false);
|
||||
actionSaveConfig->setEnabled(false);
|
||||
}
|
||||
|
||||
void MainWindow::onUpdateActions()
|
||||
{
|
||||
if (ctx->settings.find(ctx->id("pack")) == ctx->settings.end())
|
||||
actionLoadLPF->setEnabled(true);
|
||||
if (ctx->settings.find(ctx->id("route")) != ctx->settings.end())
|
||||
actionSaveConfig->setEnabled(true);
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -1,55 +1,55 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "../basewindow.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class MainWindow : public BaseMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent = 0);
|
||||
virtual ~MainWindow();
|
||||
|
||||
public:
|
||||
void createMenu();
|
||||
|
||||
protected:
|
||||
void onDisableActions() override;
|
||||
void onUpdateActions() override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void new_proj() override;
|
||||
void newContext(Context *ctx);
|
||||
void open_lpf();
|
||||
void save_config();
|
||||
|
||||
private:
|
||||
QAction *actionLoadLPF;
|
||||
QAction *actionSaveConfig;
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "../basewindow.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class MainWindow : public BaseMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent = 0);
|
||||
virtual ~MainWindow();
|
||||
|
||||
public:
|
||||
void createMenu();
|
||||
|
||||
protected:
|
||||
void onDisableActions() override;
|
||||
void onUpdateActions() override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void new_proj() override;
|
||||
void newContext(Context *ctx);
|
||||
void open_lpf();
|
||||
void save_config();
|
||||
|
||||
private:
|
||||
QAction *actionLoadLPF;
|
||||
QAction *actionSaveConfig;
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
@ -1,50 +1,50 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
* Copyright (C) 2021 Symbiflow Authors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <cstdlib>
|
||||
|
||||
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent)
|
||||
: BaseMainWindow(std::move(context), handler, parent)
|
||||
{
|
||||
initMainResource();
|
||||
QMessageBox::critical(0, "Error - FIXME", "No GUI support for nextpnr-generic");
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {}
|
||||
|
||||
void MainWindow::newContext(Context *ctx)
|
||||
{
|
||||
std::string title = "nextpnr-generic - " + ctx->getChipName();
|
||||
setWindowTitle(title.c_str());
|
||||
}
|
||||
|
||||
void MainWindow::createMenu() {}
|
||||
|
||||
void MainWindow::new_proj() {}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
* Copyright (C) 2021 Symbiflow Authors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <cstdlib>
|
||||
|
||||
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent)
|
||||
: BaseMainWindow(std::move(context), handler, parent)
|
||||
{
|
||||
initMainResource();
|
||||
QMessageBox::critical(0, "Error - FIXME", "No GUI support for nextpnr-generic");
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {}
|
||||
|
||||
void MainWindow::newContext(Context *ctx)
|
||||
{
|
||||
std::string title = "nextpnr-generic - " + ctx->getChipName();
|
||||
setWindowTitle(title.c_str());
|
||||
}
|
||||
|
||||
void MainWindow::createMenu() {}
|
||||
|
||||
void MainWindow::new_proj() {}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -1,46 +1,46 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
* Copyright (C) 2021 Symbiflow Authors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "../basewindow.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class MainWindow : public BaseMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent = 0);
|
||||
virtual ~MainWindow();
|
||||
|
||||
public:
|
||||
void createMenu();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void new_proj() override;
|
||||
void newContext(Context *ctx);
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
* Copyright (C) 2021 Symbiflow Authors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "../basewindow.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class MainWindow : public BaseMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent = 0);
|
||||
virtual ~MainWindow();
|
||||
|
||||
public:
|
||||
void createMenu();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void new_proj() override;
|
||||
void newContext(Context *ctx);
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
@ -1,52 +1,52 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <cstdlib>
|
||||
|
||||
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent)
|
||||
: BaseMainWindow(std::move(context), handler, parent)
|
||||
{
|
||||
initMainResource();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {}
|
||||
|
||||
void MainWindow::newContext(Context *ctx)
|
||||
{
|
||||
std::string title = "nextpnr-generic - " + ctx->getChipName();
|
||||
setWindowTitle(title.c_str());
|
||||
}
|
||||
|
||||
void MainWindow::createMenu() {}
|
||||
|
||||
void MainWindow::new_proj()
|
||||
{
|
||||
QMessageBox::critical(0, "Error",
|
||||
"Creating a new project not supported in Viaduct mode, please re-start from command line.");
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <cstdlib>
|
||||
|
||||
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent)
|
||||
: BaseMainWindow(std::move(context), handler, parent)
|
||||
{
|
||||
initMainResource();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {}
|
||||
|
||||
void MainWindow::newContext(Context *ctx)
|
||||
{
|
||||
std::string title = "nextpnr-generic - " + ctx->getChipName();
|
||||
setWindowTitle(title.c_str());
|
||||
}
|
||||
|
||||
void MainWindow::createMenu() {}
|
||||
|
||||
void MainWindow::new_proj()
|
||||
{
|
||||
QMessageBox::critical(0, "Error",
|
||||
"Creating a new project not supported in Viaduct mode, please re-start from command line.");
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -1,45 +1,45 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "../basewindow.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class MainWindow : public BaseMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent = 0);
|
||||
virtual ~MainWindow();
|
||||
|
||||
public:
|
||||
void createMenu();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void new_proj() override;
|
||||
void newContext(Context *ctx);
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "../basewindow.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class MainWindow : public BaseMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent = 0);
|
||||
virtual ~MainWindow();
|
||||
|
||||
public:
|
||||
void createMenu();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void new_proj() override;
|
||||
void newContext(Context *ctx);
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
@ -1,103 +1,103 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "cst.h"
|
||||
|
||||
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent)
|
||||
: BaseMainWindow(std::move(context), handler, parent)
|
||||
{
|
||||
initMainResource();
|
||||
std::string title = "nextpnr-gowin - [EMPTY]";
|
||||
setWindowTitle(title.c_str());
|
||||
connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
|
||||
createMenu();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {}
|
||||
|
||||
void MainWindow::newContext(Context *ctx)
|
||||
{
|
||||
std::string title = "nextpnr-gowin - " + ctx->getChipName();
|
||||
setWindowTitle(title.c_str());
|
||||
}
|
||||
|
||||
void MainWindow::load_cst(std::string filename)
|
||||
{
|
||||
disableActions();
|
||||
std::ifstream f(filename);
|
||||
if (read_cst(ctx.get(), f)) {
|
||||
log("Loading CST successful.\n");
|
||||
actionPack->setEnabled(true);
|
||||
} else {
|
||||
actionLoadCST->setEnabled(true);
|
||||
log("Loading CST failed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::createMenu()
|
||||
{
|
||||
actionLoadCST = new QAction("Open CST", this);
|
||||
actionLoadCST->setIcon(QIcon(":/icons/resources/open_cst.png"));
|
||||
actionLoadCST->setStatusTip("Open CST file");
|
||||
actionLoadCST->setEnabled(false);
|
||||
connect(actionLoadCST, &QAction::triggered, this, &MainWindow::open_cst);
|
||||
|
||||
// Add actions in menus
|
||||
mainActionBar->addSeparator();
|
||||
mainActionBar->addAction(actionLoadCST);
|
||||
|
||||
menuDesign->addSeparator();
|
||||
menuDesign->addAction(actionLoadCST);
|
||||
}
|
||||
|
||||
void MainWindow::new_proj() {}
|
||||
|
||||
void MainWindow::open_cst()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, QString("Open CST"), QString(), QString("*.cst"));
|
||||
if (!fileName.isEmpty()) {
|
||||
load_cst(fileName.toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onDisableActions() { actionLoadCST->setEnabled(false); }
|
||||
|
||||
void MainWindow::onUpdateActions()
|
||||
{
|
||||
if (ctx->settings.find(ctx->id("synth")) != ctx->settings.end()) {
|
||||
actionLoadCST->setEnabled(true);
|
||||
}
|
||||
if (ctx->settings.find(ctx->id("cst")) != ctx->settings.end()) {
|
||||
actionLoadCST->setEnabled(false);
|
||||
}
|
||||
if (ctx->settings.find(ctx->id("pack")) != ctx->settings.end()) {
|
||||
actionLoadCST->setEnabled(false);
|
||||
}
|
||||
}
|
||||
NEXTPNR_NAMESPACE_END
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "cst.h"
|
||||
|
||||
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent)
|
||||
: BaseMainWindow(std::move(context), handler, parent)
|
||||
{
|
||||
initMainResource();
|
||||
std::string title = "nextpnr-gowin - [EMPTY]";
|
||||
setWindowTitle(title.c_str());
|
||||
connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
|
||||
createMenu();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {}
|
||||
|
||||
void MainWindow::newContext(Context *ctx)
|
||||
{
|
||||
std::string title = "nextpnr-gowin - " + ctx->getChipName();
|
||||
setWindowTitle(title.c_str());
|
||||
}
|
||||
|
||||
void MainWindow::load_cst(std::string filename)
|
||||
{
|
||||
disableActions();
|
||||
std::ifstream f(filename);
|
||||
if (read_cst(ctx.get(), f)) {
|
||||
log("Loading CST successful.\n");
|
||||
actionPack->setEnabled(true);
|
||||
} else {
|
||||
actionLoadCST->setEnabled(true);
|
||||
log("Loading CST failed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::createMenu()
|
||||
{
|
||||
actionLoadCST = new QAction("Open CST", this);
|
||||
actionLoadCST->setIcon(QIcon(":/icons/resources/open_cst.png"));
|
||||
actionLoadCST->setStatusTip("Open CST file");
|
||||
actionLoadCST->setEnabled(false);
|
||||
connect(actionLoadCST, &QAction::triggered, this, &MainWindow::open_cst);
|
||||
|
||||
// Add actions in menus
|
||||
mainActionBar->addSeparator();
|
||||
mainActionBar->addAction(actionLoadCST);
|
||||
|
||||
menuDesign->addSeparator();
|
||||
menuDesign->addAction(actionLoadCST);
|
||||
}
|
||||
|
||||
void MainWindow::new_proj() {}
|
||||
|
||||
void MainWindow::open_cst()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, QString("Open CST"), QString(), QString("*.cst"));
|
||||
if (!fileName.isEmpty()) {
|
||||
load_cst(fileName.toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onDisableActions() { actionLoadCST->setEnabled(false); }
|
||||
|
||||
void MainWindow::onUpdateActions()
|
||||
{
|
||||
if (ctx->settings.find(ctx->id("synth")) != ctx->settings.end()) {
|
||||
actionLoadCST->setEnabled(true);
|
||||
}
|
||||
if (ctx->settings.find(ctx->id("cst")) != ctx->settings.end()) {
|
||||
actionLoadCST->setEnabled(false);
|
||||
}
|
||||
if (ctx->settings.find(ctx->id("pack")) != ctx->settings.end()) {
|
||||
actionLoadCST->setEnabled(false);
|
||||
}
|
||||
}
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -1,57 +1,57 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "../basewindow.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class MainWindow : public BaseMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent = 0);
|
||||
virtual ~MainWindow();
|
||||
|
||||
public:
|
||||
void createMenu();
|
||||
|
||||
protected:
|
||||
void onDisableActions() override;
|
||||
void onUpdateActions() override;
|
||||
|
||||
void load_cst(std::string filename);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void new_proj() override;
|
||||
|
||||
void open_cst();
|
||||
|
||||
void newContext(Context *ctx);
|
||||
|
||||
private:
|
||||
QAction *actionLoadCST;
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "../basewindow.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class MainWindow : public BaseMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent = 0);
|
||||
virtual ~MainWindow();
|
||||
|
||||
public:
|
||||
void createMenu();
|
||||
|
||||
protected:
|
||||
void onDisableActions() override;
|
||||
void onUpdateActions() override;
|
||||
|
||||
void load_cst(std::string filename);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void new_proj() override;
|
||||
|
||||
void open_cst();
|
||||
|
||||
void newContext(Context *ctx);
|
||||
|
||||
private:
|
||||
QAction *actionLoadCST;
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
@ -1,182 +1,182 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include <QAction>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QIcon>
|
||||
#include <QInputDialog>
|
||||
#include <QLineEdit>
|
||||
#include <fstream>
|
||||
#include "bitstream.h"
|
||||
#include "design_utils.h"
|
||||
#include "log.h"
|
||||
#include "pcf.h"
|
||||
|
||||
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent)
|
||||
: BaseMainWindow(std::move(context), handler, parent)
|
||||
{
|
||||
initMainResource();
|
||||
|
||||
std::string title = "nextpnr-ice40 - [EMPTY]";
|
||||
setWindowTitle(title.c_str());
|
||||
|
||||
connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
|
||||
|
||||
createMenu();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {}
|
||||
|
||||
void MainWindow::createMenu()
|
||||
{
|
||||
// Add arch specific actions
|
||||
actionLoadPCF = new QAction("Open PCF", this);
|
||||
actionLoadPCF->setIcon(QIcon(":/icons/resources/open_pcf.png"));
|
||||
actionLoadPCF->setStatusTip("Open PCF file");
|
||||
actionLoadPCF->setEnabled(false);
|
||||
connect(actionLoadPCF, &QAction::triggered, this, &MainWindow::open_pcf);
|
||||
|
||||
actionSaveAsc = new QAction("Save ASC", this);
|
||||
actionSaveAsc->setIcon(QIcon(":/icons/resources/save_asc.png"));
|
||||
actionSaveAsc->setStatusTip("Save ASC file");
|
||||
actionSaveAsc->setEnabled(false);
|
||||
connect(actionSaveAsc, &QAction::triggered, this, &MainWindow::save_asc);
|
||||
|
||||
// Add actions in menus
|
||||
mainActionBar->addSeparator();
|
||||
mainActionBar->addAction(actionLoadPCF);
|
||||
mainActionBar->addAction(actionSaveAsc);
|
||||
|
||||
menuDesign->addSeparator();
|
||||
menuDesign->addAction(actionLoadPCF);
|
||||
menuDesign->addAction(actionSaveAsc);
|
||||
}
|
||||
|
||||
void MainWindow::new_proj()
|
||||
{
|
||||
QMap<QString, int> arch;
|
||||
if (Arch::is_available(ArchArgs::LP384))
|
||||
arch.insert("Lattice iCE40LP384", ArchArgs::LP384);
|
||||
if (Arch::is_available(ArchArgs::LP1K))
|
||||
arch.insert("Lattice iCE40LP1K", ArchArgs::LP1K);
|
||||
if (Arch::is_available(ArchArgs::HX1K))
|
||||
arch.insert("Lattice iCE40HX1K", ArchArgs::HX1K);
|
||||
if (Arch::is_available(ArchArgs::U1K))
|
||||
arch.insert("Lattice iCE5LP1K", ArchArgs::U1K);
|
||||
if (Arch::is_available(ArchArgs::U2K))
|
||||
arch.insert("Lattice iCE5LP2K", ArchArgs::U2K);
|
||||
if (Arch::is_available(ArchArgs::U4K))
|
||||
arch.insert("Lattice iCE5LP4K", ArchArgs::U4K);
|
||||
if (Arch::is_available(ArchArgs::UP3K))
|
||||
arch.insert("Lattice iCE40UP3K", ArchArgs::UP3K);
|
||||
if (Arch::is_available(ArchArgs::UP5K))
|
||||
arch.insert("Lattice iCE40UP5K", ArchArgs::UP5K);
|
||||
if (Arch::is_available(ArchArgs::LP4K))
|
||||
arch.insert("Lattice iCE40LP4K", ArchArgs::LP4K);
|
||||
if (Arch::is_available(ArchArgs::LP8K))
|
||||
arch.insert("Lattice iCE40LP8K", ArchArgs::LP8K);
|
||||
if (Arch::is_available(ArchArgs::HX4K))
|
||||
arch.insert("Lattice iCE40HX4K", ArchArgs::HX4K);
|
||||
if (Arch::is_available(ArchArgs::HX8K))
|
||||
arch.insert("Lattice iCE40HX8K", ArchArgs::HX8K);
|
||||
|
||||
bool ok;
|
||||
QString item = QInputDialog::getItem(this, "Select new context", "Chip:", arch.keys(), 0, false, &ok);
|
||||
if (ok && !item.isEmpty()) {
|
||||
ArchArgs chipArgs;
|
||||
chipArgs.type = (ArchArgs::ArchArgsTypes)arch.value(item);
|
||||
|
||||
QStringList packages;
|
||||
for (auto package : Arch::get_supported_packages(chipArgs.type))
|
||||
packages.append(QLatin1String(package.data(), package.size()));
|
||||
QString package = QInputDialog::getItem(this, "Select package", "Package:", packages, 0, false, &ok);
|
||||
|
||||
if (ok && !item.isEmpty()) {
|
||||
handler->clear();
|
||||
currentProj = "";
|
||||
disableActions();
|
||||
chipArgs.package = package.toStdString().c_str();
|
||||
ctx = std::unique_ptr<Context>(new Context(chipArgs));
|
||||
actionLoadJSON->setEnabled(true);
|
||||
|
||||
Q_EMIT contextChanged(ctx.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::load_pcf(std::string filename)
|
||||
{
|
||||
disableActions();
|
||||
std::ifstream f(filename);
|
||||
if (apply_pcf(ctx.get(), filename, f)) {
|
||||
log("Loading PCF successful.\n");
|
||||
actionPack->setEnabled(true);
|
||||
} else {
|
||||
actionLoadPCF->setEnabled(true);
|
||||
log("Loading PCF failed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::newContext(Context *ctx)
|
||||
{
|
||||
std::string title = "nextpnr-ice40 - " + ctx->getChipName() + " ( " + ctx->archArgs().package + " )";
|
||||
setWindowTitle(title.c_str());
|
||||
}
|
||||
|
||||
void MainWindow::open_pcf()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, QString("Open PCF"), QString(), QString("*.pcf"));
|
||||
if (!fileName.isEmpty()) {
|
||||
load_pcf(fileName.toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::save_asc()
|
||||
{
|
||||
QString fileName = QFileDialog::getSaveFileName(this, QString("Save ASC"), QString(), QString("*.asc"));
|
||||
if (!fileName.isEmpty()) {
|
||||
std::string fn = fileName.toStdString();
|
||||
disableActions();
|
||||
std::ofstream f(fn);
|
||||
write_asc(ctx.get(), f);
|
||||
log("Saving ASC successful.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onDisableActions()
|
||||
{
|
||||
actionLoadPCF->setEnabled(false);
|
||||
actionSaveAsc->setEnabled(false);
|
||||
}
|
||||
|
||||
void MainWindow::onUpdateActions()
|
||||
{
|
||||
if (ctx->settings.find(ctx->id("pack")) == ctx->settings.end())
|
||||
actionLoadPCF->setEnabled(true);
|
||||
if (ctx->settings.find(ctx->id("route")) != ctx->settings.end())
|
||||
actionSaveAsc->setEnabled(true);
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include <QAction>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QIcon>
|
||||
#include <QInputDialog>
|
||||
#include <QLineEdit>
|
||||
#include <fstream>
|
||||
#include "bitstream.h"
|
||||
#include "design_utils.h"
|
||||
#include "log.h"
|
||||
#include "pcf.h"
|
||||
|
||||
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent)
|
||||
: BaseMainWindow(std::move(context), handler, parent)
|
||||
{
|
||||
initMainResource();
|
||||
|
||||
std::string title = "nextpnr-ice40 - [EMPTY]";
|
||||
setWindowTitle(title.c_str());
|
||||
|
||||
connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
|
||||
|
||||
createMenu();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {}
|
||||
|
||||
void MainWindow::createMenu()
|
||||
{
|
||||
// Add arch specific actions
|
||||
actionLoadPCF = new QAction("Open PCF", this);
|
||||
actionLoadPCF->setIcon(QIcon(":/icons/resources/open_pcf.png"));
|
||||
actionLoadPCF->setStatusTip("Open PCF file");
|
||||
actionLoadPCF->setEnabled(false);
|
||||
connect(actionLoadPCF, &QAction::triggered, this, &MainWindow::open_pcf);
|
||||
|
||||
actionSaveAsc = new QAction("Save ASC", this);
|
||||
actionSaveAsc->setIcon(QIcon(":/icons/resources/save_asc.png"));
|
||||
actionSaveAsc->setStatusTip("Save ASC file");
|
||||
actionSaveAsc->setEnabled(false);
|
||||
connect(actionSaveAsc, &QAction::triggered, this, &MainWindow::save_asc);
|
||||
|
||||
// Add actions in menus
|
||||
mainActionBar->addSeparator();
|
||||
mainActionBar->addAction(actionLoadPCF);
|
||||
mainActionBar->addAction(actionSaveAsc);
|
||||
|
||||
menuDesign->addSeparator();
|
||||
menuDesign->addAction(actionLoadPCF);
|
||||
menuDesign->addAction(actionSaveAsc);
|
||||
}
|
||||
|
||||
void MainWindow::new_proj()
|
||||
{
|
||||
QMap<QString, int> arch;
|
||||
if (Arch::is_available(ArchArgs::LP384))
|
||||
arch.insert("Lattice iCE40LP384", ArchArgs::LP384);
|
||||
if (Arch::is_available(ArchArgs::LP1K))
|
||||
arch.insert("Lattice iCE40LP1K", ArchArgs::LP1K);
|
||||
if (Arch::is_available(ArchArgs::HX1K))
|
||||
arch.insert("Lattice iCE40HX1K", ArchArgs::HX1K);
|
||||
if (Arch::is_available(ArchArgs::U1K))
|
||||
arch.insert("Lattice iCE5LP1K", ArchArgs::U1K);
|
||||
if (Arch::is_available(ArchArgs::U2K))
|
||||
arch.insert("Lattice iCE5LP2K", ArchArgs::U2K);
|
||||
if (Arch::is_available(ArchArgs::U4K))
|
||||
arch.insert("Lattice iCE5LP4K", ArchArgs::U4K);
|
||||
if (Arch::is_available(ArchArgs::UP3K))
|
||||
arch.insert("Lattice iCE40UP3K", ArchArgs::UP3K);
|
||||
if (Arch::is_available(ArchArgs::UP5K))
|
||||
arch.insert("Lattice iCE40UP5K", ArchArgs::UP5K);
|
||||
if (Arch::is_available(ArchArgs::LP4K))
|
||||
arch.insert("Lattice iCE40LP4K", ArchArgs::LP4K);
|
||||
if (Arch::is_available(ArchArgs::LP8K))
|
||||
arch.insert("Lattice iCE40LP8K", ArchArgs::LP8K);
|
||||
if (Arch::is_available(ArchArgs::HX4K))
|
||||
arch.insert("Lattice iCE40HX4K", ArchArgs::HX4K);
|
||||
if (Arch::is_available(ArchArgs::HX8K))
|
||||
arch.insert("Lattice iCE40HX8K", ArchArgs::HX8K);
|
||||
|
||||
bool ok;
|
||||
QString item = QInputDialog::getItem(this, "Select new context", "Chip:", arch.keys(), 0, false, &ok);
|
||||
if (ok && !item.isEmpty()) {
|
||||
ArchArgs chipArgs;
|
||||
chipArgs.type = (ArchArgs::ArchArgsTypes)arch.value(item);
|
||||
|
||||
QStringList packages;
|
||||
for (auto package : Arch::get_supported_packages(chipArgs.type))
|
||||
packages.append(QLatin1String(package.data(), package.size()));
|
||||
QString package = QInputDialog::getItem(this, "Select package", "Package:", packages, 0, false, &ok);
|
||||
|
||||
if (ok && !item.isEmpty()) {
|
||||
handler->clear();
|
||||
currentProj = "";
|
||||
disableActions();
|
||||
chipArgs.package = package.toStdString().c_str();
|
||||
ctx = std::unique_ptr<Context>(new Context(chipArgs));
|
||||
actionLoadJSON->setEnabled(true);
|
||||
|
||||
Q_EMIT contextChanged(ctx.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::load_pcf(std::string filename)
|
||||
{
|
||||
disableActions();
|
||||
std::ifstream f(filename);
|
||||
if (apply_pcf(ctx.get(), filename, f)) {
|
||||
log("Loading PCF successful.\n");
|
||||
actionPack->setEnabled(true);
|
||||
} else {
|
||||
actionLoadPCF->setEnabled(true);
|
||||
log("Loading PCF failed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::newContext(Context *ctx)
|
||||
{
|
||||
std::string title = "nextpnr-ice40 - " + ctx->getChipName() + " ( " + ctx->archArgs().package + " )";
|
||||
setWindowTitle(title.c_str());
|
||||
}
|
||||
|
||||
void MainWindow::open_pcf()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, QString("Open PCF"), QString(), QString("*.pcf"));
|
||||
if (!fileName.isEmpty()) {
|
||||
load_pcf(fileName.toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::save_asc()
|
||||
{
|
||||
QString fileName = QFileDialog::getSaveFileName(this, QString("Save ASC"), QString(), QString("*.asc"));
|
||||
if (!fileName.isEmpty()) {
|
||||
std::string fn = fileName.toStdString();
|
||||
disableActions();
|
||||
std::ofstream f(fn);
|
||||
write_asc(ctx.get(), f);
|
||||
log("Saving ASC successful.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onDisableActions()
|
||||
{
|
||||
actionLoadPCF->setEnabled(false);
|
||||
actionSaveAsc->setEnabled(false);
|
||||
}
|
||||
|
||||
void MainWindow::onUpdateActions()
|
||||
{
|
||||
if (ctx->settings.find(ctx->id("pack")) == ctx->settings.end())
|
||||
actionLoadPCF->setEnabled(true);
|
||||
if (ctx->settings.find(ctx->id("route")) != ctx->settings.end())
|
||||
actionSaveAsc->setEnabled(true);
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -1,59 +1,59 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "../basewindow.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class MainWindow : public BaseMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent = 0);
|
||||
virtual ~MainWindow();
|
||||
|
||||
public:
|
||||
void createMenu();
|
||||
|
||||
protected:
|
||||
void load_pcf(std::string filename);
|
||||
|
||||
void onDisableActions() override;
|
||||
void onUpdateActions() override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void new_proj() override;
|
||||
|
||||
void open_pcf();
|
||||
void save_asc();
|
||||
|
||||
void newContext(Context *ctx);
|
||||
|
||||
private:
|
||||
QAction *actionLoadPCF;
|
||||
QAction *actionSaveAsc;
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "../basewindow.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class MainWindow : public BaseMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent = 0);
|
||||
virtual ~MainWindow();
|
||||
|
||||
public:
|
||||
void createMenu();
|
||||
|
||||
protected:
|
||||
void load_pcf(std::string filename);
|
||||
|
||||
void onDisableActions() override;
|
||||
void onUpdateActions() override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void new_proj() override;
|
||||
|
||||
void open_pcf();
|
||||
void save_asc();
|
||||
|
||||
void newContext(Context *ctx);
|
||||
|
||||
private:
|
||||
QAction *actionLoadPCF;
|
||||
QAction *actionSaveAsc;
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
238
gui/pythontab.cc
238
gui/pythontab.cc
@ -1,119 +1,119 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "pythontab.h"
|
||||
#include <QGridLayout>
|
||||
#include "pybindings.h"
|
||||
#include "pyinterpreter.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
const QString PythonTab::PROMPT = ">>> ";
|
||||
const QString PythonTab::MULTILINE_PROMPT = "... ";
|
||||
|
||||
PythonTab::PythonTab(QWidget *parent) : QWidget(parent), initialized(false)
|
||||
{
|
||||
QFont f("unexistent");
|
||||
f.setStyleHint(QFont::Monospace);
|
||||
|
||||
// Add text area for Python output and input line
|
||||
console = new PythonConsole();
|
||||
console->setMinimumHeight(100);
|
||||
console->setReadOnly(true);
|
||||
console->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
|
||||
console->setFont(f);
|
||||
|
||||
console->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
QAction *clearAction = new QAction("Clear &buffer", this);
|
||||
clearAction->setStatusTip("Clears display buffer");
|
||||
connect(clearAction, &QAction::triggered, this, &PythonTab::clearBuffer);
|
||||
contextMenu = console->createStandardContextMenu();
|
||||
contextMenu->addSeparator();
|
||||
contextMenu->addAction(clearAction);
|
||||
connect(console, &PythonConsole::customContextMenuRequested, this, &PythonTab::showContextMenu);
|
||||
|
||||
lineEdit = new LineEditor(&parseHelper);
|
||||
lineEdit->setMinimumHeight(30);
|
||||
lineEdit->setMaximumHeight(30);
|
||||
lineEdit->setFont(f);
|
||||
lineEdit->setPlaceholderText(PythonTab::PROMPT);
|
||||
connect(lineEdit, &LineEditor::textLineInserted, this, &PythonTab::editLineReturnPressed);
|
||||
|
||||
QGridLayout *mainLayout = new QGridLayout();
|
||||
mainLayout->addWidget(console, 0, 0);
|
||||
mainLayout->addWidget(lineEdit, 1, 0);
|
||||
setLayout(mainLayout);
|
||||
|
||||
parseHelper.subscribe(console);
|
||||
|
||||
prompt = PythonTab::PROMPT;
|
||||
}
|
||||
|
||||
PythonTab::~PythonTab()
|
||||
{
|
||||
if (initialized) {
|
||||
pyinterpreter_finalize();
|
||||
deinit_python();
|
||||
}
|
||||
}
|
||||
|
||||
void PythonTab::editLineReturnPressed(QString text)
|
||||
{
|
||||
console->displayString(prompt + text + "\n");
|
||||
|
||||
parseHelper.process(text.toStdString());
|
||||
|
||||
if (parseHelper.buffered())
|
||||
prompt = PythonTab::MULTILINE_PROMPT;
|
||||
else
|
||||
prompt = PythonTab::PROMPT;
|
||||
|
||||
lineEdit->setPlaceholderText(prompt);
|
||||
}
|
||||
|
||||
void PythonTab::newContext(Context *ctx)
|
||||
{
|
||||
if (initialized) {
|
||||
pyinterpreter_finalize();
|
||||
deinit_python();
|
||||
}
|
||||
console->clear();
|
||||
|
||||
pyinterpreter_preinit();
|
||||
init_python("nextpnr");
|
||||
pyinterpreter_initialize();
|
||||
pyinterpreter_aquire();
|
||||
python_export_global("ctx", ctx);
|
||||
pyinterpreter_release();
|
||||
|
||||
initialized = true;
|
||||
|
||||
QString version = QString("Python %1 on %2\n").arg(Py_GetVersion(), Py_GetPlatform());
|
||||
console->displayString(version);
|
||||
}
|
||||
|
||||
void PythonTab::showContextMenu(const QPoint &pt) { contextMenu->exec(mapToGlobal(pt)); }
|
||||
|
||||
void PythonTab::clearBuffer() { console->clear(); }
|
||||
|
||||
void PythonTab::info(std::string str) { console->displayString(str.c_str()); }
|
||||
|
||||
void PythonTab::execute_python(std::string filename) { console->execute_python(filename); }
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "pythontab.h"
|
||||
#include <QGridLayout>
|
||||
#include "pybindings.h"
|
||||
#include "pyinterpreter.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
const QString PythonTab::PROMPT = ">>> ";
|
||||
const QString PythonTab::MULTILINE_PROMPT = "... ";
|
||||
|
||||
PythonTab::PythonTab(QWidget *parent) : QWidget(parent), initialized(false)
|
||||
{
|
||||
QFont f("unexistent");
|
||||
f.setStyleHint(QFont::Monospace);
|
||||
|
||||
// Add text area for Python output and input line
|
||||
console = new PythonConsole();
|
||||
console->setMinimumHeight(100);
|
||||
console->setReadOnly(true);
|
||||
console->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
|
||||
console->setFont(f);
|
||||
|
||||
console->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
QAction *clearAction = new QAction("Clear &buffer", this);
|
||||
clearAction->setStatusTip("Clears display buffer");
|
||||
connect(clearAction, &QAction::triggered, this, &PythonTab::clearBuffer);
|
||||
contextMenu = console->createStandardContextMenu();
|
||||
contextMenu->addSeparator();
|
||||
contextMenu->addAction(clearAction);
|
||||
connect(console, &PythonConsole::customContextMenuRequested, this, &PythonTab::showContextMenu);
|
||||
|
||||
lineEdit = new LineEditor(&parseHelper);
|
||||
lineEdit->setMinimumHeight(30);
|
||||
lineEdit->setMaximumHeight(30);
|
||||
lineEdit->setFont(f);
|
||||
lineEdit->setPlaceholderText(PythonTab::PROMPT);
|
||||
connect(lineEdit, &LineEditor::textLineInserted, this, &PythonTab::editLineReturnPressed);
|
||||
|
||||
QGridLayout *mainLayout = new QGridLayout();
|
||||
mainLayout->addWidget(console, 0, 0);
|
||||
mainLayout->addWidget(lineEdit, 1, 0);
|
||||
setLayout(mainLayout);
|
||||
|
||||
parseHelper.subscribe(console);
|
||||
|
||||
prompt = PythonTab::PROMPT;
|
||||
}
|
||||
|
||||
PythonTab::~PythonTab()
|
||||
{
|
||||
if (initialized) {
|
||||
pyinterpreter_finalize();
|
||||
deinit_python();
|
||||
}
|
||||
}
|
||||
|
||||
void PythonTab::editLineReturnPressed(QString text)
|
||||
{
|
||||
console->displayString(prompt + text + "\n");
|
||||
|
||||
parseHelper.process(text.toStdString());
|
||||
|
||||
if (parseHelper.buffered())
|
||||
prompt = PythonTab::MULTILINE_PROMPT;
|
||||
else
|
||||
prompt = PythonTab::PROMPT;
|
||||
|
||||
lineEdit->setPlaceholderText(prompt);
|
||||
}
|
||||
|
||||
void PythonTab::newContext(Context *ctx)
|
||||
{
|
||||
if (initialized) {
|
||||
pyinterpreter_finalize();
|
||||
deinit_python();
|
||||
}
|
||||
console->clear();
|
||||
|
||||
pyinterpreter_preinit();
|
||||
init_python("nextpnr");
|
||||
pyinterpreter_initialize();
|
||||
pyinterpreter_aquire();
|
||||
python_export_global("ctx", ctx);
|
||||
pyinterpreter_release();
|
||||
|
||||
initialized = true;
|
||||
|
||||
QString version = QString("Python %1 on %2\n").arg(Py_GetVersion(), Py_GetPlatform());
|
||||
console->displayString(version);
|
||||
}
|
||||
|
||||
void PythonTab::showContextMenu(const QPoint &pt) { contextMenu->exec(mapToGlobal(pt)); }
|
||||
|
||||
void PythonTab::clearBuffer() { console->clear(); }
|
||||
|
||||
void PythonTab::info(std::string str) { console->displayString(str.c_str()); }
|
||||
|
||||
void PythonTab::execute_python(std::string filename) { console->execute_python(filename); }
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
128
gui/pythontab.h
128
gui/pythontab.h
@ -1,64 +1,64 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PYTHONTAB_H
|
||||
#define PYTHONTAB_H
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QMenu>
|
||||
#include <QPlainTextEdit>
|
||||
#include "ParseHelper.h"
|
||||
#include "line_editor.h"
|
||||
#include "nextpnr.h"
|
||||
#include "pyconsole.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class PythonTab : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PythonTab(QWidget *parent = 0);
|
||||
~PythonTab();
|
||||
|
||||
private Q_SLOTS:
|
||||
void showContextMenu(const QPoint &pt);
|
||||
void editLineReturnPressed(QString text);
|
||||
public Q_SLOTS:
|
||||
void newContext(Context *ctx);
|
||||
void info(std::string str);
|
||||
void clearBuffer();
|
||||
void execute_python(std::string filename);
|
||||
|
||||
private:
|
||||
PythonConsole *console;
|
||||
LineEditor *lineEdit;
|
||||
QMenu *contextMenu;
|
||||
bool initialized;
|
||||
ParseHelper parseHelper;
|
||||
QString prompt;
|
||||
|
||||
static const QString PROMPT;
|
||||
static const QString MULTILINE_PROMPT;
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // PYTHONTAB_H
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <micko@yosyshq.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PYTHONTAB_H
|
||||
#define PYTHONTAB_H
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QMenu>
|
||||
#include <QPlainTextEdit>
|
||||
#include "ParseHelper.h"
|
||||
#include "line_editor.h"
|
||||
#include "nextpnr.h"
|
||||
#include "pyconsole.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class PythonTab : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PythonTab(QWidget *parent = 0);
|
||||
~PythonTab();
|
||||
|
||||
private Q_SLOTS:
|
||||
void showContextMenu(const QPoint &pt);
|
||||
void editLineReturnPressed(QString text);
|
||||
public Q_SLOTS:
|
||||
void newContext(Context *ctx);
|
||||
void info(std::string str);
|
||||
void clearBuffer();
|
||||
void execute_python(std::string filename);
|
||||
|
||||
private:
|
||||
PythonConsole *console;
|
||||
LineEditor *lineEdit;
|
||||
QMenu *contextMenu;
|
||||
bool initialized;
|
||||
ParseHelper parseHelper;
|
||||
QString prompt;
|
||||
|
||||
static const QString PROMPT;
|
||||
static const QString MULTILINE_PROMPT;
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // PYTHONTAB_H
|
||||
|
Loading…
Reference in New Issue
Block a user