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
};