Screen.cpp 39.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
    This file is part of Konsole, an X terminal.
    Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>

    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., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301  USA.
19 20
*/

21 22
// Own
#include "Screen.h"
23

24
// Standard
25 26 27 28 29 30 31
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <ctype.h>

32
// Qt
Dirk Mueller's avatar
Dirk Mueller committed
33 34
#include <QtCore/QTextStream>
#include <QtCore/QDate>
35

36 37 38 39
// KDE
#include <kdebug.h>

// Konsole
40
#include "konsole_wcwidth.h"
41
#include "TerminalCharacterDecoder.h"
42

43 44
using namespace Konsole;

45
//FIXME: this is emulation specific. Use false for xterm, true for ANSI.
46
//FIXME: see if we can get this from terminfo.
47
#define BS_CLEARS false
48

49 50 51 52
//Macro to convert x,y position on screen to position within an image.
//
//Originally the image was stored as one large contiguous block of 
//memory, so a position within the image could be represented as an
53 54 55
//offset from the beginning of the block.  For efficiency reasons this
//is no longer the case.  
//Many internal parts of this class still use this representation for parameters and so on,
56 57
//notably moveImage() and clearImage().
//This macro converts from an X,Y position into an image offset.
58 59 60 61
#ifndef loc
#define loc(X,Y) ((Y)*columns+(X))
#endif

62

63
Character Screen::defaultChar = Character(' ',CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR),CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR),DEFAULT_RENDITION);
64

65 66
//#define REVERSE_WRAPPED_LINES  // for wrapped line debug

67
Screen::Screen(int l, int c)
68 69
  : lines(l),
    columns(c),
70
    screenLines(new ImageLine[lines+1] ),
71
    _scrolledLines(0),
72
    _droppedLines(0),
73 74
    hist(new HistoryScrollNone()),
    cuX(0), cuY(0),
75
    cu_re(0),
76 77 78
    tmargin(0), bmargin(0),
    tabstops(0),
    sel_begin(0), sel_TL(0), sel_BR(0),
79
    sel_busy(false),
80
    columnmode(false),
81
    ef_fg(CharacterColor()), ef_bg(CharacterColor()), ef_re(0),
82
    sa_cuX(0), sa_cuY(0),
83
    sa_cu_re(0),
84
    lastPos(-1)
85
{
86
  lineProperties.resize(lines+1);
87
  for (int i=0;i<lines+1;i++)
88
          lineProperties[i]=LINE_DEFAULT;
89

90 91 92 93 94 95 96 97
  initTabStops();
  clearSelection();
  reset();
}

/*! Destructor
*/

98
Screen::~Screen()
99
{
100
  delete[] screenLines;
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
  delete[] tabstops;
  delete hist;
}

/* ------------------------------------------------------------------------- */
/*                                                                           */
/* Normalized                    Screen Operations                           */
/*                                                                           */
/* ------------------------------------------------------------------------- */

// Cursor Setting --------------------------------------------------------------

/*! \section Cursor

    The `cursor' is a location within the screen that is implicitely used in
    many operations. The operations within this section allow to manipulate
    the cursor explicitly and to obtain it's value.

    The position of the cursor is guarantied to be between (including) 0 and
    `columns-1' and `lines-1'.
*/

/*!
    Move the cursor up.

    The cursor will not be moved beyond the top margin.
*/

129
void Screen::cursorUp(int n)
130 131 132 133
//=CUU
{
  if (n == 0) n = 1; // Default
  int stop = cuY < tmargin ? 0 : tmargin;
134 135
  cuX = qMin(columns-1,cuX); // nowrap!
  cuY = qMax(stop,cuY-n);
136 137 138 139 140 141 142 143
}

/*!
    Move the cursor down.

    The cursor will not be moved beyond the bottom margin.
*/

144
void Screen::cursorDown(int n)
145 146 147 148
//=CUD
{
  if (n == 0) n = 1; // Default
  int stop = cuY > bmargin ? lines-1 : bmargin;
149 150
  cuX = qMin(columns-1,cuX); // nowrap!
  cuY = qMin(stop,cuY+n);
151 152 153 154 155 156 157 158
}

/*!
    Move the cursor left.

    The cursor will not move beyond the first column.
*/

159
void Screen::cursorLeft(int n)
160 161 162
//=CUB
{
  if (n == 0) n = 1; // Default
163 164
  cuX = qMin(columns-1,cuX); // nowrap!
  cuX = qMax(0,cuX-n);
165 166 167 168 169 170 171 172
}

/*!
    Move the cursor left.

    The cursor will not move beyond the rightmost column.
*/

173
void Screen::cursorRight(int n)
174 175 176
//=CUF
{
  if (n == 0) n = 1; // Default
177
  cuX = qMin(columns-1,cuX+n);
178 179 180 181 182 183
}

/*!
    Set top and bottom margin.
*/

184
void Screen::setMargins(int top, int bot)
185 186 187 188 189 190 191
//=STBM
{
  if (top == 0) top = 1;      // Default
  if (bot == 0) bot = lines;  // Default
  top = top - 1;              // Adjust to internal lineno
  bot = bot - 1;              // Adjust to internal lineno
  if ( !( 0 <= top && top < bot && bot < lines ) )
192
  { kDebug()<<" setRegion("<<top<<","<<bot<<") : bad range.";
193 194 195 196 197 198
    return;                   // Default error action: ignore
  }
  tmargin = top;
  bmargin = bot;
  cuX = 0;
  cuY = getMode(MODE_Origin) ? top : 0;
199 200 201

}

202
int Screen::topMargin() const
203 204 205
{
    return tmargin;
}
206
int Screen::bottomMargin() const
207 208
{
    return bmargin;
209 210 211 212 213 214 215 216 217
}

/*!
    Move the cursor down one line.

    If cursor is on bottom margin, the region between the
    actual top and bottom margin is scrolled up instead.
*/

218
void Screen::index()
219 220 221 222
//=IND
{
  if (cuY == bmargin)
  {
223
    scrollUp(1);
224 225 226 227 228 229 230 231 232 233 234 235
  }
  else if (cuY < lines-1)
    cuY += 1;
}

/*!
    Move the cursor up one line.

    If cursor is on the top margin, the region between the
    actual top and bottom margin is scrolled down instead.
*/

236
void Screen::reverseIndex()
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
//=RI
{
  if (cuY == tmargin)
     scrollDown(tmargin,1);
  else if (cuY > 0)
    cuY -= 1;
}

/*!
    Move the cursor to the begin of the next line.

    If cursor is on bottom margin, the region between the
    actual top and bottom margin is scrolled up.
*/

252
void Screen::NextLine()
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
//=NEL
{
  Return(); index();
}

// Line Editing ----------------------------------------------------------------

/*! \section inserting / deleting characters
*/

/*! erase `n' characters starting from (including) the cursor position.

    The line is filled in from the right with spaces.
*/

268
void Screen::eraseChars(int n)
269 270
{
  if (n == 0) n = 1; // Default
271
  int p = qMax(0,qMin(cuX+n-1,columns-1));
272 273 274 275 276 277 278 279
  clearImage(loc(cuX,cuY),loc(p,cuY),' ');
}

/*! delete `n' characters starting from (including) the cursor position.

    The line is filled in from the right with spaces.
*/

280
void Screen::deleteChars(int n)
281
{
282 283 284 285 286 287 288 289 290 291
  Q_ASSERT( n >= 0 );

  // always delete at least one char
  if (n == 0) 
      n = 1; 

  // if cursor is beyond the end of the line there is nothing to do
  if ( cuX >= screenLines[cuY].count() )
      return;

292 293 294 295 296
  if ( cuX+n >= screenLines[cuY].count() ) 
       n = screenLines[cuY].count() - 1 - cuX;

  Q_ASSERT( n >= 0 );
  Q_ASSERT( cuX+n < screenLines[cuY].count() );
297 298

  screenLines[cuY].remove(cuX,n);
299 300 301 302 303 304 305
}

/*! insert `n' spaces at the cursor position.

    The cursor is not moved by the operation.
*/

306
void Screen::insertChars(int n)
307 308
{
  if (n == 0) n = 1; // Default
309
  
310 311 312 313
  screenLines[cuY].insert(cuX,n,' ');

  if ( screenLines[cuY].count() > columns )
      screenLines[cuY].resize(columns);
314 315 316 317 318 319 320
}

