Fixed spell checker with the new incremental transmit editor
This commit is contained in:
parent
bb91fac20d
commit
8d4db7d376
@ -2,39 +2,154 @@
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
void setTextEditFont(QTextEdit *edit, QFont font){
|
||||
// all uppercase
|
||||
font.setCapitalization(QFont::AllUppercase);
|
||||
|
||||
edit->setFont(font);
|
||||
edit->setFontFamily(font.family());
|
||||
edit->setFontItalic(font.italic());
|
||||
edit->setFontPointSize(font.pointSize());
|
||||
edit->setFontUnderline(font.underline());
|
||||
edit->setFontWeight(font.weight());
|
||||
|
||||
auto d = edit->document();
|
||||
d->setDefaultFont(font);
|
||||
edit->setDocument(d);
|
||||
|
||||
auto c = edit->textCursor();
|
||||
c.select(QTextCursor::Document);
|
||||
auto cf = c.blockCharFormat();
|
||||
cf.setFont(font);
|
||||
cf.setFontCapitalization(QFont::AllUppercase);
|
||||
c.mergeBlockCharFormat(cf);
|
||||
|
||||
edit->updateGeometry();
|
||||
}
|
||||
|
||||
void setTextEditStyle(QTextEdit *edit, QColor fg, QColor bg, QFont font){
|
||||
edit->setStyleSheet(QString("QTextEdit { color:%1; background: %2; %3; }").arg(fg.name()).arg(bg.name()).arg(font_as_stylesheet(font)));
|
||||
|
||||
//QTimer::singleShot(10, nullptr, [edit, fg, bg](){
|
||||
QPalette p = edit->palette();
|
||||
p.setColor(QPalette::Base, bg);
|
||||
p.setColor(QPalette::Active, QPalette::Base, bg);
|
||||
p.setColor(QPalette::Disabled, QPalette::Base, bg);
|
||||
p.setColor(QPalette::Inactive, QPalette::Base, bg);
|
||||
|
||||
p.setColor(QPalette::Text, fg);
|
||||
p.setColor(QPalette::Active, QPalette::Text, fg);
|
||||
p.setColor(QPalette::Disabled, QPalette::Text, fg);
|
||||
p.setColor(QPalette::Inactive, QPalette::Text, fg);
|
||||
|
||||
edit->setBackgroundRole(QPalette::Base);
|
||||
edit->setForegroundRole(QPalette::Text);
|
||||
edit->setPalette(p);
|
||||
|
||||
edit->updateGeometry();
|
||||
edit->update();
|
||||
//});
|
||||
}
|
||||
|
||||
void highlightBlock(QTextBlock block, QFont font, QColor foreground, QColor background){
|
||||
QTextCursor cursor(block);
|
||||
|
||||
// Set background color
|
||||
QTextBlockFormat blockFormat = cursor.blockFormat();
|
||||
blockFormat.setBackground(background);
|
||||
cursor.setBlockFormat(blockFormat);
|
||||
|
||||
// Set font
|
||||
/*
|
||||
for (QTextBlock::iterator it = cursor.block().begin(); !(it.atEnd()); ++it) {
|
||||
QTextCharFormat charFormat = it.fragment().charFormat();
|
||||
charFormat.setFont(font);
|
||||
charFormat.setFontCapitalization(QFont::AllUppercase);
|
||||
charFormat.setForeground(QBrush(foreground));
|
||||
|
||||
QTextCursor tempCursor = cursor;
|
||||
tempCursor.setPosition(it.fragment().position());
|
||||
tempCursor.setPosition(it.fragment().position() + it.fragment().length(), QTextCursor::KeepAnchor);
|
||||
tempCursor.setCharFormat(charFormat);
|
||||
}
|
||||
*/
|
||||
cursor.select(QTextCursor::BlockUnderCursor);
|
||||
|
||||
auto charFormat = cursor.charFormat();
|
||||
charFormat.setFont(font);
|
||||
charFormat.setFontCapitalization(QFont::AllUppercase);
|
||||
charFormat.setForeground(QBrush(foreground));
|
||||
cursor.setCharFormat(charFormat);
|
||||
}
|
||||
|
||||
|
||||
TransmitTextEdit::TransmitTextEdit(QWidget *parent):
|
||||
QTextEdit(parent)
|
||||
QTextEdit(parent),
|
||||
m_sent { 0 },
|
||||
m_textSent { "" },
|
||||
m_protected { false }
|
||||
{
|
||||
connect(this, &QTextEdit::selectionChanged, this, &TransmitTextEdit::on_selectionChanged);
|
||||
connect(this, &QTextEdit::cursorPositionChanged, this, &TransmitTextEdit::on_selectionChanged);
|
||||
connect(this->document(), &QTextDocument::contentsChange, this, &TransmitTextEdit::on_textContentsChanged);
|
||||
}
|
||||
|
||||
void TransmitTextEdit::markCharsSent(int n){
|
||||
void TransmitTextEdit::setCharsSent(int n){
|
||||
// update sent display
|
||||
auto c = textCursor();
|
||||
c.movePosition(QTextCursor::Start);
|
||||
c.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, n);
|
||||
|
||||
auto ch = c.charFormat();
|
||||
ch.setFontStrikeOut(true);
|
||||
c.mergeCharFormat(ch);
|
||||
|
||||
// keep track
|
||||
// keep track of sent text
|
||||
m_textSent = c.selectedText().toUpper();
|
||||
m_sent = n;
|
||||
|
||||
// highlight the sent text
|
||||
//highlightCharsSent();
|
||||
highlight();
|
||||
}
|
||||
|
||||
// override
|
||||
QString TransmitTextEdit::toPlainText() const {
|
||||
return QTextEdit::toPlainText().toUpper();
|
||||
}
|
||||
|
||||
// override
|
||||
void TransmitTextEdit::setPlainText(const QString &text){
|
||||
QTextEdit::setPlainText(text);
|
||||
m_textSent.clear();
|
||||
m_sent = 0;
|
||||
}
|
||||
|
||||
//
|
||||
void TransmitTextEdit::setFont(QFont f){
|
||||
m_font = f;
|
||||
|
||||
// then rehighlight
|
||||
highlight();
|
||||
}
|
||||
|
||||
//
|
||||
void TransmitTextEdit::setFont(QFont f, QColor fg, QColor bg){
|
||||
m_font = f;
|
||||
m_fg = fg;
|
||||
m_bg = bg;
|
||||
|
||||
// then rehighlight
|
||||
highlight();
|
||||
}
|
||||
|
||||
// override
|
||||
void TransmitTextEdit::clear(){
|
||||
QTextEdit::clear();
|
||||
m_textSent.clear();
|
||||
m_sent = 0;
|
||||
}
|
||||
|
||||
void TransmitTextEdit::setProtected(bool protect){
|
||||
m_protected = protect;
|
||||
}
|
||||
|
||||
// slot
|
||||
void TransmitTextEdit::on_selectionChanged(){
|
||||
auto c = textCursor();
|
||||
@ -45,9 +160,69 @@ void TransmitTextEdit::on_selectionChanged(){
|
||||
end = start;
|
||||
start = x;
|
||||
}
|
||||
qDebug() << "selection" << start << end;
|
||||
|
||||
if(start <= m_sent){
|
||||
qDebug() << "selection" << start << end << m_sent;
|
||||
|
||||
if(m_sent && start <= m_sent){
|
||||
qDebug() << "selection in protected zone" << start << "<=" << m_sent;
|
||||
setProtected(true);
|
||||
} else {
|
||||
setProtected(false);
|
||||
}
|
||||
}
|
||||
|
||||
// slot
|
||||
void TransmitTextEdit::on_textContentsChanged(int pos, int rem, int add){
|
||||
if(rem == 0 && add == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
auto text = toPlainText();
|
||||
if(text != m_lastText){
|
||||
qDebug() << "text changed" << pos << rem << add << "from" << m_lastText << "to" << text;
|
||||
highlight();
|
||||
m_lastText = text;
|
||||
}
|
||||
}
|
||||
|
||||
void TransmitTextEdit::highlightBase(){
|
||||
auto d = document();
|
||||
if(!d){
|
||||
return;
|
||||
}
|
||||
|
||||
auto block = d->firstBlock();
|
||||
while(block.isValid()){
|
||||
highlightBlock(block, m_font, m_fg, m_bg);
|
||||
block = block.next();
|
||||
}
|
||||
}
|
||||
|
||||
void TransmitTextEdit::highlightCharsSent(){
|
||||
if(!m_sent){
|
||||
return;
|
||||
}
|
||||
|
||||
auto d = document();
|
||||
if(!d){
|
||||
return;
|
||||
}
|
||||
|
||||
// highlight sent text
|
||||
auto c = textCursor();
|
||||
if(c.isNull()){
|
||||
return;
|
||||
}
|
||||
c.movePosition(QTextCursor::Start);
|
||||
c.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, m_sent);
|
||||
|
||||
auto ch = c.charFormat();
|
||||
ch.setFontStrikeOut(true);
|
||||
c.mergeCharFormat(ch);
|
||||
}
|
||||
|
||||
void TransmitTextEdit::highlight(){
|
||||
highlightBase();
|
||||
highlightCharsSent();
|
||||
}
|
||||
|
||||
|
@ -1,22 +1,55 @@
|
||||
#ifndef TRANSMITTEXTEDIT_H
|
||||
#define TRANSMITTEXTEDIT_H
|
||||
|
||||
#include "qt_helpers.hpp"
|
||||
|
||||
#include <QTextEdit>
|
||||
#include <QTextBlock>
|
||||
#include <QTextCursor>
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QFont>
|
||||
|
||||
void setTextEditFont(QTextEdit *edit, QFont font);
|
||||
void setTextEditStyle(QTextEdit *edit, QColor fg, QColor bg, QFont font);
|
||||
void highlightBlock(QTextBlock block, QFont font, QColor foreground, QColor background);
|
||||
|
||||
class TransmitTextEdit : public QTextEdit
|
||||
{
|
||||
public:
|
||||
TransmitTextEdit(QWidget *parent);
|
||||
|
||||
void markCharsSent(int n);
|
||||
int charsSent() const {
|
||||
return m_sent;
|
||||
}
|
||||
void setCharsSent(int n);
|
||||
|
||||
QString toPlainText() const;
|
||||
void setPlainText(const QString &text);
|
||||
void setFont(QFont f);
|
||||
void setFont(QFont f, QColor fg, QColor bg);
|
||||
void clear();
|
||||
|
||||
bool isProtected() const {
|
||||
return m_protected;
|
||||
}
|
||||
void setProtected(bool protect);
|
||||
void highlightBase();
|
||||
void highlightCharsSent();
|
||||
void highlight();
|
||||
|
||||
public slots:
|
||||
void on_selectionChanged();
|
||||
void on_textContentsChanged(int pos, int rem, int add);
|
||||
|
||||
private:
|
||||
QString m_lastText;
|
||||
QString m_textSent;
|
||||
int m_sent;
|
||||
bool m_protected;
|
||||
QFont m_font;
|
||||
QColor m_fg;
|
||||
QColor m_bg;
|
||||
};
|
||||
|
||||
#endif // TRANSMITTEXTEDIT_H
|
||||
|
@ -58,7 +58,7 @@ bool cursorHasProperty(const QTextCursor &cursor, int property){
|
||||
QString nextChar(QTextCursor c){
|
||||
QTextCursor cur(c);
|
||||
cur.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
|
||||
return cur.selectedText();
|
||||
return cur.selectedText().toUpper();
|
||||
}
|
||||
|
||||
bool isNumeric(QString s){
|
||||
@ -97,7 +97,7 @@ void JSCChecker::checkRange(QTextEdit* edit, int start, int end)
|
||||
bool correct = false;
|
||||
|
||||
cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||
if(cursor.selectedText() == "@"){
|
||||
if(cursor.selectedText()/*.toUpper()*/ == "@"){
|
||||
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
|
||||
cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||
}
|
||||
@ -105,7 +105,7 @@ void JSCChecker::checkRange(QTextEdit* edit, int start, int end)
|
||||
if(cursorHasProperty(cursor, CORRECT)){
|
||||
correct = true;
|
||||
} else {
|
||||
QString word = cursor.selectedText();
|
||||
QString word = cursor.selectedText().toUpper();
|
||||
|
||||
// three or less is always "correct"
|
||||
if(word.length() < 4 || isNumeric(word)){
|
||||
@ -121,6 +121,8 @@ void JSCChecker::checkRange(QTextEdit* edit, int start, int end)
|
||||
correct = Varicode::isValidCallsign(word, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "word" << word << "correct" << correct;
|
||||
}
|
||||
|
||||
if(correct){
|
||||
|
135
mainwindow.cpp
135
mainwindow.cpp
@ -256,88 +256,6 @@ namespace
|
||||
return roundDown + multiple;
|
||||
}
|
||||
|
||||
void setTextEditFont(QTextEdit *edit, QFont font){
|
||||
edit->setFont(font);
|
||||
edit->setFontFamily(font.family());
|
||||
edit->setFontItalic(font.italic());
|
||||
edit->setFontPointSize(font.pointSize());
|
||||
edit->setFontUnderline(font.underline());
|
||||
edit->setFontWeight(font.weight());
|
||||
|
||||
auto d = edit->document();
|
||||
d->setDefaultFont(font);
|
||||
edit->setDocument(d);
|
||||
|
||||
auto c = edit->textCursor();
|
||||
c.select(QTextCursor::Document);
|
||||
auto cf = c.blockCharFormat();
|
||||
cf.setFont(font);
|
||||
c.mergeBlockCharFormat(cf);
|
||||
|
||||
edit->updateGeometry();
|
||||
}
|
||||
|
||||
void setTextEditStyle(QTextEdit *edit, QColor fg, QColor bg, QFont font){
|
||||
edit->setStyleSheet(QString("QTextEdit { color:%1; background: %2; %3; }").arg(fg.name()).arg(bg.name()).arg(font_as_stylesheet(font)));
|
||||
|
||||
QTimer::singleShot(10, nullptr, [edit, fg, bg](){
|
||||
QPalette p = edit->palette();
|
||||
p.setColor(QPalette::Base, bg);
|
||||
p.setColor(QPalette::Active, QPalette::Base, bg);
|
||||
p.setColor(QPalette::Disabled, QPalette::Base, bg);
|
||||
p.setColor(QPalette::Inactive, QPalette::Base, bg);
|
||||
|
||||
p.setColor(QPalette::Text, fg);
|
||||
p.setColor(QPalette::Active, QPalette::Text, fg);
|
||||
p.setColor(QPalette::Disabled, QPalette::Text, fg);
|
||||
p.setColor(QPalette::Inactive, QPalette::Text, fg);
|
||||
|
||||
edit->setBackgroundRole(QPalette::Base);
|
||||
edit->setForegroundRole(QPalette::Text);
|
||||
edit->setPalette(p);
|
||||
|
||||
edit->updateGeometry();
|
||||
edit->update();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
void setTextEditForeground(QTextEdit *edit, QColor color){
|
||||
QTimer::singleShot(20, nullptr, [edit, color](){
|
||||
QPalette p = edit->palette();
|
||||
p.setColor(QPalette::Text, color);
|
||||
p.setColor(QPalette::Active, QPalette::Text, color);
|
||||
p.setColor(QPalette::Disabled, QPalette::Text, color);
|
||||
p.setColor(QPalette::Inactive, QPalette::Text, color);
|
||||
|
||||
edit->setPalette(p);
|
||||
edit->updateGeometry();
|
||||
edit->update();
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
void highlightBlock(QTextBlock block, QFont font, QColor foreground, QColor background){
|
||||
QTextCursor cursor(block);
|
||||
|
||||
// Set background color
|
||||
QTextBlockFormat blockFormat = cursor.blockFormat();
|
||||
blockFormat.setBackground(background);
|
||||
cursor.setBlockFormat(blockFormat);
|
||||
|
||||
// Set font
|
||||
for (QTextBlock::iterator it = cursor.block().begin(); !(it.atEnd()); ++it) {
|
||||
QTextCharFormat charFormat = it.fragment().charFormat();
|
||||
charFormat.setFont(font);
|
||||
charFormat.setForeground(QBrush(foreground));
|
||||
|
||||
QTextCursor tempCursor = cursor;
|
||||
tempCursor.setPosition(it.fragment().position());
|
||||
tempCursor.setPosition(it.fragment().position() + it.fragment().length(), QTextCursor::KeepAnchor);
|
||||
tempCursor.setCharFormat(charFormat);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
QList<T> listCopyReverse(QList<T> const &list){
|
||||
QList<T> newList = QList<T>();
|
||||
@ -710,6 +628,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
||||
connect (&m_config, &Configuration::colors_changed, [this](){
|
||||
setTextEditStyle(ui->textEditRX, m_config.color_rx_foreground(), m_config.color_rx_background(), m_config.rx_text_font());
|
||||
setTextEditStyle(ui->extFreeTextMsgEdit, m_config.color_compose_foreground(), m_config.color_compose_background(), m_config.compose_text_font());
|
||||
ui->extFreeTextMsgEdit->setFont(m_config.compose_text_font(), m_config.color_compose_foreground(), m_config.color_compose_background());
|
||||
|
||||
// rehighlight
|
||||
auto d = ui->textEditRX->document();
|
||||
@ -1919,7 +1838,7 @@ void MainWindow::initializeDummyData(){
|
||||
#endif
|
||||
|
||||
ui->extFreeTextMsgEdit->setPlainText("HELLO BRAVE NEW WORLD");
|
||||
ui->extFreeTextMsgEdit->markCharsSent(6);
|
||||
ui->extFreeTextMsgEdit->setCharsSent(6);
|
||||
|
||||
logHeardGraph("KN4CRD", "OH8STN");
|
||||
logHeardGraph("KN4CRD", "K0OG");
|
||||
@ -2465,6 +2384,8 @@ void MainWindow::readSettings()
|
||||
|
||||
setTextEditStyle(ui->textEditRX, m_config.color_rx_foreground(), m_config.color_rx_background(), m_config.rx_text_font());
|
||||
setTextEditStyle(ui->extFreeTextMsgEdit, m_config.color_compose_foreground(), m_config.color_compose_background(), m_config.compose_text_font());
|
||||
ui->extFreeTextMsgEdit->setFont(m_config.compose_text_font(), m_config.color_compose_foreground(), m_config.color_compose_background());
|
||||
|
||||
|
||||
{
|
||||
auto const& coeffs = m_settings->value ("PhaseEqualizationCoefficients"
|
||||
@ -5408,7 +5329,7 @@ void MainWindow::stopTx()
|
||||
// start message marker
|
||||
// - keep track of the total message sent so far, and mark it having been sent
|
||||
m_totalTxMessage.append(dt.message());
|
||||
ui->extFreeTextMsgEdit->markCharsSent(m_totalTxMessage.length());
|
||||
ui->extFreeTextMsgEdit->setCharsSent(m_totalTxMessage.length());
|
||||
qDebug() << "total sent:\n" << m_totalTxMessage;
|
||||
// end message marker
|
||||
|
||||
@ -5427,6 +5348,7 @@ void MainWindow::stopTx()
|
||||
#endif
|
||||
if(!shouldContinue){
|
||||
// TODO: jsherer - split this up...
|
||||
ui->extFreeTextMsgEdit->clear();
|
||||
ui->extFreeTextMsgEdit->setReadOnly(false);
|
||||
update_dynamic_property(ui->extFreeTextMsgEdit, "transmitting", false);
|
||||
on_stopTxButton_clicked();
|
||||
@ -6319,6 +6241,7 @@ void MainWindow::on_nextFreeTextMsg_currentTextChanged (QString const& text)
|
||||
|
||||
void MainWindow::on_extFreeTextMsgEdit_currentTextChanged (QString const& text)
|
||||
{
|
||||
#if 0
|
||||
QString x;
|
||||
QString::const_iterator i;
|
||||
for(i = text.constBegin(); i != text.constEnd(); i++){
|
||||
@ -6332,13 +6255,11 @@ void MainWindow::on_extFreeTextMsgEdit_currentTextChanged (QString const& text)
|
||||
int pos = ui->extFreeTextMsgEdit->textCursor().position();
|
||||
int maxpos = x.size();
|
||||
|
||||
// don't emit current text changed or text contents changed
|
||||
ui->extFreeTextMsgEdit->blockSignals(true);
|
||||
{
|
||||
ui->extFreeTextMsgEdit->setPlainText(x);
|
||||
}
|
||||
ui->extFreeTextMsgEdit->blockSignals(false);
|
||||
int sent = ui->extFreeTextMsgEdit->charsSent();
|
||||
ui->extFreeTextMsgEdit->setPlainText(x);
|
||||
ui->extFreeTextMsgEdit->setCharsSent(sent);
|
||||
|
||||
// set cursor position
|
||||
QTextCursor c = ui->extFreeTextMsgEdit->textCursor();
|
||||
c.setPosition(pos < maxpos ? pos : maxpos, QTextCursor::MoveAnchor);
|
||||
|
||||
@ -6347,9 +6268,35 @@ void MainWindow::on_extFreeTextMsgEdit_currentTextChanged (QString const& text)
|
||||
|
||||
ui->extFreeTextMsgEdit->setTextCursor(c);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_txTextDirty = x != m_txTextDirtyLastText;
|
||||
m_txTextDirtyLastText = x;
|
||||
#if 0
|
||||
auto x = text;
|
||||
|
||||
// only highlight if dirty
|
||||
if(x != m_txTextDirtyLastText){
|
||||
// highlight the edited block with our fonts
|
||||
QTextCursor c = ui->extFreeTextMsgEdit->textCursor();
|
||||
ui->extFreeTextMsgEdit->blockSignals(true);
|
||||
{
|
||||
int pos = ui->extFreeTextMsgEdit->textCursor().position();
|
||||
int maxpos = x.size();
|
||||
|
||||
// set cursor position
|
||||
QTextCursor c = ui->extFreeTextMsgEdit->textCursor();
|
||||
c.setPosition(pos < maxpos ? pos : maxpos, QTextCursor::MoveAnchor);
|
||||
|
||||
// highlight the block with our fonts
|
||||
highlightBlock(c.block(), m_config.compose_text_font(), m_config.color_compose_foreground(), QColor(Qt::transparent));
|
||||
|
||||
ui->extFreeTextMsgEdit->setTextCursor(c);
|
||||
}
|
||||
ui->extFreeTextMsgEdit->blockSignals(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_txTextDirty = text != m_txTextDirtyLastText;
|
||||
m_txTextDirtyLastText = text;
|
||||
|
||||
// immediately update the display
|
||||
updateButtonDisplay();
|
||||
@ -8390,7 +8337,7 @@ void MainWindow::buildSuggestionsMenu(QMenu *menu, QTextEdit *edit, const QPoint
|
||||
c.movePosition(QTextCursor::StartOfWord);
|
||||
c.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||
|
||||
auto word = c.selectedText().trimmed();
|
||||
auto word = c.selectedText().toUpper().trimmed();
|
||||
if(word.isEmpty()){
|
||||
return;
|
||||
}
|
||||
@ -10468,7 +10415,7 @@ void MainWindow::processCommandActivity() {
|
||||
c = ui->textEditRX->textCursor();
|
||||
c.movePosition(QTextCursor::StartOfBlock);
|
||||
c.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
|
||||
qDebug() << "should display directed message, erasing last rx activity line..." << c.selectedText();
|
||||
qDebug() << "should display directed message, erasing last rx activity line..." << c.selectedText().toUpper();
|
||||
c.removeSelectedText();
|
||||
c.deletePreviousChar();
|
||||
c.deletePreviousChar();
|
||||
|
Loading…
Reference in New Issue
Block a user