Home | History | Annotate | Download | only in terminal
      1 /*
      2  * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
      3  *
      4  * (c) Matthias L. Jugel, Marcus Meiner 1996-2005. All Rights Reserved.
      5  *
      6  * Please visit http://javatelnet.org/ for updates and contact.
      7  *
      8  * --LICENSE NOTICE--
      9  * This program is free software; you can redistribute it and/or
     10  * modify it under the terms of the GNU General Public License
     11  * as published by the Free Software Foundation; either version 2
     12  * of the License, or (at your option) any later version.
     13  *
     14  * This program is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  * GNU General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU General Public License
     20  * along with this program; if not, write to the Free Software
     21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     22  * --LICENSE NOTICE--
     23  *
     24  */
     25 
     26 package de.mud.terminal;
     27 
     28 import java.util.Arrays;
     29 
     30 /**
     31  * Implementation of a Video Display Unit (VDU) buffer. This class contains all methods to
     32  * manipulate the buffer that stores characters and their attributes as well as the regions
     33  * displayed.
     34  *
     35  * @author Matthias L. Jugel, Marcus Meiner
     36  * @version $Id: VDUBuffer.java 503 2005-10-24 07:34:13Z marcus $
     37  */
     38 public class VDUBuffer {
     39 
     40   /** The current version id tag */
     41   public final static String ID = "$Id: VDUBuffer.java 503 2005-10-24 07:34:13Z marcus $";
     42 
     43   /** Enable debug messages. */
     44   public final static int debug = 0;
     45 
     46   public int height, width; /* rows and columns */
     47   public boolean[] update; /* contains the lines that need update */
     48   public char[][] charArray; /* contains the characters */
     49   public int[][] charAttributes; /* contains character attrs */
     50   public int bufSize;
     51   public int maxBufSize; /* buffer sizes */
     52   public int screenBase; /* the actual screen start */
     53   public int windowBase; /* where the start displaying */
     54   public int scrollMarker; /* marks the last line inserted */
     55 
     56   private int topMargin; /* top scroll margin */
     57   private int bottomMargin; /* bottom scroll margin */
     58 
     59   // cursor variables
     60   protected boolean showcursor = true;
     61   protected int cursorX, cursorY;
     62 
     63   /** Scroll up when inserting a line. */
     64   public final static boolean SCROLL_UP = false;
     65   /** Scroll down when inserting a line. */
     66   public final static boolean SCROLL_DOWN = true;
     67 
     68   /*
     69    * Attributes bit-field usage:
     70    *
     71    * 8421 8421 8421 8421 8421 8421 8421 8421 |||| |||| |||| |||| |||| |||| |||| |||`- Bold |||| ||||
     72    * |||| |||| |||| |||| |||| ||`-- Underline |||| |||| |||| |||| |||| |||| |||| |`--- Invert ||||
     73    * |||| |||| |||| |||| |||| |||| `---- Low |||| |||| |||| |||| |||| |||| |||`------ Invisible ||||
     74    * |||| |||| |||| ||`+-++++-+++------- Foreground Color |||| |||| |`++-++++-++------------------
     75    * Background Color |||| |||| `----------------------------- Fullwidth character
     76    * `+++-++++------------------------------- Reserved for future use
     77    */
     78 
     79   /** Make character normal. */
     80   public final static int NORMAL = 0x00;
     81   /** Make character bold. */
     82   public final static int BOLD = 0x01;
     83   /** Underline character. */
     84   public final static int UNDERLINE = 0x02;
     85   /** Invert character. */
     86   public final static int INVERT = 0x04;
     87   /** Lower intensity character. */
     88   public final static int LOW = 0x08;
     89   /** Invisible character. */
     90   public final static int INVISIBLE = 0x10;
     91   /** Unicode full-width character (CJK, et al.) */
     92   public final static int FULLWIDTH = 0x8000000;
     93 
     94   /** how much to left shift the foreground color */
     95   public final static int COLOR_FG_SHIFT = 5;
     96   /** how much to left shift the background color */
     97   public final static int COLOR_BG_SHIFT = 14;
     98   /** color mask */
     99   public final static int COLOR = 0x7fffe0; /* 0000 0000 0111 1111 1111 1111 1110 0000 */
    100   /** foreground color mask */
    101   public final static int COLOR_FG = 0x3fe0; /* 0000 0000 0000 0000 0011 1111 1110 0000 */
    102   /** background color mask */
    103   public final static int COLOR_BG = 0x7fc000; /* 0000 0000 0111 1111 1100 0000 0000 0000 */
    104 
    105   /**
    106    * Create a new video display buffer with the passed width and height in characters.
    107    *
    108    * @param width
    109    *          the length of the character lines
    110    * @param height
    111    *          the amount of lines on the screen
    112    */
    113   public VDUBuffer(int width, int height) {
    114     // set the display screen size
    115     setScreenSize(width, height, false);
    116   }
    117 
    118   /**
    119    * Create a standard video display buffer with 80 columns and 24 lines.
    120    */
    121   public VDUBuffer() {
    122     this(80, 24);
    123   }
    124 
    125   /**
    126    * Put a character on the screen with normal font and outline. The character previously on that
    127    * position will be overwritten. You need to call redraw() to update the screen.
    128    *
    129    * @param c
    130    *          x-coordinate (column)
    131    * @param l
    132    *          y-coordinate (line)
    133    * @param ch
    134    *          the character to show on the screen
    135    * @see #insertChar
    136    * @see #deleteChar
    137    * @see #redraw
    138    */
    139   public void putChar(int c, int l, char ch) {
    140     putChar(c, l, ch, NORMAL);
    141   }
    142 
    143   /**
    144    * Put a character on the screen with specific font and outline. The character previously on that
    145    * position will be overwritten. You need to call redraw() to update the screen.
    146    *
    147    * @param c
    148    *          x-coordinate (column)
    149    * @param l
    150    *          y-coordinate (line)
    151    * @param ch
    152    *          the character to show on the screen
    153    * @param attributes
    154    *          the character attributes
    155    * @see #BOLD
    156    * @see #UNDERLINE
    157    * @see #INVERT
    158    * @see #INVISIBLE
    159    * @see #NORMAL
    160    * @see #LOW
    161    * @see #insertChar
    162    * @see #deleteChar
    163    * @see #redraw
    164    */
    165 
    166   public void putChar(int c, int l, char ch, int attributes) {
    167     charArray[screenBase + l][c] = ch;
    168     charAttributes[screenBase + l][c] = attributes;
    169     if (l < height) {
    170       update[l + 1] = true;
    171     }
    172   }
    173 
    174   /**
    175    * Get the character at the specified position.
    176    *
    177    * @param c
    178    *          x-coordinate (column)
    179    * @param l
    180    *          y-coordinate (line)
    181    * @see #putChar
    182    */
    183   public char getChar(int c, int l) {
    184     return charArray[screenBase + l][c];
    185   }
    186 
    187   /**
    188    * Get the attributes for the specified position.
    189    *
    190    * @param c
    191    *          x-coordinate (column)
    192    * @param l
    193    *          y-coordinate (line)
    194    * @see #putChar
    195    */
    196   public int getAttributes(int c, int l) {
    197     return charAttributes[screenBase + l][c];
    198   }
    199 
    200   /**
    201    * Insert a character at a specific position on the screen. All character right to from this
    202    * position will be moved one to the right. You need to call redraw() to update the screen.
    203    *
    204    * @param c
    205    *          x-coordinate (column)
    206    * @param l
    207    *          y-coordinate (line)
    208    * @param ch
    209    *          the character to insert
    210    * @param attributes
    211    *          the character attributes
    212    * @see #BOLD
    213    * @see #UNDERLINE
    214    * @see #INVERT
    215    * @see #INVISIBLE
    216    * @see #NORMAL
    217    * @see #LOW
    218    * @see #putChar
    219    * @see #deleteChar
    220    * @see #redraw
    221    */
    222   public void insertChar(int c, int l, char ch, int attributes) {
    223     System.arraycopy(charArray[screenBase + l], c, charArray[screenBase + l], c + 1, width - c - 1);
    224     System.arraycopy(charAttributes[screenBase + l], c, charAttributes[screenBase + l], c + 1,
    225         width - c - 1);
    226     putChar(c, l, ch, attributes);
    227   }
    228 
    229   /**
    230    * Delete a character at a given position on the screen. All characters right to the position will
    231    * be moved one to the left. You need to call redraw() to update the screen.
    232    *
    233    * @param c
    234    *          x-coordinate (column)
    235    * @param l
    236    *          y-coordinate (line)
    237    * @see #putChar
    238    * @see #insertChar
    239    * @see #redraw
    240    */
    241   public void deleteChar(int c, int l) {
    242     if (c < width - 1) {
    243       System.arraycopy(charArray[screenBase + l], c + 1, charArray[screenBase + l], c, width - c
    244           - 1);
    245       System.arraycopy(charAttributes[screenBase + l], c + 1, charAttributes[screenBase + l], c,
    246           width - c - 1);
    247     }
    248     putChar(width - 1, l, (char) 0);
    249   }
    250 
    251   /**
    252    * Put a String at a specific position. Any characters previously on that position will be
    253    * overwritten. You need to call redraw() for screen update.
    254    *
    255    * @param c
    256    *          x-coordinate (column)
    257    * @param l
    258    *          y-coordinate (line)
    259    * @param s
    260    *          the string to be shown on the screen
    261    * @see #BOLD
    262    * @see #UNDERLINE
    263    * @see #INVERT
    264    * @see #INVISIBLE
    265    * @see #NORMAL
    266    * @see #LOW
    267    * @see #putChar
    268    * @see #insertLine
    269    * @see #deleteLine
    270    * @see #redraw
    271    */
    272   public void putString(int c, int l, String s) {
    273     putString(c, l, s, NORMAL);
    274   }
    275 
    276   /**
    277    * Put a String at a specific position giving all characters the same attributes. Any characters
    278    * previously on that position will be overwritten. You need to call redraw() to update the
    279    * screen.
    280    *
    281    * @param c
    282    *          x-coordinate (column)
    283    * @param l
    284    *          y-coordinate (line)
    285    * @param s
    286    *          the string to be shown on the screen
    287    * @param attributes
    288    *          character attributes
    289    * @see #BOLD
    290    * @see #UNDERLINE
    291    * @see #INVERT
    292    * @see #INVISIBLE
    293    * @see #NORMAL
    294    * @see #LOW
    295    * @see #putChar
    296    * @see #insertLine
    297    * @see #deleteLine
    298    * @see #redraw
    299    */
    300   public void putString(int c, int l, String s, int attributes) {
    301     for (int i = 0; i < s.length() && c + i < width; i++) {
    302       putChar(c + i, l, s.charAt(i), attributes);
    303     }
    304   }
    305 
    306   /**
    307    * Insert a blank line at a specific position. The current line and all previous lines are
    308    * scrolled one line up. The top line is lost. You need to call redraw() to update the screen.
    309    *
    310    * @param l
    311    *          the y-coordinate to insert the line
    312    * @see #deleteLine
    313    * @see #redraw
    314    */
    315   public void insertLine(int l) {
    316     insertLine(l, 1, SCROLL_UP);
    317   }
    318 
    319   /**
    320    * Insert blank lines at a specific position. You need to call redraw() to update the screen
    321    *
    322    * @param l
    323    *          the y-coordinate to insert the line
    324    * @param n
    325    *          amount of lines to be inserted
    326    * @see #deleteLine
    327    * @see #redraw
    328    */
    329   public void insertLine(int l, int n) {
    330     insertLine(l, n, SCROLL_UP);
    331   }
    332 
    333   /**
    334    * Insert a blank line at a specific position. Scroll text according to the argument. You need to
    335    * call redraw() to update the screen
    336    *
    337    * @param l
    338    *          the y-coordinate to insert the line
    339    * @param scrollDown
    340    *          scroll down
    341    * @see #deleteLine
    342    * @see #SCROLL_UP
    343    * @see #SCROLL_DOWN
    344    * @see #redraw
    345    */
    346   public void insertLine(int l, boolean scrollDown) {
    347     insertLine(l, 1, scrollDown);
    348   }
    349 
    350   /**
    351    * Insert blank lines at a specific position. The current line and all previous lines are scrolled
    352    * one line up. The top line is lost. You need to call redraw() to update the screen.
    353    *
    354    * @param l
    355    *          the y-coordinate to insert the line
    356    * @param n
    357    *          number of lines to be inserted
    358    * @param scrollDown
    359    *          scroll down
    360    * @see #deleteLine
    361    * @see #SCROLL_UP
    362    * @see #SCROLL_DOWN
    363    * @see #redraw
    364    */
    365   public synchronized void insertLine(int l, int n, boolean scrollDown) {
    366     char cbuf[][] = null;
    367     int abuf[][] = null;
    368     int offset = 0;
    369     int oldBase = screenBase;
    370 
    371     int newScreenBase = screenBase;
    372     int newWindowBase = windowBase;
    373     int newBufSize = bufSize;
    374 
    375     if (l > bottomMargin) {
    376       return;
    377     }
    378     int top =
    379         (l < topMargin ? 0 : (l > bottomMargin ? (bottomMargin + 1 < height ? bottomMargin + 1
    380             : height - 1) : topMargin));
    381     int bottom =
    382         (l > bottomMargin ? height - 1 : (l < topMargin ? (topMargin > 0 ? topMargin - 1 : 0)
    383             : bottomMargin));
    384 
    385     // System.out.println("l is "+l+", top is "+top+", bottom is "+bottom+", bottomargin is "+bottomMargin+", topMargin is "+topMargin);
    386 
    387     if (scrollDown) {
    388       if (n > (bottom - top)) {
    389         n = (bottom - top);
    390       }
    391       int size = bottom - l - (n - 1);
    392       if (size < 0) {
    393         size = 0;
    394       }
    395       cbuf = new char[size][];
    396       abuf = new int[size][];
    397 
    398       System.arraycopy(charArray, oldBase + l, cbuf, 0, bottom - l - (n - 1));
    399       System.arraycopy(charAttributes, oldBase + l, abuf, 0, bottom - l - (n - 1));
    400       System.arraycopy(cbuf, 0, charArray, oldBase + l + n, bottom - l - (n - 1));
    401       System.arraycopy(abuf, 0, charAttributes, oldBase + l + n, bottom - l - (n - 1));
    402       cbuf = charArray;
    403       abuf = charAttributes;
    404     } else {
    405       try {
    406         if (n > (bottom - top) + 1) {
    407           n = (bottom - top) + 1;
    408         }
    409         if (bufSize < maxBufSize) {
    410           if (bufSize + n > maxBufSize) {
    411             offset = n - (maxBufSize - bufSize);
    412             scrollMarker += offset;
    413             newBufSize = maxBufSize;
    414             newScreenBase = maxBufSize - height - 1;
    415             newWindowBase = screenBase;
    416           } else {
    417             scrollMarker += n;
    418             newScreenBase += n;
    419             newWindowBase += n;
    420             newBufSize += n;
    421           }
    422 
    423           cbuf = new char[newBufSize][];
    424           abuf = new int[newBufSize][];
    425         } else {
    426           offset = n;
    427           cbuf = charArray;
    428           abuf = charAttributes;
    429         }
    430         // copy anything from the top of the buffer (+offset) to the new top
    431         // up to the screenBase.
    432         if (oldBase > 0) {
    433           System.arraycopy(charArray, offset, cbuf, 0, oldBase - offset);
    434           System.arraycopy(charAttributes, offset, abuf, 0, oldBase - offset);
    435         }
    436         // copy anything from the top of the screen (screenBase) up to the
    437         // topMargin to the new screen
    438         if (top > 0) {
    439           System.arraycopy(charArray, oldBase, cbuf, newScreenBase, top);
    440           System.arraycopy(charAttributes, oldBase, abuf, newScreenBase, top);
    441         }
    442         // copy anything from the topMargin up to the amount of lines inserted
    443         // to the gap left over between scrollback buffer and screenBase
    444         if (oldBase >= 0) {
    445           System.arraycopy(charArray, oldBase + top, cbuf, oldBase - offset, n);
    446           System.arraycopy(charAttributes, oldBase + top, abuf, oldBase - offset, n);
    447         }
    448         // copy anything from topMargin + n up to the line linserted to the
    449         // topMargin
    450         System
    451             .arraycopy(charArray, oldBase + top + n, cbuf, newScreenBase + top, l - top - (n - 1));
    452         System.arraycopy(charAttributes, oldBase + top + n, abuf, newScreenBase + top, l - top
    453             - (n - 1));
    454         //
    455         // copy the all lines next to the inserted to the new buffer
    456         if (l < height - 1) {
    457           System.arraycopy(charArray, oldBase + l + 1, cbuf, newScreenBase + l + 1, (height - 1)
    458               - l);
    459           System.arraycopy(charAttributes, oldBase + l + 1, abuf, newScreenBase + l + 1,
    460               (height - 1) - l);
    461         }
    462       } catch (ArrayIndexOutOfBoundsException e) {
    463         // this should not happen anymore, but I will leave the code
    464         // here in case something happens anyway. That code above is
    465         // so complex I always have a hard time understanding what
    466         // I did, even though there are comments
    467         System.err.println("*** Error while scrolling up:");
    468         System.err.println("--- BEGIN STACK TRACE ---");
    469         e.printStackTrace();
    470         System.err.println("--- END STACK TRACE ---");
    471         System.err.println("bufSize=" + bufSize + ", maxBufSize=" + maxBufSize);
    472         System.err.println("top=" + top + ", bottom=" + bottom);
    473         System.err.println("n=" + n + ", l=" + l);
    474         System.err.println("screenBase=" + screenBase + ", windowBase=" + windowBase);
    475         System.err.println("newScreenBase=" + newScreenBase + ", newWindowBase=" + newWindowBase);
    476         System.err.println("oldBase=" + oldBase);
    477         System.err.println("size.width=" + width + ", size.height=" + height);
    478         System.err.println("abuf.length=" + abuf.length + ", cbuf.length=" + cbuf.length);
    479         System.err.println("*** done dumping debug information");
    480       }
    481     }
    482 
    483     // this is a little helper to mark the scrolling
    484     scrollMarker -= n;
    485 
    486     for (int i = 0; i < n; i++) {
    487       cbuf[(newScreenBase + l) + (scrollDown ? i : -i)] = new char[width];
    488       Arrays.fill(cbuf[(newScreenBase + l) + (scrollDown ? i : -i)], ' ');
    489       abuf[(newScreenBase + l) + (scrollDown ? i : -i)] = new int[width];
    490     }
    491 
    492     charArray = cbuf;
    493     charAttributes = abuf;
    494     screenBase = newScreenBase;
    495     windowBase = newWindowBase;
    496     bufSize = newBufSize;
    497 
    498     if (scrollDown) {
    499       markLine(l, bottom - l + 1);
    500     } else {
    501       markLine(top, l - top + 1);
    502     }
    503 
    504     display.updateScrollBar();
    505   }
    506 
    507   /**
    508    * Delete a line at a specific position. Subsequent lines will be scrolled up to fill the space
    509    * and a blank line is inserted at the end of the screen.
    510    *
    511    * @param l
    512    *          the y-coordinate to insert the line
    513    * @see #deleteLine
    514    */
    515   public void deleteLine(int l) {
    516     int bottom = (l > bottomMargin ? height - 1 : (l < topMargin ? topMargin : bottomMargin + 1));
    517     int numRows = bottom - l - 1;
    518 
    519     char[] discardedChars = charArray[screenBase + l];
    520     int[] discardedAttributes = charAttributes[screenBase + l];
    521 
    522     if (numRows > 0) {
    523       System.arraycopy(charArray, screenBase + l + 1, charArray, screenBase + l, numRows);
    524       System.arraycopy(charAttributes, screenBase + l + 1, charAttributes, screenBase + l, numRows);
    525     }
    526 
    527     int newBottomRow = screenBase + bottom - 1;
    528     charArray[newBottomRow] = discardedChars;
    529     charAttributes[newBottomRow] = discardedAttributes;
    530     Arrays.fill(charArray[newBottomRow], ' ');
    531     Arrays.fill(charAttributes[newBottomRow], 0);
    532 
    533     markLine(l, bottom - l);
    534   }
    535 
    536   /**
    537    * Delete a rectangular portion of the screen. You need to call redraw() to update the screen.
    538    *
    539    * @param c
    540    *          x-coordinate (column)
    541    * @param l
    542    *          y-coordinate (row)
    543    * @param w
    544    *          with of the area in characters
    545    * @param h
    546    *          height of the area in characters
    547    * @param curAttr
    548    *          attribute to fill
    549    * @see #deleteChar
    550    * @see #deleteLine
    551    * @see #redraw
    552    */
    553   public void deleteArea(int c, int l, int w, int h, int curAttr) {
    554     int endColumn = c + w;
    555     int targetRow = screenBase + l;
    556     for (int i = 0; i < h && l + i < height; i++) {
    557       Arrays.fill(charAttributes[targetRow], c, endColumn, curAttr);
    558       Arrays.fill(charArray[targetRow], c, endColumn, ' ');
    559       targetRow++;
    560     }
    561     markLine(l, h);
    562   }
    563 
    564   /**
    565    * Delete a rectangular portion of the screen. You need to call redraw() to update the screen.
    566    *
    567    * @param c
    568    *          x-coordinate (column)
    569    * @param l
    570    *          y-coordinate (row)
    571    * @param w
    572    *          with of the area in characters
    573    * @param h
    574    *          height of the area in characters
    575    * @see #deleteChar
    576    * @see #deleteLine
    577    * @see #redraw
    578    */
    579   public void deleteArea(int c, int l, int w, int h) {
    580     deleteArea(c, l, w, h, 0);
    581   }
    582 
    583   /**
    584    * Sets whether the cursor is visible or not.
    585    *
    586    * @param doshow
    587    */
    588   public void showCursor(boolean doshow) {
    589     showcursor = doshow;
    590   }
    591 
    592   /**
    593    * Check whether the cursor is currently visible.
    594    *
    595    * @return visibility
    596    */
    597   public boolean isCursorVisible() {
    598     return showcursor;
    599   }
    600 
    601   /**
    602    * Puts the cursor at the specified position.
    603    *
    604    * @param c
    605    *          column
    606    * @param l
    607    *          line
    608    */
    609   public void setCursorPosition(int c, int l) {
    610     cursorX = c;
    611     cursorY = l;
    612   }
    613 
    614   /**
    615    * Get the current column of the cursor position.
    616    */
    617   public int getCursorColumn() {
    618     return cursorX;
    619   }
    620 
    621   /**
    622    * Get the current line of the cursor position.
    623    */
    624   public int getCursorRow() {
    625     return cursorY;
    626   }
    627 
    628   /**
    629    * Set the current window base. This allows to view the scrollback buffer.
    630    *
    631    * @param line
    632    *          the line where the screen window starts
    633    * @see #setBufferSize
    634    * @see #getBufferSize
    635    */
    636   public void setWindowBase(int line) {
    637     if (line > screenBase) {
    638       line = screenBase;
    639     } else if (line < 0) {
    640       line = 0;
    641     }
    642     windowBase = line;
    643     update[0] = true;
    644     redraw();
    645   }
    646 
    647   /**
    648    * Get the current window base.
    649    *
    650    * @see #setWindowBase
    651    */
    652   public int getWindowBase() {
    653     return windowBase;
    654   }
    655 
    656   /**
    657    * Set the scroll margins simultaneously. If they're out of bounds, trim them.
    658    *
    659    * @param l1
    660    *          line that is the top
    661    * @param l2
    662    *          line that is the bottom
    663    */
    664   public void setMargins(int l1, int l2) {
    665     if (l1 > l2) {
    666       return;
    667     }
    668 
    669     if (l1 < 0) {
    670       l1 = 0;
    671     }
    672     if (l2 >= height) {
    673       l2 = height - 1;
    674     }
    675 
    676     topMargin = l1;
    677     bottomMargin = l2;
    678   }
    679 
    680   /**
    681    * Set the top scroll margin for the screen. If the current bottom margin is smaller it will
    682    * become the top margin and the line will become the bottom margin.
    683    *
    684    * @param l
    685    *          line that is the margin
    686    */
    687   public void setTopMargin(int l) {
    688     if (l > bottomMargin) {
    689       topMargin = bottomMargin;
    690       bottomMargin = l;
    691     } else {
    692       topMargin = l;
    693     }
    694     if (topMargin < 0) {
    695       topMargin = 0;
    696     }
    697     if (bottomMargin >= height) {
    698       bottomMargin = height - 1;
    699     }
    700   }
    701 
    702   /**
    703    * Get the top scroll margin.
    704    */
    705   public int getTopMargin() {
    706     return topMargin;
    707   }
    708 
    709   /**
    710    * Set the bottom scroll margin for the screen. If the current top margin is bigger it will become
    711    * the bottom margin and the line will become the top margin.
    712    *
    713    * @param l
    714    *          line that is the margin
    715    */
    716   public void setBottomMargin(int l) {
    717     if (l < topMargin) {
    718       bottomMargin = topMargin;
    719       topMargin = l;
    720     } else {
    721       bottomMargin = l;
    722     }
    723     if (topMargin < 0) {
    724       topMargin = 0;
    725     }
    726     if (bottomMargin >= height) {
    727       bottomMargin = height - 1;
    728     }
    729   }
    730 
    731   /**
    732    * Get the bottom scroll margin.
    733    */
    734   public int getBottomMargin() {
    735     return bottomMargin;
    736   }
    737 
    738   /**
    739    * Set scrollback buffer size.
    740    *
    741    * @param amount
    742    *          new size of the buffer
    743    */
    744   public void setBufferSize(int amount) {
    745     if (amount < height) {
    746       amount = height;
    747     }
    748     if (amount < maxBufSize) {
    749       char cbuf[][] = new char[amount][width];
    750       int abuf[][] = new int[amount][width];
    751       int copyStart = bufSize - amount < 0 ? 0 : bufSize - amount;
    752       int copyCount = bufSize - amount < 0 ? bufSize : amount;
    753       if (charArray != null) {
    754         System.arraycopy(charArray, copyStart, cbuf, 0, copyCount);
    755       }
    756       if (charAttributes != null) {
    757         System.arraycopy(charAttributes, copyStart, abuf, 0, copyCount);
    758       }
    759       charArray = cbuf;
    760       charAttributes = abuf;
    761       bufSize = copyCount;
    762       screenBase = bufSize - height;
    763       windowBase = screenBase;
    764     }
    765     maxBufSize = amount;
    766 
    767     update[0] = true;
    768     redraw();
    769   }
    770 
    771   /**
    772    * Retrieve current scrollback buffer size.
    773    *
    774    * @see #setBufferSize
    775    */
    776   public int getBufferSize() {
    777     return bufSize;
    778   }
    779 
    780   /**
    781    * Retrieve maximum buffer Size.
    782    *
    783    * @see #getBufferSize
    784    */
    785   public int getMaxBufferSize() {
    786     return maxBufSize;
    787   }
    788 
    789   /**
    790    * Change the size of the screen. This will include adjustment of the scrollback buffer.
    791    *
    792    * @param w
    793    *          of the screen
    794    * @param h
    795    *          of the screen
    796    */
    797   @SuppressWarnings("unused")
    798   public void setScreenSize(int w, int h, boolean broadcast) {
    799     char cbuf[][];
    800     int abuf[][];
    801     int maxSize = bufSize;
    802 
    803     if (w < 1 || h < 1) {
    804       return;
    805     }
    806 
    807     if (debug > 0) {
    808       System.err.println("VDU: screen size [" + w + "," + h + "]");
    809     }
    810 
    811     if (h > maxBufSize) {
    812       maxBufSize = h;
    813     }
    814 
    815     if (h > bufSize) {
    816       bufSize = h;
    817       screenBase = 0;
    818       windowBase = 0;
    819     }
    820 
    821     if (windowBase + h >= bufSize) {
    822       windowBase = bufSize - h;
    823     }
    824 
    825     if (screenBase + h >= bufSize) {
    826       screenBase = bufSize - h;
    827     }
    828 
    829     cbuf = new char[bufSize][w];
    830     abuf = new int[bufSize][w];
    831 
    832     for (int i = 0; i < bufSize; i++) {
    833       Arrays.fill(cbuf[i], ' ');
    834     }
    835 
    836     if (bufSize < maxSize) {
    837       maxSize = bufSize;
    838     }
    839 
    840     int rowLength;
    841     if (charArray != null && charAttributes != null) {
    842       for (int i = 0; i < maxSize && charArray[i] != null; i++) {
    843         rowLength = charArray[i].length;
    844         System.arraycopy(charArray[i], 0, cbuf[i], 0, w < rowLength ? w : rowLength);
    845         System.arraycopy(charAttributes[i], 0, abuf[i], 0, w < rowLength ? w : rowLength);
    846       }
    847     }
    848 
    849     int C = getCursorColumn();
    850     if (C < 0) {
    851       C = 0;
    852     } else if (C >= width) {
    853       C = width - 1;
    854     }
    855 
    856     int R = getCursorRow();
    857     if (R < 0) {
    858       R = 0;
    859     } else if (R >= height) {
    860       R = height - 1;
    861     }
    862 
    863     setCursorPosition(C, R);
    864 
    865     charArray = cbuf;
    866     charAttributes = abuf;
    867     width = w;
    868     height = h;
    869     topMargin = 0;
    870     bottomMargin = h - 1;
    871     update = new boolean[h + 1];
    872     update[0] = true;
    873     /*
    874      * FIXME: ??? if(resizeStrategy == RESIZE_FONT) setBounds(getBounds());
    875      */
    876   }
    877 
    878   /**
    879    * Get amount of rows on the screen.
    880    */
    881   public int getRows() {
    882     return height;
    883   }
    884 
    885   /**
    886    * Get amount of columns on the screen.
    887    */
    888   public int getColumns() {
    889     return width;
    890   }
    891 
    892   /**
    893    * Mark lines to be updated with redraw().
    894    *
    895    * @param l
    896    *          starting line
    897    * @param n
    898    *          amount of lines to be updated
    899    * @see #redraw
    900    */
    901   public void markLine(int l, int n) {
    902     for (int i = 0; (i < n) && (l + i < height); i++) {
    903       update[l + i + 1] = true;
    904     }
    905   }
    906 
    907   // private static int checkBounds(int value, int lower, int upper) {
    908   // if (value < lower)
    909   // return lower;
    910   // else if (value > upper)
    911   // return upper;
    912   // else
    913   // return value;
    914   // }
    915 
    916   /** a generic display that should redraw on demand */
    917   protected VDUDisplay display;
    918 
    919   public void setDisplay(VDUDisplay display) {
    920     this.display = display;
    921   }
    922 
    923   /**
    924    * Trigger a redraw on the display.
    925    */
    926   protected void redraw() {
    927     if (display != null) {
    928       display.redraw();
    929     }
    930   }
    931 }
    932