/*! delete `n' lines starting from (including) the cursor position.

    The cursor is not moved by the operation.
*/

321
void Screen::deleteLines(int n)
322 323 324 325 326 327 328 329 330 331
{
  if (n == 0) n = 1; // Default
  scrollUp(cuY,n);
}

/*! insert `n' lines at the cursor position.

    The cursor is not moved by the operation.
*/

332
void Screen::insertLines(int n)
333 334 335 336 337 338 339 340 341
{
  if (n == 0) n = 1; // Default
  scrollDown(cuY,n);
}

// Mode Operations -----------------------------------------------------------

/*! Set a specific mode. */

342
void Screen::setMode(int m)
343
{
344
  currParm.mode[m] = true;
345 346 347 348 349 350 351 352
  switch(m)
  {
    case MODE_Origin : cuX = 0; cuY = tmargin; break; //FIXME: home
  }
}

/*! Reset a specific mode. */

353
void Screen::resetMode(int m)
354
{
355
  currParm.mode[m] = false;
356 357 358 359 360 361 362 363
  switch(m)
  {
    case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home
  }
}

/*! Save a specific mode. */

364
void Screen::saveMode(int m)
365 366 367 368 369 370
{
  saveParm.mode[m] = currParm.mode[m];
}

/*! Restore a specific mode. */

371
void Screen::restoreMode(int m)
372 373 374 375 376 377
{
  currParm.mode[m] = saveParm.mode[m];
}

//NOTE: this is a helper function
/*! Return the setting  a specific mode. */
378
bool Screen::getMode(int m)
379 380 381 382 383 384
{
  return currParm.mode[m];
}

/*! Save the cursor position and the rendition attribute settings. */

385
void Screen::saveCursor()
386 387 388 389 390 391 392 393 394 395
{
  sa_cuX     = cuX;
  sa_cuY     = cuY;
  sa_cu_re   = cu_re;
  sa_cu_fg   = cu_fg;
  sa_cu_bg   = cu_bg;
}

/*! Restore the cursor position and the rendition attribute settings. */

396
void Screen::restoreCursor()
397
{
398 399
  cuX     = qMin(sa_cuX,columns-1);
  cuY     = qMin(sa_cuY,lines-1);
400 401 402 403 404 405 406 407 408 409 410 411
  cu_re   = sa_cu_re;
  cu_fg   = sa_cu_fg;
  cu_bg   = sa_cu_bg;
  effectiveRendition();
}

/* ------------------------------------------------------------------------- */
/*                                                                           */
/*                             Screen Operations                             */
/*                                                                           */
/* ------------------------------------------------------------------------- */

412
/*! Resize the screen image
413 414 415 416 417 418 419

    The topmost left position is maintained, while lower lines
    or right hand side columns might be removed or filled with
    spaces to fit the new size.

    The region setting is reset to the whole screen and the
    tab positions reinitialized.
420 421 422 423

    If the new image is narrower than the old image then text on lines
    which extends past the end of the new image is preserved so that it becomes
    visible again if the screen is later resized to make it larger.
424 425
*/

426
void Screen::resizeImage(int new_lines, int new_columns)
427 428 429 430 431 432 433 434 435 436 437 438
{
  if ((new_lines==lines) && (new_columns==columns)) return;

  if (cuY > new_lines-1)
  { // attempt to preserve focus and lines
    bmargin = lines-1; //FIXME: margin lost
    for (int i = 0; i < cuY-(new_lines-1); i++)
    {
      addHistLine(); scrollUp(0,1);
    }
  }

439 440 441 442 443 444 445 446 447 448
  // create new screen lines and copy from old to new
  
   ImageLine* newScreenLines = new ImageLine[new_lines+1];
   for (int i=0; i < qMin(lines-1,new_lines+1) ;i++)
           newScreenLines[i]=screenLines[i];
   for (int i=lines;(i > 0) && (i<new_lines+1);i++)
           newScreenLines[i].resize( new_columns );
   
  lineProperties.resize(new_lines+1);
  for (int i=lines;(i > 0) && (i<new_lines+1);i++)
449
          lineProperties[i] = LINE_DEFAULT;
450 451

  clearSelection();
452 453 454
 
  delete[] screenLines; 
  screenLines = newScreenLines;
455 456 457

  lines = new_lines;
  columns = new_columns;
458 459
  cuX = qMin(cuX,columns-1);
  cuY = qMin(cuY,lines-1);
460 461 462 463 464 465 466 467

  // FIXME: try to keep values, evtl.
  tmargin=0;
  bmargin=lines-1;
  initTabStops();
  clearSelection();
}

468
void Screen::setDefaultMargins()
469 470 471 472 473 474
{
	tmargin = 0;
	bmargin = lines-1;
}


475
/*
Robert Knight's avatar
 
Robert Knight committed
476
   Clarifying rendition here and in the display.
477

Robert Knight's avatar
 
Robert Knight committed
478
   currently, the display's color table is
479 480 481 482 483 484 485 486
     0       1       2 .. 9    10 .. 17
     dft_fg, dft_bg, dim 0..7, intensive 0..7

   cu_fg, cu_bg contain values 0..8;
   - 0    = default color
   - 1..8 = ansi specified color

   re_fg, re_bg contain values 0..17
487
   due to the TerminalDisplay's color table
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508

   rendition attributes are

      attr           widget screen
      -------------- ------ ------
      RE_UNDERLINE     XX     XX    affects foreground only
      RE_BLINK         XX     XX    affects foreground only
      RE_BOLD          XX     XX    affects foreground only
      RE_REVERSE       --     XX
      RE_TRANSPARENT   XX     --    affects background only
      RE_INTENSIVE     XX     --    affects foreground only

   Note that RE_BOLD is used in both widget
   and screen rendition. Since xterm/vt102
   is to poor to distinguish between bold
   (which is a font attribute) and intensive
   (which is a color attribute), we translate
   this and RE_BOLD in falls eventually appart
   into RE_BOLD and RE_INTENSIVE.
*/

509
void Screen::reverseRendition(Character* p)
510 511
{ CharacterColor f = p->foregroundColor; CharacterColor b = p->backgroundColor;
  p->foregroundColor = b; p->backgroundColor = f; //p->r &= ~RE_TRANSPARENT;
512 513
}

514
void Screen::effectiveRendition()
515 516
// calculate rendition
{
517
  //copy "current rendition" straight into "effective rendition", which is then later copied directly
518
  //into the image[] array which holds the characters and their appearance properties.
519
  //- The old version below filtered out all attributes other than underline and blink at this stage,
520
  //so that they would not be copied into the image[] array and hence would not be visible by TerminalDisplay
521 522 523 524 525 526 527 528
  //which actually paints the screen using the information from the image[] array.  
  //I don't know why it did this, but I'm fairly sure it was the wrong thing to do.  The net result
  //was that bold text wasn't printed in bold by Konsole.
  ef_re = cu_re;
  
  //OLD VERSION:
  //ef_re = cu_re & (RE_UNDERLINE | RE_BLINK);
  
529 530 531 532 533 534 535 536 537 538
  if (cu_re & RE_REVERSE)
  {
    ef_fg = cu_bg;
    ef_bg = cu_fg;
  }
  else
  {
    ef_fg = cu_fg;
    ef_bg = cu_bg;
  }
539
 
540
  if (cu_re & RE_BOLD)
Kurt Hindenburg's avatar
Kurt Hindenburg committed
541
    ef_fg.toggleIntensive();
542 543 544 545 546 547 548 549 550 551 552 553
}

/*!
    returns the image.

    Get the size of the image by \sa getLines and \sa getColumns.

    NOTE that the image returned by this function must later be
    freed.

*/

554
Character* Screen::getCookedImage( int startLine )
555
{
556
  Q_ASSERT( startLine <= hist->getLines() );
557

558
  int x,y;
559
  Character* merged = new Character[lines*columns+1];
560
  merged[lines*columns] = defaultChar;
561

562
  for (y = 0; (y < lines) && (y < (hist->getLines()-startLine)); y++)
563
  {
564
    int len = qMin(columns,hist->getLineLen(y+startLine));
565 566
    int yp  = y*columns;

567
    hist->getCells(y+startLine,0,len,merged+yp);
568
    for (x = len; x < columns; x++) merged[yp+x] = defaultChar;
569
    if (sel_begin !=-1)
570
    for (x = 0; x < columns; x++)
571
      {
572
#ifdef REVERSE_WRAPPED_LINES
573
        if (hist->isLINE_WRAPPED(y+startLine))
574 575
          reverseRendition(&merged[p]);
#endif
576
        if (isSelected(x,y+startLine)) {
577
          int p=x + yp;
578 579 580
          reverseRendition(&merged[p]); // for selection
    }
  }
581
  }
582
  if (lines >= hist->getLines()-startLine)
583
  {
584
    for (y = (hist->getLines()-startLine); y < lines ; y++)
585 586
    {
       int yp  = y*columns;
587
       int yr =  (y-hist->getLines()+startLine)*columns;
588
       for (x = 0; x < columns; x++)
589
       { int p = x + yp; int r = x + yr;
590

591 592 593 594
         // sanity checks
         assert( p >= 0 );
         assert( p < (lines*columns+1) );

595
         merged[p] = screenLines[r/columns].value(r%columns,defaultChar);
596

597
#ifdef REVERSE_WRAPPED_LINES
598
         if (lineProperties[y- hist->getLines() +startLine] & LINE_WRAPPED)
599 600
           reverseRendition(&merged[p]);
#endif
601
         if (sel_begin != -1 && isSelected(x,y+startLine))
602 603 604 605 606 607 608
           reverseRendition(&merged[p]); // for selection
       }

    }
  }
  // evtl. inverse display
  if (getMode(MODE_Screen))
609 610
  {
    for (int i = 0; i < lines*columns; i++)
611 612
      reverseRendition(&merged[i]); // for reverse display
  }
613
//  if (getMode(MODE_Cursor) && (cuY+(hist->getLines()-startLine) < lines)) // cursor visible
614

615
  int loc_ = loc(cuX, cuY+hist->getLines()-startLine);
616
  if(getMode(MODE_Cursor) && loc_ < columns*lines)
617
    merged[loc(cuX,cuY+(hist->getLines()-startLine))].rendition|=RE_CURSOR;
618 619 620
  return merged;
}

621
QVector<LineProperty> Screen::getCookedLineProperties( int startLine )
622
{
623
  Q_ASSERT( startLine <= hist->getLines() );
624

625
  QVector<LineProperty> result(lines);
626

627 628
  // properties for lines in history
  for (int y = 0; (y < lines) && (y < (hist->getLines()-startLine)); y++)
629 630
  {
	//TODO Support for line properties other than wrapped lines
631
    //result[y]=hist->isLINE_WRAPPED(y+viewHistoryCursor);
632
  
633
	  if (hist->isWrappedLine(y+startLine))
634
	  {
635
	  	result[y] = (LineProperty)(result[y] | LINE_WRAPPED);
636 637 638
	  }
  }
  
639 640 641 642 643 644
  // properties for lines in screen buffer
  if (lines >= hist->getLines()-startLine)
  {
    for (int y = (hist->getLines()-startLine); y < lines ; y++)
      result[y]=lineProperties[y - hist->getLines() + startLine];
  }
645 646 647

  return result;
}
648 649 650 651

/*!
*/

652
void Screen::reset(bool clearScreen)
653 654 655 656 657 658 659 660 661 662 663 664 665 666
{
    setMode(MODE_Wrap  ); saveMode(MODE_Wrap  );  // wrap at end of margin
  resetMode(MODE_Origin); saveMode(MODE_Origin);  // position refere to [1,1]
  resetMode(MODE_Insert); saveMode(MODE_Insert);  // overstroke
    setMode(MODE_Cursor);                         // cursor visible
  resetMode(MODE_Screen);                         // screen not inverse
  resetMode(MODE_NewLine);

  tmargin=0;
  bmargin=lines-1;

  setDefaultRendition();
  saveCursor();

667 668
  if ( clearScreen )
    clear();
669 670 671 672 673
}

/*! Clear the entire screen and home the cursor.
*/

674
void Screen::clear()
675 676 677 678 679 680 681 682
{
  clearEntireScreen();
  home();
}

/*! Moves the cursor left one column.
*/

683
void Screen::BackSpace()
684
{
685
  cuX = qMin(columns-1,cuX); // nowrap!
686
  cuX = qMax(0,cuX-1);
687
 // if (BS_CLEARS) image[loc(cuX,cuY)].character = ' ';
688 689 690 691

  if (screenLines[cuY].size() < cuX+1)
          screenLines[cuY].resize(cuX+1);

692
  if (BS_CLEARS) screenLines[cuY][cuX].character = ' ';
693 694 695 696 697
}

/*!
*/

698
void Screen::Tabulate(int n)
699 700
{
  // note that TAB is a format effector (does not write ' ');
701 702 703 704 705 706 707 708
  if (n == 0) n = 1;
  while((n > 0) && (cuX < columns-1))
  {
    cursorRight(1); while((cuX < columns-1) && !tabstops[cuX]) cursorRight(1);
    n--;
  }
}

709
void Screen::backTabulate(int n)
710 711 712 713 714 715 716 717
{
  // note that TAB is a format effector (does not write ' ');
  if (n == 0) n = 1;
  while((n > 0) && (cuX > 0))
  {
     cursorLeft(1); while((cuX > 0) && !tabstops[cuX]) cursorLeft(1);
     n--;
  }
718 719
}

720
void Screen::clearTabStops()
721
{
Stephan Kulow's avatar
Stephan Kulow committed
722
  for (int i = 0; i < columns; i++) tabstops[i] = false;
723 724
}

725
void Screen::changeTabStop(bool set)
726 727 728 729 730
{
  if (cuX >= columns) return;
  tabstops[cuX] = set;
}

731
void Screen::initTabStops()
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
{
  delete[] tabstops;
  tabstops = new bool[columns];

  // Arrg! The 1st tabstop has to be one longer than the other.
  // i.e. the kids start counting from 0 instead of 1.
  // Other programs might behave correctly. Be aware.
  for (int i = 0; i < columns; i++) tabstops[i] = (i%8 == 0 && i != 0);
}

/*!
   This behaves either as IND (Screen::Index) or as NEL (Screen::NextLine)
   depending on the NewLine Mode (LNM). This mode also
   affects the key sequence returned for newline ([CR]LF).
*/

748
void Screen::NewLine()
749 750 751 752 753 754 755 756 757 758 759
{
  if (getMode(MODE_NewLine)) Return();
  index();
}

/*! put `c' literally onto the screen at the current cursor position.

    VT100 uses the convention to produce an automatic newline (am)
    with the *first* character that would fall onto the next line (xenl).
*/

760
void Screen::checkSelection(int from, int to)
761 762 763 764 765 766 767 768 769 770
{
  if (sel_begin == -1) return;
  int scr_TL = loc(0, hist->getLines());
  //Clear entire selection if it overlaps region [from, to]
  if ( (sel_BR > (from+scr_TL) )&&(sel_TL < (to+scr_TL)) )
  {
    clearSelection();
  }
}

771
void Screen::ShowCharacter(unsigned short c)
772 773 774 775 776 777
{
  // Note that VT100 does wrapping BEFORE putting the character.
  // This has impact on the assumption of valid cursor positions.
  // We indicate the fact that a newline has to be triggered by
  // putting the cursor one right to the last column of the screen.

778 779
  int w = konsole_wcwidth(c);

Waldo Bastian's avatar
Waldo Bastian committed
780 781 782
  if (w <= 0)
     return;

783
  if (cuX+w > columns) {
Stephan Kulow's avatar
Stephan Kulow committed
784
    if (getMode(MODE_Wrap)) {
785
      lineProperties[cuY] = (LineProperty)(lineProperties[cuY] | LINE_WRAPPED);
786
      NextLine();
Stephan Kulow's avatar
Stephan Kulow committed
787 788
    }
    else
789
      cuX = columns-w;
790 791
  }

792
  if (getMode(MODE_Insert)) insertChars(w);
793

794 795 796 797 798 799
 // int i = loc(cuX,cuY);

  lastPos = loc(cuX,cuY);

 // checkSelection(i, i); // check if selection is still valid.
  checkSelection(cuX,cuY);
800

801 802 803 804 805 806 807 808 809 810 811 812
  int size = screenLines[cuY].size();
  if (size == 0 && cuY > 0)
  {
          screenLines[cuY].resize( qMax(screenLines[cuY-1].size() , cuX+1) );
  }
  else
  {
    if (size < cuX+1)
    {
          screenLines[cuY].resize(cuX+1);
    }
  }
813

814
  Character& currentChar = screenLines[cuY][cuX];
815

816 817 818 819
  currentChar.character = c;
  currentChar.foregroundColor = ef_fg;
  currentChar.backgroundColor = ef_bg;
  currentChar.rendition = ef_re;
820 821

  int i = 0;
822

823
  cuX += w--;
Stephan Kulow's avatar
Stephan Kulow committed
824

825 826 827
  while(w)
  {
     i++;
828 829 830 831
   
     if ( screenLines[cuY].size() < cuX + i + 1 )
         screenLines[cuY].resize(cuX+i+1);
     
832 833 834 835 836
     Character& ch = screenLines[cuY][cuX + i];
     ch.character = 0;
     ch.foregroundColor = ef_fg;
     ch.backgroundColor = ef_bg;
     ch.rendition = ef_re;
837

838 839
     w--;
  }
840 841
}

