⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 textarea.cpp

📁 ezxterm for motorola rokr e2
💻 CPP
字号:
/*************************************************************************** *   Copyright (C) 2007 by Motorola Commnunity around the World            * *   lahu3672@googlemail.com                                               * *                                                                         * *   This program is free software; you can redistribute it and/or modify  * *   it under the terms of the GNU General Public License as published by  * *   the Free Software Foundation; either version 2 of the License, or     * *   (at your option) any later version.                                   * *                                                                         * *   This program is distributed in the hope that it will be useful,       * *   but WITHOUT ANY WARRANTY; without even the implied warranty of        * *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         * *   GNU General Public License for more details.                          * *                                                                         * *   You should have received a copy of the GNU General Public License     * *   along with this program; if not, write to the                         * *   Free Software Foundation, Inc.,                                       * *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             * ***************************************************************************/#include "TextArea.h"TextArea::TextArea(QWidget *parent, const char *name): QFrame(parent, name){	QPixmap::setDefaultOptimization(QPixmap::NormalOptim);	mutex.lock();	QFontFactory *factory = qt_fontmanager->factories.at(0);	QDiskFont *qdf = new QDiskFont(factory, "Lucida Console", false, 25, 0, "s","/ezxlocal/lucon.ttf");	qt_fontmanager->diskfonts.append(qdf);	QFontDatabase::qwsAddDiskFont(qdf);	eseq = ESEQ_NONE;	esc_seq = "";	defAttrs.pen.setColor(black);	font.setFixedPitch(true);	font.setFamily("Lucida Console");	font.setPointSize(9);	defAttrs.attrs = 0;	defAttrs.bgColor = white;	defAttrs.textBgColor = white;	newAttrs = curAttrs = defAttrs;	setFocusPolicy(QWidget::StrongFocus);	metrics = new QFontMetrics(font);	QRect cr = contentsRect();	crd.setX(cr.left());	crd.setY(cr.top());	stcrd = crd;	row = col = 0;	topRow = 0;	fakeTopRow = 0;	ansiChanges = 0;	newCrd = crd;	newCol = col;	newRow = row;	canDraw = true;	insertMode = false;}TextArea::~TextArea(){	delete metrics;	lines.setAutoDelete(true);	lines.clear();}void TextArea::pushLine(){	QPixmap *pl = new QPixmap(contentsRect().width(), metrics->height());	lines.append(pl);	pl->fill(curAttrs.bgColor);}uint TextArea::drawText(QPixmap *pix, const QPoint &where, const QString &s){	uint len = metrics->width(s);	QRect trect = QRect(where, QSize(len, metrics->height()));	QPainter p(pix);	p.setFont(font);	p.setPen(curAttrs.pen);	p.fillRect(trect, curAttrs.textBgColor);	p.drawText(where.x(), metrics->ascent(), s);	p.end();	return metrics->width(s);}void TextArea::showLine(QPixmap *pix, const QPoint &where, uint width, QPaintDevice *dev){	if (!dev) dev = this;	bitBlt(dev, where.x(), where.y(), pix, where.x(), 0, width, pix->height());}void TextArea::renderText(int row, const QPoint &where, const QString &s){	if (!s.length()) return;	QPixmap *pix = lines.at(row);	uint width = drawText(pix, QPoint(where.x(), 0), s);	crd.rx() += width;}QPoint TextArea::lineCoord(const QPoint &c){	return QPoint(c.x() - stcrd.y(), 0);}void TextArea::moveChars(uint r, uint from, uint cnt, uint to){	if (to == from) return;	QPixmap *line = lines.at(r);	QPoint moveFrom = QPoint(getX(r, from), 0);	QPoint moveTo = QPoint(getX(r, to), 0);		QRect eraseRect;		QRect moveRect = QRect(moveFrom, QSize(contentsRect().width() - moveFrom.x(), metrics->height()));		bitBlt(line, moveTo, line, moveRect);	if (to > from)	{		eraseRect = QRect(moveFrom, QSize(moveTo.x() - moveFrom.x(), metrics->height()));		erase(eraseRect, line);	}}void TextArea::erase(const QRect &rect, QPaintDevice *p){	if (!canDraw) return;	if (!p) p = this;	QPixmap pix(rect.size());	pix.fill(curAttrs.bgColor);	bitBlt(p, rect.topLeft(), &pix, pix.rect());}void TextArea::eraseLine(uint row, EraseType type, const QPoint &crd){	QPixmap *line = lines.at(row);	switch (type)	{		case EraseAll:			erase(QRect(crd, QSize(contentsRect().width() - crd.x(), metrics->height())));			erase(QRect(lineCoord(crd), QSize(contentsRect().width() - crd.x(), metrics->height())), line);			break;		case EraseToCurrent:			erase(QRect(stcrd.x(), stcrd.y(), crd.x() - stcrd.x(), metrics->height()));			erase(QRect(0, 0, lineCoord(crd).x(), metrics->height()), line);			break;		case EraseToEnd:			erase(QRect(crd.x(), crd.y(), contentsRect().width() - crd.x(), metrics->height()));			erase(QRect(lineCoord(crd), QSize(contentsRect().width() - crd.x(), metrics->height())), line);			break;	}}void TextArea::eraseLines(uint from, uint to){	if (to < from) return;		for (uint i = from; i <= to; ++i) lines.at(i)->fill(curAttrs.bgColor);}QStringList TextArea::ansiParseArgs(){	return QStringList::split(";", esc_seq);}void TextArea::ansiSetAttrs(){	newAttrs = curAttrs;	QStringList args;	if (esc_seq.isEmpty()) args.append("0"); else args = ansiParseArgs();	for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it)	{		int arg = (*it).toUInt();		bool fg = false;		QColor color;		if ((arg>=40)&&(arg<=47))		{			fg = true;			arg-=10;		}		if ((arg>=30)&&(arg<=37))		{			switch (arg-30)			{				case 0:					color = black;					break;				case 1:					color = red;					break;				case 2:					color = green;					break;				case 3:					color = yellow;					break;				case 4:					color = blue;					break;				case 5:					color = magenta;					break;				case 6:					color = cyan;					break;				case 7:					color = white;					break;			}			if (!fg) newAttrs.pen.setColor(color); else			{				newAttrs.bgColor = color;			}		}//		if (arg == 7) newAttrs.attrs |= ANSI_ATTR_INVERSE;		if (arg == 7)		{			QColor bg = newAttrs.textBgColor;			newAttrs.textBgColor = newAttrs.pen.color();			newAttrs.pen.setColor(bg);		}		if (arg == 2) newAttrs.attrs |= ANSI_ATTR_BOLD;		if (arg == 0) newAttrs = defAttrs;		ansiChanges |= ANSI_CHANGED_ATTRS;	}}void TextArea::ansiGo(uint direction){	uint cnt = 0;	int r = 0,c = 0;	QStringList args = ansiParseArgs();	if (esc_seq.isEmpty()) cnt = r = c = 1;	else if (direction != DIR_ABSOLUTE)	{		cnt = args[0].toUInt();	} else	{		r = args[0].toUInt();		c = args[1].toUInt();	}	switch (direction)	{		case DIR_UP:			go(row - cnt, col);			break;		case DIR_DOWN:			go(row + cnt, col);			break;		case DIR_FORWARD:			go(row, col + cnt);			break;		case DIR_BACKWARD:			go(row, col - cnt);			break;		case DIR_ABSOLUTE:			go(topRow + r - 1, c - 1);			break;	}	ansiChanges |= ANSI_CHANGED_POSITION;}void TextArea::ansiEraseLine(){	uint type;	if (esc_seq.isEmpty()) type = 0;	else type = ansiParseArgs()[0].toUInt();	switch (type)	{		case 0:			eraseLine(row, EraseAll, crd);			break;		case 1:			eraseLine(row, EraseToCurrent, crd);			break;		case 2:			eraseLine(row, EraseToEnd, crd);			break;	}}void TextArea::ansiEraseChars(){	uint cnt;	if (esc_seq.isEmpty()) cnt = 1;	else cnt = ansiParseArgs()[0].toUInt();		moveChars(row, col + cnt, cnt, col);}void TextArea::ansiInsertChars(){	uint cnt;	if (esc_seq.isEmpty()) cnt = 1;	else cnt = ansiParseArgs()[0].toUInt();		moveChars(row, col, cnt, col + cnt);}	void TextArea::ansiEraseScreen(){	uint type;	if (esc_seq.isEmpty()) type = 0;	else type = ansiParseArgs()[0].toUInt();	QRect er;	switch (type)	{		case 0:			eraseLine(row, EraseToEnd, crd);			eraseLines(row + 1, lines.count() - 1);			er = QRect(QPoint(stcrd.x(), crd.y() + metrics->height()), contentsRect().bottomRight());			break;		case 1:			eraseLine(row, EraseToCurrent, crd);			eraseLines(topRow, row - 1);			er = QRect(stcrd, QPoint(contentsRect().right(), crd.y()));			break;		case 2:			eraseLines(topRow, lines.count() - 1);			er = contentsRect();			break;	}	erase(er);}void TextArea::ansiSetMode(){	if (esc_seq.isEmpty()) return;	uint mode = 0;	mode = ansiParseArgs()[0].toUInt();		switch (mode)	{		case 4:			insertMode = true;	}}void TextArea::ansiResetMode(){	if (esc_seq.isEmpty()) return;	uint mode = 0;	mode = ansiParseArgs()[0].toUInt();		switch (mode)	{		case 4:			insertMode = false;	}}	void TextArea::ansiProcess(char ch){	switch (ch)	{		case 'f':		case 'A':			ansiGo(DIR_UP);			break;		case 'B':			ansiGo(DIR_DOWN);			break;		case 'C':			ansiGo(DIR_FORWARD);			break;		case 'D':			ansiGo(DIR_BACKWARD);			break;		case 'H':			ansiGo(DIR_ABSOLUTE);			break;		case 'J':			ansiEraseScreen();			break;		case 'K':			ansiEraseLine();			break;		case 'm':			ansiSetAttrs();			break;		case 'h':			ansiSetMode();			break;		case 'l':			ansiResetMode();			break;		case '@':			ansiInsertChars();			break;		case 'P':			ansiEraseChars();			break;		default:			esc_seq += ch;			return;	}	eseq = ESEQ_ANSI_DONE;	esc_seq = "";}int TextArea::insertChar(char ch){	if (eseq == ESEQ_ANSI_STARTED)	{		ansiProcess(ch);		return eseq == ESEQ_ANSI_DONE;	}	if (eseq == ESEQ_ANSI_DONE) eseq = ESEQ_NONE;	if (eseq == ESEQ_STUB) eseq = ESEQ_NONE;	if (eseq == ESEQ_STUB2) eseq = ESEQ_STUB;	switch (ch)	{		case ESC_CHAR:			if (eseq == ESEQ_NONE) eseq = ESEQ_ESC;			else eseq = ESEQ_NONE;			break;		case '[':			if (eseq == ESEQ_ESC) eseq = ESEQ_ANSI_STARTED;			else eseq = ESEQ_NONE;			break;		case '=':		case '7':			if (eseq == ESEQ_ESC) eseq = ESEQ_STUB;			break;		case ')':			if (eseq == ESEQ_ESC) eseq = ESEQ_STUB2;			break;			default:			eseq = ESEQ_NONE;	}	return 0;}int TextArea::getX(){	return stcrd.x() + (col)*metrics->maxWidth();}int TextArea::getX(uint r, uint c){	return stcrd.x() + (c)*metrics->maxWidth();}int TextArea::getY(){	return (row - topRow) * metrics->height();}int TextArea::getY(uint r, uint c){	if (r<topRow) return 0;	return (r - topRow) * metrics->height();}void TextArea::tab(){	uint nc = col - col%TAB_SIZE + TAB_SIZE;	if (nc >= xsize) nc = xsize - 1;	crd.rx() = getX(row, nc);	col = nc;}void TextArea::back(){	if (!col && !row) return;	if (col == 0)	{		col = xsize-1;		row--;		crd.rx() = getX();	} else	{		col--;		crd.rx() -= metrics->maxWidth();	}}void TextArea::showTextBlock(uint from, uint to, uint diff){	uint count = to - from + 1;	QPoint p = QPoint(0, 0);	QSize size(contentsRect().width(), count* metrics->height());	QPoint dstStart(stcrd.x(), diff * metrics->height());	QRect pixBlock(p, size);	QPixmap pix(size);	for (uint i = from; i <= to; ++i)	{		showLine(lines.at(i), p, contentsRect().width(), &pix);		p.ry() += metrics->height();	}	bitBlt(this, dstStart, &pix, pixBlock);}bool TextArea::newlineShift(){	if (row - topRow >= ysize - 1)	{		if (canDraw) showTextBlock(topRow + 1, topRow + ysize - 1, 0);		crd.rx() = stcrd.x();		topRow++;		if (canDraw) fakeTopRow++;		return true;	} else return false;}void TextArea::newline(){	if (!newlineShift())	{		crd.ry() += metrics->height();	}	row++;	if (row >= lines.count()) pushLine();	col = 0;	crd.rx() = stcrd.x();}void TextArea::appendChar(const QChar &ch){	QByteArray arr(1);	arr[0] = (char)ch;	appendText(arr);}void TextArea::appendText(const QByteArray &text, uint offset, bool new_call){	enum {STATE_NONE = 0, STATE_NEWLINE, STATE_RETURN, STATE_TAB, STATE_BELL, STATE_BACKSPACE, STATE_ANSI};	if (new_call)	{		mutex.lock();	}	int state = STATE_NONE;	uint i;	QString chunk = "";	QPoint dcrd = crd;	for (i = offset; i < text.size(); ++i)	{		if (state != STATE_NONE) break;		switch (text[i])		{			case '\n':				state = STATE_NEWLINE;				break;			case '\r':				state = STATE_RETURN;				break;			case '\t':				state = STATE_TAB;				break;			case '\x7':				state = STATE_BELL;				break;			case '\x8':				state = STATE_BACKSPACE;				break;			default:				int ret = insertChar(text[i]);				if (eseq == ESEQ_NONE)				{					if (col == xsize)					{						state = STATE_NEWLINE;						i--;					} else					{						if (insertMode)						{							moveChars(row, col, xsize - col, col + 1);						}						chunk += text[i];						state = STATE_NONE;						col++;					}				} else				{					if (ret) state = STATE_ANSI;				}		}	}	if (chunk.length())	{		renderText(row, dcrd, chunk);	}	if (state != STATE_NONE)	{		switch (state)		{			case STATE_NEWLINE:				insertMode = false;				if (canDraw) showLine(lines.at(row), QPoint(stcrd.x(), crd.y()), contentsRect().width());				newline();				break;			case STATE_RETURN:				col = 0;				crd.rx() = stcrd.x();				break;			case STATE_BACKSPACE:				back();				break;			case STATE_TAB:				tab();				break;			case STATE_ANSI:				if (ansiChanges & ANSI_CHANGED_ATTRS) curAttrs = newAttrs;				if (ansiChanges & ANSI_CHANGED_POSITION)				{					if (canDraw) showLine(lines.at(row), QPoint(stcrd.x(), crd.y()), contentsRect().width());					row = newRow;					col = newCol;					crd = newCrd;				}				ansiChanges = 0;				break;		}		appendText(text, i, false);	} else	{		if (canDraw) showLine(lines.at(row), QPoint(stcrd.x(), crd.y()), contentsRect().width());		mutex.unlock();	}}void TextArea::scroll(int delta){	if (lines.count() <= ysize) return;	uint udelta;	if (delta > 0)	{		udelta = delta;		delta = (fakeTopRow >= udelta) ? udelta : fakeTopRow;	} else	{		udelta = -delta;		uint lastline = fakeTopRow + ysize - 1;		if (lastline >= lines.count())		{			return;		}		delta = (lines.count() - lastline >= udelta) ? -udelta : (lastline - lines.count() + 1);	}	if (!delta)	{		return;	}	showTextBlock(fakeTopRow - delta, fakeTopRow + ysize - delta - 1, 0);	fakeTopRow-=delta;	canDraw = fakeTopRow == topRow;	return;}void TextArea::home(){	mutex.lock();	fakeTopRow = topRow;	showTextBlock(topRow, lines.count() - 1, 0);	canDraw = true;	mutex.unlock();}void TextArea::drawContents(QPainter *painter){	mutex.lock();	uint to = lines.count() - fakeTopRow;	if (to > ysize - 1) to = fakeTopRow + ysize - 1; else to += fakeTopRow - 1;	showTextBlock(fakeTopRow, to, 0);	mutex.unlock();}void TextArea::resizeEvent(QResizeEvent *event){	QRect cr = contentsRect();	xsize = cr.width()/metrics->maxWidth();	ysize = cr.height()/metrics->height();	pushLine();	emit configured();	mutex.unlock();	}void TextArea::getSize(struct winsize *ws){	ws->ws_col = xsize;	ws->ws_row = ysize;	ws->ws_xpixel = contentsRect().width();	ws->ws_ypixel = contentsRect().height();}void TextArea::go(uint r, uint c){	if (r - topRow >= ysize) r = topRow + ysize - 1;	if (c >= xsize) c = xsize - 1;	int delta = r - lines.count() + 1;	while (delta-->0) pushLine();	newRow = r;	newCol = c;	newCrd.rx() = getX(r, c);	newCrd.ry() = getY(r, c);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -