📄 qeditor.cpp
字号:
#define FIXED_WIDTH_WRAP false#define FIXED_COLUMN_WRAP false#define BREAK_WITHIN_WORDS false/*#define WORD_WRAP ( d->wordwrap != QEditor::NoWrap )#define DYNAMIC_WRAP ( d->wordwrap == QEditor::WidgetWidth )#define FIXED_WIDTH_WRAP ( d->wordwrap == QEditor::FixedPixelWidth )#define FIXED_COLUMN_WRAP ( d->wordwrap == QEditor::FixedColumnWidth )#define BREAK_WITHIN_WORDS ( d->wrappolicy == QEditor::Anywhere )*/static int defTabStop = 8;static int tabStopDist(const QFontMetrics & fm){ int dist; dist = fm.width(QChar('x')); if (dist == 0) dist = fm.maxWidth(); return defTabStop * dist;}/*= Sets the distance between tab stops for all QEditor instances to \a ex, which is measured in multiples of the width of a lower case 'x' in the widget's font. The initial value is 8. \warning This function does not cause a redraw. It is best to call it before any QEditor widgets are shown. \sa defaultTabStop()*/void QEditor::setDefaultTabStop(int ex){ defTabStop = ex;}/*= Returns the distance between tab stops. \sa setDefaultTabStop();*/int QEditor::defaultTabStop(){ return defTabStop;}static int textWidthWithTabs(const QFontMetrics & fm, const QString & s, uint start, uint nChars){ if (s.isEmpty()) return 0; int dist = 0; //-fm.leftBearing(s[(int) start]); int i = start; int tabDist = -1; // lazy eval while ((uint) i < s.length() && (uint) i < start + nChars) { if (s[i] == '\t') { if (tabDist < 0) tabDist = tabStopDist(fm); dist = ((dist + tabDist + 1) / tabDist) * tabDist; i++; } else { int ii = i; while ((uint) i < s.length() && (uint) i < start + nChars && s[i] != '\t') i++; dist += fm.width(s.mid(ii, i - ii)); } } //return -fm.leftBearing(s[(int)start]) + fm.width(s.mid(start)); return dist;}static int xPosToCursorPos(const QString & s, const QFontMetrics & fm, int xPos, int width){ int i = 0; int dist; int tabDist; if (s.isEmpty()) return 0; if (xPos > width) xPos = width; if (xPos <= 0) return 0; dist = 0; //-fm.leftBearing(s[0]);// if ( align == Qt::AlignCenter || align == Qt::AlignHCenter )// dist = ( width - textWidthWithTabs( fm, s, 0, s.length(), align ) ) / 2;// else if ( align == Qt::AlignRight )// dist = width - textWidthWithTabs( fm, s, 0, s.length(), align ); int distBeforeLastTab = dist; tabDist = tabStopDist(fm); while ((uint) i < s.length() && dist < xPos) { if (s[i] == '\t') { distBeforeLastTab = dist; dist = (dist / tabDist + 1) * tabDist; } else { dist += fm.width(s[i]); } i++; } if (dist > xPos) { if (dist > width) { i--; } else { if (s[i - 1] == '\t') { // dist equals a tab stop position if (xPos - distBeforeLastTab < (dist - distBeforeLastTab) / 2) i--; } else { if (fm.width(s[i - 1]) / 2 < dist - xPos) i--; } } } return i;}/*= Constructs a new, empty, QEditor.*/QEditor::QEditor(QWidget * parent, const char *name):QGridView(parent, name, WNorthWestGravity | WRepaintNoErase){ d = new QMultiLineData; QFontMetrics fm(font()); setCellHeight(fm.lineSpacing()); setNumCols(1); contents = new QPtrList < QEditorRow >; contents->setAutoDelete(true); cursorX = 0; cursorY = 0; brotherX = -1; brotherX2 = -1; brotherY = -1; oldX = -1; oldY = -1; curXPos = 0; //setBackgroundMode(PaletteBase); //setWFlags(WResizeNoErase); setKeyCompression(true); setFocusPolicy(WheelFocus);#ifndef QT_NO_CURSOR viewport()->setCursor(ibeamCursor);#endif readOnly = false; cursorOn = false; markIsOn = false; dragScrolling = false; dragMarking = false; textDirty = false; wordMark = false; overWrite = false; showProc = true; showChange = true; useRelief = true; useColor = true; noEmitCursorMoved = 0; markAnchorX = 0; markAnchorY = 0; markDragX = 0; markDragY = 0; d->blinkTimer = new QTimer(this); connect(d->blinkTimer, SIGNAL(timeout()), this, SLOT(blinkTimerTimeout())); d->scrollTimer = new QTimer(this); connect(d->scrollTimer, SIGNAL(timeout()), this, SLOT(scrollTimerTimeout()));#ifndef QT_NO_DRAGANDDROP d->dnd_timer = new QTimer(this); connect(d->dnd_timer, SIGNAL(timeout()), this, SLOT(dndTimeout()));#endif d->scrollTime = 0; dummy = true; int w = textWidth(QString::fromLatin1("")); contents->append(new QEditorRow(QString::fromLatin1(""), w)); (void) setNumRowsAndTruncate(); setWidth(w); setAcceptDrops(true); if (d->maxlines >= 0 && d->maxlines <= 6) { setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); } else { setSizePolicy(QSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding)); } setInputMethodEnabled( TRUE ); // BM initDict(); // gcc 3.1 does not like the following: // color = default_color; for (int i = 0; i < NUM_COLORS; i++) color[i] = default_color[i]; setColor(QEditorRow::Background, color[QEditorRow::Background]); tabWidth = 2;}void QEditor::setReadOnly(bool on){ if (readOnly != on) { readOnly = on;#ifndef QT_NO_CURSOR viewport()->setCursor(on ? arrowCursor : ibeamCursor);#endif }}/*= Returns the width in pixels of the longest text line in this editor.*/int QEditor::maxLineWidth() const{ // [BM] //return QMAX(d->maxLineWidth, contentsRect().width()); return d->maxLineWidth;}/*= Destroys the QEditor*/QEditor::~QEditor(){ delete contents; delete d;}static QPixmap *buffer = 0;static void cleanupMLBuffer(){ delete buffer; buffer = 0;}static QPixmap *getCacheBuffer(QSize sz){ if (!buffer) { qAddPostRoutine(cleanupMLBuffer); buffer = new QPixmap; } if (buffer->width() < sz.width() || buffer->height() < sz.height()) buffer->resize(sz); return buffer;}/*= Implements the basic drawing logic.*/void QEditor::paintCell(QPainter * painter, int row, int){ QEditorRow *r = contents->at(row); int len = r->s.length(); bool selected = false; int x, y, w, h; int markX1, markX2; // in x-coordinate pixels int markBeginX, markBeginY; int markEndX, markEndY; bool cursor; //markX1 = markX2 = 0; // avoid gcc warning QRect updateR = cellRect(); //cellUpdateRect(); // [BM] //max_width = width() - frameWidth() * 2; //updateR.setWidth(max_width); QPixmap *buffer = getCacheBuffer(updateR.size()); ASSERT(buffer); buffer->fill(color[QEditorRow::Background]); //g.base() cursor = (hasFocus() || d->dnd_forcecursor); QPainter p(buffer); p.setFont(painter->font()); p.translate(-updateR.left(), -updateR.top()); // [BM] p.setTabStops(tabStopDist(fm)); //x = 0; // [BM] d->lr_marg - p.fontMetrics().leftBearing(s[0]); //w = cellWidth() - x; // cellWidth() - d->lr_marg - x x = d->lr_marg; y = 0; w = cellWidth(); h = cellHeight(); r->drawBack(p, 0, y, w, h, color, showCurrent && row == cursorY); selected = false; if (cursor && row == brotherY && brotherX >= 0) { int x = QMAX(mapToView(brotherX, row), 0); int w = QMAX(mapToView(brotherX + 1, row), 0) - x; p.fillRect(x, 0, w, cellHeight(), color[QEditorRow::Highlight]); x = QMAX(mapToView(brotherX2, row), 0); w = QMAX(mapToView(brotherX2 + 1, row), 0) - x; p.fillRect(x, 0, w, cellHeight(), color[QEditorRow::Highlight]); } if (markIsOn) { getMarkedRegion(&markBeginY, &markBeginX, &markEndY, &markEndX); if (row >= markBeginY && row <= markEndY) { selected = true; if (row == markBeginY) { markX1 = markBeginX; if (row == markEndY) // both marks on same row markX2 = markEndX; else { markX2 = len; // mark till end of line if (markX1 == 0) markX1 = -1; } } else { if (row == markEndY) { markX1 = -1; markX2 = markEndX; //if (markX2 == 0) // selected = false; } else { markX1 = -1; // whole line is marked markX2 = len; // whole line is marked } } if (selected) { int fillxpos1; int fillxpos2; if (markX1 < 0) fillxpos1 = 0; else fillxpos1 = mapToView(markX1, row); if (markX2 == len && row < markEndY) fillxpos2 = updateR.right() + 1; else fillxpos2 = mapToView(markX2, row); p.setClipping(true); p.setClipRect(fillxpos1 - updateR.left(), 0, fillxpos2 - fillxpos1, cellHeight()); p.fillRect(fillxpos1, 0, fillxpos2 - fillxpos1, cellHeight(), color[QEditorRow::Selection]); //p.setPen( g.highlightedText() ); //p.drawText( x, yPos, cellWidth()-d->lr_marg-x, cellHeight(), // d->align == AlignLeft?ExpandTabs:0, s ); p.setClipping(false); } } } if (useColor) { r->draw(p, x, y, w, h, color, useRelief); if (showProc && r->line) { p.setPen(color[QEditorRow::Selection]); p.drawLine(0, y, w - 1, y); } } else r->drawNormal(p, x, y, w, h, color); if (showChange && r->changed) { p.fillRect(0, y, x - 2, h, color[QEditorRow::Highlight]); //p.setPen(color[QEditorRow::Normal]); //p.drawLine(x - 2, y, x - 2, y + h - 1); } if (cursor && cursorOn) { if (row == cursorY) // && !readOnly) { int cursorPos = QMIN((int)len, cursorX); int cXPos = QMAX(mapToView(cursorPos, row), 0); int cYPos = 0; p.fillRect(cXPos, cYPos - 1, 2, cellHeight() + 2, color[QEditorRow::Normal]); } } p.end(); painter->drawPixmap(updateR.left(), updateR.top(), *buffer, 0, 0, updateR.width(), updateR.height());}/*= Returns the width in pixels of the string \a s. NOTE: only appropriate for whole lines.*/int QEditor::textWidth(const QString & s){ int w = 0; if (!s.isNull()) { w = textWidthWithTabs(QFontMetrics(font()), s, 0, s.length()); } return w + 2 * d->lr_marg + d->marg_extra;}/*= Returns the width in pixels of the text at line \a line.*/int QEditor::textWidth(int line){/* if (d->echomode == Password) { QString s = stringShown(line); return textWidth(s); }*/ QEditorRow *r = contents->at(line); return r ? r->w : 0;}/*= Starts the cursor blinking.*/void QEditor::focusInEvent(QFocusEvent *){ stopAutoScroll(); //if (!d->blinkTimer->isActive()) d->blinkLevel = 0; startBlink(); //repaintCell(cursorY, 0, false);}/*=\reimp*/void QEditor::leaveEvent(QEvent *){}/*=\reimp*/void QEditor::focusOutEvent(QFocusEvent *){ stopAutoScroll(); d->blinkLevel = 1; stopBlink(); if (!cursorOn) { cursorOn = true; repaintCell(cursorY, 0, false); }}#ifndef QT_NO_DRAGANDDROPvoid QEditor::doDrag(){ if (d->dnd_timer) { d->dnd_timer->stop(); } QDragObject *drag_text = new QTextDrag(markedText(), this); if (readOnly) { drag_text->dragCopy(); } else { if (drag_text->drag() && QDragObject::target() != this) { del(); if (textDirty && !d->isHandlingEvent) emit textChanged(); } } d->dnd_primed = false;}#endif/*= If there is marked text, sets \a line1, \a col1, \a line2 and \a col2 to the start and end of the marked region and returns true. Returns false if there is no marked text. */bool QEditor::getMarkedRegion(int *line1, int *col1, int *line2, int *col2) const{ if (!markIsOn || !line1 || !line2 || !col1 || !col2) return false; if (markAnchorY < markDragY || markAnchorY == markDragY && markAnchorX < markDragX) { *line1 = markAnchorY; *col1 = markAnchorX; *line2 = markDragY; *col2 = markDragX; if (*line2 > numLines() - 1) { *line2 = numLines() - 1; *col2 = lineLength(*line2); } } else { *line1 = markDragY; *col1 = markDragX; *line2 = markAnchorY; *col2 = markAnchorX; if (*line2 > numLines() - 1) { *line2 = numLines() - 1; *col2 = lineLength(*line2); } } return markIsOn;}/*= Returns true if there is marked text.*/bool QEditor::hasMarkedText() const{ return markIsOn;}/*= Returns a copy of the marked text.*/QString QEditor::markedText() const{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -