~verzegnassi-stefano/+junk/ubuntu-terminal-app-uitk13

« back to all changes in this revision

Viewing changes to src/plugin/qmltermwidget/qtermwidget/lib/Screen.cpp

  • Committer: Filippo Scognamiglio
  • Date: 2014-10-25 04:42:31 UTC
  • Revision ID: flscogna@gmail.com-20141025044231-javjhusbqa171127
Initial reboot commit.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   This file is part of Konsole, an X terminal.
 
3
 
 
4
   Copyright 2007-2008 by Robert Knight <robert.knight@gmail.com>
 
5
   Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
 
6
 
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 2 of the License, or
 
10
   (at your option) any later version.
 
11
 
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
 
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program; if not, write to the Free Software
 
19
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
20
   02110-1301  USA.
 
21
   */
 
22
 
 
23
// Own
 
24
#include "Screen.h"
 
25
 
 
26
// Standard
 
27
#include <stdio.h>
 
28
#include <stdlib.h>
 
29
#include <unistd.h>
 
30
#include <assert.h>
 
31
#include <string.h>
 
32
#include <ctype.h>
 
33
 
 
34
// Qt
 
35
#include <QTextStream>
 
36
#include <QDate>
 
37
 
 
38
// KDE
 
39
//#include <kdebug.h>
 
40
 
 
41
// Konsole
 
42
#include "konsole_wcwidth.h"
 
43
#include "TerminalCharacterDecoder.h"
 
44
 
 
45
using namespace Konsole;
 
46
 
 
47
//FIXME: this is emulation specific. Use false for xterm, true for ANSI.
 
48
//FIXME: see if we can get this from terminfo.
 
49
#define BS_CLEARS false
 
50
 
 
51
//Macro to convert x,y position on screen to position within an image.
 
52
//
 
53
//Originally the image was stored as one large contiguous block of 
 
54
//memory, so a position within the image could be represented as an
 
55
//offset from the beginning of the block.  For efficiency reasons this
 
56
//is no longer the case.  
 
57
//Many internal parts of this class still use this representation for parameters and so on,
 
58
//notably moveImage() and clearImage().
 
59
//This macro converts from an X,Y position into an image offset.
 
60
#ifndef loc
 
61
#define loc(X,Y) ((Y)*columns+(X))
 
62
#endif
 
63
 
 
64
 
 
65
Character Screen::defaultChar = Character(' ',
 
66
        CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR),
 
67
        CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR),
 
68
        DEFAULT_RENDITION);
 
69
 
 
70
//#define REVERSE_WRAPPED_LINES  // for wrapped line debug
 
71
 
 
72
    Screen::Screen(int l, int c)
 
73
: lines(l),
 
74
    columns(c),
 
75
    screenLines(new ImageLine[lines+1] ),
 
76
    _scrolledLines(0),
 
77
    _droppedLines(0),
 
78
    history(new HistoryScrollNone()),
 
79
    cuX(0), cuY(0),
 
80
    currentRendition(0),
 
81
    _topMargin(0), _bottomMargin(0),
 
82
    selBegin(0), selTopLeft(0), selBottomRight(0),
 
83
    blockSelectionMode(false),
 
84
    effectiveForeground(CharacterColor()), effectiveBackground(CharacterColor()), effectiveRendition(0),
 
85
    lastPos(-1)
 
86
{
 
87
    lineProperties.resize(lines+1);
 
88
    for (int i=0;i<lines+1;i++)
 
89
        lineProperties[i]=LINE_DEFAULT;
 
90
 
 
91
    initTabStops();
 
92
    clearSelection();
 
93
    reset();
 
94
}
 
95
 
 
96
/*! Destructor
 
97
*/
 
98
 
 
99
Screen::~Screen()
 
100
{
 
101
    delete[] screenLines;
 
102
    delete history;
 
103
}
 
104
 
 
105
void Screen::cursorUp(int n)
 
106
    //=CUU
 
107
{
 
108
    if (n == 0) n = 1; // Default
 
109
    int stop = cuY < _topMargin ? 0 : _topMargin;
 
110
    cuX = qMin(columns-1,cuX); // nowrap!
 
111
    cuY = qMax(stop,cuY-n);
 
112
}
 
113
 
 
114
void Screen::cursorDown(int n)
 
115
    //=CUD
 
116
{
 
117
    if (n == 0) n = 1; // Default
 
118
    int stop = cuY > _bottomMargin ? lines-1 : _bottomMargin;
 
119
    cuX = qMin(columns-1,cuX); // nowrap!
 
120
    cuY = qMin(stop,cuY+n);
 
121
}
 
122
 
 
123
void Screen::cursorLeft(int n)
 
124
    //=CUB
 
125
{
 
126
    if (n == 0) n = 1; // Default
 
127
    cuX = qMin(columns-1,cuX); // nowrap!
 
128
    cuX = qMax(0,cuX-n);
 
129
}
 
130
 
 
131
void Screen::cursorRight(int n)
 
132
    //=CUF
 
133
{
 
134
    if (n == 0) n = 1; // Default
 
135
    cuX = qMin(columns-1,cuX+n);
 
136
}
 
137
 
 
138
void Screen::setMargins(int top, int bot)
 
139
    //=STBM
 
140
{
 
141
    if (top == 0) top = 1;      // Default
 
142
    if (bot == 0) bot = lines;  // Default
 
143
    top = top - 1;              // Adjust to internal lineno
 
144
    bot = bot - 1;              // Adjust to internal lineno
 
145
    if ( !( 0 <= top && top < bot && bot < lines ) )
 
146
    { //Debug()<<" setRegion("<<top<<","<<bot<<") : bad range.";
 
147
        return;                   // Default error action: ignore
 
148
    }
 
149
    _topMargin = top;
 
150
    _bottomMargin = bot;
 
151
    cuX = 0;
 
152
    cuY = getMode(MODE_Origin) ? top : 0;
 
153
 
 
154
}
 
155
 
 
156
int Screen::topMargin() const
 
157
{
 
158
    return _topMargin;
 
159
}
 
160
int Screen::bottomMargin() const
 
161
{
 
162
    return _bottomMargin;
 
163
}
 
164
 
 
165
void Screen::index()
 
166
    //=IND
 
167
{
 
168
    if (cuY == _bottomMargin)
 
169
        scrollUp(1);
 
170
    else if (cuY < lines-1)
 
171
        cuY += 1;
 
172
}
 
173
 
 
174
void Screen::reverseIndex()
 
175
    //=RI
 
