#83 underlay/overlay for windows

This commit is contained in:
Autumn Lamonte 2021-12-24 08:28:59 -06:00
parent f513485b9e
commit 5339e760f5
8 changed files with 233 additions and 31 deletions

View file

@ -46,6 +46,7 @@ import jexer.event.TMouseEvent;
import jexer.event.TResizeEvent;
import jexer.layout.LayoutManager;
import jexer.menu.TMenu;
import jexer.tackboard.Tackboard;
import jexer.ttree.TTreeItem;
import jexer.ttree.TTreeView;
import jexer.ttree.TTreeViewWidget;
@ -1427,6 +1428,12 @@ public abstract class TWidget implements Comparable<TWidget> {
screen.setOffsetX(getAbsoluteX());
screen.setOffsetY(getAbsoluteY());
// Hang onto these in case there is an overlay to draw
int overlayClipRight = screen.getClipRight();
int overlayClipBottom = screen.getClipBottom();
int overlayOffsetX = screen.getOffsetX();
int overlayOffsetY = screen.getOffsetY();
// Draw me
draw();
if (!isDrawable()) {
@ -1452,6 +1459,20 @@ public abstract class TWidget implements Comparable<TWidget> {
if (activeChild != null) {
activeChild.drawChildren();
}
// The TWindow overlay has to be here so that it can cover drawn
// widgets.
if (this instanceof TWindow) {
Tackboard overlay = ((TWindow) this).overlay;
if (overlay != null) {
screen.setClipRight(overlayClipRight);
screen.setClipBottom(overlayClipBottom);
screen.setOffsetX(overlayOffsetX);
screen.setOffsetY(overlayOffsetY);
overlay.draw(getScreen(),
getApplication().getBackend().isImagesOverText());
}
}
}
/**

View file

@ -41,6 +41,8 @@ import jexer.event.TMenuEvent;
import jexer.event.TMouseEvent;
import jexer.event.TResizeEvent;
import jexer.menu.TMenu;
import jexer.tackboard.Tackboard;
import jexer.tackboard.TackboardItem;
import static jexer.TCommand.*;
import static jexer.TKeypress.*;
@ -204,6 +206,18 @@ public class TWindow extends TWidget {
*/
protected String helpTopic = "Help";
/**
* A means of drawing arbitrary items underneath all widgets on this
* window.
*/
protected Tackboard underlay = null;
/**
* A means of drawing arbitrary items on top of all widgets on this
* window.
*/
protected Tackboard overlay = null;
// ------------------------------------------------------------------------
// Constructors -----------------------------------------------------------
// ------------------------------------------------------------------------
@ -925,7 +939,6 @@ public class TWindow extends TWidget {
CellAttributes border = getBorder();
CellAttributes background = getBackground();
int borderType = getBorderType();
drawBox(0, 0, getWidth(), getHeight(), border, background, borderType,
true);
@ -982,6 +995,15 @@ public class TWindow extends TWidget {
}
}
}
if (underlay != null) {
// This is a tad less slick that I want. I would prefer the
// underlay to be fully contained within the window borders.
// Putting it here means it can draw over the window edge.
underlay.draw(getScreen(),
getApplication().getBackend().isImagesOverText());
}
}
// ------------------------------------------------------------------------
@ -1573,4 +1595,28 @@ public class TWindow extends TWidget {
getX(), getY(), getWidth(), getHeight(), hidden, isModal());
}
/**
* Add a tackboard item to the underlay.
*
* @param item the item to add
*/
public void addUnderlay(final TackboardItem item) {
if (underlay == null) {
underlay = new Tackboard();
}
underlay.addItem(item);
}
/**
* Add a tackboard item to the overlay.
*
* @param item the item to add
*/
public void addOverlay(final TackboardItem item) {
if (overlay == null) {
overlay = new Tackboard();
}
overlay.addItem(item);
}
}

View file

