| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <QApplication> |
| | #include <QClipboard> |
| | #include <QFile> |
| | #include <QKeyEvent> |
| | #include <QRegularExpression> |
| |
|
| | #include "qg_commandedit.h" |
| | #include "rs_dialogfactory.h" |
| | #include "rs_dialogfactoryinterface.h" |
| | #include "rs_math.h" |
| | #include "rs_settings.h" |
| |
|
| | namespace { |
| | |
| | |
| | constexpr unsigned g_maxLinesToRead = 10240; |
| | |
| | constexpr unsigned g_maxLineLength = 4096; |
| |
|
| | |
| | bool calculatorEvaluation(const QString& input){ |
| | int pos = input.indexOf(' '); |
| | if (pos == -1) |
| | pos = input.indexOf(':'); |
| | if (pos == -1) |
| | return false; |
| |
|
| | QString expression = input.mid(pos); |
| | if (expression.isEmpty()) |
| | return false; |
| | bool okay=false; |
| | double value = RS_Math::eval(expression, &okay); |
| | if (okay) { |
| | RS_DIALOGFACTORY->commandMessage(QObject::tr("Calculator: ") + expression |
| | + QString{" = %1"}.arg(value, 0, 'g', 10)); |
| | } |
| | return okay; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | QG_CommandEdit::QG_CommandEdit(QWidget* parent) |
| | : QLineEdit(parent) |
| | , m_keycode_mode(false) |
| | , m_relative_ray("none") |
| | , m_calculator_mode(false) |
| |
|
| | { |
| | #ifndef DONT_FORCE_WIDGETS_CSS |
| | setStyleSheet("selection-color: white; selection-background-color: green;"); |
| | #endif |
| | setFrame(false); |
| | setFocusPolicy(Qt::StrongFocus); |
| | } |
| |
|
| | |
| | |
| | |
| | bool QG_CommandEdit::event(QEvent* e) { |
| | if (e != nullptr && e->type()==QEvent::KeyPress) { |
| | QKeyEvent* k = static_cast<QKeyEvent*>(e); |
| | switch(k->key()) { |
| | case Qt::Key_Tab: |
| | emit tabPressed(); |
| | return true; |
| | |
| | |
| | |
| | |
| | |
| | default: |
| | break; |
| | } |
| | } |
| |
|
| | return QLineEdit::event(e); |
| | } |
| |
|
| | |
| | |
| | |
| | void QG_CommandEdit::keyPressEvent(QKeyEvent* e) { |
| | if (e->modifiers() & Qt::ControlModifier) { |
| | auto value = text(); |
| |
|
| | if (value.isEmpty()) |
| | value = m_relative_ray; |
| |
|
| | QString r_string; |
| |
|
| | switch (e->key()) { |
| | case Qt::Key_Up: |
| | r_string = "0," + value; |
| | break; |
| | case Qt::Key_Down: |
| | r_string = "0,-" + value; |
| | break; |
| | case Qt::Key_Right: |
| | r_string = value + ",0"; |
| | break; |
| | case Qt::Key_Left: |
| | r_string = "-" + value + ",0"; |
| | break; |
| | default: |
| | QLineEdit::keyPressEvent(e); |
| | return; |
| | } |
| |
|
| | |
| | if (!r_string.isEmpty()) { |
| | if (value == "none") { |
| | emit message( |
| | QObject::tr("You must input a distance first.") |
| | ); |
| | } |
| | else { |
| | m_relative_ray = value; |
| | emit command("@" + r_string); |
| | } |
| | } |
| | return; |
| | } |
| |
|
| | switch (e->key()) { |
| | case Qt::Key_Up: |
| | if (!m_historyList.isEmpty() && it > m_historyList.begin()) { |
| | it--; |
| | setText(*it); |
| | } |
| | break; |
| |
|
| | case Qt::Key_Down: |
| | if (!m_historyList.isEmpty() && it < m_historyList.end()) { |
| | it++; |
| | if (it < m_historyList.end()) { |
| | setText(*it); |
| | } |
| | else { |
| | setText(""); |
| | } |
| | } |
| | break; |
| |
|
| | case Qt::Key_Enter: |
| | case Qt::Key_Return: |
| | processInput(text()); |
| | break; |
| | case Qt::Key_Space: |
| | if (LC_GET_ONE_BOOL("Keyboard","EvaluateCommandOnSpace", false)) { |
| | processInput(text()); |
| | } |
| | else if (!text().isEmpty()) { |
| | QLineEdit::keyPressEvent(e); |
| | } |
| | break; |
| | case Qt::Key_Escape: |
| | if (text().isEmpty()) { |
| | emit escape(); |
| | } |
| | else { |
| | setText(""); |
| | } |
| | break; |
| |
|
| | default: |
| | QLineEdit::keyPressEvent(e); |
| | break; |
| | } |
| |
|
| | if (m_keycode_mode) { |
| | auto input = text(); |
| | if (input.size() == 2) { |
| | emit keycode(input); |
| | } |
| | } |
| | } |
| |
|
| | void QG_CommandEdit::evaluateExpression(QString input) { |
| | static QRegularExpression regex(R"~(([\d\.]+)deg|d)~"); |
| | input.replace(regex, R"~(\1*pi/180)~"); |
| | bool ok = true; |
| | double result = RS_Math::eval(input, &ok); |
| | if (ok) |
| | emit message(input + " = " + QString::number(result, 'g', 12)); |
| | else |
| | emit message(QObject::tr("Calculator error for input: ") + input); |
| | } |
| |
|
| | void QG_CommandEdit::focusInEvent(QFocusEvent *e) { |
| | emit focusIn(); |
| | QLineEdit::focusInEvent(e); |
| | } |
| |
|
| | void QG_CommandEdit::focusOutEvent(QFocusEvent *e) { |
| | emit focusOut(); |
| | QLineEdit::focusOutEvent(e); |
| | } |
| |
|
| | void QG_CommandEdit::processInput(QString input) { |
| | |
| |
|
| | |
| | QRegularExpression regex(R"~(([-\w\.\\]+)\.\.)~"); |
| | input.replace(regex, "@\\1,"); |
| |
|
| | if (isForeignCommand(input)) { |
| | if (input.contains(";")) { |
| | foreach(auto str, input.split(";")) { |
| | if (str.contains("\\")) |
| | processVariable(str); |
| | else |
| | emit command(str); |
| | } |
| | } |
| | else { |
| | if (input.contains("\\")) |
| | processVariable(input); |
| | else |
| | emit command(input); |
| | } |
| |
|
| | m_historyList.append(input); |
| | it = m_historyList.end(); |
| | } |
| | else if (input == "") { |
| | emit command(""); |
| | } |
| | clear(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | QString QG_CommandEdit::filterCliCal(const QString& cmd) { |
| | QString str = cmd.trimmed(); |
| | static const QRegularExpression calCmd(R"(^\s*(cal|calculate)\s?)", QRegularExpression::CaseInsensitiveOption); |
| | QRegularExpressionMatch match = calCmd.match(str); |
| | if (!(match.hasMatch() |
| | || str.startsWith(QObject::tr("cal ", "command to trigger cli calculator"), Qt::CaseInsensitive) |
| | || str.startsWith(QObject::tr("calculate ", "command to trigger cli calculator"), Qt::CaseInsensitive) |
| | )) { |
| | return cmd; |
| | } |
| | int index = match.capturedEnd(0); |
| | bool spaceFound = (index >= 0); |
| | str = str.mid(index); |
| | static QRegularExpression reSpace(R"(\S)"); |
| | index = str.indexOf(reSpace); |
| | if (!(spaceFound && index >= 0)) |
| | return cmd; |
| | str = str.mid(index); |
| | if (!str.isEmpty()) { |
| | |
| | bool okay = false; |
| | double result = RS_Math::eval(str, &okay); |
| | if (okay) { |
| | emit message(QString("%1 =%2").arg(str).arg(result, 12, 'g')); |
| | return {}; |
| | } |
| | } |
| | return cmd; |
| | } |
| |
|
| | bool QG_CommandEdit::isForeignCommand(QString input) { |
| | |
| |
|
| | bool r_value = true; |
| |
|
| | if (input == tr("clear")) { |
| | emit clearCommandsHistory(); |
| | r_value = false; |
| | } |
| | else if ((input = filterCliCal(input)).isEmpty()) { |
| | r_value = false; |
| | } |
| | else if (input.startsWith(QObject::tr("cal"))) { |
| | |
| | |
| | if (!calculatorEvaluation(input)) { |
| | m_calculator_mode = !m_calculator_mode; |
| | if (m_calculator_mode) |
| | emit message(QObject::tr("Calculator mode: On")); |
| | else |
| | emit message(QObject::tr("Calculator mode: Off")); |
| | } |
| | r_value = false; |
| | } |
| | else if (m_calculator_mode) { |
| | evaluateExpression(input); |
| | r_value = false; |
| | } |
| | else if (input.contains("=")) { |
| | auto var_value = input.split("="); |
| | m_variables[var_value[0]] = var_value[1]; |
| | r_value = false; |
| | } |
| | return r_value; |
| | } |
| |
|
| | void QG_CommandEdit::processVariable(QString input) { |
| | |
| |
|
| | if (input.contains(",")) { |
| | QString rel = ""; |
| |
|
| | if (input.contains("@")) { |
| | rel = "@"; |
| | input.remove("@"); |
| | } |
| |
|
| | auto x_y = input.split(","); |
| | if (x_y[0].contains("\\")) { |
| | x_y[0].remove("\\"); |
| | if (m_variables.contains(x_y[0])) |
| | x_y[0] = m_variables[x_y[0]]; |
| | } |
| | if (x_y[1].contains("\\")) { |
| | x_y[1].remove("\\"); |
| | if (m_variables.contains(x_y[1])) |
| | x_y[1] = m_variables[x_y[1]]; |
| | } |
| | emit command(rel + x_y[0] + "," + x_y[1]); |
| | return; |
| | } |
| |
|
| | input.remove("\\"); |
| | if (m_variables.contains(input)) { |
| | input = m_variables[input]; |
| | if (input.contains(";")) { |
| | foreach(auto str, input.split(";")) { |
| | if (str.contains("\\")) |
| | processVariable(str); |
| | else |
| | emit command(str); |
| | } |
| | } |
| | else emit command(input); |
| | } |
| | } |
| |
|
| | void QG_CommandEdit::readCommandFile(const QString& path) { |
| | |
| | QFile file(path); |
| | if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) |
| | return; |
| |
|
| | |
| | size_t pos = 0; |
| | bool ended = false; |
| | while (!ended) { |
| | if (!file.isOpen()) { |
| | if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) |
| | break; |
| | file.skip(pos); |
| | } |
| |
|
| | |
| | QTextStream txt_stream(&file); |
| | QStringList lines; |
| | for (unsigned i = 0; i < g_maxLinesToRead; ++i) { |
| | if (txt_stream.atEnd()) |
| | break; |
| | lines << txt_stream.readLine(g_maxLineLength); |
| | } |
| | ended = txt_stream.atEnd(); |
| | pos = txt_stream.pos(); |
| |
|
| | |
| | file.close(); |
| |
|
| | |
| | for (QString line : lines) { |
| | line.remove(" "); |
| | if (!line.startsWith("#")) |
| | processInput(line); |
| | } |
| | } |
| | } |
| |
|
| | void QG_CommandEdit::modifiedPaste() { |
| | auto txt = qApp->clipboard()->text(); |
| | txt.replace("\n", ";"); |
| | setText(txt); |
| | } |
| |
|