176
{
 
177
    if (cuY == _topMargin)
 
178
        scrollDown(_topMargin,1);
 
179
    else if (cuY > 0)
 
180
        cuY -= 1;
 
181
}
 
182
 
 
183
void Screen::nextLine()
 
184
    //=NEL
 
185
{
 
186
    toStartOfLine(); index();
 
187
}
 
188
 
 
189
void Screen::eraseChars(int n)
 
190
{
 
191
    if (n == 0) n = 1; // Default
 
192
    int p = qMax(0,qMin(cuX+n-1,columns-1));
 
193
    clearImage(loc(cuX,cuY),loc(p,cuY),' ');
 
194
}
 
195
 
 
196
void Screen::deleteChars(int n)
 
197
{
 
198
    Q_ASSERT( n >= 0 );
 
199
 
 
200
    // always delete at least one char
 
201
    if (n == 0) 
 
202
        n = 1; 
 
203
 
 
204
    // if cursor is beyond the end of the line there is nothing to do
 
205
    if ( cuX >= screenLines[cuY].count() )
 
206
        return;
 
207
 
 
208
    if ( cuX+n > screenLines[cuY].count() ) 
 
209
        n = screenLines[cuY].count() - cuX;
 
210
 
 
211
    Q_ASSERT( n >= 0 );
 
212
    Q_ASSERT( cuX+n <= screenLines[cuY].count() );
 
213
 
 
214
    screenLines[cuY].remove(cuX,n);
 
215
}
 
216
 
 
217
void Screen::insertChars(int n)
 
218
{
 
219
    if (n == 0) n = 1; // Default
 
220
 
 
221
    if ( screenLines[cuY].size() < cuX )
 
222
        screenLines[cuY].resize(cuX);
 
223
 
 
224
    screenLines[cuY].insert(cuX,n,' ');
 
225
 
 
226
    if ( screenLines[cuY].count() > columns )
 
227
        screenLines[cuY].resize(columns);
 
228
}
 
229
 
 
230
void Screen::deleteLines(int n)
 
231
{
 
232
    if (n == 0) n = 1; // Default
 
233
    scrollUp(cuY,n);
 
234
}
 
235
 
 
236
void Screen::insertLines(int n)
 
237
{
 
238
    if (n == 0) n = 1; // Default
 
239
    scrollDown(cuY,n);
 
240
}
 
241
 
 
242
void Screen::setMode(int m)
 
243
{
 
244
    currentModes[m] = true;
 
245
    switch(m)
 
246
    {
 
247
        case MODE_Origin : cuX = 0; cuY = _topMargin; break; //FIXME: home
 
248
    }
 
249
}
 
250
 
 
251
void Screen::resetMode(int m)
 
252
{
 
253
    currentModes[m] = false;
 
254
    switch(m)
 
255
    {
 
256
        case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home
 
257
    }
 
258
}
 
259
 
 
260
void Screen::saveMode(int m)
 
261
{
 
262
    savedModes[m] = currentModes[m];
 
263
}
 
264
 
 
265
void Screen::restoreMode(int m)
 
266
{
 
267
    currentModes[m] = savedModes[m];
 
268
}
 
269
 
 
270
bool Screen::getMode(int m) const
 
271
{
 
272
    return currentModes[m];
 
273
}
 
274
 
 
275
void Screen::saveCursor()
 
276
{
 
277
    savedState.cursorColumn = cuX;
 
278
    savedState.cursorLine  = cuY;
 
279
    savedState.rendition = currentRendition;
 
280
    savedState.foreground = currentForeground;
 
281
    savedState.background = currentBackground;
 
282
}
 
283
 
 
284
void Screen::restoreCursor()
 
285
{
 
286
    cuX     = qMin(savedState.cursorColumn,columns-1);
 
287
    cuY     = qMin(savedState.cursorLine,lines-1);
 
288
    currentRendition   = savedState.rendition; 
 
289
    currentForeground   = savedState.foreground;
 
290
    currentBackground   = savedState.background;
 
291
    updateEffectiveRendition();
 
292
}
 
293
 
 
294
void Screen::resizeImage(int new_lines, int new_columns)
 
295
{
 
296
    if ((new_lines==lines) && (new_columns==columns)) return;
 
297
 
 
298
    if (cuY > new_lines-1)
 
299
    { // attempt to preserve focus and lines
 
300
        _bottomMargin = lines-1; //FIXME: margin lost
 
301
        for (int i = 0; i < cuY-(new_lines-1); i++)
 
302
        {
 
303
            addHistLine(); scrollUp(0,1);
 
304
        }
 
305
    }
 
306
 
 
307
    // create new screen lines and copy from old to new
 
308
 
 
309
    ImageLine* newScreenLines = new ImageLine[new_lines+1];
 
310
    for (int i=0; i < qMin(lines-1,new_lines+1) ;i++)
 
311
        newScreenLines[i]=screenLines[i];
 
312
    for (int i=lines;(i > 0) && (i<new_lines+1);i++)
 
313
        newScreenLines[i].resize( new_columns );
 
314
 
 
315
    lineProperties.resize(new_lines+1);
 
316
    for (int i=lines;(i > 0) && (i<new_lines+1);i++)
 
317
        lineProperties[i] = LINE_DEFAULT;
 
318
 
 
319
    clearSelection();
 
320
 
 
321
    delete[] screenLines; 
 
322
    screenLines = newScreenLines;
 
323
 
 
324
    lines = new_lines;
 
325
    columns = new_columns;
 
326
    cuX = qMin(cuX,columns-1);
 
327
    cuY = qMin(cuY,lines-1);
 
328
 
 
329
    // FIXME: try to keep values, evtl.
 
330
    _topMargin=0;
 
331
    _bottomMargin=lines-1;
 
332
    initTabStops();
 
333
    clearSelection();
 
334
}
 
335
 
 
336
void Screen::setDefaultMargins()
 
337
{
 
338
    _topMargin = 0;
 
339
    _bottomMargin = lines-1;
 
340
}
 
341
 
 
342
 
 
343
/*
 
344
   Clarifying rendition here and in the display.
 
345
 
 
346
   currently, the display's color table is
 
347
   0       1       2 .. 9    10 .. 17
 
348
   dft_fg, dft_bg, dim 0..7, intensive 0..7
 
349
 
 
350
   currentForeground, currentBackground contain values 0..8;
 
351
   - 0    = default color
 
352
   - 1..8 = ansi specified color
 
353
 
 
354
   re_fg, re_bg contain values 0..17
 
355
   due to the TerminalDisplay's color table
 
356
 
 
357
   rendition attributes are
 
358
 
 
359
   attr           widget screen
 
360
   -------------- ------ ------
 
361
   RE_UNDERLINE     XX     XX    affects foreground only
 
362
   RE_BLINK         XX     XX    affects foreground only
 
363
   RE_BOLD          XX     XX    affects foreground only
 
364
   RE_REVERSE       --     XX
 
365
   RE_TRANSPARENT   XX     --    affects background only
 
366
   RE_INTENSIVE     XX     --    affects foreground only
 
367
 
 
368
   Note that RE_BOLD is used in both widget
 
369
   and screen rendition. Since xterm/vt102
 
370
   is to poor to distinguish between bold
 
371
   (which is a font attribute) and intensive
 
372
   (which is a color attribute), we translate
 
373
   this and RE_BOLD in falls eventually appart
 
374
   into RE_BOLD and RE_INTENSIVE.
 
375
   */
 
376
 
 
377
void Screen::reverseRendition(Character& p) const
 
378
 
379
    CharacterColor f = p.foregroundColor; 
 
380
    CharacterColor b = p.backgroundColor;
 
381
 
 
382
    p.foregroundColor = b; 
 
383
    p.backgroundColor = f; //p->r &= ~RE_TRANSPARENT;
 
384
}
 
385
 
 
386
void Screen::updateEffectiveRendition()
 
387
{
 
388
    effectiveRendition = currentRendition;
 
389
    if (currentRendition & RE_REVERSE)
 
390
    {
 
391
        effectiveForeground = currentBackground;
 
392
        effectiveBackground = currentForeground;
 
393
    }
 
394
    else
 
395
    {
 
396
        effectiveForeground = currentForeground;
 
397
        effectiveBackground = currentBackground;
 
398
    }
 
399
 
 
400
    if (currentRendition & RE_BOLD)
 
401
        effectiveForeground.toggleIntensive();
 
402
}
 
403
 
 
404
void Screen::copyFromHistory(Character* dest, int startLine, int count) const
 
405
{
 
406
    Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= history->getLines() );
 
407
 
 
408
    for (int line = startLine; line < startLine + count; line++) 
 
409
    {
 
410
        const int length = qMin(columns,history->getLineLen(line));
 
411
        const int destLineOffset  = (line-startLine)*columns;
 
412
 
 
413
        history->getCells(line,0,length,dest + destLineOffset);
 
414
 
 
415
        for (int column = length; column < columns; column++) 
 
416
            dest[destLineOffset+column] = defaultChar;
 
417
 
 
418
        // invert selected text
 
419
        if (selBegin !=-1)
 
420
        {
 
421
            for (int column = 0; column < columns; column++)
 
422
            {
 
423
                if (isSelected(column,line)) 
 
424
                {
 
425
                    reverseRendition(dest[destLineOffset + column]); 
 
426
                }
 
427
            }
 
428
        }
 
429
    }
 
430
}
 
431
 
 
432
void Screen::copyFromScreen(Character* dest , int startLine , int count) const
 
433
{
 
434
    Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= lines );
 
435
 
 
436
    for (int line = startLine; line < (startLine+count) ; line++)
 
437
    {
 
438
        int srcLineStartIndex  = line*columns;
 
439
        int destLineStartIndex = (line-startLine)*columns;
 
440
 
 
441
        for (int column = 0; column < columns; column++)
 
442
        { 
 
443
            int srcIndex = srcLineStartIndex + column; 
 
444
            int destIndex = destLineStartIndex + column;
 
445
 
 
446
            dest[destIndex] = screenLines[srcIndex/columns].value(srcIndex%columns,defaultChar);
 
447
 
 
448
            // invert selected text
 
449
            if (selBegin != -1 && isSelected(column,line + history->getLines()))
 
450
                reverseRendition(dest[destIndex]); 
 
451
        }
 
452
 
 
453
    }
 
454
}
 
455
 
 
456
void Screen::getImage( Character* dest, int size, int startLine, int endLine ) const
 
457
{
 
458
    Q_ASSERT( startLine >= 0 );
 
459
    Q_ASSERT( endLine >= startLine && endLine < history->getLines() + lines );
 
460
 
 
461
    const int mergedLines = endLine - startLine + 1;
 
462
 
 
463
    Q_ASSERT( size >= mergedLines * columns ); 
 
464
    Q_UNUSED( size );
 
465
 
 
466
    const int linesInHistoryBuffer = qBound(0,history->getLines()-startLine,mergedLines);
 
467
    const int linesInScreenBuffer = mergedLines - linesInHistoryBuffer;
 
468
 
 
469
    // copy lines from history buffer
 
470
    if (linesInHistoryBuffer > 0)
 
471
        copyFromHistory(dest,startLine,linesInHistoryBuffer); 
 
472
 
 
473
    // copy lines from screen buffer
 
474
    if (linesInScreenBuffer > 0)
 
475
        copyFromScreen(dest + linesInHistoryBuffer*columns,
 
476
                startLine + linesInHistoryBuffer - history->getLines(),
 
477
                linesInScreenBuffer);
 
478
 
 
479
    // invert display when in screen mode
 
480
    if (getMode(MODE_Screen))
 
481
    {
 
482
        for (int i = 0; i < mergedLines*columns; i++)
 
483
            reverseRendition(dest[i]); // for reverse display
 
484
    }
 
485
 
 
486
    // mark the character at the current cursor position
 
487
    int cursorIndex = loc(cuX, cuY + linesInHistoryBuffer);
 
488
    if(getMode(MODE_Cursor) && cursorIndex < columns*mergedLines)
 
489
        dest[cursorIndex].rendition |= RE_CURSOR;
 
490
}
 
491
 
 
492
QVector<LineProperty> Screen::getLineProperties( int startLine , int endLine ) const
 
493
{
 
494
    Q_ASSERT( startLine >= 0 ); 
 
495
    Q_ASSERT( endLine >= startLine && endLine < history->getLines() + lines );
 
496
 
 
497
    const int mergedLines = endLine-startLine+1;
 
498
    const int linesInHistory = qBound(0,history->getLines()-startLine,mergedLines);
 
499
    const int linesInScreen = mergedLines - linesInHistory;
 
500
 
 
501
    QVector<LineProperty> result(mergedLines);
 
502
    int index = 0;
 
503
 
 
504
    // copy properties for lines in history
 
505
    for (int line = startLine; line < startLine + linesInHistory; line++) 
 
506
    {
 
507
        //TODO Support for line properties other than wrapped lines
 
508
        if (history->isWrappedLine(line))
 
509
        {
 
510
            result[index] = (LineProperty)(result[index] | LINE_WRAPPED);
 
511
        }
 
512
        index++;
 
513
    }
 
514
 
 
515
    // copy properties for lines in screen buffer
 
516
    const int firstScreenLine = startLine + linesInHistory - history->getLines();
 
517
    for (int line = firstScreenLine; line < firstScreenLine+linesInScreen; line++)
 
518
    {
 
519
        result[index]=lineProperties[line];
 
520
        index++;
 
521
    }
 
522
 
 
523
    return result;
 
524
}
 
525
 
 
526
void Screen::reset(bool clearScreen)
 
527
{
 
528
    setMode(MODE_Wrap  ); saveMode(MODE_Wrap  );  // wrap at end of margin
 
529
    resetMode(MODE_Origin); saveMode(MODE_Origin);  // position refere to [1,1]
 
530
    resetMode(MODE_Insert); saveMode(MODE_Insert);  // overstroke
 
531
    setMode(MODE_Cursor);                         // cursor visible
 
532
    resetMode(MODE_Screen);                         // screen not inverse
 
533
    resetMode(MODE_NewLine);
 
534
 
 
535
    _topMargin=0;
 
536
    _bottomMargin=lines-1;
 
537
 
 
538
    setDefaultRendition();
 
539
    saveCursor();
 
540
 
 
541
    if ( clearScreen )
 
542
        clear();
 
543
}
 
544
 
 
545
void Screen::clear()
 
546
{
 
547
    clearEntireScreen();
 
548
    home();
 
549
}
 
550
 
 
551
void Screen::backspace()
 
552
{
 
553
    cuX = qMin(columns-1,cuX); // nowrap!
 
554
    cuX = qMax(0,cuX-1);
 
555
 
 
556
    if (screenLines[cuY].size() < cuX+1)
 
557
        screenLines[cuY].resize(cuX+1);
 
558
 
 
559
    if (BS_CLEARS) 
 
560
        screenLines[cuY][cuX].character = ' ';
 
561
}
 
562
 
 
563
void Screen::tab(int n)
 
564
{
 
565
    // note that TAB is a format effector (does not write ' ');
 
566
    if (n == 0) n = 1;
 
567
    while((n > 0) && (cuX < columns-1))
 
568
    {
 
569
        cursorRight(1); 
 
570
        while((cuX < columns-1) && !tabStops[cuX]) 
 
571
            cursorRight(1);
 
572
        n--;
 
573
    }
 
574
}
 
575
 
 
576
void Screen::backtab(int n)
 
577
{
 
578
    // note that TAB is a format effector (does not write ' ');
 
579
    if (n == 0) n = 1;
 
580
    while((n > 0) && (cuX > 0))
 
581
    {
 
582
        cursorLeft(1); while((cuX > 0) && !tabStops[cuX]) cursorLeft(1);
 
583
        n--;
 
584
    }
 
585
}
 
586
 
 
587
void Screen::clearTabStops()
 
588
{
 
589
    for (int i = 0; i < columns; i++) tabStops[i] = false;
 
590
}
 
591
 
 
592
void Screen::changeTabStop(bool set)
 
593
{
 
594
    if (cuX >= columns) return;
 
595
    tabStops[cuX] = set;
 
596
}
 
597
 
 
598
void Screen::initTabStops()
 
599
{
 
600
    tabStops.resize(columns);
 
601
 
 
602
    // Arrg! The 1st tabstop has to be one longer than the other.
 
603
    // i.e. the kids start counting from 0 instead of 1.
 
604
    // Other programs might behave correctly. Be aware.
 
605
    for (int i = 0; i < columns; i++) 
 
606
        tabStops[i] = (i%8 == 0 && i != 0);
 
607
}
 
608
 
 
609
void Screen::newLine()
 
610
{
 
611
    if (getMode(MODE_NewLine)) 
 
612
        toStartOfLine();
 
613
    index();
 
614
}
 
615
 
 
616
void Screen::checkSelection(int from, int to)
 
617
{
 
618
    if (selBegin == -1) 
 
619
        return;
 
620
    int scr_TL = loc(0, history->getLines());
 
621
    //Clear entire selection if it overlaps region [from, to]
 
622
    if ( (selBottomRight >= (from+scr_TL)) && (selTopLeft <= (to+scr_TL)) )
 
623
        clearSelection();
 
624
}
 
625
 
 
626
void Screen::displayCharacter(unsigned short c)
 
627
{
 
628
    // Note that VT100 does wrapping BEFORE putting the character.
 
629
    // This has impact on the assumption of valid cursor positions.
 
630
    // We indicate the fact that a newline has to be triggered by
 
631
    // putting the cursor one right to the last column of the screen.
 
632
 
 
633
    int w = konsole_wcwidth(c);
 
634
    if (w <= 0)
 
635
        return;
 
636
 
 
637
    if (cuX+w > columns) {
 
638
        if (getMode(MODE_Wrap)) {
 
639
            lineProperties[cuY] = (LineProperty)(lineProperties[cuY] | LINE_WRAPPED);
 
640
            nextLine();
 
641
        }
 
642
        else
 
643
            cuX = columns-w;
 
644
    }
 
645
 
 
646
    // ensure current line vector has enough elements
 
647
    int size = screenLines[cuY].size();
 
648
    if (size < cuX+w)
 
649
    {
 
650
        screenLines[cuY].resize(cuX+w);
 
651
    }
 
652
 
 
653
    if (getMode(MODE_Insert)) insertChars(w);
 
654
 
 
655
    lastPos = loc(cuX,cuY);
 
656
 
 
657
    // check if selection is still valid.
 
658
    checkSelection(lastPos, lastPos);
 
659
 
 
660
    Character& currentChar = screenLines[cuY][cuX];
 
661
 
 
662
    currentChar.character = c;
 
663
    currentChar.foregroundColor = effectiveForeground;
 
664
    currentChar.backgroundColor = effectiveBackground;
 
665
    currentChar.rendition = effectiveRendition;
 
666
 
 
667
    int i = 0;
 
668
    int newCursorX = cuX + w--;
 
669
    while(w)
 
670
    {
 
671
        i++;
 
672
 
 
673
        if ( screenLines[cuY].size() < cuX + i + 1 )
 
674
            screenLines[cuY].resize(cuX+i+1);
 
675
 
 
676
        Character& ch = screenLines[cuY][cuX + i];
 
677
        ch.character = 0;
 
678
        ch.foregroundColor = effectiveForeground;
 
679
        ch.backgroundColor = effectiveBackground;
 
680
        ch.rendition = effectiveRendition;
 
681
 
 
682
        w--;
 
683
    }
 
684
    cuX = newCursorX;
 
685
}
 
