Commit a7bac175 authored by Robert Knight's avatar Robert Knight
Browse files

Add support for double width and double height lines.

svn path=/trunk/KDE/kdebase/apps/konsole/; revision=568707
parent 7b3fbf88
......@@ -72,6 +72,12 @@ struct ColorEntry
#define RE_INTENSIVE (1 << 3) // Widget only
#define RE_CURSOR (1 << 4)
typedef unsigned char LineProperty;
static const int LINE_DEFAULT = 0;
static const int LINE_WRAPPED = (1 << 0);
static const int LINE_DOUBLEWIDTH = (1 << 1);
static const int LINE_DOUBLEHEIGHT = (1 << 2);
/* cacol is a union of the various color spaces.
......
......@@ -98,7 +98,8 @@ TEScreen::TEScreen(int l, int c)
histCursor = 0;
*/
line_wrapped.resize(lines+1);
lineProperties.resize(lines+1);
//line_wrapped.resize(lines+1);
initTabStops();
clearSelection();
reset();
......@@ -424,7 +425,7 @@ void TEScreen::resizeImage(int new_lines, int new_columns)
// make new image
ca* newimg = new ca[(new_lines+1)*new_columns];
QBitArray newwrapped(new_lines+1);
QVector<LineProperty> newLineProperties(new_lines+1);
clearSelection();
// clear new image
......@@ -436,7 +437,7 @@ void TEScreen::resizeImage(int new_lines, int new_columns)
newimg[y*new_columns+x].b = cacol(CO_DFT,DEFAULT_BACK_COLOR);
newimg[y*new_columns+x].r = DEFAULT_RENDITION;
}
newwrapped[y]=false;
newLineProperties[y] = 0;
}
int cpy_lines = qMin(new_lines, lines);
int cpy_columns = qMin(new_columns,columns);
......@@ -449,11 +450,12 @@ void TEScreen::resizeImage(int new_lines, int new_columns)
newimg[y*new_columns+x].b = image[loc(x,y)].b;
newimg[y*new_columns+x].r = image[loc(x,y)].r;
}
newwrapped[y]=line_wrapped[y];
newLineProperties[y]=lineProperties[y];
}
delete[] image;
image = newimg;
line_wrapped = newwrapped;
//line_wrapped = newwrapped;
lineProperties = newLineProperties;
lines = new_lines;
columns = new_columns;
cuX = qMin(cuX,columns-1);
......@@ -576,7 +578,7 @@ ca* TEScreen::getCookedImage()
for (x = 0; x < columns; x++)
{
#ifdef REVERSE_WRAPPED_LINES
if (hist->isWrappedLine(y+histCursor))
if (hist->isLINE_WRAPPED(y+histCursor))
reverseRendition(&merged[p]);
#endif
if (testIsSelected(x,y)) {
......@@ -596,7 +598,7 @@ ca* TEScreen::getCookedImage()
{ int p = x + yp; int r = x + yr;
merged[p] = image[r];
#ifdef REVERSE_WRAPPED_LINES
if (line_wrapped[y- hist->getLines() +histCursor])
if (lineProperties[y- hist->getLines() +histCursor] & LINE_WRAPPED)
reverseRendition(&merged[p]);
#endif
if (sel_begin != -1 && testIsSelected(x,y))
......@@ -619,16 +621,24 @@ ca* TEScreen::getCookedImage()
return merged;
}
QBitArray TEScreen::getCookedLineWrapped()
QVector<LineProperty> TEScreen::getCookedLineProperties()
{
QBitArray result(lines);
QVector<LineProperty> result(lines);
for (int y = 0; (y < lines) && (y < (hist->getLines()-histCursor)); y++)
result[y]=hist->isWrappedLine(y+histCursor);
{
//TODO Support for line properties other than wrapped lines
//result[y]=hist->isLINE_WRAPPED(y+histCursor);
if (hist->isWrappedLine(y+histCursor))
{
result[y] = result[y] | LINE_WRAPPED;
}
}
if (lines >= hist->getLines()-histCursor)
for (int y = (hist->getLines()-histCursor); y < lines ; y++)
result[y]=line_wrapped[y- hist->getLines() +histCursor];
result[y]=lineProperties[y- hist->getLines() +histCursor];
return result;
}
......@@ -763,7 +773,7 @@ void TEScreen::ShowCharacter(unsigned short c)
if (cuX+w > columns) {
if (getMode(MODE_Wrap)) {
line_wrapped[cuY]=true;
lineProperties[cuY] |= LINE_WRAPPED;
NextLine();
}
else
......@@ -923,6 +933,8 @@ int TEScreen::getCursorY()
This is an internal helper functions. The parameter types are internal
addresses of within the screen image and make use of the way how the
screen matrix is mapped to the image vector.
NOTE: This only erases characters in the image, properties associated with individual lines are not affected.
*/
void TEScreen::clearImage(int loca, int loce, char c)
......@@ -946,8 +958,6 @@ void TEScreen::clearImage(int loca, int loce, char c)
image[i].r = DEFAULT_RENDITION;
}
for (i = loca/columns; i<=loce/columns; i++)
line_wrapped[i]=false;
}
/*! move image between (including) `loca' and `loce' to 'dst'.
......@@ -967,7 +977,7 @@ void TEScreen::moveImage(int dst, int loca, int loce)
//kDebug(1211) << "Using memmove to scroll up" << endl;
memmove(&image[dst],&image[loca],(loce-loca+1)*sizeof(ca));
for (int i=0;i<=(loce-loca+1)/columns;i++)
line_wrapped[(dst/columns)+i]=line_wrapped[(loca/columns)+i];
lineProperties[(dst/columns)+i]=lineProperties[(loca/columns)+i];
if (lastPos != -1)
{
int diff = dst - loca; // Scroll by this amount
......@@ -1405,14 +1415,14 @@ void TEScreen::getSelText(bool preserve_line_breaks, QTextStream *stream)
{
while ((eol > s) &&
(!image[eol - hist_BR].c || isSpace(image[eol - hist_BR].c)) &&
!line_wrapped[(eol-hist_BR)/columns])
!(lineProperties[(eol-hist_BR)/columns] & LINE_WRAPPED))
{
eol--;
}
}
else if (eol == sel_BR)
{
if (!line_wrapped[(eol - hist_BR)/columns])
if (!(lineProperties[(eol - hist_BR)/columns] & LINE_WRAPPED))
addNewLine = true;
}
else
......@@ -1432,7 +1442,7 @@ void TEScreen::getSelText(bool preserve_line_breaks, QTextStream *stream)
bool wrap = false;
if ((eol + 1) % columns == 0)
{ // the whole line is filled
if (line_wrapped[(eol - hist_BR)/columns])
if (lineProperties[(eol - hist_BR)/columns] & LINE_WRAPPED)
wrap = true;
}
if (wrap)
......@@ -1495,13 +1505,13 @@ void TEScreen::addHistLine()
{ ca dft;
int end = columns-1;
while (end >= 0 && image[end] == dft && !line_wrapped[0])
while (end >= 0 && image[end] == dft && !(lineProperties[0] & LINE_WRAPPED))
end -= 1;
int oldHistLines = hist->getLines();
hist->addCells(image,end+1);
hist->addLine(line_wrapped[0]);
hist->addLine( lineProperties[0] & LINE_WRAPPED );
int newHistLines = hist->getLines();
......@@ -1589,3 +1599,15 @@ const HistoryType& TEScreen::getScroll()
{
return hist->getType();
}
void TEScreen::setLineProperty(LineProperty property , bool enable)
{
if ( enable )
{
lineProperties[cuY] |= property;
}
else
{
lineProperties[cuY] &= ~property;
}
}
......@@ -149,8 +149,9 @@ public: // these are all `Screen' operations
//
void resizeImage(int new_lines, int new_columns);
//
ca* getCookedImage();
QBitArray getCookedLineWrapped();
ca* getCookedImage();
QVector<LineProperty> getCookedLineProperties();
/*! return the number of lines. */
int getLines() { return lines; }
......@@ -183,6 +184,15 @@ public: // these are all `Screen' operations
void checkSelection(int from, int to);
/**
* Sets or clears an attribute of the current line.
* Possible properties are:
* LINE_WRAPPED: Specifies that the line is wrapped.
* LINE_DOUBLEWIDTH: Specifies that the characters in the current line should be double the normal width.
* LINE_DOUBLEHEIGHT:Specifies that the characters in the current line should be double the normal height.
*/
void setLineProperty(LineProperty property , bool enable);
private: // helper
void clearImage(int loca, int loce, char c);
......@@ -213,8 +223,10 @@ private: // helper
int lines;
int columns;
ca *image; // [lines][columns]
QBitArray line_wrapped; // [lines]
//QBitArray line_wrapped; // [lines]
QVector<LineProperty> lineProperties; // [lines]
// history buffer ---------------
int histCursor; // display position relative to start of the history buffer
......
......@@ -772,6 +772,8 @@ void TEWidget::drawAttrStr(QPainter &paint, const QRect& rect,
currentFont.setBold(true);
paint.setFont( currentFont );
}
if (!(blinking && (attr->r & RE_BLINK)))
{
......@@ -1000,12 +1002,17 @@ void TEWidget::setImage(const ca* const newimg, int lines, int columns)
if (doubleWidth)
fixed_font = false;
updateLine = true;
updateLine = true;
fixed_font = save_fixed_font;
fixed_font = save_fixed_font;
x += len - 1;
}
}
//both the top and bottom halves of double height lines must always be redrawn
//although both top and bottom halves contain the same characters, only the top one is actually
//drawn.
updateLine |= (lineProperties[y] & LINE_DOUBLEHEIGHT);
if (updateLine)
{
......@@ -1236,16 +1243,47 @@ void TEWidget::paintContents(QPainter &paint, const QRect &rect)
fixed_font = false;
QString unistr(disstrU,p);
if (y < lineProperties.size())
{
if (lineProperties[y] & LINE_DOUBLEWIDTH)
paint.scale(2,1);
if (lineProperties[y] & LINE_DOUBLEHEIGHT)
paint.scale(1,2);
}
//calculate the area in which the text will be drawn
QRect textArea = QRect( bX+tLx+font_w*x , bY+tLy+font_h*y , font_w*len , font_h);
//move the calculated area to take account of scaling applied to the painter.
//the position of the area from the origin (0,0) is scaled by the opposite of whatever
//transformation has been applied to the painter. this ensures that
//painting does actually start from textArea.topLeft() (instead of textArea.topLeft() * painter-scale)
QMatrix inverted = paint.matrix().inverted();
textArea.moveTopLeft( inverted.map(textArea.topLeft()) );
//paint text fragment
drawAttrStr( paint,
QRect( bX+tLx+font_w*x , bY+tLy+font_h*y , font_w*len , font_h),
textArea,
unistr,
&image[loc(x,y)],
0,
!isPrinting );
fixed_font = save_fixed_font;
//reset back to single-width, single-height lines
paint.resetMatrix();
if (y < lineProperties.size())
{
//double-height lines are represented by two adjacent lines containing the same characters
//both lines will have the LINE_DOUBLEHEIGHT attribute. If the current line has the LINE_DOUBLEHEIGHT
//attribute, we can therefore skip the next line
if (lineProperties[y] & LINE_DOUBLEHEIGHT)
y++;
}
x += len - 1;
}
}
......@@ -1572,7 +1610,8 @@ void TEWidget::extendSelection( QPoint pos )
i = loc(left.x(),left.y());
if (i>=0 && i<=image_size) {
selClass = charClass(image[i].c);
while ( ((left.x()>0) || (left.y()>0 && m_line_wrapped[left.y()-1])) && charClass(image[i-1].c) == selClass )
while ( ((left.x()>0) || (left.y()>0 && (lineProperties[left.y()-1] & LINE_WRAPPED) ))
&& charClass(image[i-1].c) == selClass )
{ i--; if (left.x()>0) left.rx()--; else {left.rx()=columns-1; left.ry()--;} }
}
......@@ -1581,7 +1620,8 @@ void TEWidget::extendSelection( QPoint pos )
i = loc(right.x(),right.y());
if (i>=0 && i<=image_size) {
selClass = charClass(image[i].c);
while( ((right.x()<columns-1) || (right.y()<lines-1 && m_line_wrapped[right.y()])) && charClass(image[i+1].c) == selClass )
while( ((right.x()<columns-1) || (right.y()<lines-1 && (lineProperties[right.y()] & LINE_WRAPPED) ))
&& charClass(image[i+1].c) == selClass )
{ i++; if (right.x()<columns-1) right.rx()++; else {right.rx()=0; right.ry()++; } }
}
......@@ -1605,9 +1645,9 @@ void TEWidget::extendSelection( QPoint pos )
QPoint above = above_not_below ? here : iPntSelCorr;
QPoint below = above_not_below ? iPntSelCorr : here;
while (above.y()>0 && m_line_wrapped[above.y()-1])
while (above.y()>0 && (lineProperties[above.y()-1] & LINE_WRAPPED) )
above.ry()--;
while (below.y()<lines-1 && m_line_wrapped[below.y()])
while (below.y()<lines-1 && (lineProperties[below.y()] & LINE_WRAPPED) )
below.ry()++;
above.setX(0);
......@@ -1654,7 +1694,8 @@ void TEWidget::extendSelection( QPoint pos )
selClass = charClass(image[i-1].c);
if (selClass == ' ')
{
while ( right.x() < columns-1 && charClass(image[i+1].c) == selClass && (right.y()<lines-1) && !m_line_wrapped[right.y()])
while ( right.x() < columns-1 && charClass(image[i+1].c) == selClass && (right.y()<lines-1) &&
!(lineProperties[right.y()] & LINE_WRAPPED))
{ i++; right.rx()++; }
if (right.x() < columns-1)
right = left_not_right ? iPntSelCorr : here;
......@@ -1772,7 +1813,8 @@ void TEWidget::mouseDoubleClickEvent(QMouseEvent* ev)
{
// set the start...
int x = bgnSel.x();
while ( ((x>0) || (bgnSel.y()>0 && m_line_wrapped[bgnSel.y()-1])) && charClass(image[i-1].c) == selClass )
while ( ((x>0) || (bgnSel.y()>0 && (lineProperties[bgnSel.y()-1] & LINE_WRAPPED) ))
&& charClass(image[i-1].c) == selClass )
{ i--; if (x>0) x--; else {x=columns-1; bgnSel.ry()--;} }
bgnSel.setX(x);
emit beginSelectionSignal( bgnSel.x(), bgnSel.y(), false );
......@@ -1780,7 +1822,8 @@ void TEWidget::mouseDoubleClickEvent(QMouseEvent* ev)
// set the end...
i = loc( endSel.x(), endSel.y() );
x = endSel.x();
while( ((x<columns-1) || (endSel.y()<lines-1 && m_line_wrapped[endSel.y()])) && charClass(image[i+1].c) == selClass )
while( ((x<columns-1) || (endSel.y()<lines-1 && (lineProperties[endSel.y()] & LINE_WRAPPED) ))
&& charClass(image[i+1].c) == selClass )
{ i++; if (x<columns-1) x++; else {x=0; endSel.ry()++; } }
endSel.setX(x);
......@@ -1834,14 +1877,15 @@ void TEWidget::mouseTripleClickEvent(QMouseEvent* ev)
actSel = 2; // within selection
emit isBusySelecting(true); // Keep it steady...
while (iPntSel.y()>0 && m_line_wrapped[iPntSel.y()-1])
while (iPntSel.y()>0 && (lineProperties[iPntSel.y()-1] & LINE_WRAPPED) )
iPntSel.ry()--;
if (cuttobeginningofline) {
// find word boundary start
int i = loc(iPntSel.x(),iPntSel.y());
int selClass = charClass(image[i].c);
int x = iPntSel.x();
while ( ((x>0) || (iPntSel.y()>0 && m_line_wrapped[iPntSel.y()-1])) && charClass(image[i-1].c) == selClass )
while ( ((x>0) || (iPntSel.y()>0 && (lineProperties[iPntSel.y()-1] & LINE_WRAPPED) ))
&& charClass(image[i-1].c) == selClass )
{ i--; if (x>0) x--; else {x=columns-1; iPntSel.ry()--;} }
emit beginSelectionSignal( x, iPntSel.y(), false );
......@@ -1852,7 +1896,7 @@ void TEWidget::mouseTripleClickEvent(QMouseEvent* ev)
tripleSelBegin = QPoint( 0, iPntSel.y() );
}
while (iPntSel.y()<lines-1 && m_line_wrapped[iPntSel.y()])
while (iPntSel.y()<lines-1 && (lineProperties[iPntSel.y()] & LINE_WRAPPED) )
iPntSel.ry()++;
emit extendSelectionSignal( columns-1, iPntSel.y() );
......
......@@ -96,7 +96,7 @@ public:
void emitText(QString text);
void setImage(const ca* const newimg, int lines, int columns);
void setLineWrapped(QBitArray line_wrapped) { m_line_wrapped=line_wrapped; }
void setLineProperties(QVector<LineProperty> properties) { lineProperties=properties; }
void setCursorPos(const int curx, const int cury);
......@@ -256,7 +256,7 @@ private:
int contentWidth;
ca *image; // [lines][columns]
int image_size;
QBitArray m_line_wrapped;
QVector<LineProperty> lineProperties;
ColorEntry color_table[TABLE_COLORS];
QColor defaultBgColor;
......
......@@ -549,10 +549,22 @@ switch( N )
case TY_ESC_CS('%', 'G') : setCodec (1 ); break; //LINUX
case TY_ESC_CS('%', '@') : setCodec (0 ); break; //LINUX
case TY_ESC_DE('3' ) : /* IGNORED: double high, top half */ break;
case TY_ESC_DE('4' ) : /* IGNORED: double high, bottom half */ break;
case TY_ESC_DE('5' ) : /* IGNORED: single width, single high*/ break;
case TY_ESC_DE('6' ) : /* IGNORED: double width, single high*/ break;
case TY_ESC_DE('3' ) : /* Double height line, top half */
scr->setLineProperty( LINE_DOUBLEWIDTH , true );
scr->setLineProperty( LINE_DOUBLEHEIGHT , true );
break;
case TY_ESC_DE('4' ) : /* Double height line, bottom half */
scr->setLineProperty( LINE_DOUBLEWIDTH , true );
scr->setLineProperty( LINE_DOUBLEHEIGHT , true );
break;
case TY_ESC_DE('5' ) : /* Single width, single height line*/
scr->setLineProperty( LINE_DOUBLEWIDTH , false);
scr->setLineProperty( LINE_DOUBLEHEIGHT , false);
break;
case TY_ESC_DE('6' ) : /* Double width, single height line*/
scr->setLineProperty( LINE_DOUBLEWIDTH , true);
scr->setLineProperty( LINE_DOUBLEHEIGHT , false);
break;
case TY_ESC_DE('8' ) : scr->helpAlign ( ); break;
// resize = \e[8;<row>;<col>t
......
......@@ -499,13 +499,16 @@ void TEmulation::showBulk()
if (connected)
{
ca* image = scr->getCookedImage(); // get the image
gui->setImage(image,
//TODO: Setting line properties and image should be done in the same method call
//to ensure that the two don't get out of sync in the gui.
gui->setLineProperties( scr->getCookedLineProperties() );
gui->setImage(image,
scr->getLines(),
scr->getColumns()); // actual refresh
gui->setCursorPos(scr->getCursorX(), scr->getCursorY()); // set XIM position
free(image);
//FIXME: check that we do not trigger other draw event here.
gui->setLineWrapped( scr->getCookedLineWrapped() );
//kDebug(1211)<<"TEmulation::showBulk(): setScroll()"<<endl;
gui->setScroll(scr->getHistCursor(),scr->getHistLines());
//kDebug(1211)<<"TEmulation::showBulk(): setScroll() done"<<endl;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment