Page MenuHomePhabricator (Chris)

No OneTemporary

Size
25 KB
Referenced Files
None
Subscribers
None
diff --git a/src/texteditor/TextEditorWidget.cpp b/src/texteditor/TextEditorWidget.cpp
index 11398fb..e2f406a 100644
--- a/src/texteditor/TextEditorWidget.cpp
+++ b/src/texteditor/TextEditorWidget.cpp
@@ -1,885 +1,913 @@
#include "TextEditorWidget.h"
#include "TextEditorWidget.h"
#include <QDebug>
#include <QFile>
#include <QFontDatabase>
#include <QKeyEvent>
#include <QPainter>
#include <QScrollBar>
#include <QApplication>
#include <functional>
#include <QMenu>
#include <QTextCodec>
#include <QTimer>
#include "common/misc.h"
#include "InputMethodPopup.h"
#include "unicode.h"
+#define PROPORTIONAL_FONT_SUPPORT 0
+
class CharacterSize {
private:
QFont font_;
mutable int ascii_[128];
mutable int height_ = 0;
mutable std::map<unsigned int, int> map_;
public:
void reset(QFont const &font)
{
font_ = font;
height_ = 0;
map_.clear();
for (int i = 0; i < 128; i++) {
ascii_[i] = 0;
}
}
int width(unsigned int c) const
{
if (height_ == 0) {
QPixmap pm(1, 1);
QPainter pr(&pm);
pr.setFont(font_);
QFontMetrics fm = pr.fontMetrics();
height_ = fm.ascent() + fm.descent();
for (int i = 0; i < 0x20; i++) {
ascii_[i] = 0;
}
for (int i = 0x20; i < 0x80; i++) {
char tmp[2];
tmp[0] = i;
tmp[1] = 0;
ascii_[i] = fm.size(0, tmp).width();
}
}
if (c < 0x80) {
return ascii_[c];
}
auto it = map_.find(c);
if (it != map_.end()) {
return it->second;
} else {
QPixmap pm(1, 1);
QPainter pr(&pm);
pr.setFont(font_);
QFontMetrics fm = pr.fontMetrics();
QString s = QChar(c);
int w = fm.size(0, s).width();
map_[c] = w;
return w;
}
}
int height() const
{
if (height_ == 0) {
width(' ');
}
return height_;
}
};
struct TextEditorWidget::Private {
PreEditText preedit;
QFont text_font;
InputMethodPopup *ime_popup = nullptr;
int top_margin = 0;
int bottom_margin = 0;
CharacterSize character_size;
int ascent = 0;
int descent = 0;
QString status_line;
QScrollBar *scroll_bar_v = nullptr;
QScrollBar *scroll_bar_h = nullptr;
TextEditorThemePtr theme;
int wheel_delta = 0;
bool is_focus_frame_visible = false;
unsigned int idle_count = 0;
std::function<void(void)> custom_context_menu_requested;
};
TextEditorWidget::TextEditorWidget(QWidget *parent)
: QWidget(parent)
, m(new Private)
{
#ifdef Q_OS_WIN
+
+
+#if PROPORTIONAL_FONT_SUPPORT
+ setTextFont(QFont("MS PGothic", 30));
+#else
setTextFont(QFont("MS Gothic", 10));
-// setTextFont(QFont("MS PGothic", 20));
+#endif
+
+
#endif
#ifdef Q_OS_LINUX
setTextFont(QFont("Monospace", 9));
#endif
#ifdef Q_OS_MACX
setTextFont(QFontDatabase().font("Osaka", "Regular-Mono", 14));
#endif
#ifdef Q_OS_HAIKU
setTextFont(QFont("Noto Mono", 9));
#endif
m->top_margin = 0;
m->bottom_margin = 1;
QPixmap pm(1, 1);
QPainter pr(&pm);
pr.setFont(textFont());
QFontMetrics fm = pr.fontMetrics();
m->ascent = fm.ascent();
m->descent = fm.descent();
initEditor();
setFont(textFont());
setAttribute(Qt::WA_InputMethodEnabled);
#ifdef Q_OS_WIN
// m->ime_popup = new InputMethodPopup();
// m->ime_popup->setFont(font());
// m->ime_popup->setPreEditText(PreEditText());
#endif
setContextMenuPolicy(Qt::DefaultContextMenu);
setRenderingMode(DecoratedMode);
updateCursorRect(true);
+ setScrollUnit(ScrollByCharacter);
+
startTimer(100);
}
TextEditorWidget::~TextEditorWidget()
{
delete m;
}
void TextEditorWidget::setTheme(TextEditorThemePtr const &theme)
{
m->theme = theme;
}
TextEditorTheme const *TextEditorWidget::theme() const
{
if (!m->theme) {
const_cast<TextEditorWidget *>(this)->setTheme(TextEditorTheme::Light());
}
return m->theme.get();
}
void TextEditorWidget::setTextFont(QFont const &font)
{
m->text_font = font;
m->character_size.reset(m->text_font);
}
void TextEditorWidget::setRenderingMode(RenderingMode mode)
{
rendering_mode = mode;
if (rendering_mode == DecoratedMode) {
showLineNumber(false);
} else {
showLineNumber(true);
}
update();
}
void AbstractCharacterBasedApplication::loadExampleFile()
{
#ifdef Q_OS_WIN
QString path = "C:/develop/ore/example.txt";
#elif defined(Q_OS_MAC)
QString path = "/Users/soramimi/develop/ore/example.txt";
#else
QString path = "/home/soramimi/develop/ore/example.txt";
#endif
openFile(path);
}
bool TextEditorWidget::event(QEvent *event)
{
if (event->type() == QEvent::Polish) {
clearParsedLine();
updateVisibility(true, true, true);
}
return QWidget::event(event);
}
int TextEditorWidget::charWidth2(unsigned int c) const
{
return m->character_size.width(c);
}
int TextEditorWidget::lineHeight() const
{
return m->character_size.height() + m->top_margin + m->bottom_margin;
}
int TextEditorWidget::defaultCharWidth() const
{
return m->character_size.width('8');
// return charWidth2('W');
}
class chars : public abstract_unicode_reader {
private:
TextEditorWidget::Char const *ptr;
size_t len;
size_t pos = 0;
public:
chars(TextEditorWidget::Char const *ptr, size_t len)
: ptr(ptr)
, len(len)
{
}
virtual uint32_t next() override
{
if (pos < len) {
return ptr[pos++].unicode;
}
return 0;
}
};
int TextEditorWidget::parseLine3(int row, int col, std::vector<Char> *vec) const
{
parseLine2(row, vec);
QPixmap pm(1, 1);
QPainter pr(&pm);
pr.setFont(m->text_font);
int pos = 0;
QString s;
for (size_t i = 0; i < vec->size(); i++) {
vec->at(i).pos = pos;
ushort tmp[3];
uint32_t u = vec->at(i).unicode;
if (u >= 0x10000 && u < 0x110000) {
// サロゲートペア
uint16_t h = (u - 0x10000) / 0x400 + 0xd800;
uint16_t l = (u - 0x10000) % 0x400 + 0xDC00;
tmp[0] = h;
tmp[1] = l;
tmp[2] = 0;
} else {
tmp[0] = u;
tmp[1] = 0;
}
s += QString::fromUtf16(tmp);
pos = pr.fontMetrics().size(0, s).width();
}
if (vec->empty()) {
pos = 0;
} else if (col >= 0 && col < (int)vec->size()) {
pos = vec->at(col).pos;
} else {
pos = pos;
}
return pos;
}
QPoint TextEditorWidget::mapFromPixel(QPoint const &pt)
{
- const int col = cx()->current_col;
+// const int col = cx()->current_col;
const int y = pt.y() / lineHeight();
const int row = y + cx()->scroll_row_pos - cx()->viewport_org_y;
const int w = defaultCharWidth();
const int x = pt.x() + (cx()->scroll_col_pos - cx()->viewport_org_x) * w;
std::vector<Char> vec;
- parseLine3(row, col, &vec);
- for (int col = 0; col + 1 < (int)vec.size(); col++) {
- if (x < (int)vec[col + 1].pos) {
- return QPoint(col, row);
+ int end = parseLine3(row, -1, &vec);
+ int left = 0;
+ for (int col = 0; col < (int)vec.size(); col++) {
+ int right = (col + 1 < (int)vec.size()) ? vec[col + 1].pos : end;
+ if (x < right) {
+ int l = left - x;
+ int r = right - x;
+ if (l * l < r * r) {
+ return QPoint(col, row);
+ } else {
+ return QPoint(col + 1, row);
+ }
}
+ left = right;
}
- return QPoint(vec.size(), row);
+ return QPoint(end, row);
}
QPoint TextEditorWidget::mapToPixel(QPoint const &pt)
{
int x = pt.x() * defaultCharWidth();
int y = pt.y() * lineHeight();
return QPoint(x, y);
}
void TextEditorWidget::bindScrollBar(QScrollBar *vsb, QScrollBar *hsb)
{
m->scroll_bar_v = vsb;
m->scroll_bar_h = hsb;
}
void TextEditorWidget::setupForLogWidget(QScrollBar *vsb, QScrollBar *hsb, TextEditorThemePtr const &theme)
{
bindScrollBar(vsb, hsb);
setTheme(theme);
setAutoLayout(true);
setTerminalMode(true);
layoutEditor();
}
QRect TextEditorWidget::updateCursorRect(bool auto_scroll)
{
updateCursorPos(auto_scroll);
int x = cx()->viewport_org_x + cursorX();
int y = cx()->viewport_org_y + cursorY();
x *= defaultCharWidth();
y *= lineHeight();
QPoint pt = QPoint(x, y);
int w = cx()->current_char_span * defaultCharWidth();
int h = lineHeight();
cx()->cursor_rect = QRect(pt.x(), pt.y(), w, h);
QApplication::inputMethod()->update(Qt::ImCursorRectangle);
return cx()->cursor_rect;
}
void TextEditorWidget::internalUpdateScrollBar()
{
QScrollBar *sb;
sb = m->scroll_bar_v;
if (sb) {
sb->blockSignals(true);
sb->setRange(0, document()->lines.size() - cx()->viewport_height / 2);
sb->setPageStep(editorViewportHeight());
sb->setValue(cx()->scroll_row_pos);
sb->blockSignals(false);
}
sb = m->scroll_bar_h;
if (sb) {
int w = editorViewportWidth();
sb->blockSignals(true);
sb->setRange(0, (w + 100) * reference_char_width_);
sb->setPageStep(w * reference_char_width_);
sb->setValue(cx()->scroll_col_pos);
sb->blockSignals(false);
}
emit updateScrollBar();
}
void TextEditorWidget::internalUpdateVisibility(bool ensure_current_line_visible, bool change_col, bool auto_scroll)
{
if (ensure_current_line_visible) {
ensureCurrentLineVisible();
}
updateCursorRect(auto_scroll);
if (change_col) {
cx()->current_col_hint = cx()->current_col;
}
if (isPaintingSuppressed()) {
return;
}
internalUpdateScrollBar();
update();
}
void TextEditorWidget::updateVisibility(bool ensure_current_line_visible, bool change_col, bool auto_scroll)
{
internalUpdateVisibility(ensure_current_line_visible, change_col, auto_scroll);
emit moved(cx()->current_row, cx()->current_col, cx()->scroll_row_pos, cx()->scroll_col_pos);
}
void TextEditorWidget::move(int cur_row, int cur_col, int scr_row, int scr_col, bool auto_scroll)
{
if ((cur_row >= 0 && cx()->current_row != cur_row) || (cur_col >= 0 && cx()->current_col != cur_col) || cx()->scroll_row_pos != scr_row || cx()->scroll_col_pos != scr_col) {
if (cur_row >= 0) cx()->current_row = cur_row;
if (cur_col >= 0) cx()->current_col = cur_col;
if (scr_row >= 0) cx()->scroll_row_pos = scr_row;
if (scr_col >= 0) cx()->scroll_col_pos = scr_col;
internalUpdateVisibility(false, true, auto_scroll);
}
}
//void TextEditorWidget::setPreEditText(const PreEditText &preedit)
//{
// m->preedit = preedit;
// update();
//}
QFont TextEditorWidget::textFont() const
{
return m->text_font;
}
void TextEditorWidget::drawText(QPainter *painter, int px, int py, QString const &str)
{
painter->drawText(px, py + lineHeight() - m->bottom_margin - m->descent, str);
}
QColor TextEditorWidget::defaultForegroundColor()
{
if (renderingMode() == DecoratedMode) {
return theme()->fgDefault();
}
return Qt::white;
}
QColor TextEditorWidget::defaultBackgroundColor()
{
if (renderingMode() == DecoratedMode) {
return theme()->bgDefault();
}
return Qt::black;
}
QColor TextEditorWidget::colorForIndex(CharAttr const &attr, bool foreground)
{
if (foreground && attr.color.isValid()) {
return attr.color;
}
switch (attr.index) {
case CharAttr::Invert:
return foreground ? defaultBackgroundColor() : defaultForegroundColor();
}
return foreground ? defaultForegroundColor() : Qt::transparent;//defaultBackgroundColor();
}
void TextEditorWidget::paintScreen(QPainter *painter)
{
int w = screenWidth();
int h = screenHeight();
for (int y = 0; y < h; y++) {
int x = 0;
int x2 = 0;
int x3 = 0;
while (x < w) {
std::vector<uint16_t> text;
text.reserve(w);
int o = y * w;
CharAttr charattr;
Character const *line = &char_screen()->at(o);
int n = 0;
while (x + n < w) {
uint32_t c = line[x + n].c;
uint32_t d = 0;
if (c == 0 || c == 0xffff) break;
if ((c & 0xfc00) == 0xdc00) {
// surrogate 2nd
break;
}
uint32_t unicode = c;
if ((c & 0xfc00) == 0xd800) {
// surrogate 1st
if (x + n + 1 < w) {
uint16_t t = line[x + n + 1].c;
if ((t & 0xfc00) == 0xdc00) {
d = t;
unicode = (((c & 0x03c0) + 0x0040) << 10) | ((c & 0x003f) << 10) | (d & 0x03ff);
} else {
break;
}
} else {
break;
}
}
int cw = charWidth(unicode);
if (cw < 1) break;
if (n == 0) {
charattr = line[x].a;
} else if (charattr != line[x + n].a) {
break;
}
if (d == 0) {
text.push_back(c);
} else { // surrogate pair
text.push_back(c);
text.push_back(d);
}
x3 += charWidth2(unicode);
n += cw;
}
if (n == 0) {
n = 1;
x3 += defaultCharWidth();
} else if (!text.empty()) {
QString str = QString::fromUtf16(&text[0], text.size());
int px = x * defaultCharWidth();
int py = y * lineHeight();
px = x2;
painter->setFont(textFont());
QFontMetrics fm = painter->fontMetrics();
int w = fm.width(str);
int h = lineHeight();
QColor fgcolor = colorForIndex(charattr, true);
QColor bgcolor = colorForIndex(charattr, false);
painter->fillRect(px, py, w, h, bgcolor);
painter->setPen(fgcolor);
drawText(painter, px, py, str);
}
x += n;
x2 = x3;
}
}
}
void TextEditorWidget::drawFocusFrame(QPainter *pr)
{
misc::drawFrame(pr, 0, 0, width(), height(), QColor(0, 128, 255, 128));
misc::drawFrame(pr, 1, 1, width() - 2, height() - 2, QColor(0, 128, 255, 64));
}
-#define SCROLL_BY_PIXEL 0
+void TextEditorWidget::setScrollUnit(int n)
+{
+ scroll_unit_ = n;
+}
+
+int TextEditorWidget::scrollUnit() const
+{
+ return scroll_unit_;
+}
+
int TextEditorWidget::xScrollPosInPixel()
{
-#if SCROLL_BY_PIXEL
- return editor_cx->scroll_col_pos;// * defaultCharWidth();
-#else
- return editor_cx->scroll_col_pos * defaultCharWidth();
-#endif
+ int u = scrollUnit();
+ int n = editor_cx->scroll_col_pos;
+ n *= (u == ScrollByCharacter) ? defaultCharWidth() : u;
+ return n;
}
void TextEditorWidget::drawCursor(QPainter *pr)
{
std::vector<Char> vec;
int row = cursorY() + cx()->scroll_row_pos - cx()->viewport_org_y;
const int col = cx()->current_col;
int x = parseLine3(row, col, &vec);
x += cx()->viewport_org_x * defaultCharWidth();
x -= xScrollPosInPixel();
const int lineheight = lineHeight();
const int y = (cx()->viewport_org_y + cursorY()) * lineheight;
pr->fillRect(x -1, y, 2, lineheight, theme()->fgCursor());
pr->fillRect(x - 2, y, 4, 2, theme()->fgCursor());
pr->fillRect(x - 2, y + lineheight - 2, 4, 2, theme()->fgCursor());
}
void TextEditorWidget::paintEvent(QPaintEvent *)
{
bool has_focus = hasFocus();
preparePaintScreen();
QPainter pr(this);
pr.fillRect(0, 0, width(), height(), defaultBackgroundColor());
// diff mode
if (renderingMode() == DecoratedMode) {
auto FillRowBackground = [&](int row, QColor const &color){
int y = editor_cx->viewport_org_y + row - editor_cx->scroll_row_pos;
y *= lineHeight();
pr.fillRect(0, y, width(), lineHeight(), color);
};
Document const &doc = editor_cx->engine->document;
for (int i = 0; i < editor_cx->viewport_height; i++) {
int row = i + editor_cx->scroll_row_pos;
if (row < doc.lines.size()) {
if (doc.lines[row].type == Document::Line::Unknown) {
FillRowBackground(row, theme()->bgDiffUnknown());
} else if (doc.lines[row].type == Document::Line::Add) {
FillRowBackground(row, theme()->bgDiffAdd());
} else if (doc.lines[row].type == Document::Line::Del) {
FillRowBackground(row, theme()->bgDiffDel());
}
}
}
}
auto visualY = [&](TextEditorContext const *context){
return context->viewport_org_y + editor_cx->current_row - editor_cx->scroll_row_pos;
};
// カーソル描画
if (has_focus) {
if (isCursorVisible()) {
// 現在行の下線
if (renderingMode() == DecoratedMode) {
int x = cx()->viewport_org_x * defaultCharWidth();
int y = visualY(cx()) * lineHeight();
pr.fillRect(x, y, width() - x, lineHeight(), theme()->bgCurrentLine());
pr.fillRect(x, y + lineHeight() - 1, width() - x, 1, theme()->fgCursor());
}
// カーソル
drawCursor(&pr);
}
}
int linenum_width = editor_cx->viewport_org_x * defaultCharWidth();
// テキスト描画
if (renderingMode() == DecoratedMode) {
int view_row = 0;
int line_row = editor_cx->scroll_row_pos;
int lh = lineHeight();
pr.save();
pr.setClipRect(linenum_width, 0, width() - linenum_width, height());
while (isValidRowIndex(line_row)) {
int x = linenum_width - xScrollPosInPixel();
int y = view_row * lh;
if (y >= height()) break;
QList<FormattedLine> fline = formatLine2(line_row);
for (FormattedLine const &fl : fline) {
pr.setPen(defaultForegroundColor());
pr.drawText(QRect(x, y, width() - linenum_width, lh), fl.text);
}
view_row++;
line_row++;
}
pr.restore();
} else {
paintScreen(&pr);
}
// 行番号描画
if (renderingMode() == DecoratedMode) {
auto FillLineNumberBG = [&](int y, int h, QColor color){
pr.fillRect(0, y, linenum_width - 2, h, color);
};
int bottom = editor_cx->bottom_line_y;
int view_y = editor_cx->viewport_org_y;
int view_h = editor_cx->viewport_height;
view_y *= lineHeight();
view_h *= lineHeight();
FillLineNumberBG(view_y, view_h, theme()->bgLineNumber());
paintLineNumbers([&](int y, QString text, Document::Line const *line){
if (bottom >= 0 && y > bottom) return;
if (isCursorVisible() && y == visualY(editor_cx.get())) {
FillLineNumberBG(y * lineHeight(), lineHeight(), theme()->bgCurrentLineNumber());
}
pr.setBackground(Qt::transparent);
pr.setPen(theme()->fgLineNumber());
drawText(&pr, 0, y * lineHeight(), text);
if (line) {
char const *mark = nullptr;
if (line->type == Document::Line::Add) {
mark = "+";
} else if (line->type == Document::Line::Del) {
mark = "-";
}
if (mark) {
pr.setPen(theme()->fgDefault());
drawText(&pr, linenum_width - defaultCharWidth() * 3 / 2, y * lineHeight(), mark);
}
}
});
if (linenum_width > 0) {
pr.fillRect(0, view_y, 1, view_h, Qt::black);
}
pr.fillRect(linenum_width - 2, view_y, 1, view_h, Qt::black);
if (bottom >= 0) {
int y = (editor_cx->viewport_org_y + bottom) * lineHeight() + 1;
pr.fillRect(0, y, width(), 1, Qt::black);
}
}
// フォーカス枠描画
if (m->is_focus_frame_visible && has_focus) {
drawFocusFrame(&pr);
}
}
void TextEditorWidget::moveCursorByMouse()
{
QPoint mousepos = mapFromGlobal(QCursor::pos());
QPoint pos = mapFromPixel(mousepos);
int row = pos.y();
int col = pos.x();
// row
if (!isSingleLineMode()) {
if (row < 0) {
row = 0;
} else {
int maxrow = cx()->engine->document.lines.size();
maxrow = maxrow > 0 ? (maxrow - 1) : 0;
if (row > maxrow) {
row = maxrow;
}
}
}
setCursorRow(row, false, true);
setCursorCol(col, false, true);
clearParsedLine();
updateVisibility(false, true, false);
}
void TextEditorWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::RightButton) return;
savePos();
bool shift = (event->modifiers() & Qt::ShiftModifier);
if (shift) {
if (isSelectionAnchorEnabled()) {
setSelectionAnchor(SelectionAnchor::EnabledEasy, false, false);
} else {
setSelectionAnchor(SelectionAnchor::EnabledEasy, true, false);
}
}
moveCursorByMouse();
if (shift) {
setSelectionAnchor(SelectionAnchor::EnabledEasy, false, false);
} else {
setSelectionAnchor(SelectionAnchor::EnabledEasy, true, false);
}
selection_anchor_1 = selection_anchor_0;
if (isTerminalMode()) {
clearParsedLine();
restorePos();
}
}
void TextEditorWidget::mouseReleaseEvent(QMouseEvent * /*event*/)
{
}
void TextEditorWidget::mouseMoveEvent(QMouseEvent * /*event*/)
{
savePos();
moveCursorByMouse();
setSelectionAnchor(SelectionAnchor::EnabledEasy, true, false);
if (isTerminalMode()) {
clearParsedLine();
restorePos();
}
}
QVariant TextEditorWidget::inputMethodQuery(Qt::InputMethodQuery q) const
{
if (q == Qt::ImCursorRectangle) {
QRect r = cx()->cursor_rect;
return r;
}
return QWidget::inputMethodQuery(q);
}
void TextEditorWidget::inputMethodEvent(QInputMethodEvent *e)
{
#ifdef Q_OS_WIN
PreEditText preedit;
preedit.text = e->preeditString();
for (QInputMethodEvent::Attribute const &a : e->attributes()) {
if (a.type == QInputMethodEvent::TextFormat) {
QTextFormat f = qvariant_cast<QTextFormat>(a.value);
if (f.type() == QTextFormat::CharFormat) {
preedit.format.emplace_back(a.start, a.length, f);
} else {
}
}
}
if (preedit.text.isEmpty()) {
// m->ime_popup->hide();
} else {
QPoint pt = mapToGlobal(cx()->cursor_rect.topLeft());
// m->ime_popup->move(pt);
// m->ime_popup->setFont(font());
// m->ime_popup->setPreEditText(preedit);
// m->ime_popup->show();
}
#endif
// qDebug() << e->preeditString() << e->commitString();
QString const &commit_text = e->commitString();
if (!commit_text.isEmpty()) {
write_(commit_text, true);
}
}
void TextEditorWidget::refrectScrollBar()
{
int v = m->scroll_bar_v ? m->scroll_bar_v->value() : -1;
int h = m->scroll_bar_h ? m->scroll_bar_h->value() : -1;
move(-1, -1, v, h, false);
}
void TextEditorWidget::layoutEditor()
{
if (isAutoLayout()) {
int h = height() / lineHeight();
int w = width() / defaultCharWidth();
setScreenSize(w, h, false);
}
AbstractTextEditorApplication::layoutEditor();
}
void TextEditorWidget::resizeEvent(QResizeEvent * /*event*/)
{
if (isAutoLayout()) {
layoutEditor();
}
internalUpdateScrollBar();
}
void TextEditorWidget::wheelEvent(QWheelEvent *event)
{
int pos = 0;
m->wheel_delta += event->delta();
while (m->wheel_delta >= 40) {
m->wheel_delta -= 40;
pos--;
}
while (m->wheel_delta <= -40) {
m->wheel_delta += 40;
pos++;
}
if (m->scroll_bar_v) {
m->scroll_bar_v->setValue(m->scroll_bar_v->value() + pos);
}
}
void TextEditorWidget::setFocusFrameVisible(bool f)
{
m->is_focus_frame_visible = f;
}
void TextEditorWidget::timerEvent(QTimerEvent *)
{
if (!isChanged()) {
m->idle_count++;
if (m->idle_count >= 10) {
m->idle_count = 0;
emit idle();
}
}
}
void TextEditorWidget::contextMenuEvent(QContextMenuEvent *event)
{
QMenu menu;
QAction *a_cut = nullptr;
if (!isReadOnly() && !isTerminalMode()) a_cut = menu.addAction("Cut");
QAction *a_copy = menu.addAction("Copy");
QAction *a_paste = nullptr;
if (!isReadOnly() && !isTerminalMode()) a_paste = menu.addAction("Paste");
QAction *a = menu.exec(misc::contextMenuPos(this, event));
if (a) {
if (a == a_cut) {
editCut();
return;
}
if (a == a_copy) {
editCopy();
return;
}
if (a == a_paste) {
editPaste();
return;
}
}
}
diff --git a/src/texteditor/TextEditorWidget.h b/src/texteditor/TextEditorWidget.h
index 4466f80..e2d98f1 100644
--- a/src/texteditor/TextEditorWidget.h
+++ b/src/texteditor/TextEditorWidget.h
@@ -1,105 +1,111 @@
#ifndef OREWIDGET_H
#define OREWIDGET_H
#include <QTextFormat>
#include <QWidget>
#include <vector>
#include <cstdint>
#include <memory>
#include "AbstractCharacterBasedApplication.h"
#include "TextEditorTheme.h"
class QScrollBar;
struct PreEditText {
struct Format {
int start;
int length;
QTextFormat format;
Format(int start, int length, QTextFormat const &f)
: start(start)
, length(length)
, format(f)
{
}
};
QString text;
std::vector<Format> format;
};
class TextEditorWidget : public QWidget, public AbstractTextEditorApplication {
Q_OBJECT
public:
private:
struct Private;
Private *m;
void paintScreen(QPainter *painter);
void drawCursor(QPainter *pr);
void drawFocusFrame(QPainter *pr);
QRect updateCursorRect(bool auto_scroll);
QColor defaultForegroundColor();
QColor defaultBackgroundColor();
QColor colorForIndex(CharAttr const &attr, bool foreground);
void internalUpdateVisibility(bool ensure_current_line_visible, bool change_col, bool auto_scroll);
void internalUpdateScrollBar();
void moveCursorByMouse();
void setTextFont(const QFont &font);
int parseLine3(int row, int col, std::vector<Char> *vec) const;
int xScrollPosInPixel();
public:
int defaultCharWidth() const;
protected:
void paintEvent(QPaintEvent *) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void contextMenuEvent(QContextMenuEvent *event) override;
QFont textFont() const;
void drawText(QPainter *painter, int px, int py, QString const &str);
public:
explicit TextEditorWidget(QWidget *parent = nullptr);
~TextEditorWidget() override;
void setTheme(const TextEditorThemePtr &theme);
TextEditorTheme const *theme() const;
int charWidth2(unsigned int c) const;
int lineHeight() const;
// void setPreEditText(PreEditText const &preedit);
void updateVisibility(bool ensure_current_line_visible, bool change_col, bool auto_scroll) override;
bool event(QEvent *event) override;
void bindScrollBar(QScrollBar *vsb, QScrollBar *hsb);
void setupForLogWidget(QScrollBar *vsb, QScrollBar *hsb, const TextEditorThemePtr &theme);
QPoint mapFromPixel(const QPoint &pt);
QPoint mapToPixel(const QPoint &pt);
QVariant inputMethodQuery(Qt::InputMethodQuery q) const override;
void inputMethodEvent(QInputMethodEvent *e) override;
void refrectScrollBar();
void setRenderingMode(RenderingMode mode);
void move(int cur_row, int cur_col, int scr_row, int scr_col, bool auto_scroll);
void layoutEditor() override;
void setFocusFrameVisible(bool f);
+ enum ScrollUnit {
+ ScrollByCharacter = 0,
+ };
+ int scroll_unit_ = ScrollByCharacter;
+ void setScrollUnit(int n);
+ int scrollUnit() const;
signals:
void moved(int cur_row, int cur_col, int scr_row, int scr_col);
void updateScrollBar();
void idle();
protected:
void timerEvent(QTimerEvent *) override;
};
#endif // OREWIDGET_H

File Metadata

Mime Type
text/x-diff
Expires
Sat, Feb 7, 11:37 AM (14 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55937
Default Alt Text
(25 KB)

Event Timeline