686
 
 
687
void Screen::compose(const QString& /*compose*/)
 
688
{
 
689
    Q_ASSERT( 0 /*Not implemented yet*/ );
 
690
 
 
691
    /*  if (lastPos == -1)
 
692
        return;
 
693
 
 
694
        QChar c(image[lastPos].character);
 
695
        compose.prepend(c);
 
696
    //compose.compose(); ### FIXME!
 
697
    image[lastPos].character = compose[0].unicode();*/
 
698
}
 
699
 
 
700
int Screen::scrolledLines() const
 
701
{
 
702
    return _scrolledLines;
 
703
}
 
704
int Screen::droppedLines() const
 
705
{
 
706
    return _droppedLines;
 
707
}
 
708
void Screen::resetDroppedLines()
 
709
{
 
710
    _droppedLines = 0;
 
711
}
 
712
void Screen::resetScrolledLines()
 
713
{
 
714
    _scrolledLines = 0;
 
715
}
 
716
 
 
717
void Screen::scrollUp(int n)
 
718
{
 
719
    if (n == 0) n = 1; // Default
 
720
    if (_topMargin == 0) addHistLine(); // history.history
 
721
    scrollUp(_topMargin, n);
 
722
}
 
723
 
 
724
QRect Screen::lastScrolledRegion() const
 
725
{
 
726
    return _lastScrolledRegion;
 
727
}
 
728
 
 
729
void Screen::scrollUp(int from, int n)
 
730
{
 
731
    if (n <= 0 || from + n > _bottomMargin) return;
 
732
 
 
733
    _scrolledLines -= n;
 
734
    _lastScrolledRegion = QRect(0,_topMargin,columns-1,(_bottomMargin-_topMargin));
 
735
 
 
736
    //FIXME: make sure `topMargin', `bottomMargin', `from', `n' is in bounds.
 
737
    moveImage(loc(0,from),loc(0,from+n),loc(columns-1,_bottomMargin));
 
738
    clearImage(loc(0,_bottomMargin-n+1),loc(columns-1,_bottomMargin),' ');
 
739
}
 
740
 
 
741
void Screen::scrollDown(int n)
 
742
{
 
743
    if (n == 0) n = 1; // Default
 
744
    scrollDown(_topMargin, n);
 
745
}
 
746
 
 
747
void Screen::scrollDown(int from, int n)
 
748
{
 
749
    _scrolledLines += n;
 
750
 
 
751
    //FIXME: make sure `topMargin', `bottomMargin', `from', `n' is in bounds.
 
752
    if (n <= 0) 
 
753
        return;
 
754
    if (from > _bottomMargin) 
 
755
        return;
 
756
    if (from + n > _bottomMargin) 
 
757
        n = _bottomMargin - from;
 
758
    moveImage(loc(0,from+n),loc(0,from),loc(columns-1,_bottomMargin-n));
 
759
    clearImage(loc(0,from),loc(columns-1,from+n-1),' ');
 
760
}
 
761
 
 
762
void Screen::setCursorYX(int y, int x)
 
763
{
 
764
    setCursorY(y); setCursorX(x);
 
765
}
 
766
 
 
767
void Screen::setCursorX(int x)
 
768
{
 
769
    if (x == 0) x = 1; // Default
 
770
    x -= 1; // Adjust
 
771
    cuX = qMax(0,qMin(columns-1, x));
 
772
}
 
773
 
 
774
void Screen::setCursorY(int y)
 
775
{
 
776
    if (y == 0) y = 1; // Default
 
777
    y -= 1; // Adjust
 
778
    cuY = qMax(0,qMin(lines  -1, y + (getMode(MODE_Origin) ? _topMargin : 0) ));
 
779
}
 
780
 
 
781
void Screen::home()
 
782
{
 
783
    cuX = 0;
 
784
    cuY = 0;
 
785
}
 
786
 
 
787
void Screen::toStartOfLine()
 
788
{
 
789
    cuX = 0;
 
790
}
 
791
 
 
792
int Screen::getCursorX() const
 
793
{
 
794
    return cuX;
 
795
}
 
796
 
 
797
int Screen::getCursorY() const
 
798
{
 
799
    return cuY;
 
800
}
 
801
 
 
802
void Screen::clearImage(int loca, int loce, char c)
 
803
 
804
    int scr_TL=loc(0,history->getLines());
 
805
    //FIXME: check positions
 
806
 
 
807
    //Clear entire selection if it overlaps region to be moved...
 
808
    if ( (selBottomRight > (loca+scr_TL) )&&(selTopLeft < (loce+scr_TL)) )
 
809
    {
 
810
        clearSelection();
 
811
    }
 
812
 
 
813
    int topLine = loca/columns;
 
814
    int bottomLine = loce/columns;
 
815
 
 
816
    Character clearCh(c,currentForeground,currentBackground,DEFAULT_RENDITION);
 
817
 
 
818
    //if the character being used to clear the area is the same as the
 
819
    //default character, the affected lines can simply be shrunk.
 
820
    bool isDefaultCh = (clearCh == Character());
 
821
 
 
822
    for (int y=topLine;y<=bottomLine;y++)
 
823
    {
 
824
        lineProperties[y] = 0;
 
825
 
 
826
        int endCol = ( y == bottomLine) ? loce%columns : columns-1;
 
827
        int startCol = ( y == topLine ) ? loca%columns : 0;
 
828
 
 
829
        QVector<Character>& line = screenLines[y];
 
830
 
 
831
        if ( isDefaultCh && endCol == columns-1 )
 
832
        {
 
833
            line.resize(startCol);
 
834
        }
 
835
        else
 
836
        {
 
837
            if (line.size() < endCol + 1)
 
838
                line.resize(endCol+1);
 
839
 
 
840
            Character* data = line.data();
 
841
            for (int i=startCol;i<=endCol;i++)
 
842
                data[i]=clearCh;
 
843
        }
 
844
    }
 
845
}
 
846
 
 
847
void Screen::moveImage(int dest, int sourceBegin, int sourceEnd)
 
