wip
This commit is contained in:
@@ -79,6 +79,9 @@ qt_env.SharedLibrary("qt/python_helpers", ["qt/qt_window.cc"], LIBS=qt_libs)
|
|||||||
qt_env.Program("_text", ["qt/text.cc"], LIBS=qt_libs)
|
qt_env.Program("_text", ["qt/text.cc"], LIBS=qt_libs)
|
||||||
qt_env.Program("_spinner", ["qt/spinner.cc"], LIBS=qt_libs)
|
qt_env.Program("_spinner", ["qt/spinner.cc"], LIBS=qt_libs)
|
||||||
|
|
||||||
|
# Clearpilot tools
|
||||||
|
qt_env.Program("/data/openpilot/system/clearpilot/tools/qt_shell", ["/data/openpilot/system/clearpilot/tools/qt_shell.cc"], LIBS=qt_libs)
|
||||||
|
|
||||||
# build main UI
|
# build main UI
|
||||||
qt_env.Program("ui", qt_src + [asset_obj], LIBS=qt_libs)
|
qt_env.Program("ui", qt_src + [asset_obj], LIBS=qt_libs)
|
||||||
if GetOption('extras'):
|
if GetOption('extras'):
|
||||||
|
|||||||
BIN
system/clearpilot/tools/qt_shell
Executable file
BIN
system/clearpilot/tools/qt_shell
Executable file
Binary file not shown.
76
system/clearpilot/tools/qt_shell.cc
Normal file
76
system/clearpilot/tools/qt_shell.cc
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#include <QApplication>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <qpa/qplatformnativeinterface.h>
|
||||||
|
#include <wayland-client-protocol.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("Usage: %s '<command>'\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget window;
|
||||||
|
window.setWindowTitle("Shell Command Output Viewer");
|
||||||
|
window.setStyleSheet("background-color: black;");
|
||||||
|
window.showFullScreen();
|
||||||
|
|
||||||
|
auto windowHandle = window.windowHandle();
|
||||||
|
if (!windowHandle) {
|
||||||
|
fprintf(stderr, "Error: Unable to obtain window handle.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface();
|
||||||
|
auto *s = static_cast<wl_surface*>(native->nativeResourceForWindow("surface", windowHandle));
|
||||||
|
if (!s) {
|
||||||
|
fprintf(stderr, "Error: Unable to obtain native Wayland surface.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_surface_set_buffer_transform(s, WL_OUTPUT_TRANSFORM_270);
|
||||||
|
wl_surface_commit(s);
|
||||||
|
|
||||||
|
window.setFixedSize(2160, 1080);
|
||||||
|
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout(&window);
|
||||||
|
QTextEdit *outputDisplay = new QTextEdit;
|
||||||
|
outputDisplay->setFont(QFont("Consolas", 32));
|
||||||
|
outputDisplay->setReadOnly(true);
|
||||||
|
outputDisplay->setFixedSize(2160, 1080);
|
||||||
|
outputDisplay->setStyleSheet("color: white; background-color: black;");
|
||||||
|
outputDisplay->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Hide the vertical scrollbar
|
||||||
|
|
||||||
|
layout->addWidget(outputDisplay);
|
||||||
|
|
||||||
|
QProcess process;
|
||||||
|
QObject::connect(&process, &QProcess::readyReadStandardOutput, [&]() {
|
||||||
|
static QStringList lines;
|
||||||
|
QString output = process.readAllStandardOutput();
|
||||||
|
lines += output.split("\n", QString::SkipEmptyParts);
|
||||||
|
while (lines.size() > 100) {
|
||||||
|
lines.removeFirst();
|
||||||
|
}
|
||||||
|
outputDisplay->setPlainText(lines.join("\n"));
|
||||||
|
outputDisplay->verticalScrollBar()->setValue(outputDisplay->verticalScrollBar()->maximum());
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(&process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [&]() {
|
||||||
|
app.quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
QString command = argv[1];
|
||||||
|
process.start(QString("bash -c \"%1\"").arg(command));
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
sudo su comma -c "python3 shell.py \"echo hello; sleep 5\"
|
sudo su comma -c "python3 /data/openpilot/system/clearpilot/tools/shell.py \"echo hello; sleep 5\"
|
||||||
|
|||||||
785
system/clearpilot/tools_wip_4_28/QConsole.cc
Normal file
785
system/clearpilot/tools_wip_4_28/QConsole.cc
Normal file
@@ -0,0 +1,785 @@
|
|||||||
|
/**
|
||||||
|
Change log:
|
||||||
|
(C) 2005 by Houssem BDIOUI <houssem.bdioui@gmail.com>
|
||||||
|
(C) 2010 by YoungTaek Oh. (migrated to Qt4)
|
||||||
|
(C) 2014-2015 Igor Malinovskiy
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// #include "qconsole.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
|
||||||
|
//#define USE_POPUP_COMPLETER
|
||||||
|
#define WRITE_ONLY QIODevice::WriteOnly
|
||||||
|
|
||||||
|
QSize PopupListWidget::sizeHint() const
|
||||||
|
{
|
||||||
|
QAbstractItemModel *model = this->model();
|
||||||
|
QAbstractItemDelegate *delegate = this->itemDelegate();
|
||||||
|
const QStyleOptionViewItem sovi;
|
||||||
|
int left, top, right, bottom = 0;
|
||||||
|
|
||||||
|
QMargins margin = this->contentsMargins();
|
||||||
|
|
||||||
|
top = margin.top();
|
||||||
|
bottom = margin.bottom();
|
||||||
|
left = margin.left();
|
||||||
|
right = margin.right();
|
||||||
|
|
||||||
|
const int vOffset = top + bottom;
|
||||||
|
const int hOffset = left + right;
|
||||||
|
|
||||||
|
bool vScrollOn = false;
|
||||||
|
int height = 0;
|
||||||
|
int width = 0;
|
||||||
|
for (int i=0; i<this->count(); ++i) {
|
||||||
|
QModelIndex index = model->index(i, 0);
|
||||||
|
QSize itemSizeHint = delegate->sizeHint(sovi, index);
|
||||||
|
if (itemSizeHint.width() > width)
|
||||||
|
width = itemSizeHint.width();
|
||||||
|
|
||||||
|
// height
|
||||||
|
const int nextHeight = height + itemSizeHint.height();
|
||||||
|
if (nextHeight + vOffset < this->maximumHeight())
|
||||||
|
height = nextHeight;
|
||||||
|
else {
|
||||||
|
// early termination
|
||||||
|
vScrollOn = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize sizeHint(width + hOffset, 0);
|
||||||
|
sizeHint.setHeight(height + vOffset);
|
||||||
|
if (vScrollOn) {
|
||||||
|
int scrollWidth = this->verticalScrollBar()->sizeHint().width();
|
||||||
|
sizeHint.setWidth(sizeHint.width() + scrollWidth);
|
||||||
|
}
|
||||||
|
return sizeHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupListWidget::keyPressEvent(QKeyEvent *e) {
|
||||||
|
if (e->key() == Qt::Key_Tab ||
|
||||||
|
e->key() == Qt::Key_Return)
|
||||||
|
Q_EMIT itemActivated(currentItem());
|
||||||
|
else
|
||||||
|
QListWidget::keyPressEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupCompleter::PopupCompleter(const QStringList& sl, QWidget *parent)
|
||||||
|
: QDialog(parent, Qt::Popup)
|
||||||
|
{
|
||||||
|
setModal(true);
|
||||||
|
|
||||||
|
listWidget_ = new PopupListWidget();
|
||||||
|
listWidget_->setMaximumHeight(200);
|
||||||
|
qDebug() << "sizeHint(): " << listWidget_->sizeHint();
|
||||||
|
Q_FOREACH(QString str, sl) {
|
||||||
|
QListWidgetItem *item = new QListWidgetItem;
|
||||||
|
item->setText(str);
|
||||||
|
listWidget_->addItem(item);
|
||||||
|
}
|
||||||
|
qDebug() << "sizeHint(): " << listWidget_->sizeHint();
|
||||||
|
listWidget_->setFixedSize(listWidget_->sizeHint());
|
||||||
|
|
||||||
|
|
||||||
|
QLayout *layout = new QVBoxLayout();
|
||||||
|
layout->setSizeConstraint(QLayout::SetFixedSize);
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
layout->addWidget(listWidget_);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
// connect signal
|
||||||
|
connect(listWidget_, SIGNAL(itemActivated(QListWidgetItem *)),
|
||||||
|
SLOT(onItemActivated(QListWidgetItem*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupCompleter::~PopupCompleter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupCompleter::showEvent(QShowEvent *event)
|
||||||
|
{
|
||||||
|
listWidget_->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupCompleter::onItemActivated(QListWidgetItem *event)
|
||||||
|
{
|
||||||
|
selected_ = event->text();
|
||||||
|
done(QDialog::Accepted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief execute PopupCompleter at appropriate position.
|
||||||
|
*
|
||||||
|
* @param parent Parent of this popup completer. usually QConsole.
|
||||||
|
* @return see QDialog::exec
|
||||||
|
* @see QDialog::exec
|
||||||
|
*/
|
||||||
|
int PopupCompleter::exec(QTextEdit *parent)
|
||||||
|
{
|
||||||
|
QSize popupSizeHint = this->sizeHint();
|
||||||
|
QRect cursorRect = parent->cursorRect();
|
||||||
|
QPoint globalPt = parent->mapToGlobal(cursorRect.bottomRight());
|
||||||
|
QDesktopWidget *dsk = QApplication::desktop();
|
||||||
|
QRect screenGeom = dsk->screenGeometry(dsk->screenNumber(this));
|
||||||
|
if (globalPt.y() + popupSizeHint.height() > screenGeom.height()) {
|
||||||
|
globalPt = parent->mapToGlobal(cursorRect.topRight());
|
||||||
|
globalPt.setY(globalPt.y() - popupSizeHint.height());
|
||||||
|
}
|
||||||
|
this->move(globalPt);
|
||||||
|
this->setFocus();
|
||||||
|
return QDialog::exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a common word of the given list
|
||||||
|
*
|
||||||
|
* @param list String list
|
||||||
|
*
|
||||||
|
* @return common word in the given string.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
QString getCommonWord(QStringList& list)
|
||||||
|
{
|
||||||
|
QChar ch;
|
||||||
|
QVector<QString> strarray = list.toVector();
|
||||||
|
QString common;
|
||||||
|
int col = 0, min_len;
|
||||||
|
bool cont = true;
|
||||||
|
|
||||||
|
// get minimum length
|
||||||
|
min_len = strarray.at(0).size();
|
||||||
|
for (int i=1; i<strarray.size(); ++i) {
|
||||||
|
const int len = strarray.at(i).size();
|
||||||
|
if (len < min_len)
|
||||||
|
min_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(col < min_len) {
|
||||||
|
ch = strarray.at(0)[col];
|
||||||
|
for (int i=1; i<strarray.size(); ++i) {
|
||||||
|
const QString& current_string = strarray.at(i);
|
||||||
|
if (ch != current_string[col])
|
||||||
|
{
|
||||||
|
cont = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!cont)
|
||||||
|
break;
|
||||||
|
|
||||||
|
common.push_back(ch);
|
||||||
|
++col;
|
||||||
|
}
|
||||||
|
return common;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Clear the console
|
||||||
|
void QConsole::clear()
|
||||||
|
{
|
||||||
|
QTextEdit::clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reset the console
|
||||||
|
void QConsole::reset(const QString &welcomeText)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
append(welcomeText);
|
||||||
|
append("");
|
||||||
|
|
||||||
|
//init attributes
|
||||||
|
historyIndex = 0;
|
||||||
|
history.clear();
|
||||||
|
recordedScript.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//QConsole constructor (init the QTextEdit & the attributes)
|
||||||
|
QConsole::QConsole(QWidget *parent, const QString &welcomeText)
|
||||||
|
: QTextEdit(parent), errColor_(Qt::red),
|
||||||
|
outColor_(Qt::white), completionColor(Qt::darkGreen),
|
||||||
|
promptLength(0), promptParagraph(0), isLocked(false)
|
||||||
|
{
|
||||||
|
// Disable accepting rich text from user
|
||||||
|
setAcceptRichText(false);
|
||||||
|
|
||||||
|
//Disable undo/redo
|
||||||
|
setUndoRedoEnabled(false);
|
||||||
|
|
||||||
|
|
||||||
|
//Disable context menu
|
||||||
|
//This menu is useful for undo/redo, cut/copy/paste, del, select all,
|
||||||
|
// see function QConsole::contextMenuEvent(...)
|
||||||
|
//setContextMenuPolicy(Qt::NoContextMenu);
|
||||||
|
|
||||||
|
|
||||||
|
//resets the console
|
||||||
|
reset(welcomeText);
|
||||||
|
const int tabwidth = QFontMetrics(currentFont()).width('a') * 4;
|
||||||
|
setTabStopWidth(tabwidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sets the prompt and cache the prompt length to optimize the processing speed
|
||||||
|
void QConsole::setPrompt(const QString &newPrompt, bool display)
|
||||||
|
{
|
||||||
|
prompt = newPrompt;
|
||||||
|
promptLength = prompt.length();
|
||||||
|
//display the new prompt
|
||||||
|
if (display)
|
||||||
|
displayPrompt();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Displays the prompt and move the cursor to the end of the line.
|
||||||
|
void QConsole::displayPrompt()
|
||||||
|
{
|
||||||
|
//Prevent previous text displayed to be undone
|
||||||
|
setUndoRedoEnabled(false);
|
||||||
|
//displays the prompt
|
||||||
|
setTextColor(cmdColor_);
|
||||||
|
QTextCursor cur = textCursor();
|
||||||
|
cur.insertText(prompt);
|
||||||
|
cur.movePosition(QTextCursor::EndOfLine);
|
||||||
|
setTextCursor(cur);
|
||||||
|
//Saves the paragraph number of the prompt
|
||||||
|
promptParagraph = cur.blockNumber();
|
||||||
|
|
||||||
|
//Enable undo/redo for the actual command
|
||||||
|
setUndoRedoEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QConsole::setFont(const QFont& f) {
|
||||||
|
QTextCharFormat format;
|
||||||
|
QTextCursor oldCursor = textCursor();
|
||||||
|
format.setFont(f);
|
||||||
|
selectAll();
|
||||||
|
textCursor().setBlockCharFormat(format);
|
||||||
|
setCurrentFont(f);
|
||||||
|
setTextCursor(oldCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Give suggestions to autocomplete a command (should be reimplemented)
|
||||||
|
//the return value of the function is the string list of all suggestions
|
||||||
|
QStringList QConsole::suggestCommand(const QString&, QString& prefix)
|
||||||
|
{
|
||||||
|
prefix = "";
|
||||||
|
return QStringList();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Treat the tab key & autocomplete the current command
|
||||||
|
void QConsole::handleTabKeyPress()
|
||||||
|
{
|
||||||
|
QString command = getCurrentCommand();
|
||||||
|
QString commandPrefix;
|
||||||
|
QStringList sl = suggestCommand(command, commandPrefix);
|
||||||
|
if (sl.count() == 0)
|
||||||
|
textCursor().insertText("\t");
|
||||||
|
else {
|
||||||
|
if (sl.count() == 1)
|
||||||
|
replaceCurrentCommand(commandPrefix + sl[0]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// common word completion
|
||||||
|
QString commonWord = getCommonWord(sl);
|
||||||
|
command = commonWord;
|
||||||
|
|
||||||
|
PopupCompleter *popup = new PopupCompleter(sl);
|
||||||
|
if (popup->exec(this) == QDialog::Accepted)
|
||||||
|
replaceCurrentCommand(commandPrefix + popup->selected());
|
||||||
|
delete popup;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If return pressed, do the evaluation and append the result
|
||||||
|
void QConsole::handleReturnKeyPress()
|
||||||
|
{
|
||||||
|
//Get the command to validate
|
||||||
|
QString command = getCurrentCommand();
|
||||||
|
//execute the command and get back its text result and its return value
|
||||||
|
if (isCommandComplete(command))
|
||||||
|
pExecCommand(command);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
append("");
|
||||||
|
moveCursor(QTextCursor::EndOfLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QConsole::handleBackspaceKeyPress()
|
||||||
|
{
|
||||||
|
QTextCursor cur = textCursor();
|
||||||
|
const int col = cur.columnNumber();
|
||||||
|
const int blk = cur.blockNumber();
|
||||||
|
if (blk == promptParagraph && col == promptLength)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QConsole::handleUpKeyPress()
|
||||||
|
{
|
||||||
|
if (history.count())
|
||||||
|
{
|
||||||
|
QString command = getCurrentCommand();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (historyIndex)
|
||||||
|
historyIndex--;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(history[historyIndex] == command);
|
||||||
|
replaceCurrentCommand(history[historyIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QConsole::handleDownKeyPress()
|
||||||
|
{
|
||||||
|
if (history.count())
|
||||||
|
{
|
||||||
|
QString command = getCurrentCommand();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (++historyIndex >= history.size())
|
||||||
|
{
|
||||||
|
historyIndex = history.size() - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(history[historyIndex] == command);
|
||||||
|
replaceCurrentCommand(history[historyIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void QConsole::setHome(bool select)
|
||||||
|
{
|
||||||
|
QTextCursor cursor = textCursor();
|
||||||
|
cursor.movePosition(QTextCursor::StartOfBlock, select ? QTextCursor::KeepAnchor :
|
||||||
|
QTextCursor::MoveAnchor);
|
||||||
|
if(textCursor().blockNumber() == promptParagraph)
|
||||||
|
{
|
||||||
|
cursor.movePosition(QTextCursor::Right, select ? QTextCursor::KeepAnchor :
|
||||||
|
QTextCursor::MoveAnchor,
|
||||||
|
promptLength);
|
||||||
|
}
|
||||||
|
setTextCursor(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reimplemented key press event
|
||||||
|
void QConsole::keyPressEvent( QKeyEvent *e )
|
||||||
|
{
|
||||||
|
if (isLocked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//If the user wants to copy or cut outside
|
||||||
|
//the editing area we perform a copy
|
||||||
|
if(textCursor().hasSelection())
|
||||||
|
{
|
||||||
|
if(e->modifiers() == Qt::CTRL)
|
||||||
|
{
|
||||||
|
if( e->matches(QKeySequence::Cut) )
|
||||||
|
{
|
||||||
|
e->accept();
|
||||||
|
if(!isInEditionZone())
|
||||||
|
{
|
||||||
|
copy();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cut();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(e->matches(QKeySequence::Copy) )
|
||||||
|
{
|
||||||
|
e->accept();
|
||||||
|
copy();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QTextEdit::keyPressEvent( e );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
// if the cursor out of editing zone put it back first
|
||||||
|
if(!isInEditionZone())
|
||||||
|
{
|
||||||
|
QTextCursor editCursor = textCursor();
|
||||||
|
editCursor.setPosition(oldEditPosition);
|
||||||
|
setTextCursor(editCursor);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// control is pressed
|
||||||
|
if ( (e->modifiers() & Qt::ControlModifier) && (e->key() == Qt::Key_C) )
|
||||||
|
{
|
||||||
|
if ( isSelectionInEditionZone())
|
||||||
|
{
|
||||||
|
//If Ctrl + C pressed, then undo the current commant
|
||||||
|
//append("");
|
||||||
|
//displayPrompt();
|
||||||
|
|
||||||
|
//(Thierry Belair:)I humbly suggest that ctrl+C copies the text, as is expected,
|
||||||
|
//and indicated in the contextual menu
|
||||||
|
copy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (e->key()) {
|
||||||
|
case Qt::Key_Tab:
|
||||||
|
if(isSelectionInEditionZone())
|
||||||
|
{
|
||||||
|
handleTabKeyPress();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case Qt::Key_Enter:
|
||||||
|
case Qt::Key_Return:
|
||||||
|
if (isSelectionInEditionZone())
|
||||||
|
{
|
||||||
|
handleReturnKeyPress();
|
||||||
|
}
|
||||||
|
// ignore return key
|
||||||
|
return;
|
||||||
|
|
||||||
|
case Qt::Key_Backspace:
|
||||||
|
if (handleBackspaceKeyPress() || !isSelectionInEditionZone())
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qt::Key_Home:
|
||||||
|
setHome(e->modifiers() & Qt::ShiftModifier);
|
||||||
|
case Qt::Key_Down:
|
||||||
|
if (isInEditionZone())
|
||||||
|
{
|
||||||
|
handleDownKeyPress();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case Qt::Key_Up:
|
||||||
|
if (isInEditionZone())
|
||||||
|
{
|
||||||
|
handleUpKeyPress();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Default behaviour
|
||||||
|
case Qt::Key_End:
|
||||||
|
case Qt::Key_Left:
|
||||||
|
case Qt::Key_Right:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (textCursor().hasSelection() ) {
|
||||||
|
if (!isSelectionInEditionZone())
|
||||||
|
{
|
||||||
|
moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //no selection
|
||||||
|
//when typing normal characters,
|
||||||
|
//make sure the cursor is positionned in the
|
||||||
|
//edition zone
|
||||||
|
if ( !isInEditionZone() )
|
||||||
|
{
|
||||||
|
moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} //end of switch
|
||||||
|
} //end of else : no control pressed
|
||||||
|
|
||||||
|
QTextEdit::keyPressEvent( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the current command
|
||||||
|
QString QConsole::getCurrentCommand()
|
||||||
|
{
|
||||||
|
QTextCursor cursor = textCursor(); //Get the current command: we just remove the prompt
|
||||||
|
cursor.movePosition(QTextCursor::StartOfBlock);
|
||||||
|
cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, promptLength);
|
||||||
|
cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
|
||||||
|
QString command = cursor.selectedText();
|
||||||
|
cursor.clearSelection();
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Replace current command with a new one
|
||||||
|
void QConsole::replaceCurrentCommand(const QString &newCommand)
|
||||||
|
{
|
||||||
|
QTextCursor cursor = textCursor();
|
||||||
|
cursor.movePosition(QTextCursor::StartOfLine);
|
||||||
|
cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, promptLength);
|
||||||
|
cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
|
||||||
|
cursor.insertText(newCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
//default implementation: command always complete
|
||||||
|
bool QConsole::isCommandComplete(const QString &)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Tests whether the cursor is in th edition zone or not (after the prompt
|
||||||
|
//or in the next lines (in case of multi-line mode)
|
||||||
|
bool QConsole::isInEditionZone()
|
||||||
|
{
|
||||||
|
const int para = textCursor().blockNumber();
|
||||||
|
const int index = textCursor().columnNumber();
|
||||||
|
return (para > promptParagraph) || ( (para == promptParagraph) && (index >= promptLength) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Tests whether position (in parameter) is in the edition zone or not (after the prompt
|
||||||
|
//or in the next lines (in case of multi-line mode)
|
||||||
|
bool QConsole::isInEditionZone(const int& pos)
|
||||||
|
{
|
||||||
|
QTextCursor cur = textCursor();
|
||||||
|
cur.setPosition(pos);
|
||||||
|
const int para = cur.blockNumber();
|
||||||
|
const int index = cur.columnNumber();
|
||||||
|
return (para > promptParagraph) || ( (para == promptParagraph) && (index >= promptLength) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Tests whether the current selection is in th edition zone or not
|
||||||
|
bool QConsole::isSelectionInEditionZone()
|
||||||
|
{
|
||||||
|
QTextCursor cursor(document());
|
||||||
|
int range[2];
|
||||||
|
|
||||||
|
range[0] = textCursor().selectionStart();
|
||||||
|
range[1] = textCursor().selectionEnd();
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
cursor.setPosition(range[i]);
|
||||||
|
int para = cursor.blockNumber();
|
||||||
|
int index = cursor.columnNumber();
|
||||||
|
if ((para <= promptParagraph) && ( (para != promptParagraph) || (index < promptLength) ))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Basically, puts the command into the history list
|
||||||
|
//And emits a signal (should be called by reimplementations)
|
||||||
|
QString QConsole::addCommandToHistory(const QString &command)
|
||||||
|
{
|
||||||
|
//Add the command to the recordedScript list
|
||||||
|
recordedScript.append(command);
|
||||||
|
//update the history and its index
|
||||||
|
QString modifiedCommand = command;
|
||||||
|
modifiedCommand.replace("\n", "\\n");
|
||||||
|
history.append(modifiedCommand);
|
||||||
|
historyIndex = history.size();
|
||||||
|
//emit the commandExecuted signal
|
||||||
|
Q_EMIT commandAddedToHistory(modifiedCommand);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
//pExecCommand(QString) executes the command and displays back its result
|
||||||
|
void QConsole::pExecCommand(const QString &command)
|
||||||
|
{
|
||||||
|
isLocked = true;
|
||||||
|
|
||||||
|
addCommandToHistory(command);
|
||||||
|
|
||||||
|
emit execCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QConsole::printCommandExecutionResults(const QString &result, ResultType type)
|
||||||
|
{
|
||||||
|
//According to the return value, display the result either in red or in blue
|
||||||
|
if (type == ResultType::Error)
|
||||||
|
setTextColor(errColor_);
|
||||||
|
else
|
||||||
|
setTextColor(outColor_);
|
||||||
|
|
||||||
|
append(result);
|
||||||
|
|
||||||
|
//Display the prompt again
|
||||||
|
if (type == ResultType::Complete || type == ResultType::Error) {
|
||||||
|
if (!result.endsWith("\n"))
|
||||||
|
append("\n");
|
||||||
|
|
||||||
|
isLocked = false;
|
||||||
|
displayPrompt();
|
||||||
|
}
|
||||||
|
|
||||||
|
moveCursor(QTextCursor::End);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Change paste behaviour
|
||||||
|
void QConsole::insertFromMimeData(const QMimeData *source)
|
||||||
|
{
|
||||||
|
if (isSelectionInEditionZone())
|
||||||
|
{
|
||||||
|
QTextEdit::insertFromMimeData(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Implement paste with middle mouse button
|
||||||
|
void QConsole::mousePressEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
oldPosition = textCursor().position();
|
||||||
|
if (event->button() == Qt::MidButton)
|
||||||
|
{
|
||||||
|
copy();
|
||||||
|
QTextCursor cursor = cursorForPosition(event->pos());
|
||||||
|
setTextCursor(cursor);
|
||||||
|
paste();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextEdit::mousePressEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Redefinition of the dropEvent to have a copy paste
|
||||||
|
//instead of a cut paste when copying out of the
|
||||||
|
//editable zone
|
||||||
|
void QConsole::dropEvent ( QDropEvent * event)
|
||||||
|
{
|
||||||
|
if(!isInEditionZone())
|
||||||
|
{
|
||||||
|
//Execute un drop a drop at the old position
|
||||||
|
//if the drag started out of the editable zone
|
||||||
|
QTextCursor cur = textCursor();
|
||||||
|
cur.setPosition(oldPosition);
|
||||||
|
setTextCursor(cur);
|
||||||
|
}
|
||||||
|
//Execute a normal drop
|
||||||
|
QTextEdit::dropEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void QConsole::dragMoveEvent( QDragMoveEvent * event)
|
||||||
|
{
|
||||||
|
//Get a cursor for the actual mouse position
|
||||||
|
QTextCursor cur = textCursor();
|
||||||
|
cur.setPosition(cursorForPosition(event->pos()).position());
|
||||||
|
|
||||||
|
if(!isInEditionZone(cursorForPosition(event->pos()).position()))
|
||||||
|
{
|
||||||
|
//Ignore the event if out of the editable zone
|
||||||
|
event->ignore(cursorRect(cur));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Accept the event if out of the editable zone
|
||||||
|
event->accept(cursorRect(cur));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void QConsole::contextMenuEvent ( QContextMenuEvent * event)
|
||||||
|
{
|
||||||
|
if (isLocked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QMenu *menu = new QMenu(this);
|
||||||
|
|
||||||
|
QAction *undo = new QAction(tr("Undo"), this);
|
||||||
|
undo->setShortcut(tr("Ctrl+Z"));
|
||||||
|
QAction *redo = new QAction(tr("Redo"), this);
|
||||||
|
redo->setShortcut(tr("Ctrl+Y"));
|
||||||
|
QAction *cut = new QAction(tr("Cut"), this);
|
||||||
|
cut->setShortcut(tr("Ctrl+X"));
|
||||||
|
QAction *copy = new QAction(tr("Copy"), this);
|
||||||
|
copy->setShortcut(tr("Ctrl+Ins"));
|
||||||
|
QAction *paste = new QAction(tr("Paste"), this);
|
||||||
|
paste->setShortcut(tr("Ctrl+V"));
|
||||||
|
QAction *del = new QAction(tr("Delete"), this);
|
||||||
|
del->setShortcut(tr("Del"));
|
||||||
|
QAction *selectAll = new QAction(tr("Select All"), this);
|
||||||
|
selectAll->setShortcut(tr("Ctrl+A"));
|
||||||
|
|
||||||
|
menu->addAction(undo);
|
||||||
|
menu->addAction(redo);
|
||||||
|
menu->addSeparator();
|
||||||
|
menu->addAction(cut);
|
||||||
|
menu->addAction(copy);
|
||||||
|
menu->addAction(paste);
|
||||||
|
menu->addAction(del);
|
||||||
|
menu->addSeparator();
|
||||||
|
menu->addAction(selectAll);
|
||||||
|
|
||||||
|
connect(undo, SIGNAL(triggered()), this, SLOT(undo()));
|
||||||
|
connect(redo, SIGNAL(triggered()), this, SLOT(redo()));
|
||||||
|
connect(cut, SIGNAL(triggered()), this, SLOT(cut()));
|
||||||
|
connect(copy, SIGNAL(triggered()), this, SLOT(copy()));
|
||||||
|
connect(paste, SIGNAL(triggered()), this, SLOT(paste()));
|
||||||
|
connect(del, SIGNAL(triggered()), this, SLOT(del()));
|
||||||
|
connect(selectAll, SIGNAL(triggered()), this, SLOT(selectAll()));
|
||||||
|
|
||||||
|
|
||||||
|
menu->exec(event->globalPos());
|
||||||
|
|
||||||
|
delete menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QConsole::cut()
|
||||||
|
{
|
||||||
|
//Cut only in the editing zone,
|
||||||
|
//perfom a copy otherwise
|
||||||
|
if(isSelectionInEditionZone())
|
||||||
|
{
|
||||||
|
QTextEdit::cut();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextEdit::copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
//Allows pasting with middle mouse button (x window)
|
||||||
|
//when clicking outside of the edition zone
|
||||||
|
void QConsole::paste()
|
||||||
|
{
|
||||||
|
restoreOldPosition();
|
||||||
|
QTextEdit::paste();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void QConsole::del()
|
||||||
|
{
|
||||||
|
//Delete only in the editing zone
|
||||||
|
if(isInEditionZone())
|
||||||
|
{
|
||||||
|
textCursor().movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||||
|
textCursor().deleteChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QConsole::correctPathName(QString& pathName)
|
||||||
|
{
|
||||||
|
if(pathName.contains(tr(":\\")))
|
||||||
|
{
|
||||||
|
pathName.replace('\\', tr("/"));
|
||||||
|
}
|
||||||
|
}
|
||||||
211
system/clearpilot/tools_wip_4_28/QConsole.h
Normal file
211
system/clearpilot/tools_wip_4_28/QConsole.h
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/**
|
||||||
|
Change log:
|
||||||
|
(C) 2005 by Houssem BDIOUI <houssem.bdioui@gmail.com>
|
||||||
|
(C) 2010 by YoungTaek Oh. (migrated to Qt4)
|
||||||
|
(C) 2014-2015 Igor Malinovskiy
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasssing QListWidget
|
||||||
|
*
|
||||||
|
* @author YoungTaek Oh
|
||||||
|
*/
|
||||||
|
class PopupListWidget : public QListWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
PopupListWidget(QWidget *parent = 0): QListWidget(parent) {
|
||||||
|
setUniformItemSizes(true);
|
||||||
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
}
|
||||||
|
virtual ~PopupListWidget() { }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual QSize sizeHint() const;
|
||||||
|
virtual void keyPressEvent(QKeyEvent *e);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Popup Completer class
|
||||||
|
*
|
||||||
|
* @author YoungTaek Oh
|
||||||
|
* @todo 1. beautifying
|
||||||
|
* 2. icons for classifying words (eg. functions, properties...)
|
||||||
|
* 3. bugs?
|
||||||
|
* @note still experimental
|
||||||
|
*/
|
||||||
|
class PopupCompleter : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
PopupCompleter(const QStringList&, QWidget *parent = 0);
|
||||||
|
virtual ~PopupCompleter();
|
||||||
|
|
||||||
|
public:
|
||||||
|
QString selected(void) { return selected_; }
|
||||||
|
int exec(QTextEdit*);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void showEvent(QShowEvent*);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void onItemActivated(QListWidgetItem*);
|
||||||
|
|
||||||
|
public:
|
||||||
|
QListWidget *listWidget_;
|
||||||
|
QString selected_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract Qt console
|
||||||
|
* @author Houssem BDIOUI
|
||||||
|
*/
|
||||||
|
class QConsole : public QTextEdit
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
//constructor
|
||||||
|
QConsole(QWidget *parent = NULL, const QString &welcomeText = "");
|
||||||
|
//set the prompt of the console
|
||||||
|
void setPrompt(const QString &prompt, bool display = true);
|
||||||
|
|
||||||
|
//clear & reset the console (useful sometimes)
|
||||||
|
void clear();
|
||||||
|
void reset(const QString &welcomeText = "");
|
||||||
|
|
||||||
|
//cosmetic methods !
|
||||||
|
|
||||||
|
// @{
|
||||||
|
/// get/set command color
|
||||||
|
QColor cmdColor() const { return cmdColor_; }
|
||||||
|
void setCmdColor(QColor c) {cmdColor_ = c;}
|
||||||
|
// @}
|
||||||
|
|
||||||
|
// @{
|
||||||
|
/// get/set error color
|
||||||
|
QColor errColor() const { return errColor_; }
|
||||||
|
void setErrColor(QColor c) {errColor_ = c;}
|
||||||
|
// @}
|
||||||
|
|
||||||
|
// @{
|
||||||
|
/// get/set output color
|
||||||
|
QColor outColor() const { return outColor_; }
|
||||||
|
void setOutColor(QColor c) {outColor_ = c;}
|
||||||
|
// @}
|
||||||
|
void setCompletionColor(QColor c) {completionColor = c;}
|
||||||
|
|
||||||
|
// @{
|
||||||
|
/// get set font
|
||||||
|
void setFont(const QFont& f);
|
||||||
|
QFont font() const { return currentFont(); }
|
||||||
|
// @}
|
||||||
|
|
||||||
|
void correctPathName(QString& pathName);
|
||||||
|
|
||||||
|
enum ResultType {Error, Partial, Complete};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void dropEvent( QDropEvent * event);
|
||||||
|
void dragMoveEvent( QDragMoveEvent * event);
|
||||||
|
|
||||||
|
void keyPressEvent(QKeyEvent * e);
|
||||||
|
void contextMenuEvent( QContextMenuEvent * event);
|
||||||
|
|
||||||
|
//Return false if the command is incomplete (e.g. unmatched braces)
|
||||||
|
virtual bool isCommandComplete(const QString &command);
|
||||||
|
//Get the command to validate
|
||||||
|
QString getCurrentCommand();
|
||||||
|
|
||||||
|
//Replace current command with a new one
|
||||||
|
void replaceCurrentCommand(const QString &newCommand);
|
||||||
|
|
||||||
|
//Test whether the cursor is in the edition zone
|
||||||
|
bool isInEditionZone();
|
||||||
|
bool isInEditionZone(const int& pos);
|
||||||
|
|
||||||
|
//Test whether the selection is in the edition zone
|
||||||
|
bool isSelectionInEditionZone();
|
||||||
|
//Change paste behaviour
|
||||||
|
void insertFromMimeData(const QMimeData *);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//colors
|
||||||
|
QColor cmdColor_, errColor_, outColor_, completionColor;
|
||||||
|
|
||||||
|
int oldPosition;
|
||||||
|
// cached prompt length
|
||||||
|
int promptLength;
|
||||||
|
// The prompt string
|
||||||
|
QString prompt;
|
||||||
|
// The commands history
|
||||||
|
QStringList history;
|
||||||
|
//Contains the commands that has succeeded
|
||||||
|
QStringList recordedScript;
|
||||||
|
// Current history index (needed because afaik QStringList does not have such an index)
|
||||||
|
int historyIndex;
|
||||||
|
//Holds the paragraph number of the prompt (useful for multi-line command handling)
|
||||||
|
int promptParagraph;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//Implement paste with middle mouse button
|
||||||
|
void mousePressEvent(QMouseEvent*);
|
||||||
|
|
||||||
|
//execute a validated command (should be reimplemented and called at the end)
|
||||||
|
//the return value of the function is the string result
|
||||||
|
//res must hold back the return value of the command (0: passed; else: error)
|
||||||
|
virtual QString addCommandToHistory(const QString &command);
|
||||||
|
|
||||||
|
//give suggestions to autocomplete a command (should be reimplemented)
|
||||||
|
//the return value of the function is the string list of all suggestions
|
||||||
|
//the returned prefix is useful to complete "sub-commands"
|
||||||
|
virtual QStringList suggestCommand(const QString &cmd, QString &prefix);
|
||||||
|
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
//Contextual menu slots
|
||||||
|
void cut();
|
||||||
|
//void paste();
|
||||||
|
void del();
|
||||||
|
//displays the prompt
|
||||||
|
void displayPrompt();
|
||||||
|
|
||||||
|
void printCommandExecutionResults(const QString &, ResultType t = ResultType::Complete);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
//Signal emitted after that a command is executed
|
||||||
|
void commandAddedToHistory(const QString &command);
|
||||||
|
void execCommand(const QString &command);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool isLocked;
|
||||||
|
|
||||||
|
void handleTabKeyPress();
|
||||||
|
void handleReturnKeyPress();
|
||||||
|
bool handleBackspaceKeyPress();
|
||||||
|
void handleUpKeyPress();
|
||||||
|
void handleDownKeyPress();
|
||||||
|
void setHome(bool);
|
||||||
|
void pExecCommand(const QString &command);
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "QConsole.cc"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
Metadata-Version: 1.0
|
||||||
|
Name: RotationModule
|
||||||
|
Version: 1.0
|
||||||
|
Summary: Module for rotating display via native interface
|
||||||
|
Home-page: UNKNOWN
|
||||||
|
Author: UNKNOWN
|
||||||
|
Author-email: UNKNOWN
|
||||||
|
License: UNKNOWN
|
||||||
|
Description: UNKNOWN
|
||||||
|
Platform: UNKNOWN
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
rotation_module.cc
|
||||||
|
rotation_module_build.py
|
||||||
|
RotationModule.egg-info/PKG-INFO
|
||||||
|
RotationModule.egg-info/SOURCES.txt
|
||||||
|
RotationModule.egg-info/dependency_links.txt
|
||||||
|
RotationModule.egg-info/top_level.txt
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
rotation
|
||||||
17
system/clearpilot/tools_wip_4_28/decrypt
Normal file
17
system/clearpilot/tools_wip_4_28/decrypt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Check for the correct number of arguments
|
||||||
|
if [ "$#" -ne 2 ]; then
|
||||||
|
echo "Usage: $0 source destination"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set variables for source and destination
|
||||||
|
src="$1"
|
||||||
|
dest="$2"
|
||||||
|
|
||||||
|
# Read DongleId for decryption key
|
||||||
|
dongle_id=/data/params/d/DongleId
|
||||||
|
|
||||||
|
# Decrypt the file
|
||||||
|
cat "$src" | ccrypt -d -k "$dongle_id" > "$dest"
|
||||||
17
system/clearpilot/tools_wip_4_28/encrypt
Normal file
17
system/clearpilot/tools_wip_4_28/encrypt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Check for the correct number of arguments
|
||||||
|
if [ "$#" -ne 2 ]; then
|
||||||
|
echo "Usage: $0 source destination"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set variables for source and destination
|
||||||
|
src="$1"
|
||||||
|
dest="$2"
|
||||||
|
|
||||||
|
# Read DongleId for encryption key
|
||||||
|
dongle_id=/data/params/d/DongleId
|
||||||
|
|
||||||
|
# Encrypt the file
|
||||||
|
cat "$src" | ccrypt -e -k "$dongle_id" > "$dest"
|
||||||
81
system/clearpilot/tools_wip_4_28/faketty.py
Normal file
81
system/clearpilot/tools_wip_4_28/faketty.py
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from sys import argv
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
|
||||||
|
# I've had problems with python's File objects at this low a level, so
|
||||||
|
# we're going to use integers to specify all files in this script.
|
||||||
|
stdin = 0
|
||||||
|
stdout = 1
|
||||||
|
stderr = 2
|
||||||
|
# Include this if passing the command and arguments to fish to
|
||||||
|
# prevent fish from applying any expansions.
|
||||||
|
#import re
|
||||||
|
#def fish_escape(args):
|
||||||
|
# def escape_one(arg):
|
||||||
|
# return "'" + re.sub(r"('|\\)", r'\\\1', arg) + "'"
|
||||||
|
# escaped_args = map(escape_one, args)
|
||||||
|
# return ' '.join(escaped_args)
|
||||||
|
|
||||||
|
if len(argv) < 2:
|
||||||
|
os.write(stderr,
|
||||||
|
b"""A tragically beautiful piece of hackery, made to fool programs like ls,
|
||||||
|
grep, rg, and fd into thinking they're actually connected to a terminal.
|
||||||
|
Its usage:
|
||||||
|
|
||||||
|
pty command [arg1 arg2 ...]
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
pty ls --color -R | less -r
|
||||||
|
git log -p | pty rg <search terms> | less -r
|
||||||
|
""")
|
||||||
|
exit(255)
|
||||||
|
|
||||||
|
# We do not use forkpty here because it would block ^Cs from reaching the
|
||||||
|
# child process. And we don't need that.
|
||||||
|
ptm, pts = os.openpty()
|
||||||
|
pid = os.fork()
|
||||||
|
if pid == 0:
|
||||||
|
# The child runs this.
|
||||||
|
# To get the behaviour we want, we only need to replace the process's
|
||||||
|
# stdout with pts. Everything else should remain in place, so that things
|
||||||
|
# like `ps -eF | pty rg python | less -r` will still work as intended.
|
||||||
|
os.dup2(pts, stdout)
|
||||||
|
# This is not like a subprocess.call(). It replaces the entire child
|
||||||
|
# process with argv[1:], meaning execvp will not return! Web search
|
||||||
|
# "fork exec" for more.
|
||||||
|
os.execvp(argv[1], argv[1:])
|
||||||
|
# Use this if calling fish.
|
||||||
|
#os.execvp('fish', ['fish', '-c', fish_escape(argv[1:])])
|
||||||
|
|
||||||
|
|
||||||
|
# The parent runs this.
|
||||||
|
|
||||||
|
# If the parent doesn't close the slave end, the script won't be able to
|
||||||
|
# exit. The next read on ptm after the child process terminates would hang
|
||||||
|
# forever because pts would technically still be open.
|
||||||
|
os.close(pts)
|
||||||
|
|
||||||
|
# The whole process group gets SIGINT, including the child, so we don't need
|
||||||
|
# to react to it. We'll know when to leave, judging by what the child does.
|
||||||
|
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
chunk = os.read(ptm, 4096)
|
||||||
|
except OSError:
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
os.write(stdout, chunk)
|
||||||
|
except BrokenPipeError:
|
||||||
|
# This happens when the parent is piping output to another process in a
|
||||||
|
# pipeline, like in `pty ls --color -R | less -r`, and the receiving
|
||||||
|
# process is terminated before the child has exited. If the receiving
|
||||||
|
# process is less, this can happen very easily. It happens every time
|
||||||
|
# the user decides to quit less before it has displayed all output. So,
|
||||||
|
# we need to stop the child process now.
|
||||||
|
os.kill(pid, signal.SIGTERM)
|
||||||
|
break
|
||||||
|
wait_pid, status = os.waitpid(pid, 0)
|
||||||
|
exit(status >> 8)
|
||||||
188
system/clearpilot/tools_wip_4_28/moc_test2.cc
Normal file
188
system/clearpilot/tools_wip_4_28/moc_test2.cc
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
** Meta object code from reading C++ file 'test2.h'
|
||||||
|
**
|
||||||
|
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.12.8)
|
||||||
|
**
|
||||||
|
** WARNING! All changes made in this file will be lost!
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "test2.h"
|
||||||
|
#include <QtCore/qbytearray.h>
|
||||||
|
#include <QtCore/qmetatype.h>
|
||||||
|
#if !defined(Q_MOC_OUTPUT_REVISION)
|
||||||
|
#error "The header file 'test2.h' doesn't include <QObject>."
|
||||||
|
#elif Q_MOC_OUTPUT_REVISION != 67
|
||||||
|
#error "This file was generated using the moc from 5.12.8. It"
|
||||||
|
#error "cannot be used with the include files from this version of Qt."
|
||||||
|
#error "(The moc has changed too much.)"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QT_BEGIN_MOC_NAMESPACE
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
|
struct qt_meta_stringdata_TrackWidget_t {
|
||||||
|
QByteArrayData data[1];
|
||||||
|
char stringdata0[12];
|
||||||
|
};
|
||||||
|
#define QT_MOC_LITERAL(idx, ofs, len) \
|
||||||
|
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
|
||||||
|
qptrdiff(offsetof(qt_meta_stringdata_TrackWidget_t, stringdata0) + ofs \
|
||||||
|
- idx * sizeof(QByteArrayData)) \
|
||||||
|
)
|
||||||
|
static const qt_meta_stringdata_TrackWidget_t qt_meta_stringdata_TrackWidget = {
|
||||||
|
{
|
||||||
|
QT_MOC_LITERAL(0, 0, 11) // "TrackWidget"
|
||||||
|
|
||||||
|
},
|
||||||
|
"TrackWidget"
|
||||||
|
};
|
||||||
|
#undef QT_MOC_LITERAL
|
||||||
|
|
||||||
|
static const uint qt_meta_data_TrackWidget[] = {
|
||||||
|
|
||||||
|
// content:
|
||||||
|
8, // revision
|
||||||
|
0, // classname
|
||||||
|
0, 0, // classinfo
|
||||||
|
0, 0, // methods
|
||||||
|
0, 0, // properties
|
||||||
|
0, 0, // enums/sets
|
||||||
|
0, 0, // constructors
|
||||||
|
0, // flags
|
||||||
|
0, // signalCount
|
||||||
|
|
||||||
|
0 // eod
|
||||||
|
};
|
||||||
|
|
||||||
|
void TrackWidget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
|
||||||
|
{
|
||||||
|
Q_UNUSED(_o);
|
||||||
|
Q_UNUSED(_id);
|
||||||
|
Q_UNUSED(_c);
|
||||||
|
Q_UNUSED(_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
QT_INIT_METAOBJECT const QMetaObject TrackWidget::staticMetaObject = { {
|
||||||
|
&QWidget::staticMetaObject,
|
||||||
|
qt_meta_stringdata_TrackWidget.data,
|
||||||
|
qt_meta_data_TrackWidget,
|
||||||
|
qt_static_metacall,
|
||||||
|
nullptr,
|
||||||
|
nullptr
|
||||||
|
} };
|
||||||
|
|
||||||
|
|
||||||
|
const QMetaObject *TrackWidget::metaObject() const
|
||||||
|
{
|
||||||
|
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *TrackWidget::qt_metacast(const char *_clname)
|
||||||
|
{
|
||||||
|
if (!_clname) return nullptr;
|
||||||
|
if (!strcmp(_clname, qt_meta_stringdata_TrackWidget.stringdata0))
|
||||||
|
return static_cast<void*>(this);
|
||||||
|
return QWidget::qt_metacast(_clname);
|
||||||
|
}
|
||||||
|
|
||||||
|
int TrackWidget::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
||||||
|
{
|
||||||
|
_id = QWidget::qt_metacall(_c, _id, _a);
|
||||||
|
return _id;
|
||||||
|
}
|
||||||
|
struct qt_meta_stringdata_Spinner_t {
|
||||||
|
QByteArrayData data[4];
|
||||||
|
char stringdata0[18];
|
||||||
|
};
|
||||||
|
#define QT_MOC_LITERAL(idx, ofs, len) \
|
||||||
|
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
|
||||||
|
qptrdiff(offsetof(qt_meta_stringdata_Spinner_t, stringdata0) + ofs \
|
||||||
|
- idx * sizeof(QByteArrayData)) \
|
||||||
|
)
|
||||||
|
static const qt_meta_stringdata_Spinner_t qt_meta_stringdata_Spinner = {
|
||||||
|
{
|
||||||
|
QT_MOC_LITERAL(0, 0, 7), // "Spinner"
|
||||||
|
QT_MOC_LITERAL(1, 8, 6), // "update"
|
||||||
|
QT_MOC_LITERAL(2, 15, 0), // ""
|
||||||
|
QT_MOC_LITERAL(3, 16, 1) // "n"
|
||||||
|
|
||||||
|
},
|
||||||
|
"Spinner\0update\0\0n"
|
||||||
|
};
|
||||||
|
#undef QT_MOC_LITERAL
|
||||||
|
|
||||||
|
static const uint qt_meta_data_Spinner[] = {
|
||||||
|
|
||||||
|
// content:
|
||||||
|
8, // revision
|
||||||
|
0, // classname
|
||||||
|
0, 0, // classinfo
|
||||||
|
1, 14, // methods
|
||||||
|
0, 0, // properties
|
||||||
|
0, 0, // enums/sets
|
||||||
|
0, 0, // constructors
|
||||||
|
0, // flags
|
||||||
|
0, // signalCount
|
||||||
|
|
||||||
|
// slots: name, argc, parameters, tag, flags
|
||||||
|
1, 1, 19, 2, 0x0a /* Public */,
|
||||||
|
|
||||||
|
// slots: parameters
|
||||||
|
QMetaType::Void, QMetaType::Int, 3,
|
||||||
|
|
||||||
|
0 // eod
|
||||||
|
};
|
||||||
|
|
||||||
|
void Spinner::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
|
||||||
|
{
|
||||||
|
if (_c == QMetaObject::InvokeMetaMethod) {
|
||||||
|
auto *_t = static_cast<Spinner *>(_o);
|
||||||
|
Q_UNUSED(_t)
|
||||||
|
switch (_id) {
|
||||||
|
case 0: _t->update((*reinterpret_cast< int(*)>(_a[1]))); break;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QT_INIT_METAOBJECT const QMetaObject Spinner::staticMetaObject = { {
|
||||||
|
&QWidget::staticMetaObject,
|
||||||
|
qt_meta_stringdata_Spinner.data,
|
||||||
|
qt_meta_data_Spinner,
|
||||||
|
qt_static_metacall,
|
||||||
|
nullptr,
|
||||||
|
nullptr
|
||||||
|
} };
|
||||||
|
|
||||||
|
|
||||||
|
const QMetaObject *Spinner::metaObject() const
|
||||||
|
{
|
||||||
|
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Spinner::qt_metacast(const char *_clname)
|
||||||
|
{
|
||||||
|
if (!_clname) return nullptr;
|
||||||
|
if (!strcmp(_clname, qt_meta_stringdata_Spinner.stringdata0))
|
||||||
|
return static_cast<void*>(this);
|
||||||
|
return QWidget::qt_metacast(_clname);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Spinner::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
||||||
|
{
|
||||||
|
_id = QWidget::qt_metacall(_c, _id, _a);
|
||||||
|
if (_id < 0)
|
||||||
|
return _id;
|
||||||
|
if (_c == QMetaObject::InvokeMetaMethod) {
|
||||||
|
if (_id < 1)
|
||||||
|
qt_static_metacall(this, _c, _id, _a);
|
||||||
|
_id -= 1;
|
||||||
|
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
|
||||||
|
if (_id < 1)
|
||||||
|
*reinterpret_cast<int*>(_a[0]) = -1;
|
||||||
|
_id -= 1;
|
||||||
|
}
|
||||||
|
return _id;
|
||||||
|
}
|
||||||
|
QT_WARNING_POP
|
||||||
|
QT_END_MOC_NAMESPACE
|
||||||
41
system/clearpilot/tools_wip_4_28/provision.sh
Normal file
41
system/clearpilot/tools_wip_4_28/provision.sh
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Provision script for BrianBot
|
||||||
|
# These actions only occur on BrianBot's comma device.
|
||||||
|
|
||||||
|
# 1. Check the string in /data/params/d/DongleId
|
||||||
|
dongle_id=$(cat /data/params/d/DongleId)
|
||||||
|
if [[ ! $dongle_id == 90bb71a* ]]; then
|
||||||
|
echo "Invalid dongle ID."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "BrianBot dongle ID detected."
|
||||||
|
|
||||||
|
# 2. Check if ccrypt is installed, install if not
|
||||||
|
if ! command -v ccrypt >/dev/null 2>&1; then
|
||||||
|
echo "Installing ccrypt..."
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y ccrypt
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. Decrypt SSH keys if they have not been decrypted yet
|
||||||
|
if [ ! -f /data/openpilot/system/clearpilot/dev/id_rsa.pub ]; then
|
||||||
|
echo "Decrypting SSH keys..."
|
||||||
|
ccrypt -d -k "$dongle_id" /data/openpilot/system/clearpilot/dev/id_rsa.pub.ccrypt
|
||||||
|
ccrypt -d -k "$dongle_id" /data/openpilot/system/clearpilot/dev/id_rsa.ccrypt
|
||||||
|
ccrypt -d -k "$dongle_id" /data/openpilot/system/clearpilot/dev/reverse_ssh.ccrypt
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. Ensure .ssh directory and keys exist
|
||||||
|
ssh_dir="/home/comma/.ssh"
|
||||||
|
if [[ ! -f "$ssh_dir/id_rsa" || ! -f "$ssh_dir/id_rsa.pub" ]]; then
|
||||||
|
echo "Setting up SSH directory and keys..."
|
||||||
|
mkdir -p "$ssh_dir"
|
||||||
|
cp /data/openpilot/system/clearpilot/dev/id_rsa /data/openpilot/system/clearpilot/dev/id_rsa.pub "$ssh_dir"
|
||||||
|
chmod 700 "$ssh_dir"
|
||||||
|
chmod 600 "$ssh_dir/id_rsa" "$ssh_dir/id_rsa.pub"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Script execution complete."
|
||||||
|
exit 0
|
||||||
1
system/clearpilot/tools_wip_4_28/remount_ro.sh
Normal file
1
system/clearpilot/tools_wip_4_28/remount_ro.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
sudo mount -o remount,ro /
|
||||||
1
system/clearpilot/tools_wip_4_28/remount_rw.sh
Normal file
1
system/clearpilot/tools_wip_4_28/remount_rw.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
sudo mount -o remount,rw /
|
||||||
33
system/clearpilot/tools_wip_4_28/rotation_module.cpp
Normal file
33
system/clearpilot/tools_wip_4_28/rotation_module.cpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include <Python.h>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QWidget>
|
||||||
|
#include "/usr/include/aarch64-linux-gnu/qt5/QtGui/5.12.8/QtGui/qpa/qplatformnativeinterface.h"
|
||||||
|
#include <wayland-client-protocol.h>
|
||||||
|
|
||||||
|
#include <QWindow>
|
||||||
|
#include <sipAPIrotation.h>
|
||||||
|
|
||||||
|
static PyObject* rotate_display(PyObject* self, PyObject* args) {
|
||||||
|
PyObject* pyObj;
|
||||||
|
if (!PyArg_ParseTuple(args, "O", &pyObj))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
QWindow* window = sipUnwrapInstance<QWindow>(pyObj, sipAPI_rotation);
|
||||||
|
if (!window) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Invalid window object.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface();
|
||||||
|
wl_surface *s = static_cast<wl_surface*>(native->nativeResourceForWindow("surface", window));
|
||||||
|
if (!s) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Failed to obtain native Wayland surface.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_surface_set_buffer_transform(s, WL_OUTPUT_TRANSFORM_270);
|
||||||
|
wl_surface_commit(s);
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
19
system/clearpilot/tools_wip_4_28/rotation_module.sip
Normal file
19
system/clearpilot/tools_wip_4_28/rotation_module.sip
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// Define the module
|
||||||
|
%Module rotation 0
|
||||||
|
|
||||||
|
// Import PyQt types
|
||||||
|
%Import QtCore/QtCoremod.sip
|
||||||
|
%Import QtGui/QtGuimod.sip
|
||||||
|
|
||||||
|
|
||||||
|
// Define your class with the necessary methods
|
||||||
|
class QWindow;
|
||||||
|
|
||||||
|
%MethodCode
|
||||||
|
QWindow* window = reinterpret_cast<QWindow*>(a0);
|
||||||
|
if (!window) {
|
||||||
|
sipError = sipBadCallableArg;
|
||||||
|
}
|
||||||
|
%End
|
||||||
|
|
||||||
|
void rotate_display(QWindow *window);
|
||||||
32
system/clearpilot/tools_wip_4_28/rotation_module_build.py
Normal file
32
system/clearpilot/tools_wip_4_28/rotation_module_build.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from setuptools import setup, Extension
|
||||||
|
from distutils.command.build_ext import build_ext
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Specify the C++ compiler
|
||||||
|
os.environ["CC"] = "clang++"
|
||||||
|
os.environ["CXX"] = "clang++"
|
||||||
|
|
||||||
|
class BuildExt(build_ext):
|
||||||
|
def build_extensions(self):
|
||||||
|
c_opts = ['-std=c++1z', '-DQCOM2', '-mcpu=cortex-a57', '-Wno-deprecated-declarations', '-O2', '-Wunused', '-Werror', '-Wshadow']
|
||||||
|
for e in self.extensions:
|
||||||
|
e.extra_compile_args = c_opts
|
||||||
|
build_ext.build_extensions(self)
|
||||||
|
|
||||||
|
module = Extension('rotation',
|
||||||
|
sources=['rotation_module.cpp'],
|
||||||
|
libraries=['Qt5Core', 'Qt5Gui', 'Qt5Widgets', 'wayland-client'],
|
||||||
|
include_dirs=[
|
||||||
|
'/usr/include/aarch64-linux-gnu/qt5',
|
||||||
|
'/usr/include/aarch64-linux-gnu/qt5/QtCore',
|
||||||
|
'/usr/include/aarch64-linux-gnu/qt5/QtGui',
|
||||||
|
'/usr/include/aarch64-linux-gnu/qt5/QtWidgets'
|
||||||
|
],
|
||||||
|
library_dirs=['/usr/lib/aarch64-linux-gnu', '/lib/aarch64-linux-gnu'],
|
||||||
|
language='c++')
|
||||||
|
|
||||||
|
setup(name='RotationModule',
|
||||||
|
version='1.0',
|
||||||
|
description='Module for rotating display via native interface',
|
||||||
|
ext_modules=[module],
|
||||||
|
cmdclass={'build_ext': BuildExt})
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
python3 rotation_module_build.py build
|
||||||
|
cp build/lib.linux-aarch64-cpython-311/rotation.cpython-311-aarch64-linux-gnu.so ./rotation.so
|
||||||
37
system/clearpilot/tools_wip_4_28/scrun
Normal file
37
system/clearpilot/tools_wip_4_28/scrun
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Usage:
|
||||||
|
# scrun instancename command
|
||||||
|
|
||||||
|
# - If instancename doesnt exist, starts a screen with instancename and executes the given command.
|
||||||
|
# - Does not run if the instance is already running.
|
||||||
|
# - Runs in the same context as a shell (loads environment variables).
|
||||||
|
# - Logs output into /var/log/scrun/instance/DATE.log, with rotation
|
||||||
|
|
||||||
|
# bash -l -c "$@"
|
||||||
|
|
||||||
|
# Based on https://gist.github.com/camperdave/980040
|
||||||
|
echo "defshell -bash" > ~/.screenrc
|
||||||
|
echo "startup_message off" >> ~/.screenrc
|
||||||
|
echo "vbell off" >> ~/.screenrc
|
||||||
|
echo "deflogin on" >> ~/.screenrc
|
||||||
|
echo "defscrollback 10000" >> ~/.screenrc
|
||||||
|
echo "defutf8 on" >> ~/.screenrc
|
||||||
|
echo "defflow off" >> ~/.screenrc
|
||||||
|
echo "msgwait 20" >> ~/.screenrc
|
||||||
|
echo "term screen-256color-bce" >> ~/.screenrc
|
||||||
|
|
||||||
|
#SCREENNAME=scrun_$1_
|
||||||
|
SCREENNAME=$1
|
||||||
|
|
||||||
|
screen -wipe 2>/dev/null >/dev/null
|
||||||
|
|
||||||
|
if ! screen -list | grep -q $SCREENNAME; then
|
||||||
|
cesc="${@:2}" # Everything but first one
|
||||||
|
# cesc="${cesc@Q}" # Escape it
|
||||||
|
screen -dmS $SCREENNAME python3 /data/openpilot/system/clearpilot/tools/faketty.py bash -l -c "$cesc"
|
||||||
|
echo screen -dmS $SCREENNAME python3 /data/openpilot/system/clearpilot/tools/faketty.py bash -l -c "$cesc"
|
||||||
|
# screen -dmS $1 "$@"
|
||||||
|
else
|
||||||
|
echo $SCREENNAME is already running
|
||||||
|
fi
|
||||||
90
system/clearpilot/tools_wip_4_28/shell.py
Normal file
90
system/clearpilot/tools_wip_4_28/shell.py
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import signal
|
||||||
|
import logging
|
||||||
|
import platform
|
||||||
|
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QScrollBar, QGraphicsView, QGraphicsScene, QGraphicsProxyWidget
|
||||||
|
from PyQt5.QtCore import Qt, QCoreApplication
|
||||||
|
from PyQt5.QtGui import QFont, QScreen
|
||||||
|
|
||||||
|
import termqt
|
||||||
|
from termqt import Terminal, TerminalPOSIXExecIO
|
||||||
|
|
||||||
|
class ExitOnMessageHandler(logging.Handler):
|
||||||
|
def emit(self, record):
|
||||||
|
if "Spawned process has been killed" in record.getMessage():
|
||||||
|
QApplication.quit() # Exit the application gracefully
|
||||||
|
|
||||||
|
def setup_logger():
|
||||||
|
logger = logging.getLogger()
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
handler = logging.StreamHandler()
|
||||||
|
formatter = logging.Formatter("[%(asctime)s] > [%(filename)s:%(lineno)d] %(message)s")
|
||||||
|
handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
handler2 = ExitOnMessageHandler()
|
||||||
|
logger.addHandler(handler2)
|
||||||
|
return logger
|
||||||
|
|
||||||
|
def create_terminal_app():
|
||||||
|
os.environ["XDG_RUNTIME_DIR"] = "/var/tmp/weston"
|
||||||
|
os.environ["WAYLAND_DISPLAY"] = "wayland-0"
|
||||||
|
os.environ["QT_QPA_PLATFORM"] = "wayland"
|
||||||
|
os.environ["QT_WAYLAND_SHELL_INTEGRATION"] = "wl-shell"
|
||||||
|
|
||||||
|
|
||||||
|
QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
desktop = QApplication.desktop()
|
||||||
|
ag = desktop.availableGeometry(desktop.primaryScreen())
|
||||||
|
print (ag.width())
|
||||||
|
print (ag.height())
|
||||||
|
|
||||||
|
window = QWidget()
|
||||||
|
window.setWindowTitle("termqt on {}".format(platform.system()))
|
||||||
|
window.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
|
||||||
|
window.setGeometry(0,0, ag.width(), ag.height())
|
||||||
|
window.setStyleSheet("background-color: black;")
|
||||||
|
window.showFullScreen()
|
||||||
|
|
||||||
|
scene = QGraphicsScene()
|
||||||
|
view = QGraphicsView(scene, window)
|
||||||
|
print (window.width())
|
||||||
|
print (window.height())
|
||||||
|
view.setGeometry(0, 0, window.width(), window.height())
|
||||||
|
view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||||
|
view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||||
|
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
terminal = Terminal(window.width(), window.height(), logger=setup_logger(), font_size=32)
|
||||||
|
|
||||||
|
proxy_terminal = scene.addWidget(terminal)
|
||||||
|
view.setScene(scene)
|
||||||
|
view.rotate(90) # Rotate the view by 90 degrees clockwise
|
||||||
|
|
||||||
|
window_layout = QHBoxLayout(window)
|
||||||
|
window_layout.addWidget(view)
|
||||||
|
window_layout.setContentsMargins(0,0,0,0)
|
||||||
|
window.setLayout(window_layout)
|
||||||
|
|
||||||
|
return app, window, terminal
|
||||||
|
|
||||||
|
def main():
|
||||||
|
signal.signal(signal.SIGINT, signal.SIG_DFL) # Enable Ctrl+C
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python start.py '<command>'")
|
||||||
|
return
|
||||||
|
|
||||||
|
command = "bash -c '{}'".format(sys.argv[1])
|
||||||
|
app, window, terminal = create_terminal_app()
|
||||||
|
platform_name = platform.system()
|
||||||
|
terminal_io = TerminalPOSIXExecIO(terminal.col_len, terminal.row_len, command, os.environ, setup_logger())
|
||||||
|
terminal_io.stdout_callback = terminal.stdout
|
||||||
|
terminal.stdin_callback = terminal_io.write
|
||||||
|
terminal.resize_callback = terminal_io.resize
|
||||||
|
terminal_io.spawn()
|
||||||
|
exit_code = app.exec_()
|
||||||
|
sys.exit(exit_code)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
1
system/clearpilot/tools_wip_4_28/shell.sh
Normal file
1
system/clearpilot/tools_wip_4_28/shell.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
sudo su comma -c "python3 shell.py \"echo hello; sleep 5\"
|
||||||
28
system/clearpilot/tools_wip_4_28/test.c
Normal file
28
system/clearpilot/tools_wip_4_28/test.c
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static void activate(GtkApplication* app, gpointer user_data) {
|
||||||
|
GtkWidget *window;
|
||||||
|
window = gtk_application_window_new(app);
|
||||||
|
gtk_window_set_title(GTK_WINDOW(window), "Basic C GTK App");
|
||||||
|
gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
|
||||||
|
gtk_widget_show_all(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
GtkApplication *app;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
// Signal handling
|
||||||
|
signal(SIGINT, SIG_DFL);
|
||||||
|
|
||||||
|
app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
|
||||||
|
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
|
||||||
|
status = g_application_run(G_APPLICATION(app), argc, argv);
|
||||||
|
g_object_unref(app);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
BIN
system/clearpilot/tools_wip_4_28/test2
Executable file
BIN
system/clearpilot/tools_wip_4_28/test2
Executable file
Binary file not shown.
62
system/clearpilot/tools_wip_4_28/test2.cc
Normal file
62
system/clearpilot/tools_wip_4_28/test2.cc
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#include <QApplication>
|
||||||
|
#include <QWebView>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QtWebKit>
|
||||||
|
#include <QtWebKitWidgets>
|
||||||
|
|
||||||
|
#include "/data/openpilot/system/hardware/hw.h"
|
||||||
|
#include "/data/openpilot/selfdrive/ui/qt/qt_window.h"
|
||||||
|
#include "/data/openpilot/selfdrive/ui/qt/util.h"
|
||||||
|
|
||||||
|
static void handleSignal(int sig) {
|
||||||
|
QApplication::quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "Usage: %s <url>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up Ctrl+C signal handler
|
||||||
|
signal(SIGINT, handleSignal);
|
||||||
|
|
||||||
|
QWidget window;
|
||||||
|
window.setWindowTitle("Web Viewer");
|
||||||
|
window.setStyleSheet("background-color: black;");
|
||||||
|
window.showFullScreen(); // Show the window to ensure the handle is valid
|
||||||
|
|
||||||
|
auto windowHandle = window.windowHandle();
|
||||||
|
if (!windowHandle) {
|
||||||
|
fprintf(stderr, "Error: Unable to obtain window handle.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface();
|
||||||
|
auto *s = static_cast<wl_surface*>(native->nativeResourceForWindow("surface", windowHandle));
|
||||||
|
if (!s) {
|
||||||
|
fprintf(stderr, "Error: Unable to obtain native Wayland surface.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_surface_set_buffer_transform(s, WL_OUTPUT_TRANSFORM_270);
|
||||||
|
wl_surface_commit(s);
|
||||||
|
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout(&window);
|
||||||
|
QWebView *view = new QWebView;
|
||||||
|
view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // Ensure it expands to fill layout
|
||||||
|
layout->addWidget(view);
|
||||||
|
|
||||||
|
QString url = argv[1];
|
||||||
|
view->load(QUrl(url));
|
||||||
|
|
||||||
|
// Resize window after setting up layout and loading the page
|
||||||
|
window.setFixedSize(2160, 1080); // Set fixed size after rotation
|
||||||
|
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
10
system/clearpilot/tools_wip_4_28/test2.h
Normal file
10
system/clearpilot/tools_wip_4_28/test2.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QProgressBar>
|
||||||
|
#include <QSocketNotifier>
|
||||||
|
#include <QVariantAnimation>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include <QConsole.h>
|
||||||
120
system/clearpilot/tools_wip_4_28/test3.cc
Normal file
120
system/clearpilot/tools_wip_4_28/test3.cc
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
#include "test2.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QString>
|
||||||
|
#include <QTransform>
|
||||||
|
|
||||||
|
#include "/data/openpilot/system/hardware/hw.h"
|
||||||
|
#include "/data/openpilot/selfdrive/ui/qt/qt_window.h"
|
||||||
|
#include "/data/openpilot/selfdrive/ui/qt/util.h"
|
||||||
|
|
||||||
|
TrackWidget::TrackWidget(QWidget *parent) : QWidget(parent) {
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
setFixedSize(spinner_size);
|
||||||
|
|
||||||
|
// pre-compute all the track imgs. make this a gif instead?
|
||||||
|
QPixmap comma_img = loadPixmap("../assets/img_spinner_comma.png", spinner_size);
|
||||||
|
QPixmap track_img = loadPixmap("../assets/img_spinner_track.png", spinner_size);
|
||||||
|
|
||||||
|
QTransform transform(1, 0, 0, 1, width() / 2, height() / 2);
|
||||||
|
QPixmap pm(spinner_size);
|
||||||
|
QPainter p(&pm);
|
||||||
|
p.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||||
|
for (int i = 0; i < track_imgs.size(); ++i) {
|
||||||
|
p.resetTransform();
|
||||||
|
p.fillRect(0, 0, spinner_size.width(), spinner_size.height(), Qt::black);
|
||||||
|
p.drawPixmap(0, 0, comma_img);
|
||||||
|
p.setTransform(transform.rotate(360 / spinner_fps));
|
||||||
|
p.drawPixmap(-width() / 2, -height() / 2, track_img);
|
||||||
|
track_imgs[i] = pm.copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_anim.setDuration(1000);
|
||||||
|
m_anim.setStartValue(0);
|
||||||
|
m_anim.setEndValue(int(track_imgs.size() -1));
|
||||||
|
m_anim.setLoopCount(-1);
|
||||||
|
m_anim.start();
|
||||||
|
connect(&m_anim, SIGNAL(valueChanged(QVariant)), SLOT(update()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackWidget::paintEvent(QPaintEvent *event) {
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.drawPixmap(0, 0, track_imgs[m_anim.currentValue().toInt()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spinner
|
||||||
|
|
||||||
|
Spinner::Spinner(QWidget *parent) : QWidget(parent) {
|
||||||
|
QGridLayout *main_layout = new QGridLayout(this);
|
||||||
|
main_layout->setSpacing(0);
|
||||||
|
main_layout->setMargin(200);
|
||||||
|
|
||||||
|
main_layout->addWidget(new TrackWidget(this), 0, 0, Qt::AlignHCenter | Qt::AlignVCenter);
|
||||||
|
|
||||||
|
text = new QLabel();
|
||||||
|
text->setWordWrap(true);
|
||||||
|
text->setVisible(false);
|
||||||
|
text->setAlignment(Qt::AlignCenter);
|
||||||
|
main_layout->addWidget(text, 1, 0, Qt::AlignHCenter);
|
||||||
|
|
||||||
|
progress_bar = new QProgressBar();
|
||||||
|
progress_bar->setRange(5, 100);
|
||||||
|
progress_bar->setTextVisible(false);
|
||||||
|
progress_bar->setVisible(false);
|
||||||
|
progress_bar->setFixedHeight(20);
|
||||||
|
main_layout->addWidget(progress_bar, 1, 0, Qt::AlignHCenter);
|
||||||
|
|
||||||
|
setStyleSheet(R"(
|
||||||
|
Spinner {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
QLabel {
|
||||||
|
color: white;
|
||||||
|
font-size: 80px;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
QProgressBar {
|
||||||
|
background-color: #373737;
|
||||||
|
width: 1000px;
|
||||||
|
border solid white;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
QProgressBar::chunk {
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: rgba(23, 134, 68, 255);
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
|
||||||
|
notifier = new QSocketNotifier(fileno(stdin), QSocketNotifier::Read);
|
||||||
|
QObject::connect(notifier, &QSocketNotifier::activated, this, &Spinner::update);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Spinner::update(int n) {
|
||||||
|
std::string line;
|
||||||
|
std::getline(std::cin, line);
|
||||||
|
|
||||||
|
if (line.length()) {
|
||||||
|
bool number = std::all_of(line.begin(), line.end(), ::isdigit);
|
||||||
|
text->setVisible(!number);
|
||||||
|
progress_bar->setVisible(number);
|
||||||
|
text->setText(QString::fromStdString(line));
|
||||||
|
if (number) {
|
||||||
|
progress_bar->setValue(std::stoi(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
initApp(argc, argv);
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
Spinner spinner;
|
||||||
|
setMainWindow(&spinner);
|
||||||
|
return a.exec();
|
||||||
|
}
|
||||||
37
system/clearpilot/tools_wip_4_28/test3.h
Normal file
37
system/clearpilot/tools_wip_4_28/test3.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QProgressBar>
|
||||||
|
#include <QSocketNotifier>
|
||||||
|
#include <QVariantAnimation>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
constexpr int spinner_fps = 30;
|
||||||
|
constexpr QSize spinner_size = QSize(360, 360);
|
||||||
|
|
||||||
|
class TrackWidget : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
TrackWidget(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
std::array<QPixmap, spinner_fps> track_imgs;
|
||||||
|
QVariantAnimation m_anim;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Spinner : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Spinner(QWidget *parent = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLabel *text;
|
||||||
|
QProgressBar *progress_bar;
|
||||||
|
QSocketNotifier *notifier;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void update(int n);
|
||||||
|
};
|
||||||
64
system/clearpilot/tools_wip_4_28/test4.cc
Normal file
64
system/clearpilot/tools_wip_4_28/test4.cc
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#include <QApplication>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QString>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
|
||||||
|
#include <qpa/qplatformnativeinterface.h>
|
||||||
|
#include <wayland-client-protocol.h>
|
||||||
|
#include <QPlatformSurfaceEvent>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("Usage: %s '<command>'\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget window;
|
||||||
|
window.setWindowTitle("Shell Command Output Viewer");
|
||||||
|
window.setStyleSheet("background-color: black;");
|
||||||
|
|
||||||
|
QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface();
|
||||||
|
wl_surface *s = reinterpret_cast<wl_surface*>(native->nativeResourceForWindow("surface", window.windowHandle()));
|
||||||
|
wl_surface_set_buffer_transform(s, WL_OUTPUT_TRANSFORM_270);
|
||||||
|
wl_surface_commit(s);
|
||||||
|
void *egl = native->nativeResourceForWindow("egldisplay", window.windowHandle());
|
||||||
|
assert(egl != nullptr);
|
||||||
|
|
||||||
|
window.showFullScreen();
|
||||||
|
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout(&window);
|
||||||
|
QTextEdit *outputDisplay = new QTextEdit;
|
||||||
|
outputDisplay->setFont(QFont("Consolas", 32));
|
||||||
|
outputDisplay->setReadOnly(true);
|
||||||
|
outputDisplay->setStyleSheet("color: white; background-color: black;");
|
||||||
|
layout->addWidget(outputDisplay);
|
||||||
|
|
||||||
|
QProcess process;
|
||||||
|
QObject::connect(&process, &QProcess::readyReadStandardOutput, [&]() {
|
||||||
|
static QStringList lines;
|
||||||
|
QString output = process.readAllStandardOutput();
|
||||||
|
lines += output.split("\n", QString::SkipEmptyParts);
|
||||||
|
while (lines.size() > 100) {
|
||||||
|
lines.removeFirst();
|
||||||
|
}
|
||||||
|
outputDisplay->setPlainText(lines.join("\n"));
|
||||||
|
outputDisplay->verticalScrollBar()->setValue(outputDisplay->verticalScrollBar()->maximum());
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(&process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [&]() {
|
||||||
|
app.quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
QString command = argv[1];
|
||||||
|
process.start(QString("bash -c \"%1\"").arg(command));
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
66
system/clearpilot/tools_wip_4_28/webview.py
Normal file
66
system/clearpilot/tools_wip_4_28/webview.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QGraphicsView, QGraphicsScene
|
||||||
|
from PyQt5.QtCore import Qt, QUrl, QTimer
|
||||||
|
from PyQt5.QtGui import QCursor, QPixmap, QTransform
|
||||||
|
from PyQt5.QtWebEngineWidgets import QWebEngineView
|
||||||
|
import rotation
|
||||||
|
|
||||||
|
def create_webview_app():
|
||||||
|
# Set environment for Wayland
|
||||||
|
os.environ["XDG_RUNTIME_DIR"] = "/var/tmp/weston"
|
||||||
|
os.environ["WAYLAND_DISPLAY"] = "wayland-0"
|
||||||
|
os.environ["QT_QPA_PLATFORM"] = "wayland"
|
||||||
|
os.environ["QT_WAYLAND_SHELL_INTEGRATION"] = "wl-shell"
|
||||||
|
|
||||||
|
# Application setup
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = QWidget()
|
||||||
|
window.setWindowTitle("Qt WebView Example")
|
||||||
|
window.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
|
||||||
|
sg = QApplication.desktop().availableGeometry(window)
|
||||||
|
window.setGeometry(0, 0, sg.height(), sg.width())
|
||||||
|
window.setStyleSheet("background-color: black;")
|
||||||
|
|
||||||
|
scene = QGraphicsScene()
|
||||||
|
view = QGraphicsView(scene, window)
|
||||||
|
view.setGeometry(0, 0, sg.width(), sg.height())
|
||||||
|
view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||||
|
view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||||
|
|
||||||
|
webview = QWebEngineView()
|
||||||
|
webview.load(QUrl("https://cdpn.io/yananas/fullpage/rwvZvY"))
|
||||||
|
webview.setGeometry(0, 0, sg.width(), sg.height())
|
||||||
|
scene.addWidget(webview)
|
||||||
|
view.setScene(scene)
|
||||||
|
|
||||||
|
window_layout = QHBoxLayout(window)
|
||||||
|
window_layout.addWidget(view)
|
||||||
|
|
||||||
|
window.setLayout(window_layout)
|
||||||
|
|
||||||
|
window.showFullScreen()
|
||||||
|
|
||||||
|
window_handle = window.windowHandle()
|
||||||
|
rotation.rotate_display(window_handle)
|
||||||
|
|
||||||
|
# Delay rotation using QTimer
|
||||||
|
# QTimer.singleShot(1000, lambda: rotate_display(window))
|
||||||
|
|
||||||
|
return app, window
|
||||||
|
|
||||||
|
def rotate_display(window):
|
||||||
|
window_handle = window.windowHandle()
|
||||||
|
if window_handle:
|
||||||
|
print("Rotating display.")
|
||||||
|
try:
|
||||||
|
print(int(window_handle.winId()))
|
||||||
|
rotation.rotate_display(int(window_handle.winId()))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error rotating display: {e}")
|
||||||
|
else:
|
||||||
|
print("Window handle is not valid.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app, _ = create_webview_app()
|
||||||
|
sys.exit(app.exec_())
|
||||||
1
system/clearpilot/tools_wip_4_28/webview.sh
Normal file
1
system/clearpilot/tools_wip_4_28/webview.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
sudo su comma -c "nice python3 webview.py"
|
||||||
75
system/clearpilot/tools_wip_4_28/webview2.py
Normal file
75
system/clearpilot/tools_wip_4_28/webview2.py
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import signal
|
||||||
|
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QGraphicsView, QGraphicsScene
|
||||||
|
from PyQt5.QtCore import Qt, QUrl, QPointF, QTimer, QObject, QEvent
|
||||||
|
from PyQt5.QtGui import QCursor, QPixmap, QTransform
|
||||||
|
from PyQt5.QtWebEngineWidgets import QWebEngineView
|
||||||
|
|
||||||
|
import rotation
|
||||||
|
|
||||||
|
webview = None
|
||||||
|
|
||||||
|
def create_webview_app():
|
||||||
|
global webview
|
||||||
|
|
||||||
|
# Set environment for Wayland
|
||||||
|
os.environ["XDG_RUNTIME_DIR"] = "/var/tmp/weston"
|
||||||
|
os.environ["WAYLAND_DISPLAY"] = "wayland-0"
|
||||||
|
os.environ["QT_QPA_PLATFORM"] = "wayland"
|
||||||
|
os.environ["QT_WAYLAND_SHELL_INTEGRATION"] = "wl-shell"
|
||||||
|
|
||||||
|
# Application setup
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
desktop = QApplication.desktop()
|
||||||
|
|
||||||
|
sg = desktop.availableGeometry(desktop.primaryScreen())
|
||||||
|
|
||||||
|
window = QWidget()
|
||||||
|
window.setWindowTitle("Qt WebView Example")
|
||||||
|
window.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
|
||||||
|
window.setGeometry(0, 0, sg.height(), sg.width())
|
||||||
|
window.setStyleSheet("background-color: black;")
|
||||||
|
window.showFullScreen()
|
||||||
|
|
||||||
|
scene = QGraphicsScene()
|
||||||
|
view = QGraphicsView(scene, window)
|
||||||
|
view.setGeometry(0, 0, sg.width(), sg.height())
|
||||||
|
view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||||
|
view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||||
|
|
||||||
|
# Create WebView
|
||||||
|
webview = QWebEngineView()
|
||||||
|
webview.load(QUrl("https://cdpn.io/yananas/fullpage/rwvZvY"))
|
||||||
|
webview.setGeometry(0, 0, sg.width(), sg.height())
|
||||||
|
|
||||||
|
# Add WebView to the scene
|
||||||
|
proxy_webview = scene.addWidget(webview)
|
||||||
|
view.setScene(scene)
|
||||||
|
# view.rotate(90) # Rotate the view by 90 degrees
|
||||||
|
|
||||||
|
# Layout setup
|
||||||
|
window_layout = QHBoxLayout(window)
|
||||||
|
window_layout.addWidget(view)
|
||||||
|
window_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
window.setLayout(window_layout)
|
||||||
|
|
||||||
|
window_handle = int(window.winId())
|
||||||
|
# window_handle = window.windowHandle()
|
||||||
|
print ("Handle:")
|
||||||
|
print (window_handle)
|
||||||
|
# if window_handle:
|
||||||
|
# rotation.rotate_display(window_handle)
|
||||||
|
# else:
|
||||||
|
# print("Window handle is not valid.")
|
||||||
|
|
||||||
|
return app, window
|
||||||
|
|
||||||
|
def main():
|
||||||
|
signal.signal(signal.SIGINT, signal.SIG_DFL) # Enable Ctrl+C to terminate the application
|
||||||
|
app, window = create_webview_app()
|
||||||
|
exit_code = app.exec_()
|
||||||
|
sys.exit(exit_code)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user