@ -179,6 +179,15 @@ public class LogicalScreen implements Screen {
this.offsetX = offsetX;
}
/**
* Get drawing offset for x.
*
* @return the drawing offset
*/
public int getOffsetX() {
return offsetX;
}
/**
* Set drawing offset for y.
*
@ -188,6 +197,15 @@ public class LogicalScreen implements Screen {
this.offsetY = offsetY;
}
/**
* Get drawing offset for y.
*
* @return the drawing offset
*/
public int getOffsetY() {
return offsetY;
}
/**
* Get right drawing clipping boundary.
*
@ -299,7 +317,7 @@ public class LogicalScreen implements Screen {
}
/**
* Get the cell at one location.
* Get the cell at one location in absolute coordinates.
*
* @param x column coordinate. 0 is the left-most column.
* @param y row coordinate. 0 is the top-most row.
@ -313,6 +331,41 @@ public class LogicalScreen implements Screen {
return cell;
}
/**
* Get the cell at one location, in either absolute or clipped
* coordinates.
*
* @param x column coordinate. 0 is the left-most column.
* @param y row coordinate. 0 is the top-most row.
* @param clip if true, honor clipping/offset
*
* @return the character + attributes, or null if this position is
* outside the clipping/offset region
*/
public Cell getCharXY(final int x, final int y, final boolean clip) {
int X = x;
int Y = y;
if (clip) {
if ((x < clipLeft)
|| (x >= clipRight)
|| (y < clipTop)
|| (y >= clipBottom)
) {
return null;
}
X += offsetX;
Y += offsetY;
}
if ((X >= 0) && (X < width) && (Y >= 0) && (Y < height)) {
Cell cell = new Cell();
cell.setTo(logical[X][Y]);
return cell;
}
return null;
}
/**
* Set the attributes at one location.
*

View file

@ -81,6 +81,20 @@ public class MultiScreen implements Screen {
}
}
/**
* Get drawing offset for x.
*
* @return the drawing offset
*/
public int getOffsetX() {
synchronized (screens) {
if (screens.size() > 0) {
return screens.get(0).getOffsetX();
}
return 0;
}
}
/**
* Set drawing offset for y.
*
@ -94,6 +108,20 @@ public class MultiScreen implements Screen {
}
}
/**
* Get drawing offset for y.
*
* @return the drawing offset
*/
public int getOffsetY() {
synchronized (screens) {
if (screens.size() > 0) {
return screens.get(0).getOffsetY();
}
return 0;
}
}
/**
* Get right drawing clipping boundary.
*
@ -251,6 +279,26 @@ public class MultiScreen implements Screen {
}
}
/**
* Get the cell at one location, in either absolute or clipped
* coordinates.
*
* @param x column coordinate. 0 is the left-most column.
* @param y row coordinate. 0 is the top-most row.
* @param clip if true, honor clipping/offset
*
* @return the character + attributes, or null if this position is
* outside the clipping/offset region
*/
public Cell getCharXY(final int x, final int y, final boolean clip) {
synchronized (screens) {
if (screens.size() > 0) {
return screens.get(0).getCharXY(x, y, clip);
}
return null;
}
}
/**
* Set the attributes at one location.
*

View file

@ -44,6 +44,13 @@ public interface Screen {
*/
public void setOffsetX(final int offsetX);
/**
* Get drawing offset for x.
*
* @return the drawing offset
*/
public int getOffsetX();
/**
* Set drawing offset for y.
*
@ -51,6 +58,13 @@ public interface Screen {
*/
public void setOffsetY(final int offsetY);
/**
* Get drawing offset for y.
*
* @return the drawing offset
*/
public int getOffsetY();
/**
* Get right drawing clipping boundary.
*
@ -125,7 +139,7 @@ public interface Screen {
public CellAttributes getAttrXY(final int x, final int y);
/**
* Get the cell at one location.
* Get the cell at one location in absolute coordinates.
*
* @param x column coordinate. 0 is the left-most column.
* @param y row coordinate. 0 is the top-most row.
@ -133,6 +147,19 @@ public interface Screen {
*/
public Cell getCharXY(final int x, final int y);
/**
* Get the cell at one location, in either absolute or clipped
* coordinates.
*
* @param x column coordinate. 0 is the left-most column.
* @param y row coordinate. 0 is the top-most row.
* @param clip if true, honor clipping/offset
*
* @return the character + attributes, or null if this position is
* outside the clipping/offset region
*/
public Cell getCharXY(final int x, final int y, final boolean clip);
/**
* Set the attributes at one location.
*

View file

@ -32,6 +32,7 @@ import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javax.imageio.ImageIO;
@ -49,7 +50,6 @@ import jexer.TWindow;
import jexer.event.TCommandEvent;
import jexer.layout.StretchLayoutManager;
import jexer.tackboard.Bitmap;
import jexer.tackboard.Tackboard;
import jexer.tackboard.TackboardItem;
import static jexer.TCommand.*;
import static jexer.TKeypress.*;
@ -113,11 +113,6 @@ public class DemoMainWindow extends TWindow {
*/
TProgressBar progressBar2;
/**
* Tackboard can display pixels over text.
*/
Tackboard tackboard = new Tackboard();
/**
* Direction for the bitmaps to move.
*/
@ -321,13 +316,20 @@ public class DemoMainWindow extends TWindow {
loader = Thread.currentThread().getContextClassLoader();
BufferedImage image;
image = ImageIO.read(loader.getResource("trans_icon.png"));
tackboard.addItem(new Bitmap(17, 41, 0, image));
tackboard.addItem(new Bitmap(41, 97, 0, image));
addUnderlay(new Bitmap(17, 33, 0, image));
addOverlay(new Bitmap(41, 97, 0, image));
timer3 = getApplication().addTimer(100, true,
new TAction() {
public void DO() {
List<TackboardItem> items = tackboard.getItems();
List<TackboardItem> items;
items = new ArrayList<TackboardItem>();
if (underlay != null) {
items.addAll(underlay.getItems());
}
if (overlay != null) {
items.addAll(overlay.getItems());
}
int i = 0;
for (TackboardItem item: items) {
i++;
@ -393,19 +395,6 @@ public class DemoMainWindow extends TWindow {
// TWindow ----------------------------------------------------------------
// ------------------------------------------------------------------------
/**
* Show the bitmap(s) on the Tackboard.
*/
@Override
public void draw() {
super.draw();
// For this one, render to the entire screen, not to the window.
getScreen().resetClipping();
tackboard.draw(getScreen(),
getApplication().getBackend().isImagesOverText());
}
/**
* We need to override onClose so that the timer will no longer be called
* after we close the window. TTimers currently are completely unaware

View file

@ -208,9 +208,13 @@ public class Tackboard {
break;
}
// This cell is visible on the screen.
assert (sx + textX + left < screen.getWidth());
assert (sy + textY + top < screen.getHeight());
Cell oldCell = screen.getCharXY(sx + textX + left,
sy + textY + top, true);
if (oldCell == null) {
// This image fragment would not be visible on the
// screen.
continue;
}
BufferedImage newImage;
newImage = image.getSubimage(sx * cellWidth,
@ -224,8 +228,6 @@ public class Tackboard {
// newImage has the image that needs to be overlaid on
// (sx + textX + left, sy + textY + top)
Cell oldCell = screen.getCharXY(sx + textX + left,
sy + textY + top);
if (oldCell.isImage()) {
// Blit this image over that one.
BufferedImage oldImage = oldCell.getImage();

View file

@ -44,6 +44,11 @@ public class TackboardItem implements Comparable<TackboardItem> {
// Variables --------------------------------------------------------------
// ------------------------------------------------------------------------
/**
* The board this item is on.
*/
private Tackboard tackboard;
/**
* X pixel coordinate.
*/
@ -179,7 +184,8 @@ public class TackboardItem implements Comparable<TackboardItem> {
return false;
}
TackboardItem that = (TackboardItem) rhs;
return ((this.x == that.x)
return ((this.tackboard == that.tackboard)
&& (this.x == that.x)
&& (this.y == that.y)
&& (this.z == that.z));
}
@ -241,4 +247,14 @@ public class TackboardItem implements Comparable<TackboardItem> {
return null;
}
/**
* Remove this item from its board.
*/
final public void remove() {
if (tackboard != null) {
tackboard.getItems().remove(this);
}
tackboard = null;
}
}