842
void Screen::compose(const QString& /*compose*/)
843
{
844 845 846
   Q_ASSERT( 0 /*Not implemented yet*/ );

/*  if (lastPos == -1)
847 848
     return;
     
849
  QChar c(image[lastPos].character);
850
  compose.prepend(c);
851
  //compose.compose(); ### FIXME!
852
  image[lastPos].character = compose[0].unicode();*/
853 854
}

855
int Screen::scrolledLines() const
856 857 858
{
        return _scrolledLines;
}
859 860 861 862 863 864 865 866
int Screen::droppedLines() const
{
    return _droppedLines;
}
void Screen::resetDroppedLines()
{
    _droppedLines = 0;
}
867
void Screen::resetScrolledLines()
868
{
Robert Knight's avatar
 
Robert Knight committed
869 870
    //qDebug() << "scrolled lines reset";

871 872 873
    _scrolledLines = 0;
}

874 875
// Region commands -------------------------------------------------------------

876
void Screen::scrollUp(int n)
877 878 879 880 881
{
   if (n == 0) n = 1; // Default
   if (tmargin == 0) addHistLine(); // hist.history
   scrollUp(tmargin, n);
}
882 883 884 885 886 887

/*! scroll up `n' lines within current region.
    The `n' new lines are cleared.
    \sa setRegion \sa scrollDown
*/

888 889 890 891 892
QRect Screen::lastScrolledRegion() const
{
    return _lastScrolledRegion;
}

893
void Screen::scrollUp(int from, int n)
894 895
{
  if (n <= 0 || from + n > bmargin) return;
896 897

  _scrolledLines -= n;
898
  _lastScrolledRegion = QRect(0,tmargin,columns-1,(bmargin-tmargin));
899

Robert Knight's avatar
 
Robert Knight committed
900 901
  //qDebug() << "Screen::scrollUp( from: " << from << " , n: " << n << ")";

902 903 904 905 906
  //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds.
  moveImage(loc(0,from),loc(0,from+n),loc(columns-1,bmargin));
  clearImage(loc(0,bmargin-n+1),loc(columns-1,bmargin),' ');
}

907
void Screen::scrollDown(int n)
908 909 910 911 912
{
   if (n == 0) n = 1; // Default
   scrollDown(tmargin, n);
}

913 914 915 916 917
/*! scroll down `n' lines within current region.
    The `n' new lines are cleared.
    \sa setRegion \sa scrollUp
*/

918
void Screen::scrollDown(int from, int n)
919
{
920

Robert Knight's avatar
 
Robert Knight committed
921 922
  //qDebug() << "Screen::scrollDown( from: " << from << " , n: " << n << ")";
  
923 924
  _scrolledLines += n;

925 926 927 928 929 930 931 932 933
//FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds.
  if (n <= 0) return;
  if (from > bmargin) return;
  if (from + n > bmargin) n = bmargin - from;
  moveImage(loc(0,from+n),loc(0,from),loc(columns-1,bmargin-n));
  clearImage(loc(0,from),loc(columns-1,from+n-1),' ');
}

