Add 'src/jexer/' from commit 'cf01c92f5809a0732409e280fb0f32f27393618d'
[nikiroo-utils.git] / src / jexer / backend / MultiScreen.java
index 209105d92f167a87795e05372edeb36a8addedfe..9d66b69342896a50c6d8683d6cc4c463db4491c2 100644 (file)
@@ -3,7 +3,7 @@
  *
  * The MIT License (MIT)
  *
- * Copyright (C) 2017 Kevin Lamonte
+ * Copyright (C) 2019 Kevin Lamonte
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -28,7 +28,7 @@
  */
 package jexer.backend;
 
-import java.util.LinkedList;
+import java.util.ArrayList;
 import java.util.List;
 
 import jexer.bits.Cell;
@@ -39,10 +39,18 @@ import jexer.bits.CellAttributes;
  */
 public class MultiScreen implements Screen {
 
+    // ------------------------------------------------------------------------
+    // Variables --------------------------------------------------------------
+    // ------------------------------------------------------------------------
+
     /**
      * The list of screens to use.
      */
-    private List<Screen> screens = new LinkedList<Screen>();
+    private List<Screen> screens = new ArrayList<Screen>();
+
+    // ------------------------------------------------------------------------
+    // Constructors -----------------------------------------------------------
+    // ------------------------------------------------------------------------
 
     /**
      * Public constructor requires one screen.
@@ -53,25 +61,9 @@ public class MultiScreen implements Screen {
         screens.add(screen);
     }
 
-    /**
-     * Add a screen to the list.
-     *
-     * @param screen the screen to add
-     */
-    public void addScreen(final Screen screen) {
-        screens.add(screen);
-    }
-
-    /**
-     * Remove a screen from the list.
-     *
-     * @param screen the screen to remove
-     */
-    public void removeScreen(final Screen screen) {
-        if (screens.size() > 1) {
-            screens.remove(screen);
-        }
-    }
+    // ------------------------------------------------------------------------
+    // Screen -----------------------------------------------------------------
+    // ------------------------------------------------------------------------
 
     /**
      * Set drawing offset for x.
@@ -182,7 +174,12 @@ public class MultiScreen implements Screen {
      * screen
      */
     public boolean isDirty() {
-        return screens.get(0).isDirty();
+        for (Screen screen: screens) {
+            if (screen.isDirty()) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -244,7 +241,7 @@ public class MultiScreen implements Screen {
      * @param ch character to draw
      * @param attr attributes to use (bold, foreColor, backColor)
      */
-    public void putAll(final char ch, final CellAttributes attr) {
+    public void putAll(final int ch, final CellAttributes attr) {
         for (Screen screen: screens) {
             screen.putAll(ch, attr);
         }
@@ -271,7 +268,7 @@ public class MultiScreen implements Screen {
      * @param ch character to draw
      * @param attr attributes to use (bold, foreColor, backColor)
      */
-    public void putCharXY(final int x, final int y, final char ch,
+    public void putCharXY(final int x, final int y, final int ch,
         final CellAttributes attr) {
 
         for (Screen screen: screens) {
@@ -286,7 +283,7 @@ public class MultiScreen implements Screen {
      * @param y row coordinate.  0 is the top-most row.
      * @param ch character to draw
      */
-    public void putCharXY(final int x, final int y, final char ch) {
+    public void putCharXY(final int x, final int y, final int ch) {
         for (Screen screen: screens) {
             screen.putCharXY(x, y, ch);
         }
@@ -332,7 +329,7 @@ public class MultiScreen implements Screen {
      * @param attr attributes to use (bold, foreColor, backColor)
      */
     public void vLineXY(final int x, final int y, final int n,
-        final char ch, final CellAttributes attr) {
+        final int ch, final CellAttributes attr) {
 
         for (Screen screen: screens) {
             screen.vLineXY(x, y, n, ch, attr);
@@ -349,7 +346,7 @@ public class MultiScreen implements Screen {
      * @param attr attributes to use (bold, foreColor, backColor)
      */
     public void hLineXY(final int x, final int y, final int n,
-        final char ch, final CellAttributes attr) {
+        final int ch, final CellAttributes attr) {
 
         for (Screen screen: screens) {
             screen.hLineXY(x, y, n, ch, attr);
@@ -389,7 +386,20 @@ public class MultiScreen implements Screen {
      */
     public void setDimensions(final int width, final int height) {
         for (Screen screen: screens) {
-            screen.setDimensions(width, height);
+            // Do not blindly call setDimension() on every screen.  Instead
+            // call it only on those screens that do not already have the
+            // requested dimension.  With this very small check, we have the
+            // ability for ANY screen in the MultiBackend to resize ALL of
+            // the screens.
+            if ((screen.getWidth() != width)
+                || (screen.getHeight() != height)
+            ) {
+                screen.setDimensions(width, height);
+            } else {
+                // The screen that didn't change is probably the one that
+                // prompted the resize.  Force it to repaint.
+                screen.clearPhysical();
+            }
         }
     }
 
@@ -399,7 +409,14 @@ public class MultiScreen implements Screen {
      * @return current screen height
      */
     public int getHeight() {
-        return screens.get(0).getHeight();
+        // Return the smallest height of the screens.
+        int height = screens.get(0).getHeight();
+        for (Screen screen: screens) {
+            if (screen.getHeight() < height) {
+                height = screen.getHeight();
+            }
+        }
+        return height;
     }
 
     /**
@@ -408,7 +425,14 @@ public class MultiScreen implements Screen {
      * @return current screen width
      */
     public int getWidth() {
-        return screens.get(0).getWidth();
+        // Return the smallest width of the screens.
+        int width = screens.get(0).getWidth();
+        for (Screen screen: screens) {
+            if (screen.getWidth() < width) {
+                width = screen.getWidth();
+            }
+        }
+        return width;
     }
 
     /**
@@ -499,6 +523,27 @@ public class MultiScreen implements Screen {
         }
     }
 
+    /**
+     * Clear the physical screen.
+     */
+    public void clearPhysical() {
+        for (Screen screen: screens) {
+            screen.clearPhysical();
+        }
+    }
+
+    /**
+     * Unset every image cell on one row of the physical screen, forcing
+     * images on that row to be redrawn.
+     *
+     * @param y row coordinate.  0 is the top-most row.
+     */
+    public final void unsetImageRow(final int y) {
+        for (Screen screen: screens) {
+            screen.unsetImageRow(y);
+        }
+    }
+
     /**
      * Classes must provide an implementation to push the logical screen to
      * the physical device.
@@ -569,4 +614,60 @@ public class MultiScreen implements Screen {
         }
     }
 
+    // ------------------------------------------------------------------------
+    // MultiScreen ------------------------------------------------------------
+    // ------------------------------------------------------------------------
+
+    /**
+     * Add a screen to the list.
+     *
+     * @param screen the screen to add
+     */
+    public void addScreen(final Screen screen) {
+        screens.add(screen);
+    }
+
+    /**
+     * Remove a screen from the list.
+     *
+     * @param screen the screen to remove
+     */
+    public void removeScreen(final Screen screen) {
+        if (screens.size() > 1) {
+            screens.remove(screen);
+        }
+    }
+
+    /**
+     * Get the width of a character cell in pixels.
+     *
+     * @return the width in pixels of a character cell
+     */
+    public int getTextWidth() {
+        int textWidth = 16;
+        for (Screen screen: screens) {
+            int newTextWidth = screen.getTextWidth();
+            if (newTextWidth < textWidth) {
+                textWidth = newTextWidth;
+            }
+        }
+        return textWidth;
+    }
+
+    /**
+     * Get the height of a character cell in pixels.
+     *
+     * @return the height in pixels of a character cell
+     */
+    public int getTextHeight() {
+        int textHeight = 20;
+        for (Screen screen: screens) {
+            int newTextHeight = screen.getTextHeight();
+            if (newTextHeight < textHeight) {
+                textHeight = newTextHeight;
+            }
+        }
+        return textHeight;
+    }
+
 }