00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00044 #include <stdio.h>
00045 #include <stdlib.h>
00046 #include <unistd.h>
00047
00048
00049 #include <assert.h>
00050 #include <string.h>
00051 #include <ctype.h>
00052
00053 #include "screen.h"
00054
00055 #define HERE printf("%s(%d): here\n",__FILE__,__LINE__)
00056
00057
00058
00059 #define BS_CLEARS FALSE
00060
00061 #define loc(X,Y) ((Y)*columns+(X))
00062
00066 Screen::Screen(int lines, int columns)
00067 {
00068 this->lines = lines;
00069 this->columns = columns;
00070
00071 image = QArray<Character>( lines*columns );
00072 tabstops = NULL; initTabStops();
00073
00074 histCursor = 0;
00075
00076 clearSelection();
00077 reset();
00078 }
00079
00083 Screen::~Screen()
00084 {
00085 delete image;
00086 if (tabstops) free(tabstops);
00087 }
00088
00089
00090
00091
00092
00093
00094
00095
00096
00113 void Screen::cursorUp(int n)
00114
00115 {
00116 if (n == 0) n = 1;
00117 int stop = cuY < tmargin ? 0 : tmargin;
00118 cuX = QMIN(columns-1,cuX);
00119 cuY = QMAX(stop,cuY-n);
00120 }
00121
00128 void Screen::cursorDown(int n)
00129
00130 {
00131 if (n == 0) n = 1;
00132 int stop = cuY > bmargin ? lines-1 : bmargin;
00133 cuX = QMIN(columns-1,cuX);
00134 cuY = QMIN(stop,cuY+n);
00135 }
00136
00143 void Screen::cursorLeft(int n)
00144
00145 {
00146 if (n == 0) n = 1;
00147 cuX = QMIN(columns-1,cuX);
00148 cuX = QMAX(0,cuX-n);
00149 }
00150
00157 void Screen::cursorRight(int n)
00158
00159 {
00160 if (n == 0) n = 1;
00161 cuX = QMIN(columns-1,cuX+n);
00162 }
00163
00168 void Screen::setMargins(int top, int bot)
00169
00170 {
00171 if (top == 0) top = 1;
00172 if (bot == 0) bot = lines;
00173 top = top - 1;
00174 bot = bot - 1;
00175 if ( !( 0 <= top && top < bot && bot < lines ) )
00176 { fprintf(stderr,"%s(%d) : setRegion(%d,%d) : bad range.\n",
00177 __FILE__,__LINE__,top,bot);
00178 return;
00179 }
00180 tmargin = top;
00181 bmargin = bot;
00182 cuX = 0;
00183 cuY = getMode(MODE_Origin) ? top : 0;
00184 }
00185
00193 void Screen::index()
00194
00195 {
00196 if (cuY == bmargin)
00197 {
00198 if (tmargin == 0 && bmargin == lines-1) addHistLine();
00199 scrollUp(tmargin,1);
00200 }
00201 else if (cuY < lines-1)
00202 cuY += 1;
00203 }
00204
00212 void Screen::reverseIndex()
00213
00214 {
00215 if (cuY == tmargin)
00216 scrollDown(tmargin,1);
00217 else if (cuY > 0)
00218 cuY -= 1;
00219 }
00220
00228 void Screen::NextLine()
00229
00230 {
00231 Return(); index();
00232 }
00233
00234
00235
00244 void Screen::eraseChars(int n)
00245 {
00246 if (n == 0) n = 1;
00247 int p = QMAX(0,QMIN(cuX+n-1,columns-1));
00248 clearImage(loc(cuX,cuY),loc(p,cuY),' ');
00249 }
00250
00256 void Screen::deleteChars(int n)
00257 {
00258 if (n == 0) n = 1;
00259 int p = QMAX(0,QMIN(cuX+n,columns-1));
00260 moveImage(loc(cuX,cuY),loc(p,cuY),loc(columns-1,cuY));
00261 clearImage(loc(columns-n,cuY),loc(columns-1,cuY),' ');
00262 }
00263
00269 void Screen::insertChars(int n)
00270 {
00271 if (n == 0) n = 1;
00272 int p = QMAX(0,QMIN(columns-1-n,columns-1));
00273 int q = QMAX(0,QMIN(cuX+n,columns-1));
00274 moveImage(loc(q,cuY),loc(cuX,cuY),loc(p,cuY));
00275 clearImage(loc(cuX,cuY),loc(q-1,cuY),' ');
00276 }
00277
00283 void Screen::deleteLines(int n)
00284 {
00285 if (n == 0) n = 1;
00286 scrollUp(cuY,n);
00287 }
00288
00294 void Screen::insertLines(int n)
00295 {
00296 if (n == 0) n = 1;
00297 scrollDown(cuY,n);
00298 }
00299
00300
00301
00304 void Screen::setMode(int m)
00305 {
00306 currParm.mode[m] = TRUE;
00307 switch(m)
00308 {
00309 case MODE_Origin : cuX = 0; cuY = tmargin; break;
00310 }
00311 }
00312
00315 void Screen::resetMode(int m)
00316 {
00317 currParm.mode[m] = FALSE;
00318 switch(m)
00319 {
00320 case MODE_Origin : cuX = 0; cuY = 0; break;
00321 }
00322 }
00323
00326 void Screen::saveMode(int m)
00327 {
00328 saveParm.mode[m] = currParm.mode[m];
00329 }
00330
00333 void Screen::restoreMode(int m)
00334 {
00335 currParm.mode[m] = saveParm.mode[m];
00336 }
00337
00338
00340 BOOL Screen::getMode(int m)
00341 {
00342 return currParm.mode[m];
00343 }
00344
00347 void Screen::saveCursor()
00348 {
00349 sa_cuX = cuX;
00350 sa_cuY = cuY;
00351 sa_cu_re = cu_re;
00352 sa_cu_fg = cu_fg;
00353 sa_cu_bg = cu_bg;
00354 }
00355
00358 void Screen::restoreCursor()
00359 {
00360 cuX = QMIN(sa_cuX,columns-1);
00361 cuY = QMIN(sa_cuY,lines-1);
00362 cu_re = sa_cu_re;
00363 cu_fg = sa_cu_fg;
00364 cu_bg = sa_cu_bg;
00365 effectiveRendition();
00366 }
00367
00368
00369
00370
00371
00372
00373
00384 void Screen::resizeImage(int new_lines, int new_columns)
00385 {
00386
00387 if (cuY > new_lines-1)
00388 {
00389 bmargin = lines-1;
00390 for (int i = 0; i < cuY-(new_lines-1); i++)
00391 {
00392 addHistLine(); scrollUp(0,1);
00393 }
00394 }
00395
00396
00397 QArray<Character> newimg = QArray<Character>( new_lines * new_columns );
00398
00399 clearSelection();
00400
00401
00402 for (int y = 0; y < new_lines; y++)
00403 for (int x = 0; x < new_columns; x++)
00404 {
00405 newimg[y*new_columns+x].c = ' ';
00406 newimg[y*new_columns+x].f = DEFAULT_FORE_COLOR;
00407 newimg[y*new_columns+x].b = DEFAULT_BACK_COLOR;
00408 newimg[y*new_columns+x].r = DEFAULT_RENDITION;
00409 }
00410 int cpy_lines = QMIN(new_lines, lines);
00411 int cpy_columns = QMIN(new_columns,columns);
00412
00413 for (int y = 0; y < cpy_lines; y++)
00414 for (int x = 0; x < cpy_columns; x++)
00415 {
00416 newimg[y*new_columns+x].c = image[loc(x,y)].c;
00417 newimg[y*new_columns+x].f = image[loc(x,y)].f;
00418 newimg[y*new_columns+x].b = image[loc(x,y)].b;
00419 newimg[y*new_columns+x].r = image[loc(x,y)].r;
00420 }
00421 delete image;
00422 image = newimg;
00423 lines = new_lines;
00424 columns = new_columns;
00425 cuX = QMIN(cuX,columns-1);
00426 cuY = QMIN(cuY,lines-1);
00427
00428
00429 tmargin=0;
00430 bmargin=lines-1;
00431 initTabStops();
00432 clearSelection();
00433 }
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469 void Screen::reverseRendition(Character *p)
00470 { UINT8 f = p->f; UINT8 b = p->b;
00471 p->f = b; p->b = f;
00472 }
00473
00474 void Screen::effectiveRendition()
00475
00476 {
00477 ef_re = cu_re & (RE_UNDERLINE | RE_BLINK);
00478 if (cu_re & RE_REVERSE)
00479 {
00480 ef_fg = cu_bg;
00481 ef_bg = cu_fg;
00482 }
00483 else
00484 {
00485 ef_fg = cu_fg;
00486 ef_bg = cu_bg;
00487 }
00488 if (cu_re & RE_BOLD)
00489 {
00490 if (ef_fg < BASE_COLORS)
00491 ef_fg += BASE_COLORS;
00492 else
00493 ef_fg -= BASE_COLORS;
00494 }
00495 }
00496
00507 QArray<Character> Screen::getCookedImage()
00508 { int x,y;
00509 Character* merged = (Character*) malloc( lines * columns * sizeof( Character ) );
00510 Character dft(' ',DEFAULT_FORE_COLOR,DEFAULT_BACK_COLOR,DEFAULT_RENDITION);
00511
00512 for (y = 0; (y < lines) && (y < (hist.getLines()-histCursor)); y++)
00513 {
00514 int len = QMIN(columns,hist.getLineLen(y+histCursor));
00515 int yp = y*columns;
00516 int yq = (y+histCursor)*columns;
00517
00518 hist.getCells( y+histCursor, 0, len, merged+yp );
00519 for (x = len; x < columns; x++) merged[yp+x] = dft;
00520 for (x = 0; x < columns; x++)
00521 { int p=x + yp; int q=x + yq;
00522 if ( ( q >= sel_TL ) && ( q <= sel_BR ) )
00523 reverseRendition(&merged[p]);
00524 }
00525 }
00526 if (lines >= hist.getLines()-histCursor)
00527 {
00528 for (y = (hist.getLines()-histCursor); y < lines ; y++)
00529 {
00530 int yp = y*columns;
00531 int yq = (y+histCursor)*columns;
00532 int yr = (y-hist.getLines()+histCursor)*columns;
00533 for (x = 0; x < columns; x++)
00534 { int p = x + yp; int q = x + yq; int r = x + yr;
00535 merged[p] = image[r];
00536 if ( q >= sel_TL && q <= sel_BR )
00537 reverseRendition(&merged[p]);
00538 }
00539
00540 }
00541 }
00542
00543 if (getMode(MODE_Screen))
00544 { int i,n = lines*columns;
00545 for (i = 0; i < n; i++)
00546 reverseRendition(&merged[i]);
00547 }
00548 if (getMode(MODE_Cursor) && (cuY+(hist.getLines()-histCursor) < lines))
00549 reverseRendition(&merged[loc(cuX,cuY+(hist.getLines()-histCursor))]);
00550 QArray<Character> res( sizeof( merged ) / sizeof( Character ) );
00551 res.assign( merged, sizeof( merged ) / sizeof( Character ) );
00552 return res;
00553 }
00554
00555
00559 void Screen::reset()
00560 {
00561 setMode(MODE_Wrap ); saveMode(MODE_Wrap );
00562 resetMode(MODE_Origin); saveMode(MODE_Origin);
00563 resetMode(MODE_Insert); saveMode(MODE_Insert);
00564 setMode(MODE_Cursor);
00565 resetMode(MODE_Screen);
00566 resetMode(MODE_NewLine);
00567
00568 tmargin=0;
00569 bmargin=lines-1;
00570
00571 setDefaultRendition();
00572 saveCursor();
00573
00574 clear();
00575 }
00576
00580 void Screen::clear()
00581 {
00582 clearEntireScreen();
00583 home();
00584 }
00585
00589 void Screen::BackSpace()
00590 {
00591 cuX = QMAX(0,cuX-1);
00592 if (BS_CLEARS) image[loc(cuX,cuY)].c = ' ';
00593 }
00594
00598 void Screen::Tabulate()
00599 {
00600
00601 cursorRight(1); while(cuX < columns-1 && !tabstops[cuX]) cursorRight(1);
00602 }
00603
00604 void Screen::clearTabStops()
00605 {
00606 for (int i = 0; i < columns; i++) tabstops[i-1] = FALSE;
00607 }
00608
00609 void Screen::changeTabStop(bool set)
00610 {
00611 if (cuX >= columns) return;
00612 tabstops[cuX] = set;
00613 }
00614
00615 void Screen::initTabStops()
00616 {
00617 if (tabstops) free(tabstops);
00618 tabstops = (bool*)malloc(columns*sizeof(bool));
00619
00620
00621
00622 for (int i = 0; i < columns; i++) tabstops[i] = (i%8 == 0 && i != 0);
00623 }
00624
00631 void Screen::NewLine()
00632 {
00633 if (getMode(MODE_NewLine)) Return();
00634 index();
00635 }
00636
00643 void Screen::checkSelection(int from, int to)
00644 {
00645 if (sel_begin == -1) return;
00646 int scr_TL = loc(0, hist.getLines());
00647
00648 if ( (sel_BR > (from+scr_TL) )&&(sel_TL < (to+scr_TL)) )
00649 {
00650 clearSelection();
00651 }
00652 }
00653
00654 void Screen::ShowCharacter(unsigned short c)
00655 {
00656
00657
00658
00659
00660
00661 if (cuX >= columns)
00662 {
00663 if (getMode(MODE_Wrap)) NextLine(); else cuX = columns-1;
00664 }
00665
00666 if (getMode(MODE_Insert)) insertChars(1);
00667
00668 int i = loc(cuX,cuY);
00669
00670 checkSelection(i, i);
00671
00672 image[i].c = c;
00673 image[i].f = ef_fg;
00674 image[i].b = ef_bg;
00675 image[i].r = ef_re;
00676
00677 cuX += 1;
00678 }
00679
00680
00681
00682
00688 void Screen::scrollUp(int from, int n)
00689 {
00690 if (n <= 0 || from + n > bmargin) return;
00691
00692 moveImage(loc(0,from),loc(0,from+n),loc(columns-1,bmargin));
00693 clearImage(loc(0,bmargin-n+1),loc(columns-1,bmargin),' ');
00694 }
00695
00701 void Screen::scrollDown(int from, int n)
00702 {
00703
00704 if (n <= 0) return;
00705 if (from > bmargin) return;
00706 if (from + n > bmargin) n = bmargin - from;
00707 moveImage(loc(0,from+n),loc(0,from),loc(columns-1,bmargin-n));
00708 clearImage(loc(0,from),loc(columns-1,from+n-1),' ');
00709 }
00710
00712 void Screen::setCursorYX(int y, int x)
00713 {
00714 setCursorY(y); setCursorX(x);
00715 }
00716
00719 void Screen::setCursorX(int x)
00720 {
00721 if (x == 0) x = 1;
00722 x -= 1;
00723 cuX = QMAX(0,QMIN(columns-1, x));
00724 }
00725
00728 void Screen::setCursorY(int y)
00729 {
00730 if (y == 0) y = 1;
00731 y -= 1;
00732 cuY = QMAX(0,QMIN(lines -1, y + (getMode(MODE_Origin) ? tmargin : 0) ));
00733 }
00734
00738 void Screen::home()
00739 {
00740 cuX = 0;
00741 cuY = 0;
00742 }
00743
00747 void Screen::Return()
00748 {
00749 cuX = 0;
00750 }
00751
00755 int Screen::getCursorX()
00756 {
00757 return cuX;
00758 }
00759
00763 int Screen::getCursorY()
00764 {
00765 return cuY;
00766 }
00767
00768
00769
00786 void Screen::clearImage(int loca, int loce, char c)
00787 { int i;
00788 int scr_TL=loc(0,hist.getLines());
00789
00790
00791
00792 if ( (sel_BR > (loca+scr_TL) )&&(sel_TL < (loce+scr_TL)) )
00793 {
00794 clearSelection();
00795 }
00796 for (i = loca; i <= loce; i++)
00797 {
00798 image[i].c = c;
00799 image[i].f = ef_fg;
00800 image[i].b = ef_bg;
00801 image[i].r = ef_re;
00802 }
00803 }
00804
00812 void Screen::moveImage(int dst, int loca, int loce)
00813 {
00814
00815 if (loce < loca) {
00816
00817 return;
00818 }
00819 memmove(&image[dst],&image[loca],(loce-loca+1)*sizeof(Character));
00820 }
00821
00825 void Screen::clearToEndOfScreen()
00826 {
00827 clearImage(loc(cuX,cuY),loc(columns-1,lines-1),' ');
00828 }
00829
00833 void Screen::clearToBeginOfScreen()
00834 {
00835 clearImage(loc(0,0),loc(cuX,cuY),' ');
00836 }
00837
00841 void Screen::clearEntireScreen()
00842 {
00843 clearImage(loc(0,0),loc(columns-1,lines-1),' ');
00844 }
00845
00850 void Screen::helpAlign()
00851 {
00852 clearImage(loc(0,0),loc(columns-1,lines-1),'E');
00853 }
00854
00858 void Screen::clearToEndOfLine()
00859 {
00860 clearImage(loc(cuX,cuY),loc(columns-1,cuY),' ');
00861 }
00862
00866 void Screen::clearToBeginOfLine()
00867 {
00868 clearImage(loc(0,cuY),loc(cuX,cuY),' ');
00869 }
00870
00874 void Screen::clearEntireLine()
00875 {
00876 clearImage(loc(0,cuY),loc(columns-1,cuY),' ');
00877 }
00878
00879
00880
00885 void Screen::setRendition(int re)
00886 {
00887 cu_re |= re;
00888 effectiveRendition();
00889 }
00890
00895 void Screen::resetRendition(int re)
00896 {
00897 cu_re &= ~re;
00898 effectiveRendition();
00899 }
00900
00904 void Screen::setDefaultRendition()
00905 {
00906 setForeColorToDefault();
00907 setBackColorToDefault();
00908 cu_re = DEFAULT_RENDITION;
00909 effectiveRendition();
00910 }
00911
00915 void Screen::setForeColor(int fgcolor)
00916 {
00917 cu_fg = (fgcolor&7)+((fgcolor&8) ? 4+8 : 2);
00918 effectiveRendition();
00919 }
00920
00924 void Screen::setBackColor(int bgcolor)
00925 {
00926 cu_bg = (bgcolor&7)+((bgcolor&8) ? 4+8 : 2);
00927 effectiveRendition();
00928 }
00929
00933 void Screen::setBackColorToDefault()
00934 {
00935 cu_bg = DEFAULT_BACK_COLOR;
00936 effectiveRendition();
00937 }
00938
00942 void Screen::setForeColorToDefault()
00943 {
00944 cu_fg = DEFAULT_FORE_COLOR;
00945 effectiveRendition();
00946 }
00947
00948
00949
00950
00951
00952
00953
00954 void Screen::clearSelection()
00955 {
00956 sel_BR = -1;
00957 sel_TL = -1;
00958 sel_begin = -1;
00959 }
00960
00961 void Screen::setSelBeginXY(const int x, const int y)
00962 {
00963 sel_begin = loc(x,y+histCursor) ;
00964 sel_BR = sel_begin;
00965 sel_TL = sel_begin;
00966 }
00967
00968 void Screen::setSelExtentXY(const int x, const int y)
00969 {
00970 if (sel_begin == -1) return;
00971 int l = loc(x,y + histCursor);
00972
00973 if (l < sel_begin)
00974 {
00975 sel_TL = l;
00976 sel_BR = sel_begin;
00977 }
00978 else
00979 {
00980
00981 if (( x == columns )|| (x == 0)) l--;
00982
00983 sel_TL = sel_begin;
00984 sel_BR = l;
00985 }
00986 }
00987
00988 QString Screen::getSelText(const BOOL preserve_line_breaks)
00989 {
00990 if (sel_begin == -1)
00991 return QString::null;
00992
00993 int *m;
00994 int s, d;
00995 int hist_BR = loc(0, hist.getLines());
00996 int hY = sel_TL / columns;
00997 int hX = sel_TL % columns;
00998 int eol;
00999
01000 s = sel_TL;
01001
01002
01003
01004 d = (sel_BR - sel_TL) / columns + 1;
01005 m = new int[d * (columns + 1) + 2];
01006 d = 0;
01007
01008 while (s <= sel_BR)
01009 {
01010 if (s < hist_BR)
01011 {
01012
01013 eol = hist.getLineLen(hY);
01014
01015 if ((hY == (sel_BR / columns)) &&
01016 (eol >= (sel_BR % columns)))
01017 {
01018 eol = sel_BR % columns + 1;
01019 }
01020
01021 while (hX < eol)
01022 {
01023 m[d++] = hist.getCell(hY, hX++).c;
01024 s++;
01025 }
01026
01027 if (s <= sel_BR)
01028 {
01029
01030
01031
01032 if (eol % columns == 0)
01033 {
01034
01035
01036 if (eol == 0)
01037 {
01038 m[d++] = '\n';
01039 }
01040 else
01041 {
01042
01043
01044
01045 }
01046 }
01047 else if ((eol + 1) % columns == 0)
01048 {
01049
01050
01051
01052 m[d++] = ' ';
01053 }
01054 else
01055 {
01056
01057
01058
01059 m[d++] = preserve_line_breaks ? '\n' : ' ';
01060 }
01061 }
01062
01063 hY++;
01064 hX = 0;
01065 s = hY * columns;
01066 }
01067 else
01068 {
01069 eol = (s / columns + 1) * columns - 1;
01070
01071 if (eol < sel_BR)
01072 {
01073 while ((eol > s) &&
01074 isspace(image[eol - hist_BR].c))
01075 {
01076 eol--;
01077 }
01078 }
01079 else
01080 {
01081 eol = sel_BR;
01082 }
01083
01084 while (s <= eol)
01085 {
01086 m[d++] = image[s++ - hist_BR].c;
01087 }
01088
01089 if (eol < sel_BR)
01090 {
01091
01092 if ((eol + 1) % columns == 0)
01093 {
01094 if (image[eol - hist_BR].c == ' ')
01095 {
01096 m[d++] = ' ';
01097 }
01098 }
01099 else
01100 {
01101 m[d++] = ((preserve_line_breaks ||
01102 ((eol % columns) == 0)) ?
01103 '\n' : ' ');
01104 }
01105 }
01106
01107 s = (eol / columns + 1) * columns;
01108 }
01109 }
01110
01111 QChar* qc = new QChar[d];
01112
01113 for (int i = 0; i < d; i++)
01114 {
01115 qc[i] = m[i];
01116 }
01117
01118 QString res(qc, d);
01119
01120 delete m;
01121 delete qc;
01122
01123 return res;
01124 }
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150 void Screen::addHistLine()
01151 {
01152 assert(hasScroll() || histCursor == 0);
01153
01154
01155
01156
01157 if (hasScroll())
01158 { Character dft;
01159
01160 int end = columns-1;
01161 while (end >= 0 && image[end] == dft)
01162 end -= 1;
01163
01164 hist.addCells(image.data(), end+1);
01165 hist.addLine();
01166
01167
01168 histCursor += (hist.getLines()-1 == histCursor);
01169 }
01170
01171 if (!hasScroll()) histCursor = 0;
01172 }
01173
01174 void Screen::setHistCursor(int cursor)
01175 {
01176 histCursor = cursor;
01177 }
01178
01179 int Screen::getHistCursor()
01180 {
01181 return histCursor;
01182 }
01183
01184 int Screen::getHistLines()
01185 {
01186 return hist.getLines();
01187 }
01188
01189 void Screen::setScroll(bool on)
01190 {
01191 histCursor = 0;
01192 clearSelection();
01193 hist.setScroll(on);
01194 }
01195
01196 bool Screen::hasScroll()
01197 {
01198 return hist.hasScroll();
01199 }