/*! position the cursor to a specific line and column. */
934
void Screen::setCursorYX(int y, int x)
935 936 937 938 939 940
{
  setCursorY(y); setCursorX(x);
}

/*! Set the cursor to x-th line. */

941
void Screen::setCursorX(int x)
942 943 944
{
  if (x == 0) x = 1; // Default
  x -= 1; // Adjust
945
  cuX = qMax(0,qMin(columns-1, x));
946 947 948 949
}

/*! Set the cursor to y-th line. */

950
void Screen::setCursorY(int y)
951 952 953
{
  if (y == 0) y = 1; // Default
  y -= 1; // Adjust
954
  cuY = qMax(0,qMin(lines  -1, y + (getMode(MODE_Origin) ? tmargin : 0) ));
955 956 957 958 959
}

/*! set cursor to the `left upper' corner of the screen (1,1).
*/

960
void Screen::home()
961 962 963 964 965 966 967 968
{
  cuX = 0;
  cuY = 0;
}

/*! set cursor to the begin of the current line.
*/

969
void Screen::Return()
970 971 972 973 974 975 976
{
  cuX = 0;
}

/*! returns the current cursor columns.
*/

977
int Screen::getCursorX() const
978 979 980 981 982 983 984
{
  return cuX;
}

/*! returns the current cursor line.
*/

985
int Screen::getCursorY() const
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000
{
  return cuY;
}

// Erasing ---------------------------------------------------------------------

/*! \section Erasing

    This group of operations erase parts of the screen contents by filling
    it with spaces colored due to the current rendition settings.

    Althought the cursor position is involved in most of these operations,
    it is never modified by them.
*/

1001
/*! fill screen between (including) `loca' (start) and `loce' (end) with spaces.
1002 1003 1004 1005

    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.
1006 1007

NOTE:  This only erases characters in the image, properties associated with individual lines are not affected.
1008 1009
*/

1010
void Screen::clearImage(int loca, int loce, char c)
1011
{ 
1012 1013 1014 1015 1016 1017 1018 1019
  int scr_TL=loc(0,hist->getLines());
  //FIXME: check positions

  //Clear entire selection if it overlaps region to be moved...
  if ( (sel_BR > (loca+scr_TL) )&&(sel_TL < (loce+scr_TL)) )
  {
    clearSelection();
  }
1020 1021 1022 1023

  int topLine = loca/columns;
  int bottomLine = loce/columns;

1024
  Character clearCh(c,cu_fg,cu_bg,DEFAULT_RENDITION);
1025
  
1026 1027
  //if the character being used to clear the area is the same as the
  //default character, the affected lines can simply be shrunk.
1028
  bool isDefaultCh = (clearCh == Character());
1029 1030

  for (int y=topLine;y<=bottomLine;y++)
1031
  {
1032 1033 1034
        int endCol = ( y == bottomLine) ? loce%columns : columns-1;
        int startCol = ( y == topLine ) ? loca%columns : 0;

1035
        QVector<Character>& line = screenLines[y];
1036 1037 1038 1039 1040 1041 1042 1043 1044

        if ( isDefaultCh && endCol == columns-1 )
        {
            line.resize(startCol);
        }
        else
        {
            if (line.size() < endCol + 1)
                line.resize(endCol+1);
1045

1046
            Character* data = line.data();
1047 1048 1049 1050
            for (int i=startCol;i<=endCol;i++)
                data[i]=clearCh;
        }
  }
1051 1052
}

1053 1054 1055 1056 1057 1058
/*! move image between (including) `sourceBegin' and `sourceEnd' to 'dest'.
    
    The 'dest', 'sourceBegin' and 'sourceEnd' parameters can be generated using
    the loc(column,line) macro.

NOTE:  moveImage() can only move whole lines.
1059 1060 1061 1062 1063 1064

    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.
*/

1065
void Screen::moveImage(int dest, int sourceBegin, int sourceEnd)
1066
{
Robert Knight's avatar
 
Robert Knight committed
1067 1068 1069 1070
  //qDebug() << "moving image from (" << (sourceBegin/columns) 
  //    << "," << (sourceEnd/columns) << ") to " <<
  //    (dest/columns);