848
{
 
849
    Q_ASSERT( sourceBegin <= sourceEnd );
 
850
 
 
851
    int lines=(sourceEnd-sourceBegin)/columns;
 
852
 
 
853
    //move screen image and line properties:
 
854
    //the source and destination areas of the image may overlap, 
 
855
    //so it matters that we do the copy in the right order - 
 
856
    //forwards if dest < sourceBegin or backwards otherwise.
 
857
    //(search the web for 'memmove implementation' for details)
 
858
    if (dest < sourceBegin)
 
859
    {
 
860
        for (int i=0;i<=lines;i++)
 
861
        {
 
862
            screenLines[ (dest/columns)+i ] = screenLines[ (sourceBegin/columns)+i ];
 
863
            lineProperties[(dest/columns)+i]=lineProperties[(sourceBegin/columns)+i];
 
864
        }
 
865
    }
 
866
    else
 
867
    {
 
868
        for (int i=lines;i>=0;i--)
 
869
        {
 
870
            screenLines[ (dest/columns)+i ] = screenLines[ (sourceBegin/columns)+i ];
 
871
            lineProperties[(dest/columns)+i]=lineProperties[(sourceBegin/columns)+i];
 
872
        }
 
873
    }
 
874
 
 
875
    if (lastPos != -1)
 
876
    {
 
877
        int diff = dest - sourceBegin; // Scroll by this amount
 
878
        lastPos += diff;
 
879
        if ((lastPos < 0) || (lastPos >= (lines*columns)))
 
880
            lastPos = -1;
 
881
    }
 
882
 
 
883
    // Adjust selection to follow scroll.
 
884
    if (selBegin != -1)
 
885
    {
 
886
        bool beginIsTL = (selBegin == selTopLeft);
 
887
        int diff = dest - sourceBegin; // Scroll by this amount
 
888
        int scr_TL=loc(0,history->getLines());
 
889
        int srca = sourceBegin+scr_TL; // Translate index from screen to global
 
890
        int srce = sourceEnd+scr_TL; // Translate index from screen to global
 
891
        int desta = srca+diff;
 
892
        int deste = srce+diff;
 
893
 
 
894
        if ((selTopLeft >= srca) && (selTopLeft <= srce))
 
895
            selTopLeft += diff;
 
896
        else if ((selTopLeft >= desta) && (selTopLeft <= deste))
 
897
            selBottomRight = -1; // Clear selection (see below)
 
898
 
 
899
        if ((selBottomRight >= srca) && (selBottomRight <= srce))
 
900
            selBottomRight += diff;
 
901
        else if ((selBottomRight >= desta) && (selBottomRight <= deste))
 
902
            selBottomRight = -1; // Clear selection (see below)
 
903
 
 
904
        if (selBottomRight < 0)
 
905
        {
 
906
            clearSelection();
 
907
        }
 
908
        else
 
909
        {
 
910
            if (selTopLeft < 0)
 
911
                selTopLeft = 0;
 
912
        }
 
913
 
 
914
        if (beginIsTL)
 
915
            selBegin = selTopLeft;
 
916
        else
 
917
            selBegin = selBottomRight;
 
918
    }
 
919
}
 
920
 
 
921
void Screen::clearToEndOfScreen()
 
922
{
 
923
    clearImage(loc(cuX,cuY),loc(columns-1,lines-1),' ');
 
924
}
 
925
 
 
926
void Screen::clearToBeginOfScreen()
 
927
{
 
928
    clearImage(loc(0,0),loc(cuX,cuY),' ');
 
929
}
 
930
 
 
931
void Screen::clearEntireScreen()
 
932
{
 
933
    // Add entire screen to history
 
934
    for (int i = 0; i < (lines-1); i++)
 
935
    {
 
936
        addHistLine(); scrollUp(0,1);
 
937
    }
 
938
 
 
939
    clearImage(loc(0,0),loc(columns-1,lines-1),' ');
 
940
}
 
941
 
 
942
/*! fill screen with 'E'
 
943
  This is to aid screen alignment
 
944
  */
 
945
 
 
946
void Screen::helpAlign()
 
947
{
 
948
    clearImage(loc(0,0),loc(columns-1,lines-1),'E');
 
949
}
 
950
 
 
951
void Screen::clearToEndOfLine()
 
952
{
 
953
    clearImage(loc(cuX,cuY),loc(columns-1,cuY),' ');
 
954
}
 
955
 
 
956
void Screen::clearToBeginOfLine()
 
957
{
 
958
    clearImage(loc(0,cuY),loc(cuX,cuY),' ');
 
959
}
 
960
 
 
961
void Screen::clearEntireLine()
 
962
{
 
963
    clearImage(loc(0,cuY),loc(columns-1,cuY),' ');
 
964
}
 
965
 
 
966
void Screen::setRendition(int re)
 
967
{
 
968
    currentRendition |= re;
 
969
    updateEffectiveRendition();
 
970
}
 
971
 
 
972
void Screen::resetRendition(int re)
 
973
{
 
974
    currentRendition &= ~re;
 
975
    updateEffectiveRendition();
 
976
}
 
977
 
 
978
void Screen::setDefaultRendition()
 
979
{
 
980
    setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
 
981
    setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
 
982
    currentRendition   = DEFAULT_RENDITION;
 
983
    updateEffectiveRendition();
 
984
}
 
985
 
 
986
void Screen::setForeColor(int space, int color)
 
987
{
 
988
    currentForeground = CharacterColor(space, color);
 
989
 
 
990
    if ( currentForeground.isValid() ) 
 
991
        updateEffectiveRendition();
 
992
    else 
 
993
        setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
 
994
}
 
995
 
 
996
void Screen::setBackColor(int space, int color)
 
997
{
 
998
    currentBackground = CharacterColor(space, color);
 
999
 
 
1000
    if ( currentBackground.isValid() ) 
 
1001
        updateEffectiveRendition();
 
1002
    else
 
1003
        setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
 
1004
}
 
1005
 
 
1006
void Screen::clearSelection() 
 
1007
{
 
1008
    selBottomRight = -1;
 
1009
    selTopLeft = -1;
 
1010
    selBegin = -1;
 
1011
}
 
1012
 
 
1013
void Screen::getSelectionStart(int& column , int& line) const
 
1014
{
 
1015
    if ( selTopLeft != -1 )
 
1016
    {
 
1017
        column = selTopLeft % columns;
 
1018
        line = selTopLeft / columns; 
 
1019
    }
 
1020
    else
 
1021
    {
 
1022
        column = cuX + getHistLines();
 
1023
        line = cuY + getHistLines();
 
1024
    }
 
1025
}
 
1026
void Screen::getSelectionEnd(int& column , int& line) const
 
1027
{
 
1028
    if ( selBottomRight != -1 )
 
1029
    {
 
1030
        column = selBottomRight % columns;
 
1031
        line = selBottomRight / columns;
 
1032
    }
 
1033
    else
 
1034
    {
 
1035
        column = cuX + getHistLines();
 
1036
        line = cuY + getHistLines();
 
1037
    } 
 
1038
}
 
1039
void Screen::setSelectionStart(const int x, const int y, const bool mode)
 
1040
{
 
1041
    selBegin = loc(x,y); 
 
1042
    /* FIXME, HACK to correct for x too far to the right... */
 
1043
    if (x == columns) selBegin--;
 
1044
 
 
1045
    selBottomRight = selBegin;
 
1046
    selTopLeft = selBegin;
 
1047
    blockSelectionMode = mode;
 
1048
}
 
1049
 
 
1050
void Screen::setSelectionEnd( const int x, const int y)
 
1051
{
 
1052
    if (selBegin == -1) 
 
1053
        return;
 
1054
 
 
1055
    int endPos =  loc(x,y); 
 
1056
 
 
1057
    if (endPos < selBegin)
 
1058
    {
 
1059
        selTopLeft = endPos;
 
1060
        selBottomRight = selBegin;
 
1061
    }
 
1062
    else
 
1063
    {
 
1064
        /* FIXME, HACK to correct for x too far to the right... */
 
1065
        if (x == columns) 
 
1066
            endPos--;
 
1067
 
 
1068
        selTopLeft = selBegin;
 
1069
        selBottomRight = endPos;
 
1070
    }
 
1071
 
 
1072
    // Normalize the selection in column mode
 
1073
    if (blockSelectionMode)
 
1074
    {
 
1075
        int topRow = selTopLeft / columns;
 
1076
        int topColumn = selTopLeft % columns;
 
1077
        int bottomRow = selBottomRight / columns;
 
1078
        int bottomColumn = selBottomRight % columns;
 
1079
 
 
1080
        selTopLeft = loc(qMin(topColumn,bottomColumn),topRow);
 
1081
        selBottomRight = loc(qMax(topColumn,bottomColumn),bottomRow);
 
1082
    }
 
1083
}
 
1084
 
 
1085
bool Screen::isSelected( const int x,const int y) const
 
1086
{
 
1087
    bool columnInSelection = true;
 
1088
    if (blockSelectionMode)
 
1089
    {
 
1090
        columnInSelection = x >= (selTopLeft % columns) &&
 
1091
            x <= (selBottomRight % columns);
 
1092
    }
 
1093
 
 
1094
    int pos = loc(x,y);
 
1095
    return pos >= selTopLeft && pos <= selBottomRight && columnInSelection;
 
1096
}
 
1097
 
 
1098
QString Screen::selectedText(bool preserveLineBreaks) const
 
1099
{
 
1100
    QString result;
 
1101
    QTextStream stream(&result, QIODevice::ReadWrite);
 
1102
 
 
1103
    PlainTextDecoder decoder;
 
1104
    decoder.begin(&stream);
 
1105
    writeSelectionToStream(&decoder , preserveLineBreaks);
 
1106
    decoder.end();
 
1107
 
 
1108
    return result;
 
1109
}
 
1110
 
 
1111
bool Screen::isSelectionValid() const
 
1112
{
 
1113
    return selTopLeft >= 0 && selBottomRight >= 0;
 
1114
}
 
1115
 
 
1116
void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder , 
 
1117
        bool preserveLineBreaks) const
 
1118
{
 
1119
    if (!isSelectionValid())
 
1120
        return;
 
1121
    writeToStream(decoder,selTopLeft,selBottomRight,preserveLineBreaks);
 
1122
}
 
1123
 
 
1124
void Screen::writeToStream(TerminalCharacterDecoder* decoder, 
 
1125
        int startIndex, int endIndex,
 
1126
        bool preserveLineBreaks) const
 
1127
{
 
1128
    int top = startIndex / columns;    
 
1129
    int left = startIndex % columns;
 
1130
 
 
1131
    int bottom = endIndex / columns;
 
1132
    int right = endIndex % columns;
 
1133
 
 
1134
    Q_ASSERT( top >= 0 && left >= 0 && bottom >= 0 && right >= 0 );
 
1135
 
 
1136
    for (int y=top;y<=bottom;y++)
 
1137
    {
 
1138
        int start = 0;
 
1139
        if ( y == top || blockSelectionMode ) start = left;
 
1140
 
 
1141
        int count = -1;
 
1142
        if ( y == bottom || blockSelectionMode ) count = right - start + 1;
 
1143
 
 
1144
        const bool appendNewLine = ( y != bottom );
 
1145
        int copied = copyLineToStream( y,
 
1146
                start,
 
1147
                count,
 
1148
                decoder, 
 
1149
                appendNewLine,
 
1150
                preserveLineBreaks );
 
1151
 
 
1152
        // if the selection goes beyond the end of the last line then
 
1153
        // append a new line character.
 
1154
        //
 
1155
        // this makes it possible to 'select' a trailing new line character after
 
1156
        // the text on a line.  
 
1157
        if ( y == bottom && 
 
1158
                copied < count    )
 
1159
        {
 
1160
            Character newLineChar('\n');
 
1161
            decoder->decodeLine(&newLineChar,1,0);
 
1162
        }
 
1163
    }    
 
1164
}
 
1165
 
 
1166
int Screen::copyLineToStream(int line , 
 
1167
        int start, 
 
1168
        int count,
 
1169
        TerminalCharacterDecoder* decoder,
 
1170
        bool appendNewLine,
 
1171
        bool preserveLineBreaks) const
 
1172
{
 
1173
    //buffer to hold characters for decoding
 
1174
    //the buffer is static to avoid initialising every 
 
1175
    //element on each call to copyLineToStream
 
1176
    //(which is unnecessary since all elements will be overwritten anyway)
 
1177
    static const int MAX_CHARS = 1024;
 
1178
    static Character characterBuffer[MAX_CHARS];
 
1179
 
 
1180
    assert( count < MAX_CHARS );
 
1181
 
 
1182
    LineProperty currentLineProperties = 0;
 
1183
 
 
1184
    //determine if the line is in the history buffer or the screen image
 
1185
    if (line < history->getLines())
 
1186
    {
 
1187
        const int lineLength = history->getLineLen(line);
 
1188
 
 
1189
        // ensure that start position is before end of line
 
1190
        start = qMin(start,qMax(0,lineLength-1));
 
1191
 
 
1192
        // retrieve line from history buffer.  It is assumed
 
1193
        // that the history buffer does not store trailing white space
 
1194
        // at the end of the line, so it does not need to be trimmed here 
 
1195
        if (count == -1)
 
1196
        {
 
1197
            count = lineLength-start;
 
1198
        }
 
1199
        else
 
1200
        {
 
1201
            count = qMin(start+count,lineLength)-start;
 
1202
        }
 
1203
 
 
1204
        // safety checks
 
1205
        assert( start >= 0 );
 
1206
        assert( count >= 0 );    
 
1207
        assert( (start+count) <= history->getLineLen(line) );
 
1208
 
 
1209
        history->getCells(line,start,count,characterBuffer);
 
1210
 
 
1211
        if ( history->isWrappedLine(line) )
 
1212
            currentLineProperties |= LINE_WRAPPED;
 
1213
    }
 
1214
    else
 
1215
    {
 
1216
        if ( count == -1 )
 
1217
            count = columns - start;
 
1218
 
 
1219
        assert( count >= 0 );
 
1220
 
 
1221
        const int screenLine = line-history->getLines();
 
1222
 
 
1223
        Character* data = screenLines[screenLine].data();
 
1224
        int length = screenLines[screenLine].count();
 
1225
 
 
1226
        //retrieve line from screen image
 
1227
        for (int i=start;i < qMin(start+count,length);i++)
 
1228
        {
 
1229
            characterBuffer[i-start] = data[i];
 
1230
        }
 
1231
 
 
1232
        // count cannot be any greater than length
 
1233
        count = qBound(0,count,length-start);
 
1234
 
 
1235
        Q_ASSERT( screenLine < lineProperties.count() );
 
1236
        currentLineProperties |= lineProperties[screenLine]; 
 
1237
    }
 
1238
 
 
1239
    // add new line character at end
 
1240
    const bool omitLineBreak = (currentLineProperties & LINE_WRAPPED) ||
 
1241
        !preserveLineBreaks;
 
1242
 
 
1243
    if ( !omitLineBreak && appendNewLine && (count+1 < MAX_CHARS) )
 
1244
    {
 
1245
        characterBuffer[count] = '\n';
 
1246
        count++;
 
1247
    }
 
1248
 
 
1249
    //decode line and write to text stream    
 
1250
    decoder->decodeLine( (Character*) characterBuffer , 
 
1251
            count, currentLineProperties );
 
1252
 
 
1253
    return count;
 
1254
}
 
1255
 
 
1256
void Screen::writeLinesToStream(TerminalCharacterDecoder* decoder, int fromLine, int toLine) const
 
1257
{
 
1258
    writeToStream(decoder,loc(0,fromLine),loc(columns-1,toLine));
 
1259
}
 
1260
 
 
1261
void Screen::addHistLine()
 
1262
{
 
1263
    // add line to history buffer
 
1264
    // we have to take care about scrolling, too...
 
1265
 
 
1266
    if (hasScroll())
 
1267
    {
 
1268
        int oldHistLines = history->getLines();
 
1269
 
 
1270
        history->addCellsVector(screenLines[0]);
 
1271
        history->addLine( lineProperties[0] & LINE_WRAPPED );
 
1272
 
 
1273
        int newHistLines = history->getLines();
 
1274
 
 
1275
        bool beginIsTL = (selBegin == selTopLeft);
 
1276
 
 
1277
        // If the history is full, increment the count
 
1278
        // of dropped lines
 
1279
        if ( newHistLines == oldHistLines )
 
1280
            _droppedLines++;
 
1281
 
 
1282
        // Adjust selection for the new point of reference
 
1283
        if (newHistLines > oldHistLines)
 
1284
        {
 
1285
            if (selBegin != -1)
 
1286
            {
 
1287
                selTopLeft += columns;
 
1288
                selBottomRight += columns;
 
1289
            }
 
1290
        }
 
1291
 
 
1292
        if (selBegin != -1)
 
1293
        {
 
1294
            // Scroll selection in history up
 
1295
            int top_BR = loc(0, 1+newHistLines);
 
1296
 
 
1297
            if (selTopLeft < top_BR)
 
1298
                selTopLeft -= columns;
 
1299
 
 
1300
            if (selBottomRight < top_BR)
 
1301
                selBottomRight -= columns;
 
1302
 
 
1303
            if (selBottomRight < 0)
 
1304
                clearSelection();
 
1305
            else
 
1306
            {
 
1307
                if (selTopLeft < 0)
 
1308
                    selTopLeft = 0;
 
1309
            }
 
1310
 
 
1311
            if (beginIsTL)
 
1312
                selBegin = selTopLeft;
 
1313
            else
 
1314
                selBegin = selBottomRight;
 
1315
        }
 
1316
    }
 
1317
 
 
1318
}
 
1319
 
 
1320
int Screen::getHistLines() const
 
1321
{
 
1322
    return history->getLines();
 
1323
}
 
1324
 
 
1325
void Screen::setScroll(const HistoryType& t , bool copyPreviousScroll)
 
1326
{
 
1327
    clearSelection();
 
1328
 
 
1329
    if ( copyPreviousScroll )
 
1330
        history = t.scroll(history);
 
1331
    else
 
1332
    {
 
1333
        HistoryScroll* oldScroll = history;
 
1334
        history = t.scroll(0);
 
1335
        delete oldScroll;
 
1336
    }
 
1337
}
 
1338
 
 
1339
bool Screen::hasScroll() const
 
1340
{
 
1341
    return history->hasScroll();
 
1342
}
 
1343
 
 
1344
const HistoryType& Screen::getScroll() const
 
1345
{
 
1346
    return history->getType();
 
1347
}
 
1348
 
 
1349
void Screen::setLineProperty(LineProperty property , bool enable)
 
1350
{
 
1351
    if ( enable )
 
1352
        lineProperties[cuY] = (LineProperty)(lineProperties[cuY] | property);
 
1353
    else
 
1354
        lineProperties[cuY] = (LineProperty)(lineProperties[cuY] & ~property);
 
1355
}
 
1356
void Screen::fillWithDefaultChar(Character* dest, int count)
 
1357
{
 
1358
    for (int i=0;i<count;i++)
 
1359
        dest[i] = defaultChar;
 
1360
}