mirror of
https://gitlab.com/AutumnMeowMeow/jexer
synced 2024-09-19 11:50:19 -06:00
window fade in/out effect
This commit is contained in:
parent
edc1303af1
commit
a229c8cbd0
10 changed files with 519 additions and 21 deletions
|
@ -13,8 +13,8 @@ like this:
|
||||||
![Terminal, Image, Table](/screenshots/new_demo1.png?raw=true "Terminal, Image, Table")
|
![Terminal, Image, Table](/screenshots/new_demo1.png?raw=true "Terminal, Image, Table")
|
||||||
|
|
||||||
...or anything in between. Translucent windows -- including layered
|
...or anything in between. Translucent windows -- including layered
|
||||||
images -- are supported and generally look like as one would expect in
|
images -- are supported and generally look as one would expect in a
|
||||||
a modern graphical environment...but it's mostly text. Translucent
|
modern graphical environment...but it's mostly text. Translucent
|
||||||
windows were inspired in part by
|
windows were inspired in part by
|
||||||
[notcurses](https://github.com/dankamongmen/notcurses).
|
[notcurses](https://github.com/dankamongmen/notcurses).
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,9 @@ import jexer.bits.CellAttributes;
|
||||||
import jexer.bits.Clipboard;
|
import jexer.bits.Clipboard;
|
||||||
import jexer.bits.ColorTheme;
|
import jexer.bits.ColorTheme;
|
||||||
import jexer.bits.StringUtils;
|
import jexer.bits.StringUtils;
|
||||||
|
import jexer.effect.Effect;
|
||||||
|
import jexer.effect.WindowFadeInEffect;
|
||||||
|
import jexer.effect.WindowFadeOutEffect;
|
||||||
import jexer.event.TCommandEvent;
|
import jexer.event.TCommandEvent;
|
||||||
import jexer.event.TInputEvent;
|
import jexer.event.TInputEvent;
|
||||||
import jexer.event.TKeypressEvent;
|
import jexer.event.TKeypressEvent;
|
||||||
|
@ -407,6 +410,11 @@ public class TApplication implements Runnable {
|
||||||
*/
|
*/
|
||||||
protected boolean translucence = true;
|
protected boolean translucence = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of desktop/window effects to run.
|
||||||
|
*/
|
||||||
|
private List<Effect> effects = new LinkedList<Effect>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WidgetEventHandler is the main event consumer loop. There are at most
|
* WidgetEventHandler is the main event consumer loop. There are at most
|
||||||
* two such threads in existence: the primary for normal case and a
|
* two such threads in existence: the primary for normal case and a
|
||||||
|
@ -905,7 +913,7 @@ public class TApplication implements Runnable {
|
||||||
addTimer(millis, true,
|
addTimer(millis, true,
|
||||||
new TAction() {
|
new TAction() {
|
||||||
public void DO() {
|
public void DO() {
|
||||||
TApplication.this.doRepaint();
|
doRepaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -919,9 +927,9 @@ public class TApplication implements Runnable {
|
||||||
addTimer(millis, true,
|
addTimer(millis, true,
|
||||||
new TAction() {
|
new TAction() {
|
||||||
public void DO() {
|
public void DO() {
|
||||||
TApplication.this.doRepaint();
|
doRepaint();
|
||||||
// Update idle checks.
|
// Update idle checks.
|
||||||
TApplication.this.getBackend().hasEvents();
|
getBackend().hasEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -932,6 +940,7 @@ public class TApplication implements Runnable {
|
||||||
TTimer animationTimer = addTimer(1000 / ANIMATION_FPS, true,
|
TTimer animationTimer = addTimer(1000 / ANIMATION_FPS, true,
|
||||||
new TAction() {
|
new TAction() {
|
||||||
public void DO() {
|
public void DO() {
|
||||||
|
runEffects();
|
||||||
doRepaint();
|
doRepaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1824,6 +1833,38 @@ public class TApplication implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the desktop and window effects.
|
||||||
|
*/
|
||||||
|
private void runEffects() {
|
||||||
|
// System.err.println("runEffects() enter");
|
||||||
|
synchronized (effects) {
|
||||||
|
if (effects.size() == 0) {
|
||||||
|
// System.err.println("runEffects() NOP");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<Effect> effectsToRun = new ArrayList<Effect>();
|
||||||
|
List<Effect> effectsToRemove = new ArrayList<Effect>();
|
||||||
|
synchronized (effects) {
|
||||||
|
effectsToRun.addAll(effects);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (effectsToRun.size() > 0) {
|
||||||
|
Effect effect = effectsToRun.remove(0);
|
||||||
|
if (effect.isCompleted()) {
|
||||||
|
effectsToRemove.add(effect);
|
||||||
|
}
|
||||||
|
effect.update();
|
||||||
|
}
|
||||||
|
if (effectsToRemove.size() > 0) {
|
||||||
|
synchronized (effects) {
|
||||||
|
effects.removeAll(effectsToRemove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// System.err.println("runEffects() exit");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do stuff when there is no user input.
|
* Do stuff when there is no user input.
|
||||||
*/
|
*/
|
||||||
|
@ -1859,6 +1900,11 @@ public class TApplication implements Runnable {
|
||||||
timers.addAll(keepTimers);
|
timers.addAll(keepTimers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (debugThreads) {
|
||||||
|
System.err.printf(System.currentTimeMillis() + " " +
|
||||||
|
Thread.currentThread() + " doIdle() 3\n");
|
||||||
|
}
|
||||||
|
|
||||||
// Call onIdle's
|
// Call onIdle's
|
||||||
for (TWindow window: windows) {
|
for (TWindow window: windows) {
|
||||||
window.onIdle();
|
window.onIdle();
|
||||||
|
@ -1879,6 +1925,11 @@ public class TApplication implements Runnable {
|
||||||
}
|
}
|
||||||
doRepaint();
|
doRepaint();
|
||||||
|
|
||||||
|
if (debugThreads) {
|
||||||
|
System.err.printf(System.currentTimeMillis() + " " +
|
||||||
|
Thread.currentThread() + " doIdle() - exit\n");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2597,7 +2648,7 @@ public class TApplication implements Runnable {
|
||||||
// Recreate the shadow effect by blending a black rectangle over just
|
// Recreate the shadow effect by blending a black rectangle over just
|
||||||
// the shadow region.
|
// the shadow region.
|
||||||
final int shadowOpacity = 30;
|
final int shadowOpacity = 30;
|
||||||
final int shadowAlpha = shadowOpacity * 255 / 100;
|
final int shadowAlpha = shadowOpacity * window.getAlpha() / 100;
|
||||||
screen.blendRectangle(windowX + windowWidth, windowY + 1,
|
screen.blendRectangle(windowX + windowWidth, windowY + 1,
|
||||||
2, windowHeight - 1, 0x000000, shadowAlpha);
|
2, windowHeight - 1, 0x000000, shadowAlpha);
|
||||||
screen.blendRectangle(windowX + 2, windowY + windowHeight,
|
screen.blendRectangle(windowX + 2, windowY + windowHeight,
|
||||||
|
@ -3190,6 +3241,18 @@ public class TApplication implements Runnable {
|
||||||
// visible on screen.
|
// visible on screen.
|
||||||
window.onPreClose();
|
window.onPreClose();
|
||||||
|
|
||||||
|
// If the window has a close effect, kick that off.
|
||||||
|
if (!window.disableCloseEffect()) {
|
||||||
|
String windowCloseEffect = System.getProperty("jexer.effect.windowClose",
|
||||||
|
"none").toLowerCase();
|
||||||
|
|
||||||
|
if (windowCloseEffect.equals("fade")) {
|
||||||
|
synchronized (effects) {
|
||||||
|
effects.add(new WindowFadeOutEffect(window));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (windows) {
|
synchronized (windows) {
|
||||||
|
|
||||||
window.stopMovements();
|
window.stopMovements();
|
||||||
|
@ -3380,6 +3443,15 @@ public class TApplication implements Runnable {
|
||||||
desktop.setActive(false);
|
desktop.setActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the window has an open effect, kick that off.
|
||||||
|
String windowOpenEffect = System.getProperty("jexer.effect.windowOpen",
|
||||||
|
"none").toLowerCase();
|
||||||
|
|
||||||
|
if (windowOpenEffect.equals("fade")) {
|
||||||
|
synchronized (effects) {
|
||||||
|
effects.add(new WindowFadeInEffect(window));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -252,6 +252,11 @@ public class TWindow extends TWidget {
|
||||||
*/
|
*/
|
||||||
private int alpha = 255;
|
private int alpha = 255;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The window open effect timer.
|
||||||
|
*/
|
||||||
|
private TTimer openEffectTimer = null;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Constructors -----------------------------------------------------------
|
// Constructors -----------------------------------------------------------
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -339,9 +344,6 @@ public class TWindow extends TWidget {
|
||||||
// Center window if specified
|
// Center window if specified
|
||||||
center();
|
center();
|
||||||
|
|
||||||
// Add me to the application
|
|
||||||
application.addWindowToApplication(this);
|
|
||||||
|
|
||||||
// Set default borders
|
// Set default borders
|
||||||
setBorderStyleForeground(null);
|
setBorderStyleForeground(null);
|
||||||
setBorderStyleInactive(null);
|
setBorderStyleInactive(null);
|
||||||
|
@ -358,6 +360,9 @@ public class TWindow extends TWidget {
|
||||||
// SQUASH
|
// SQUASH
|
||||||
}
|
}
|
||||||
setAlpha(opacity * 255 / 100);
|
setAlpha(opacity * 255 / 100);
|
||||||
|
|
||||||
|
// Add me to the application
|
||||||
|
application.addWindowToApplication(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -1860,4 +1865,15 @@ public class TWindow extends TWidget {
|
||||||
return alpha;
|
return alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, disable any window closing effect. This is used by the
|
||||||
|
* window closing effects themselves so that they can be closed when
|
||||||
|
* finished.
|
||||||
|
*
|
||||||
|
* @return true if the window close effect should be disabled
|
||||||
|
*/
|
||||||
|
public boolean disableCloseEffect() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1931,10 +1931,9 @@ public class ECMA48Terminal extends LogicalScreen
|
||||||
if (imageThreadCount > 1) {
|
if (imageThreadCount > 1) {
|
||||||
// Collect all the encoded images.
|
// Collect all the encoded images.
|
||||||
while (imageResults.size() > 0) {
|
while (imageResults.size() > 0) {
|
||||||
|
Future<String> image = imageResults.get(0);
|
||||||
try {
|
try {
|
||||||
Future<String> image = imageResults.get(0);
|
|
||||||
sb.append(image.get());
|
sb.append(image.get());
|
||||||
imageResults.remove(0);
|
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// SQUASH
|
// SQUASH
|
||||||
// e.printStackTrace();
|
// e.printStackTrace();
|
||||||
|
@ -1942,6 +1941,7 @@ public class ECMA48Terminal extends LogicalScreen
|
||||||
// SQUASH
|
// SQUASH
|
||||||
// e.printStackTrace();
|
// e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
imageResults.remove(0);
|
||||||
}
|
}
|
||||||
imageExecutor.shutdown();
|
imageExecutor.shutdown();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1354,6 +1354,38 @@ public class LogicalScreen implements Screen {
|
||||||
return other;
|
return other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain a snapshot copy of a rectangular portion of the screen of the
|
||||||
|
* PHYSICAL screen - what was LAST emitted.
|
||||||
|
*
|
||||||
|
* @param x left column of rectangle. 0 is the left-most column.
|
||||||
|
* @param y top row of the rectangle. 0 is the top-most row.
|
||||||
|
* @param width number of columns to copy
|
||||||
|
* @param height number of rows to copy
|
||||||
|
* @return a copy of the screen's data from this rectangle. Any cells
|
||||||
|
* outside the actual screen dimensions will be blank.
|
||||||
|
*/
|
||||||
|
public Screen snapshotPhysical(final int x, final int y, final int width,
|
||||||
|
final int height) {
|
||||||
|
|
||||||
|
LogicalScreen other = null;
|
||||||
|
synchronized (this) {
|
||||||
|
other = new LogicalScreen(width, height);
|
||||||
|
for (int row = y; (row < y + height) && (row < this.height); row++) {
|
||||||
|
if (row < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int col = x; (col < x + width) && (col < this.width); col++) {
|
||||||
|
if (col < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
other.logical[col - x][row - y] = new Cell(physical[col][row]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return other;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy all of screen's data to this screen.
|
* Copy all of screen's data to this screen.
|
||||||
*
|
*
|
||||||
|
@ -1468,6 +1500,8 @@ public class LogicalScreen implements Screen {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to blend the background colors of other's cells over the
|
* We need to blend the background colors of other's cells over the
|
||||||
* cells of this screen (foreground and background), honoring our
|
* cells of this screen (foreground and background), honoring our
|
||||||
|
@ -1480,6 +1514,8 @@ public class LogicalScreen implements Screen {
|
||||||
BufferedImage.TYPE_INT_ARGB);
|
BufferedImage.TYPE_INT_ARGB);
|
||||||
BufferedImage thisBackground = new BufferedImage(width, height,
|
BufferedImage thisBackground = new BufferedImage(width, height,
|
||||||
BufferedImage.TYPE_INT_ARGB);
|
BufferedImage.TYPE_INT_ARGB);
|
||||||
|
BufferedImage overForeground = new BufferedImage(width, height,
|
||||||
|
BufferedImage.TYPE_INT_ARGB);
|
||||||
BufferedImage overBackground = new BufferedImage(width, height,
|
BufferedImage overBackground = new BufferedImage(width, height,
|
||||||
BufferedImage.TYPE_INT_ARGB);
|
BufferedImage.TYPE_INT_ARGB);
|
||||||
BufferedImage thisOldBackground = new BufferedImage(width, height,
|
BufferedImage thisOldBackground = new BufferedImage(width, height,
|
||||||
|
@ -1515,6 +1551,16 @@ public class LogicalScreen implements Screen {
|
||||||
}
|
}
|
||||||
|
|
||||||
Cell over = otherScreen.getCharXY(col - x, row - y);
|
Cell over = otherScreen.getCharXY(col - x, row - y);
|
||||||
|
int overFg = over.getForeColorRGB();
|
||||||
|
if (over.isPulse()) {
|
||||||
|
overFg = over.getForeColorPulseRGB(backend, now);
|
||||||
|
} else if (overFg < 0) {
|
||||||
|
if (backend != null) {
|
||||||
|
overFg = backend.attrToForegroundColor(over).getRGB();
|
||||||
|
} else {
|
||||||
|
overFg = SwingTerminal.attrToForegroundColor(over).getRGB();
|
||||||
|
}
|
||||||
|
}
|
||||||
int overBg = over.getBackColorRGB();
|
int overBg = over.getBackColorRGB();
|
||||||
if (overBg < 0) {
|
if (overBg < 0) {
|
||||||
if (backend != null) {
|
if (backend != null) {
|
||||||
|
@ -1526,18 +1572,23 @@ public class LogicalScreen implements Screen {
|
||||||
thisFg |= OPAQUE;
|
thisFg |= OPAQUE;
|
||||||
thisBg |= OPAQUE;
|
thisBg |= OPAQUE;
|
||||||
overBg |= OPAQUE;
|
overBg |= OPAQUE;
|
||||||
|
overFg |= OPAQUE;
|
||||||
|
|
||||||
thisForeground.setRGB(col - x, row - y, thisFg);
|
thisForeground.setRGB(col - x, row - y, thisFg);
|
||||||
thisBackground.setRGB(col - x, row - y, thisBg);
|
thisBackground.setRGB(col - x, row - y, thisBg);
|
||||||
thisOldBackground.setRGB(col - x, row - y, thisBg);
|
thisOldBackground.setRGB(col - x, row - y, thisBg);
|
||||||
|
overForeground.setRGB(col - x, row - y, overFg);
|
||||||
overBackground.setRGB(col - x, row - y, overBg);
|
overBackground.setRGB(col - x, row - y, overBg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The three bitmaps are ready. We have skipped over
|
// The four bitmaps are ready. We have skipped over cells/pixels
|
||||||
// cells/pixels that cannot overlap. Now blit overBackground
|
// that cannot overlap. Now blit overBackground over both
|
||||||
// over both thisForeground and thisBackground, and then assign
|
// thisForeground and thisBackground, and then assign cell colors
|
||||||
// cell colors and cell chars/images.
|
// and cell chars/images.
|
||||||
|
//
|
||||||
|
// Also blit overForeground over thisBackground to handle the new
|
||||||
|
// layer's glyph opacity.
|
||||||
float fAlpha = (float) (alpha / 255.0);
|
float fAlpha = (float) (alpha / 255.0);
|
||||||
Graphics2D g2d = thisForeground.createGraphics();
|
Graphics2D g2d = thisForeground.createGraphics();
|
||||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
|
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
|
||||||
|
@ -1551,6 +1602,15 @@ public class LogicalScreen implements Screen {
|
||||||
g2d.drawImage(overBackground, 0, 0, null);
|
g2d.drawImage(overBackground, 0, 0, null);
|
||||||
g2d.dispose();
|
g2d.dispose();
|
||||||
|
|
||||||
|
BufferedImage glyphForeground = new BufferedImage(width, height,
|
||||||
|
BufferedImage.TYPE_INT_ARGB);
|
||||||
|
g2d = glyphForeground.createGraphics();
|
||||||
|
g2d.drawImage(thisBackground, 0, 0, null);
|
||||||
|
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
|
||||||
|
fAlpha));
|
||||||
|
g2d.drawImage(overForeground, 0, 0, null);
|
||||||
|
g2d.dispose();
|
||||||
|
|
||||||
for (int row = y; (row < y + height) && (row < this.height); row++) {
|
for (int row = y; (row < y + height) && (row < this.height); row++) {
|
||||||
if (row < 0) {
|
if (row < 0) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1565,6 +1625,7 @@ public class LogicalScreen implements Screen {
|
||||||
int thisBg = thisBackground.getRGB(col - x, row - y);
|
int thisBg = thisBackground.getRGB(col - x, row - y);
|
||||||
int thisOldBg = thisOldBackground.getRGB(col - x, row - y);
|
int thisOldBg = thisOldBackground.getRGB(col - x, row - y);
|
||||||
int overBg = overBackground.getRGB(col - x, row - y);
|
int overBg = overBackground.getRGB(col - x, row - y);
|
||||||
|
int overFg = glyphForeground.getRGB(col - x, row - y);
|
||||||
|
|
||||||
thisCell.setBackColorRGB(thisBg | OPAQUE);
|
thisCell.setBackColorRGB(thisBg | OPAQUE);
|
||||||
thisCell.setForeColorRGB(thisFg | OPAQUE);
|
thisCell.setForeColorRGB(thisFg | OPAQUE);
|
||||||
|
@ -1595,6 +1656,7 @@ public class LogicalScreen implements Screen {
|
||||||
if (imageId > 0) {
|
if (imageId > 0) {
|
||||||
thisCell.setImage(newImage, imageId);
|
thisCell.setImage(newImage, imageId);
|
||||||
thisCell.mixImageId(overBg);
|
thisCell.mixImageId(overBg);
|
||||||
|
thisCell.mixImageId(alpha);
|
||||||
} else {
|
} else {
|
||||||
thisCell.setImage(newImage);
|
thisCell.setImage(newImage);
|
||||||
}
|
}
|
||||||
|
@ -1632,17 +1694,13 @@ public class LogicalScreen implements Screen {
|
||||||
|
|
||||||
// The overlaying cell has a character, use it.
|
// The overlaying cell has a character, use it.
|
||||||
thisCell.setChar(overCell.getChar());
|
thisCell.setChar(overCell.getChar());
|
||||||
int fg = overCell.getForeColorRGB();
|
thisCell.setForeColorRGB(overFg);
|
||||||
if (fg < 0) {
|
|
||||||
thisCell.setForeColor(overCell.getForeColor());
|
|
||||||
} else {
|
|
||||||
thisCell.setForeColorRGB(fg);
|
|
||||||
}
|
|
||||||
thisCell.setBold(overCell.isBold());
|
thisCell.setBold(overCell.isBold());
|
||||||
thisCell.setBlink(overCell.isBlink());
|
thisCell.setBlink(overCell.isBlink());
|
||||||
thisCell.setUnderline(overCell.isUnderline());
|
thisCell.setUnderline(overCell.isUnderline());
|
||||||
thisCell.setProtect(overCell.isProtect());
|
thisCell.setProtect(overCell.isProtect());
|
||||||
thisCell.setAnimations(overCell.getAnimations());
|
thisCell.setAnimations(overCell.getAnimations());
|
||||||
|
thisCell.setPulse(false, false, 0);
|
||||||
|
|
||||||
if (!overCell.isImage()) {
|
if (!overCell.isImage()) {
|
||||||
// If we had an image, destroy it. Text ALWAYS
|
// If we had an image, destroy it. Text ALWAYS
|
||||||
|
@ -1678,6 +1736,7 @@ public class LogicalScreen implements Screen {
|
||||||
if (imageId > 0) {
|
if (imageId > 0) {
|
||||||
thisCell.setImage(newImage, imageId);
|
thisCell.setImage(newImage, imageId);
|
||||||
thisCell.mixImageId(thisOldBg);
|
thisCell.mixImageId(thisOldBg);
|
||||||
|
thisCell.mixImageId(alpha);
|
||||||
} else {
|
} else {
|
||||||
thisCell.setImage(newImage);
|
thisCell.setImage(newImage);
|
||||||
}
|
}
|
||||||
|
@ -1713,6 +1772,7 @@ public class LogicalScreen implements Screen {
|
||||||
if (imageId > 0) {
|
if (imageId > 0) {
|
||||||
thisCell.setImage(newImage, imageId);
|
thisCell.setImage(newImage, imageId);
|
||||||
thisCell.mixImageId(overCell);
|
thisCell.mixImageId(overCell);
|
||||||
|
thisCell.mixImageId(alpha);
|
||||||
} else {
|
} else {
|
||||||
thisCell.setImage(newImage);
|
thisCell.setImage(newImage);
|
||||||
}
|
}
|
||||||
|
@ -1747,6 +1807,7 @@ public class LogicalScreen implements Screen {
|
||||||
thisCell.setImage(newImage, imageId);
|
thisCell.setImage(newImage, imageId);
|
||||||
thisCell.mixImageId(overCell);
|
thisCell.mixImageId(overCell);
|
||||||
thisCell.mixImageId(overBg);
|
thisCell.mixImageId(overBg);
|
||||||
|
thisCell.mixImageId(alpha);
|
||||||
} else {
|
} else {
|
||||||
thisCell.setImage(newImage);
|
thisCell.setImage(newImage);
|
||||||
}
|
}
|
||||||
|
@ -1782,6 +1843,7 @@ public class LogicalScreen implements Screen {
|
||||||
thisCell.setImage(newImage, imageId);
|
thisCell.setImage(newImage, imageId);
|
||||||
thisCell.mixImageId(overBg);
|
thisCell.mixImageId(overBg);
|
||||||
thisCell.mixImageId(thisOldBg);
|
thisCell.mixImageId(thisOldBg);
|
||||||
|
thisCell.mixImageId(alpha);
|
||||||
} else {
|
} else {
|
||||||
thisCell.setImage(newImage);
|
thisCell.setImage(newImage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -511,6 +511,20 @@ public interface Screen {
|
||||||
*/
|
*/
|
||||||
public Screen snapshot();
|
public Screen snapshot();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain a snapshot copy of a rectangular portion of the screen of the
|
||||||
|
* PHYSICAL screen - what was LAST emitted.
|
||||||
|
*
|
||||||
|
* @param x left column of rectangle. 0 is the left-most column.
|
||||||
|
* @param y top row of the rectangle. 0 is the top-most row.
|
||||||
|
* @param width number of columns to copy
|
||||||
|
* @param height number of rows to copy
|
||||||
|
* @return a copy of the screen's data from this rectangle. Any cells
|
||||||
|
* outside the actual screen dimensions will be blank.
|
||||||
|
*/
|
||||||
|
public Screen snapshotPhysical(final int x, final int y, final int width,
|
||||||
|
final int height);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain a snapshot copy of a rectangular portion of the screen.
|
* Obtain a snapshot copy of a rectangular portion of the screen.
|
||||||
*
|
*
|
||||||
|
|
49
src/jexer/effect/Effect.java
Normal file
49
src/jexer/effect/Effect.java
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Jexer - Java Text User Interface
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 Autumn Lamonte
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author Autumn Lamonte ⚧ Trans Liberation Now
|
||||||
|
* @version 1
|
||||||
|
*/
|
||||||
|
package jexer.effect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A desktop or window effect does a blingy transformation before the screen
|
||||||
|
* is sent to the device.
|
||||||
|
*/
|
||||||
|
public interface Effect {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the effect.
|
||||||
|
*/
|
||||||
|
public void update();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, the effect is completed and can be removed.
|
||||||
|
*
|
||||||
|
* @return true if this effect is finished
|
||||||
|
*/
|
||||||
|
public boolean isCompleted();
|
||||||
|
|
||||||
|
}
|
100
src/jexer/effect/WindowFadeInEffect.java
Normal file
100
src/jexer/effect/WindowFadeInEffect.java
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Jexer - Java Text User Interface
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 Autumn Lamonte
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author Autumn Lamonte ⚧ Trans Liberation Now
|
||||||
|
* @version 1
|
||||||
|
*/
|
||||||
|
package jexer.effect;
|
||||||
|
|
||||||
|
import jexer.TWindow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A desktop or window effect does a blingy transformation before the screen
|
||||||
|
* is sent to the device.
|
||||||
|
*/
|
||||||
|
public class WindowFadeInEffect implements Effect {
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Constants --------------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Variables --------------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The window to fade in.
|
||||||
|
*/
|
||||||
|
private TWindow window;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The window's original alpha value we are ramping up to.
|
||||||
|
*/
|
||||||
|
private int targetAlpha = 0;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Constructors -----------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public contructor.
|
||||||
|
*
|
||||||
|
* @param window the window to fade in
|
||||||
|
*/
|
||||||
|
public WindowFadeInEffect(final TWindow window) {
|
||||||
|
this.window = window;
|
||||||
|
targetAlpha = window.getAlpha();
|
||||||
|
window.setAlpha(64);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Effect -----------------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the effect.
|
||||||
|
*/
|
||||||
|
public void update() {
|
||||||
|
if (!window.isShown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int alpha = window.getAlpha();
|
||||||
|
if (alpha < targetAlpha) {
|
||||||
|
// Aiming for 1/8 second, at 32 FPS = 4 frames. 256 / 4 = 64.
|
||||||
|
alpha = Math.min(alpha + 64, targetAlpha);
|
||||||
|
window.setAlpha(alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, the effect is completed and can be removed.
|
||||||
|
*
|
||||||
|
* @return true if this effect is finished
|
||||||
|
*/
|
||||||
|
public boolean isCompleted() {
|
||||||
|
return (window.getAlpha() >= targetAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
152
src/jexer/effect/WindowFadeOutEffect.java
Normal file
152
src/jexer/effect/WindowFadeOutEffect.java
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* Jexer - Java Text User Interface
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 Autumn Lamonte
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author Autumn Lamonte ⚧ Trans Liberation Now
|
||||||
|
* @version 1
|
||||||
|
*/
|
||||||
|
package jexer.effect;
|
||||||
|
|
||||||
|
import jexer.TWindow;
|
||||||
|
import jexer.backend.Screen;
|
||||||
|
import jexer.event.TInputEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A desktop or window effect does a blingy transformation before the screen
|
||||||
|
* is sent to the device.
|
||||||
|
*/
|
||||||
|
public class WindowFadeOutEffect implements Effect {
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Constants --------------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Variables --------------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fake window to fade out.
|
||||||
|
*/
|
||||||
|
private TWindow fakeWindow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The region of the screen the window last rendered to.
|
||||||
|
*/
|
||||||
|
private Screen oldScreen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The alpha value to set fakeWindow to.
|
||||||
|
*/
|
||||||
|
private int alpha;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Constructors -----------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public contructor.
|
||||||
|
*
|
||||||
|
* @param window the window to fade in
|
||||||
|
*/
|
||||||
|
public WindowFadeOutEffect(final TWindow window) {
|
||||||
|
final Screen oldScreen = window.getScreen().snapshotPhysical(
|
||||||
|
window.getX(), window.getY(),
|
||||||
|
window.getWidth(), window.getHeight());
|
||||||
|
|
||||||
|
alpha = window.getAlpha();
|
||||||
|
|
||||||
|
final int x = window.getX();
|
||||||
|
final int y = window.getY();
|
||||||
|
|
||||||
|
window.getApplication().invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
fakeWindow = new TWindow(window.getApplication(), "",
|
||||||
|
window.getX(), window.getY(),
|
||||||
|
window.getWidth(), window.getHeight(),
|
||||||
|
TWindow.MODAL) {
|
||||||
|
|
||||||
|
// Disable all inputs.
|
||||||
|
@Override
|
||||||
|
public void handleEvent(final TInputEvent event) {
|
||||||
|
// NOP
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the old screen.
|
||||||
|
@Override
|
||||||
|
public void draw() {
|
||||||
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
|
putCharXY(x, y, oldScreen.getCharXY(x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean disableCloseEffect() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fakeWindow.setX(x);
|
||||||
|
fakeWindow.setY(y);
|
||||||
|
fakeWindow.setAlpha(alpha);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Effect -----------------------------------------------------------------
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the effect.
|
||||||
|
*/
|
||||||
|
public void update() {
|
||||||
|
if (fakeWindow == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (alpha > 0) {
|
||||||
|
// Aiming for 1/8 second, at 32 FPS = 4 frames. 256 / 4 = 64.
|
||||||
|
alpha = Math.max(alpha - 96, 0);
|
||||||
|
fakeWindow.setAlpha(alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, the effect is completed and can be removed.
|
||||||
|
*
|
||||||
|
* @return true if this effect is finished
|
||||||
|
*/
|
||||||
|
public boolean isCompleted() {
|
||||||
|
if (fakeWindow != null) {
|
||||||
|
if (alpha == 0) {
|
||||||
|
fakeWindow.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
33
src/jexer/effect/package-info.java
Normal file
33
src/jexer/effect/package-info.java
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Jexer - Java Text User Interface
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 Autumn Lamonte
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author Autumn Lamonte ⚧ Trans Liberation Now
|
||||||
|
* @version 1
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Desktop and window effects.
|
||||||
|
*/
|
||||||
|
package jexer.effect;
|
Loading…
Reference in a new issue