PMD code sweep, #6 don't add MyWindow twice to MyApplication
[fanfix.git] / src / jexer / backend / LogicalScreen.java
index 8432e4eae526f8a74f395303ebb8fbd3d5f3c09e..c24703e7a23098740804f5be8f4873b27ceb1324 100644 (file)
@@ -37,6 +37,10 @@ import jexer.bits.GraphicsChars;
  */
 public class LogicalScreen implements Screen {
 
+    // ------------------------------------------------------------------------
+    // Variables --------------------------------------------------------------
+    // ------------------------------------------------------------------------
+
     /**
      * Width of the visible window.
      */
@@ -52,6 +56,84 @@ public class LogicalScreen implements Screen {
      */
     private int offsetX;
 
+    /**
+     * Drawing offset for y.
+     */
+    private int offsetY;
+
+    /**
+     * Ignore anything drawn right of clipRight.
+     */
+    private int clipRight;
+
+    /**
+     * Ignore anything drawn below clipBottom.
+     */
+    private int clipBottom;
+
+    /**
+     * Ignore anything drawn left of clipLeft.
+     */
+    private int clipLeft;
+
+    /**
+     * Ignore anything drawn above clipTop.
+     */
+    private int clipTop;
+
+    /**
+     * The physical screen last sent out on flush().
+     */
+    protected Cell [][] physical;
+
+    /**
+     * The logical screen being rendered to.
+     */
+    protected Cell [][] logical;
+
+    /**
+     * Set if the user explicitly wants to redraw everything starting with a
+     * ECMATerminal.clearAll().
+     */
+    protected boolean reallyCleared;
+
+    /**
+     * If true, the cursor is visible and should be placed onscreen at
+     * (cursorX, cursorY) during a call to flushPhysical().
+     */
+    protected boolean cursorVisible;
+
+    /**
+     * Cursor X position if visible.
+     */
+    protected int cursorX;
+
+    /**
+     * Cursor Y position if visible.
+     */
+    protected int cursorY;
+
+    // ------------------------------------------------------------------------
+    // Constructors -----------------------------------------------------------
+    // ------------------------------------------------------------------------
+
+    /**
+     * Public constructor.  Sets everything to not-bold, white-on-black.
+     */
+    protected LogicalScreen() {
+        offsetX  = 0;
+        offsetY  = 0;
+        width    = 80;
+        height   = 24;
+        logical  = null;
+        physical = null;
+        reallocate(width, height);
+    }
+
+    // ------------------------------------------------------------------------
+    // Screen -----------------------------------------------------------------
+    // ------------------------------------------------------------------------
+
     /**
      * Set drawing offset for x.
      *
@@ -61,11 +143,6 @@ public class LogicalScreen implements Screen {
         this.offsetX = offsetX;
     }
 
-    /**
-     * Drawing offset for y.
-     */
-    private int offsetY;
-
     /**
      * Set drawing offset for y.
      *
@@ -75,11 +152,6 @@ public class LogicalScreen implements Screen {
         this.offsetY = offsetY;
     }
 
-    /**
-     * Ignore anything drawn right of clipRight.
-     */
-    private int clipRight;
-
     /**
      * Get right drawing clipping boundary.
      *
@@ -98,11 +170,6 @@ public class LogicalScreen implements Screen {
         this.clipRight = clipRight;
     }
 
-    /**
-     * Ignore anything drawn below clipBottom.
-     */
-    private int clipBottom;
-
     /**
      * Get bottom drawing clipping boundary.
      *
@@ -121,11 +188,6 @@ public class LogicalScreen implements Screen {
         this.clipBottom = clipBottom;
     }
 
-    /**
-     * Ignore anything drawn left of clipLeft.
-     */
-    private int clipLeft;
-
     /**
      * Get left drawing clipping boundary.
      *
@@ -144,11 +206,6 @@ public class LogicalScreen implements Screen {
         this.clipLeft = clipLeft;
     }
 
-    /**
-     * Ignore anything drawn above clipTop.
-     */
-    private int clipTop;
-
     /**
      * Get top drawing clipping boundary.
      *
@@ -167,21 +224,6 @@ public class LogicalScreen implements Screen {
         this.clipTop = clipTop;
     }
 
-    /**
-     * The physical screen last sent out on flush().
-     */
-    protected Cell [][] physical;
-
-    /**
-     * The logical screen being rendered to.
-     */
-    protected Cell [][] logical;
-
-    /**
-     * When true, logical != physical.
-     */
-    protected volatile boolean dirty;
-
     /**
      * Get dirty flag.
      *
@@ -189,30 +231,21 @@ public class LogicalScreen implements Screen {
      * screen
      */
     public final boolean isDirty() {
-        return dirty;
-    }
-
-    /**
-     * Set if the user explicitly wants to redraw everything starting with a
-     * ECMATerminal.clearAll().
-     */
-    protected boolean reallyCleared;
-
-    /**
-     * If true, the cursor is visible and should be placed onscreen at
-     * (cursorX, cursorY) during a call to flushPhysical().
-     */
-    protected boolean cursorVisible;
-
-    /**
-     * Cursor X position if visible.
-     */
-    protected int cursorX;
+        for (int x = 0; x < width; x++) {
+            for (int y = 0; y < height; y++) {
+                if (!logical[x][y].equals(physical[x][y])) {
+                    return true;
+                }
+                if (logical[x][y].isBlink()) {
+                    // Blinking screens are always dirty.  There is
+                    // opportunity for a Netscape blink tag joke here...
+                    return true;
+                }
+            }
+        }
 
-    /**
-     * Cursor Y position if visible.
-     */
-    protected int cursorY;
+        return false;
+    }
 
     /**
      * Get the attributes at one location.
@@ -229,6 +262,21 @@ public class LogicalScreen implements Screen {
         return attr;
     }
 
+    /**
+     * Get the cell at one location.
+     *
+     * @param x column coordinate.  0 is the left-most column.
+     * @param y row coordinate.  0 is the top-most row.
+     * @return the character + attributes
+     */
+    public Cell getCharXY(final int x, final int y) {
+        Cell cell = new Cell();
+        if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) {
+            cell.setTo(logical[x][y]);
+        }
+        return cell;
+    }
+
     /**
      * Set the attributes at one location.
      *
@@ -269,14 +317,17 @@ public class LogicalScreen implements Screen {
         }
 
         if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
-            dirty = true;
-            logical[X][Y].setForeColor(attr.getForeColor());
-            logical[X][Y].setBackColor(attr.getBackColor());
-            logical[X][Y].setBold(attr.isBold());
-            logical[X][Y].setBlink(attr.isBlink());
-            logical[X][Y].setReverse(attr.isReverse());
-            logical[X][Y].setUnderline(attr.isUnderline());
-            logical[X][Y].setProtect(attr.isProtect());
+            logical[X][Y].setTo(attr);
+
+            // If this happens to be the cursor position, make the position
+            // dirty.
+            if ((cursorX == X) && (cursorY == Y)) {
+                if (physical[cursorX][cursorY].getChar() == 'Q') {
+                    physical[cursorX][cursorY].setChar('X');
+                } else {
+                    physical[cursorX][cursorY].setChar('Q');
+                }
+            }
         }
     }
 
@@ -331,20 +382,23 @@ public class LogicalScreen implements Screen {
         // System.err.printf("putCharXY: %d, %d, %c\n", X, Y, ch);
 
         if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
-            dirty = true;
 
             // Do not put control characters on the display
             assert (ch >= 0x20);
             assert (ch != 0x7F);
 
+            logical[X][Y].setTo(attr);
             logical[X][Y].setChar(ch);
-            logical[X][Y].setForeColor(attr.getForeColor());
-            logical[X][Y].setBackColor(attr.getBackColor());
-            logical[X][Y].setBold(attr.isBold());
-            logical[X][Y].setBlink(attr.isBlink());
-            logical[X][Y].setReverse(attr.isReverse());
-            logical[X][Y].setUnderline(attr.isUnderline());
-            logical[X][Y].setProtect(attr.isProtect());
+
+            // If this happens to be the cursor position, make the position
+            // dirty.
+            if ((cursorX == X) && (cursorY == Y)) {
+                if (physical[cursorX][cursorY].getChar() == 'Q') {
+                    physical[cursorX][cursorY].setChar('X');
+                } else {
+                    physical[cursorX][cursorY].setChar('Q');
+                }
+            }
         }
     }
 
@@ -371,8 +425,17 @@ public class LogicalScreen implements Screen {
         // System.err.printf("putCharXY: %d, %d, %c\n", X, Y, ch);
 
         if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
-            dirty = true;
             logical[X][Y].setChar(ch);
+
+            // If this happens to be the cursor position, make the position
+            // dirty.
+            if ((cursorX == X) && (cursorY == Y)) {
+                if (physical[cursorX][cursorY].getChar() == 'Q') {
+                    physical[cursorX][cursorY].setChar('X');
+                } else {
+                    physical[cursorX][cursorY].setChar('Q');
+                }
+            }
         }
     }
 
@@ -453,51 +516,6 @@ public class LogicalScreen implements Screen {
         }
     }
 
-    /**
-     * Reallocate screen buffers.
-     *
-     * @param width new width
-     * @param height new height
-     */
-    private synchronized void reallocate(final int width, final int height) {
-        if (logical != null) {
-            for (int row = 0; row < this.height; row++) {
-                for (int col = 0; col < this.width; col++) {
-                    logical[col][row] = null;
-                }
-            }
-            logical = null;
-        }
-        logical = new Cell[width][height];
-        if (physical != null) {
-            for (int row = 0; row < this.height; row++) {
-                for (int col = 0; col < this.width; col++) {
-                    physical[col][row] = null;
-                }
-            }
-            physical = null;
-        }
-        physical = new Cell[width][height];
-
-        for (int row = 0; row < height; row++) {
-            for (int col = 0; col < width; col++) {
-                physical[col][row] = new Cell();
-                logical[col][row] = new Cell();
-            }
-        }
-
-        this.width = width;
-        this.height = height;
-
-        clipLeft = 0;
-        clipTop = 0;
-        clipRight = width;
-        clipBottom = height;
-
-        reallyCleared = true;
-        dirty = true;
-    }
-
     /**
      * Change the width.  Everything on-screen will be destroyed and must be
      * redrawn.
@@ -547,25 +565,11 @@ public class LogicalScreen implements Screen {
         return this.width;
     }
 
-    /**
-     * Public constructor.  Sets everything to not-bold, white-on-black.
-     */
-    protected LogicalScreen() {
-        offsetX  = 0;
-        offsetY  = 0;
-        width    = 80;
-        height   = 24;
-        logical  = null;
-        physical = null;
-        reallocate(width, height);
-    }
-
     /**
      * Reset screen to not-bold, white-on-black.  Also flushes the offset and
      * clip variables.
      */
     public final synchronized void reset() {
-        dirty = true;
         for (int row = 0; row < height; row++) {
             for (int col = 0; col < width; col++) {
                 logical[col][row].reset();
@@ -593,18 +597,6 @@ public class LogicalScreen implements Screen {
         reset();
     }
 
-    /**
-     * Clear the physical screen.
-     */
-    public final void clearPhysical() {
-        dirty = true;
-        for (int row = 0; row < height; row++) {
-            for (int col = 0; col < width; col++) {
-                physical[col][row].reset();
-            }
-        }
-    }
-
     /**
      * Draw a box with a border and empty background.
      *
@@ -758,6 +750,18 @@ public class LogicalScreen implements Screen {
      * @param y row coordinate to put the cursor on
      */
     public void putCursor(final boolean visible, final int x, final int y) {
+        if ((cursorY >= 0)
+            && (cursorX >= 0)
+            && (cursorY <= height - 1)
+            && (cursorX <= width - 1)
+        ) {
+            // Make the current cursor position dirty
+            if (physical[cursorX][cursorY].getChar() == 'Q') {
+                physical[cursorX][cursorY].setChar('X');
+            } else {
+                physical[cursorX][cursorY].setChar('Q');
+            }
+        }
 
         cursorVisible = visible;
         cursorX = x;
@@ -771,6 +775,33 @@ public class LogicalScreen implements Screen {
         cursorVisible = false;
     }
 
+    /**
+     * Get the cursor visibility.
+     *
+     * @return true if the cursor is visible
+     */
+    public boolean isCursorVisible() {
+        return cursorVisible;
+    }
+
+    /**
+     * Get the cursor X position.
+     *
+     * @return the cursor x column position
+     */
+    public int getCursorX() {
+        return cursorX;
+    }
+
+    /**
+     * Get the cursor Y position.
+     *
+     * @return the cursor y row position
+     */
+    public int getCursorY() {
+        return cursorY;
+    }
+
     /**
      * Set the window title.  Default implementation does nothing.
      *
@@ -778,4 +809,63 @@ public class LogicalScreen implements Screen {
      */
     public void setTitle(final String title) {}
 
+    // ------------------------------------------------------------------------
+    // LogicalScreen ----------------------------------------------------------
+    // ------------------------------------------------------------------------
+
+    /**
+     * Reallocate screen buffers.
+     *
+     * @param width new width
+     * @param height new height
+     */
+    private synchronized void reallocate(final int width, final int height) {
+        if (logical != null) {
+            for (int row = 0; row < this.height; row++) {
+                for (int col = 0; col < this.width; col++) {
+                    logical[col][row] = null;
+                }
+            }
+            logical = null;
+        }
+        logical = new Cell[width][height];
+        if (physical != null) {
+            for (int row = 0; row < this.height; row++) {
+                for (int col = 0; col < this.width; col++) {
+                    physical[col][row] = null;
+                }
+            }
+            physical = null;
+        }
+        physical = new Cell[width][height];
+
+        for (int row = 0; row < height; row++) {
+            for (int col = 0; col < width; col++) {
+                physical[col][row] = new Cell();
+                logical[col][row] = new Cell();
+            }
+        }
+
+        this.width = width;
+        this.height = height;
+
+        clipLeft = 0;
+        clipTop = 0;
+        clipRight = width;
+        clipBottom = height;
+
+        reallyCleared = true;
+    }
+
+    /**
+     * Clear the physical screen.
+     */
+    public final void clearPhysical() {
+        for (int row = 0; row < height; row++) {
+            for (int col = 0; col < width; col++) {
+                physical[col][row].reset();
+            }
+        }
+    }
+
 }