PythonEditorWidget::PythonEditorWidget(InviwoMainWindow* ivwwin, InviwoApplication* app) : InviwoDockWidget(tr("Python Editor"), ivwwin) , settings_("Inviwo", "Inviwo") , infoTextColor_(153, 153, 153) , errorTextColor_(255, 107, 107) , runAction_(nullptr) , script_() , unsavedChanges_(false) , app_(app) , appendLog_(true) { setObjectName("PythonEditor"); settings_.beginGroup("PythonEditor"); QString lastFile = settings_.value("lastScript", "").toString(); appendLog_ = settings_.value("appendLog", appendLog_).toBool(); settings_.endGroup(); setVisible(false); setWindowIcon(QIcon(":/icons/python.png")); QMainWindow* mainWindow = new QMainWindow(); mainWindow->setContextMenuPolicy(Qt::NoContextMenu); QToolBar* toolBar = new QToolBar(); mainWindow->addToolBar(toolBar); toolBar->setFloatable(false); toolBar->setMovable(false); setWidget(mainWindow); { runAction_ = toolBar->addAction(QIcon(":/icons/python.png"), "Compile and Run"); runAction_->setShortcut(QKeySequence(tr("F5"))); runAction_->setShortcutContext(Qt::WidgetWithChildrenShortcut); runAction_->setToolTip("Compile and Run Script"); mainWindow->addAction(runAction_); connect(runAction_, &QAction::triggered, [this]() {run(); }); } { auto action = toolBar->addAction(QIcon(":/icons/new.png"), tr("&New Script")); action->setShortcut(QKeySequence::New); action->setShortcutContext(Qt::WidgetWithChildrenShortcut); action->setToolTip("New Script"); mainWindow->addAction(action); connect(action, &QAction::triggered, [this](){setDefaultText();}); } { auto action = toolBar->addAction(QIcon(":/icons/open.png"), tr("&Open Script")); action->setShortcut(QKeySequence::Open); action->setShortcutContext(Qt::WidgetWithChildrenShortcut); action->setToolTip("Open Script"); mainWindow->addAction(action); connect(action, &QAction::triggered, [this](){open();}); } { auto action = toolBar->addAction(QIcon(":/icons/save.png"), tr("&Save Script")); action->setShortcut(QKeySequence::Save); action->setShortcutContext(Qt::WidgetWithChildrenShortcut); action->setToolTip("Save Script"); mainWindow->addAction(action); connect(action, &QAction::triggered, [this](){save();}); } { auto action = toolBar->addAction(QIcon(":/icons/saveas.png"), tr("&Save Script As...")); action->setShortcut(QKeySequence::SaveAs); action->setShortcutContext(Qt::WidgetWithChildrenShortcut); action->setToolTip("Save Script As..."); mainWindow->addAction(action); connect(action, &QAction::triggered, [this](){saveAs();}); } { QIcon icon; icon.addFile(":/icons/log-append.png", QSize(), QIcon::Normal, QIcon::On); icon.addFile(":/icons/log-clearonrun.png", QSize(), QIcon::Normal, QIcon::Off); QString str = (appendLog_ ? "Append Log" : "Clear Log on Run"); auto action = toolBar->addAction(icon, str); action->setShortcut(Qt::ControlModifier + Qt::Key_E); action->setShortcutContext(Qt::WidgetWithChildrenShortcut); action->setCheckable(true); action->setChecked(appendLog_); action->setToolTip(appendLog_ ? "Append Log" : "Clear Log on Run"); mainWindow->addAction(action); connect(action, &QAction::toggled, [this, action](bool toggle) { appendLog_ = toggle; // update tooltip and menu entry QString tglstr = (toggle ? "Append Log" : "Clear Log on Run"); action->setText(tglstr); action->setToolTip(tglstr); // update settings settings_.beginGroup("PythonEditor"); settings_.setValue("appendLog", appendLog_); settings_.endGroup(); }); } { auto action = toolBar->addAction(QIcon(":/icons/log-clear.png"), "Clear Log Output"); action->setShortcut(Qt::ControlModifier + Qt::Key_E); action->setShortcutContext(Qt::WidgetWithChildrenShortcut); action->setToolTip("Clear Log Output"); mainWindow->addAction(action); connect(action, &QAction::triggered, [this](){clearOutput();}); } // Done creating buttons QSplitter* splitter = new QSplitter(nullptr); splitter->setOrientation(Qt::Vertical); pythonCode_ = new PythonTextEditor(nullptr); pythonCode_->setObjectName("pythonEditor"); pythonCode_->setUndoRedoEnabled(true); setDefaultText(); pythonOutput_ = new QTextEdit(nullptr); pythonOutput_->setObjectName("pythonConsole"); pythonOutput_->setReadOnly(true); pythonOutput_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); syntaxHighligther_ = SyntaxHighligther::createSyntaxHighligther<Python>(pythonCode_->document()); splitter->addWidget(pythonCode_); splitter->addWidget(pythonOutput_); splitter->setStretchFactor(0, 1); splitter->setStretchFactor(1, 0); splitter->setHandleWidth(2); // enable QSplitter:hover stylesheet // QTBUG-13768 https://bugreports.qt.io/browse/QTBUG-13768 splitter->handle(1)->setAttribute(Qt::WA_Hover); mainWindow->setCentralWidget(splitter); QObject::connect(pythonCode_, SIGNAL(textChanged()), this, SLOT(onTextChange())); // close this window before the main window is closed QObject::connect(ivwwin, &InviwoMainWindow::closingMainWindow, [this]() { delete this; }); this->updateStyle(); this->resize(500, 700); if (app_) { app_->getSettingsByType<SystemSettings>()->pythonSyntax_.onChange( this, &PythonEditorWidget::updateStyle); app_->getSettingsByType<SystemSettings>()->pyFontSize_.onChange( this, &PythonEditorWidget::updateStyle); app_->registerFileObserver(this); } unsavedChanges_ = false; if (lastFile.size() != 0) loadFile(lastFile.toLocal8Bit().constData(), false); setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); setFloating(true); }