|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "toonzqt/expressionfield.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "texpression.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tparser.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tconvert.h"
|
|
Toshihiro Shimizu |
890ddd |
#include <qsyntaxhighlighter></qsyntaxhighlighter>
|
|
Toshihiro Shimizu |
890ddd |
#include <qcompleter></qcompleter>
|
|
Toshihiro Shimizu |
890ddd |
#include <qkeyevent></qkeyevent>
|
|
Toshihiro Shimizu |
890ddd |
#include <qabstractitemview></qabstractitemview>
|
|
Toshihiro Shimizu |
890ddd |
#include <qscrollbar></qscrollbar>
|
|
Toshihiro Shimizu |
890ddd |
#include <qstringlistmodel></qstringlistmodel>
|
|
Toshihiro Shimizu |
890ddd |
#include <qstandarditemmodel></qstandarditemmodel>
|
|
Toshihiro Shimizu |
890ddd |
#include <qstandarditem></qstandarditem>
|
|
Toshihiro Shimizu |
890ddd |
#include <qtooltip></qtooltip>
|
|
Toshihiro Shimizu |
890ddd |
#include <qlistview></qlistview>
|
|
Toshihiro Shimizu |
890ddd |
#include <qlabel></qlabel>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
using namespace DVGui;
|
|
Toshihiro Shimizu |
890ddd |
using namespace TSyntax;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//=============================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
class ExpressionField::SyntaxHighlighter : public QSyntaxHighlighter {
|
|
Shinya Kitaoka |
120a6e |
const Grammar *m_grammar;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
bool m_open;
|
|
Shinya Kitaoka |
120a6e |
SyntaxHighlighter(QTextDocument *parent)
|
|
Shinya Kitaoka |
120a6e |
: QSyntaxHighlighter(parent), m_grammar(0), m_open(true) {}
|
|
Shinya Kitaoka |
120a6e |
~SyntaxHighlighter() {}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
void setGrammar(const Grammar *grammar) { m_grammar = grammar; }
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
473e70 |
void highlightBlock(const QString &text) override {
|
|
Shinya Kitaoka |
120a6e |
Parser parser(m_grammar);
|
|
Shinya Kitaoka |
120a6e |
std::vector<syntaxtoken> tokens;</syntaxtoken>
|
|
Shinya Kitaoka |
120a6e |
Parser::SyntaxStatus status =
|
|
Shinya Kitaoka |
120a6e |
parser.checkSyntax(tokens, text.toStdString());
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int nextPos = 0;
|
|
Shinya Kitaoka |
120a6e |
for (int i = 0; i < (int)tokens.size(); i++) {
|
|
Shinya Kitaoka |
120a6e |
QTextCharFormat fmt;
|
|
Shinya Kitaoka |
120a6e |
int pos = tokens[i].m_pos;
|
|
Shinya Kitaoka |
120a6e |
int length = tokens[i].m_length;
|
|
Shinya Kitaoka |
120a6e |
int type = tokens[i].m_type;
|
|
Shinya Kitaoka |
120a6e |
nextPos = pos + length;
|
|
Shinya Kitaoka |
120a6e |
switch (type) {
|
|
Shinya Kitaoka |
120a6e |
case TSyntax::Unknown:
|
|
Shinya Kitaoka |
120a6e |
fmt.setForeground(Qt::black);
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
case TSyntax::Number:
|
|
Shinya Kitaoka |
120a6e |
fmt.setForeground(QColor(0x50, 0x7d, 0x0));
|
|
Shinya Kitaoka |
120a6e |
break; // number
|
|
Shinya Kitaoka |
120a6e |
case TSyntax::Constant:
|
|
Shinya Kitaoka |
120a6e |
fmt.setForeground(QColor(0x50, 0x7d, 0x0));
|
|
Shinya Kitaoka |
120a6e |
break; // constant
|
|
Shinya Kitaoka |
120a6e |
case TSyntax::Variable:
|
|
Shinya Kitaoka |
120a6e |
fmt.setForeground(QColor(0x0, 0x88, 0xc8));
|
|
Shinya Kitaoka |
120a6e |
break; // var
|
|
Shinya Kitaoka |
120a6e |
case TSyntax::Operator:
|
|
Shinya Kitaoka |
120a6e |
fmt.setForeground(QColor(50, 0, 255));
|
|
Shinya Kitaoka |
120a6e |
break; // infix
|
|
Shinya Kitaoka |
120a6e |
case TSyntax::Parenthesis:
|
|
Shinya Kitaoka |
120a6e |
fmt.setForeground(QColor(50, 50, 255));
|
|
Shinya Kitaoka |
120a6e |
break; // braket
|
|
Shinya Kitaoka |
120a6e |
case TSyntax::Function:
|
|
Shinya Kitaoka |
120a6e |
fmt.setForeground(QColor(0x0, 0x50, 0x7d));
|
|
Shinya Kitaoka |
120a6e |
break; // fname
|
|
Shinya Kitaoka |
120a6e |
case TSyntax::Comma:
|
|
Shinya Kitaoka |
120a6e |
fmt.setForeground(QColor(50, 20, 255));
|
|
Shinya Kitaoka |
120a6e |
break; // f ;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
case TSyntax::UnexpectedToken:
|
|
Shinya Kitaoka |
120a6e |
fmt.setForeground(QColor(0xdc, 0x0, 0x0));
|
|
Shinya Kitaoka |
120a6e |
break; // expression not found
|
|
Shinya Kitaoka |
120a6e |
case TSyntax::Eos:
|
|
Shinya Kitaoka |
120a6e |
fmt.setForeground(QColor(255, 127, 0));
|
|
Shinya Kitaoka |
120a6e |
break; // EOS
|
|
Shinya Kitaoka |
120a6e |
case TSyntax::Mismatch:
|
|
Shinya Kitaoka |
120a6e |
fmt.setForeground(QColor(255, 0, 0));
|
|
Shinya Kitaoka |
120a6e |
break; // token mismatch
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
default:
|
|
Shinya Kitaoka |
120a6e |
fmt.setForeground(QColor(127, 127, 255));
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (type == 4) fmt.setToolTip("Infix");
|
|
Shinya Kitaoka |
120a6e |
if (length == 0) length = 1;
|
|
Shinya Kitaoka |
120a6e |
setFormat(pos, length, fmt);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//=============================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
class MyListView : public QListView {
|
|
Shinya Kitaoka |
120a6e |
QLabel *m_tooltip;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
MyListView() : QListView() {
|
|
Shinya Kitaoka |
120a6e |
setObjectName("SuggestionPopup");
|
|
Shinya Kitaoka |
120a6e |
setStyleSheet(
|
|
Shinya Kitaoka |
120a6e |
"#SuggestionPopup {background-color:#FFFFFF; border:1px solid black;}");
|
|
Shinya Kitaoka |
120a6e |
setWindowFlags(Qt::Popup);
|
|
Shinya Kitaoka |
120a6e |
setMouseTracking(true);
|
|
Shinya Kitaoka |
120a6e |
m_tooltip = new QLabel(0, Qt::ToolTip);
|
|
Shinya Kitaoka |
120a6e |
// Stesso stile del popuop che lo contiene.
|
|
Shinya Kitaoka |
120a6e |
m_tooltip->hide();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
m_tooltip->setObjectName("helpTooltip");
|
|
Shinya Kitaoka |
120a6e |
m_tooltip->setAlignment(Qt::AlignLeft);
|
|
Shinya Kitaoka |
120a6e |
m_tooltip->setIndent(1);
|
|
Shinya Kitaoka |
120a6e |
m_tooltip->setWordWrap(false);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
473e70 |
void showEvent(QShowEvent *) override { showToolTip(currentIndex()); }
|
|
Shinya Kitaoka |
473e70 |
void hideEvent(QHideEvent *) override { m_tooltip->hide(); }
|
|
Shinya Kitaoka |
473e70 |
void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override {
|
|
Shinya Kitaoka |
120a6e |
showToolTip(current);
|
|
Shinya Kitaoka |
120a6e |
QListView::currentChanged(current, previous);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
void showToolTip(const QModelIndex &index) {
|
|
Shinya Kitaoka |
120a6e |
if (!index.isValid()) {
|
|
Shinya Kitaoka |
120a6e |
m_tooltip->hide();
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
QVariant data = model()->data(index, Qt::ToolTipRole);
|
|
Shinya Kitaoka |
120a6e |
if (!data.isValid()) {
|
|
Shinya Kitaoka |
120a6e |
m_tooltip->hide();
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
QRect rect = visualRect(index);
|
|
Shinya Kitaoka |
120a6e |
m_tooltip->setText(data.toString());
|
|
Shinya Kitaoka |
120a6e |
QPoint pos = viewport()->mapToGlobal(
|
|
Shinya Kitaoka |
120a6e |
QPoint(-m_tooltip->sizeHint().width(), rect.top()));
|
|
Shinya Kitaoka |
120a6e |
m_tooltip->setGeometry(QRect(pos, m_tooltip->sizeHint()));
|
|
Shinya Kitaoka |
120a6e |
m_tooltip->show();
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
protected:
|
|
Shinya Kitaoka |
473e70 |
void resizeEvent(QResizeEvent *e) override {
|
|
Shinya Kitaoka |
120a6e |
QListView::resizeEvent(e);
|
|
Shinya Kitaoka |
120a6e |
if (m_tooltip->isVisible()) showToolTip(currentIndex());
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//=============================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
ExpressionField::ExpressionField(QWidget *parent)
|
|
Shinya Kitaoka |
120a6e |
: QTextEdit(parent)
|
|
Shinya Kitaoka |
120a6e |
, m_editing(false)
|
|
Shinya Kitaoka |
120a6e |
, m_grammar(0)
|
|
Shinya Kitaoka |
120a6e |
, m_syntaxHighlighter(0)
|
|
Shinya Kitaoka |
120a6e |
, m_completerPopup(0)
|
|
Shinya Kitaoka |
120a6e |
, m_completerStartPos(0) {
|
|
Shinya Kitaoka |
120a6e |
setFrameStyle(QFrame::StyledPanel);
|
|
Shinya Kitaoka |
120a6e |
setObjectName("ExpressionField");
|
|
Shinya Kitaoka |
120a6e |
setLineWrapMode(NoWrap);
|
|
Shinya Kitaoka |
120a6e |
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
Shinya Kitaoka |
120a6e |
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
Shinya Kitaoka |
120a6e |
setTabChangesFocus(true);
|
|
Shinya Kitaoka |
120a6e |
// setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed));
|
|
Shinya Kitaoka |
120a6e |
connect(this, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#ifdef MACOSX
|
|
Shinya Kitaoka |
120a6e |
setFixedHeight(23);
|
|
Toshihiro Shimizu |
890ddd |
#else
|
|
Shinya Kitaoka |
120a6e |
setFixedHeight(20); // +40);
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup = new MyListView();
|
|
Shinya Kitaoka |
120a6e |
QStandardItemModel *model = new QStandardItemModel();
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->setModel(model);
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->setFocusPolicy(Qt::NoFocus);
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->setFocusProxy(this);
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->installEventFilter(this);
|
|
Shinya Kitaoka |
120a6e |
connect(m_completerPopup, SIGNAL(clicked(const QModelIndex &)), this,
|
|
Shinya Kitaoka |
120a6e |
SLOT(insertCompletion(const QModelIndex &)));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_syntaxHighlighter = new SyntaxHighlighter(document());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
ExpressionField::~ExpressionField() { delete m_syntaxHighlighter; }
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void ExpressionField::showEvent(QShowEvent *e) { QTextEdit::showEvent(e); }
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void ExpressionField::hideEvent(QHideEvent *e) { QTextEdit::hideEvent(e); }
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void ExpressionField::setExpression(std::string expression) {
|
|
Shinya Kitaoka |
120a6e |
setPlainText(QString::fromStdString(expression));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
std::string ExpressionField::getExpression() const {
|
|
Shinya Kitaoka |
120a6e |
return toPlainText().toStdString();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
bool ExpressionField::event(QEvent *e) {
|
|
Shinya Kitaoka |
120a6e |
if (e->type() == QEvent::ToolTip) {
|
|
Shinya Kitaoka |
120a6e |
QHelpEvent *helpEvent = static_cast<qhelpevent *="">(e);</qhelpevent>
|
|
Shinya Kitaoka |
120a6e |
// openCompletionPopup();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
} else if (e->type() == QEvent::ShortcutOverride) {
|
|
Shinya Kitaoka |
120a6e |
e->accept();
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
// else
|
|
Shinya Kitaoka |
120a6e |
return QTextEdit::event(e);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void ExpressionField::keyPressEvent(QKeyEvent *e) {
|
|
Shinya Kitaoka |
120a6e |
// setStyleSheet("background-color: cyan");
|
|
Shinya Kitaoka |
120a6e |
if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
|
|
Shinya Kitaoka |
120a6e |
m_editing = false;
|
|
Shinya Kitaoka |
120a6e |
emit expressionChanged();
|
|
Shinya Kitaoka |
120a6e |
} else if (e->key() == Qt::Key_F10) {
|
|
Shinya Kitaoka |
120a6e |
setAutoFillBackground(true);
|
|
Shinya Kitaoka |
120a6e |
QPalette p = palette();
|
|
Shinya Kitaoka |
120a6e |
p.setColor(QPalette::Base, Qt::cyan);
|
|
Shinya Kitaoka |
120a6e |
p.setColor(QPalette::Background, Qt::cyan);
|
|
Shinya Kitaoka |
120a6e |
setPalette(p);
|
|
Shinya Kitaoka |
120a6e |
update();
|
|
Shinya Kitaoka |
120a6e |
setStyleSheet("#ExpressionField {background-color:cyan;}");
|
|
Shinya Kitaoka |
120a6e |
} else if (e->key() == Qt::Key_F11) {
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->installEventFilter(this);
|
|
Shinya Kitaoka |
120a6e |
QRect cr = cursorRect();
|
|
Shinya Kitaoka |
120a6e |
QSize size(100, 200);
|
|
Shinya Kitaoka |
120a6e |
QPoint pos = mapToGlobal(QPoint(cr.left(), cr.top() - size.height()));
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->setGeometry(QRect(pos, size));
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->show();
|
|
Shinya Kitaoka |
120a6e |
QTextEdit::keyPressEvent(e);
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
QTextEdit::keyPressEvent(e);
|
|
Shinya Kitaoka |
120a6e |
if (m_completerPopup->isVisible()) {
|
|
Shinya Kitaoka |
120a6e |
updateCompleterPopup();
|
|
Shinya Kitaoka |
120a6e |
} else if (Qt::Key_A <= e->key() && e->key() <= Qt::Key_Z ||
|
|
Shinya Kitaoka |
120a6e |
std::string("+&|!*/=?,:-").find(e->key()) != std::string::npos) {
|
|
Shinya Kitaoka |
120a6e |
openCompleterPopup();
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
setFocus();
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
bool ExpressionField::eventFilter(QObject *obj, QEvent *e) {
|
|
Shinya Kitaoka |
120a6e |
if (e->type() == QEvent::KeyPress) {
|
|
Shinya Kitaoka |
120a6e |
QKeyEvent *keyEvent = static_cast<qkeyevent *="">(e);</qkeyevent>
|
|
Shinya Kitaoka |
120a6e |
switch (keyEvent->key()) {
|
|
Shinya Kitaoka |
120a6e |
case Qt::Key_Return:
|
|
Shinya Kitaoka |
120a6e |
case Qt::Key_Enter:
|
|
Shinya Kitaoka |
120a6e |
insertCompletion(m_completerPopup->currentIndex());
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
case Qt::Key_Left:
|
|
Shinya Kitaoka |
120a6e |
case Qt::Key_Right:
|
|
Shinya Kitaoka |
120a6e |
event(keyEvent);
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->hide();
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
case Qt::Key_Escape:
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->hide();
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
case Qt::Key_Down:
|
|
Shinya Kitaoka |
120a6e |
case Qt::Key_Up:
|
|
Shinya Kitaoka |
120a6e |
return false;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
default:
|
|
Shinya Kitaoka |
120a6e |
event(e);
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
} else if (e->type() == QEvent::MouseButtonPress) {
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->hide();
|
|
Shinya Kitaoka |
120a6e |
event(e);
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
} else if (e->type() == QEvent::ShortcutOverride) {
|
|
Shinya Kitaoka |
120a6e |
e->accept();
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
return QObject::eventFilter(obj, e);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void ExpressionField::onTextChanged() {
|
|
Shinya Kitaoka |
120a6e |
if (!m_editing) {
|
|
Shinya Kitaoka |
120a6e |
m_editing = true;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// setStyleSheet("background: rgb(250,200,200)");
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void ExpressionField::focusInEvent(QFocusEvent *e) {
|
|
Shinya Kitaoka |
120a6e |
m_syntaxHighlighter->m_open = true;
|
|
Shinya Kitaoka |
120a6e |
m_syntaxHighlighter->rehighlight();
|
|
Shinya Kitaoka |
120a6e |
QTextEdit::focusInEvent(e);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void ExpressionField::focusOutEvent(QFocusEvent *e) {
|
|
Shinya Kitaoka |
120a6e |
m_syntaxHighlighter->m_open = false;
|
|
Shinya Kitaoka |
120a6e |
m_syntaxHighlighter->rehighlight();
|
|
Shinya Kitaoka |
120a6e |
QTextEdit::focusOutEvent(e);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void ExpressionField::onCursorPositionChanged() {}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void ExpressionField::openCompleterPopup() {
|
|
Shinya Kitaoka |
120a6e |
int n = computeSuggestions();
|
|
Shinya Kitaoka |
120a6e |
if (n < 2) return;
|
|
Shinya Kitaoka |
120a6e |
if (updateCompleterPopup()) m_completerPopup->show();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
bool ExpressionField::updateCompleterPopup() {
|
|
Shinya Kitaoka |
120a6e |
int start = m_completerStartPos;
|
|
Shinya Kitaoka |
120a6e |
int pos = textCursor().position();
|
|
Shinya Kitaoka |
120a6e |
std::string text = getExpression();
|
|
Shinya Kitaoka |
120a6e |
if (m_suggestions.empty() || start < 0 || start > pos ||
|
|
Shinya Kitaoka |
120a6e |
pos > (int)text.length()) {
|
|
Shinya Kitaoka |
120a6e |
if (m_completerPopup->isVisible()) m_completerPopup->hide();
|
|
Shinya Kitaoka |
120a6e |
return false;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
QStandardItemModel *model = new QStandardItemModel();
|
|
Shinya Kitaoka |
120a6e |
std::string prefix = toLower(text.substr(start, pos - start));
|
|
Shinya Kitaoka |
120a6e |
int prefixLength = prefix.length();
|
|
Shinya Kitaoka |
120a6e |
int count = 0;
|
|
Shinya Kitaoka |
120a6e |
for (int i = 0; i < (int)m_suggestions.size(); i++) {
|
|
Shinya Kitaoka |
120a6e |
std::string item = m_suggestions[i].first;
|
|
Shinya Kitaoka |
120a6e |
if ((int)item.length() >= prefixLength &&
|
|
Shinya Kitaoka |
120a6e |
toLower(item.substr(0, prefixLength)) == prefix) {
|
|
Shinya Kitaoka |
120a6e |
QStandardItem *item = new QStandardItem();
|
|
Shinya Kitaoka |
120a6e |
item->setData(QString::fromStdString(m_suggestions[i].first),
|
|
Shinya Kitaoka |
120a6e |
Qt::EditRole);
|
|
Shinya Kitaoka |
120a6e |
if (m_suggestions[i].second != "")
|
|
Shinya Kitaoka |
120a6e |
item->setData(QString::fromStdString(m_suggestions[i].second),
|
|
Shinya Kitaoka |
120a6e |
Qt::ToolTipRole);
|
|
Shinya Kitaoka |
120a6e |
model->appendRow(item);
|
|
Shinya Kitaoka |
120a6e |
count++;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (count == 0) {
|
|
Shinya Kitaoka |
120a6e |
if (m_completerPopup->isVisible()) m_completerPopup->hide();
|
|
Shinya Kitaoka |
120a6e |
return false;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->setModel(model);
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->setCurrentIndex(model->index(0, 0));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
QTextCursor cursor(textCursor());
|
|
Shinya Kitaoka |
120a6e |
cursor.setPosition(m_completerStartPos);
|
|
Shinya Kitaoka |
120a6e |
QRect cr = cursorRect(cursor);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int w = m_completerPopup->sizeHintForColumn(0) +
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->verticalScrollBar()->sizeHint().width() + 5;
|
|
Shinya Kitaoka |
120a6e |
int h =
|
|
Shinya Kitaoka |
120a6e |
(m_completerPopup->sizeHintForRow(0) * qMin(7, model->rowCount()) + 3) +
|
|
Shinya Kitaoka |
120a6e |
3;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
QSize size(w, h);
|
|
Shinya Kitaoka |
120a6e |
QPoint popupPos = mapToGlobal(QPoint(cr.left(), cr.bottom() + 3));
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->setGeometry(QRect(popupPos, size));
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int ExpressionField::computeSuggestions() {
|
|
Shinya Kitaoka |
120a6e |
m_completerStartPos = -1;
|
|
Shinya Kitaoka |
120a6e |
m_suggestions.clear();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
std::string text = getExpression();
|
|
Shinya Kitaoka |
120a6e |
int pos = textCursor().position();
|
|
Shinya Kitaoka |
120a6e |
int start = pos;
|
|
Shinya Kitaoka |
120a6e |
if (start > 0) {
|
|
Shinya Kitaoka |
120a6e |
start--;
|
|
Shinya Kitaoka |
120a6e |
while (start > 0) {
|
|
Shinya Kitaoka |
120a6e |
char c = text[start - 1];
|
|
Shinya Kitaoka |
120a6e |
if (isascii(c) && isalpha(c) || c == '_' ||
|
|
Shinya Kitaoka |
120a6e |
c == '.' && (start - 2 < 0 ||
|
|
Shinya Kitaoka |
120a6e |
isascii(text[start - 2]) && isalpha(text[start - 2]))) {
|
|
Shinya Kitaoka |
120a6e |
} else
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
start--;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (start >= (int)text.length()) return 0;
|
|
Shinya Kitaoka |
120a6e |
m_completerStartPos = start;
|
|
Shinya Kitaoka |
120a6e |
text = text.substr(0, start);
|
|
Shinya Kitaoka |
120a6e |
TSyntax::Parser parser(m_grammar);
|
|
Shinya Kitaoka |
120a6e |
parser.getSuggestions(m_suggestions, text);
|
|
Shinya Kitaoka |
120a6e |
return (int)m_suggestions.size();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void ExpressionField::insertCompletion() {
|
|
Shinya Kitaoka |
120a6e |
if (!m_completerPopup->isVisible()) return;
|
|
Shinya Kitaoka |
120a6e |
QModelIndex index = m_completerPopup->currentIndex();
|
|
Shinya Kitaoka |
120a6e |
if (!index.isValid()) return;
|
|
Shinya Kitaoka |
120a6e |
QString item =
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->model()->data(index, Qt::EditRole).toString();
|
|
Shinya Kitaoka |
120a6e |
QTextCursor tc = textCursor();
|
|
Shinya Kitaoka |
120a6e |
int pos = tc.position();
|
|
Shinya Kitaoka |
120a6e |
// tc.movePosition(m_completionStartPos, QTextCursor::KeepAnchor);
|
|
Shinya Kitaoka |
120a6e |
tc.insertText(item);
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->hide();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void ExpressionField::insertCompletion(const QModelIndex &index) {
|
|
Shinya Kitaoka |
120a6e |
if (index.isValid()) {
|
|
Shinya Kitaoka |
120a6e |
QString item =
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->model()->data(index, Qt::EditRole).toString();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
QTextCursor tc = textCursor();
|
|
Shinya Kitaoka |
120a6e |
int pos = tc.position();
|
|
Shinya Kitaoka |
120a6e |
if (pos - m_completerStartPos >= 1)
|
|
Shinya Kitaoka |
120a6e |
tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor,
|
|
Shinya Kitaoka |
120a6e |
pos - m_completerStartPos);
|
|
Shinya Kitaoka |
120a6e |
tc.insertText(item);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
m_completerPopup->hide();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void ExpressionField::setGrammar(const Grammar *grammar) {
|
|
Shinya Kitaoka |
120a6e |
m_grammar = grammar;
|
|
Shinya Kitaoka |
120a6e |
m_syntaxHighlighter->setGrammar(grammar);
|
|
Toshihiro Shimizu |
890ddd |
};
|