mirror of
https://gitlab.com/AutumnMeowMeow/jexer
synced 2024-09-19 03:40:20 -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")
|
||||
|
||||
...or anything in between. Translucent windows -- including layered
|
||||
images -- are supported and generally look like as one would expect in
|
||||
a modern graphical environment...but it's mostly text. Translucent
|
||||
images -- are supported and generally look as one would expect in a
|
||||
modern graphical environment...but it's mostly text. Translucent
|
||||
windows were inspired in part by
|
||||
[notcurses](https://github.com/dankamongmen/notcurses).
|
||||
|
||||
|
|
|
@ -51,6 +51,9 @@ import jexer.bits.CellAttributes;
|
|||
import jexer.bits.Clipboard;
|
||||
import jexer.bits.ColorTheme;
|
||||
import jexer.bits.StringUtils;
|
||||
import jexer.effect.Effect;
|
||||
import jexer.effect.WindowFadeInEffect;
|
||||
import jexer.effect.WindowFadeOutEffect;
|
||||
import jexer.event.TCommandEvent;
|
||||
import jexer.event.TInputEvent;
|
||||
import jexer.event.TKeypressEvent;
|
||||
|
@ -407,6 +410,11 @@ public class TApplication implements Runnable {
|
|||
*/
|
||||
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
|
||||
* two such threads in existence: the primary for normal case and a
|
||||
|
@ -905,7 +913,7 @@ public class TApplication implements Runnable {
|
|||
addTimer(millis, true,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
TApplication.this.doRepaint();
|
||||
doRepaint();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -919,9 +927,9 @@ public class TApplication implements Runnable {
|
|||
addTimer(millis, true,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
TApplication.this.doRepaint();
|
||||
doRepaint();
|
||||
// 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,
|
||||
new TAction() {
|
||||
public void DO() {
|
||||
runEffects();
|
||||
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.
|
||||
*/
|
||||
|
@ -1859,6 +1900,11 @@ public class TApplication implements Runnable {
|
|||
timers.addAll(keepTimers);
|
||||
}
|
||||
|
||||
if (debugThreads) {
|
||||
System.err.printf(System.currentTimeMillis() + " " +
|
||||
Thread.currentThread() + " doIdle() 3\n");
|
||||
}
|
||||
|
||||
// Call onIdle's
|
||||
for (TWindow window: windows) {
|
||||
window.onIdle();
|
||||
|
@ -1879,6 +1925,11 @@ public class TApplication implements Runnable {
|
|||
}
|
||||
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
|
||||
// the shadow region.
|
||||
final int shadowOpacity = 30;
|
||||
final int shadowAlpha = shadowOpacity * 255 / 100;
|
||||
final int shadowAlpha = shadowOpacity * window.getAlpha() / 100;
|
||||
screen.blendRectangle(windowX + windowWidth, windowY + 1,
|
||||
2, windowHeight - 1, 0x000000, shadowAlpha);
|
||||
screen.blendRectangle(windowX + 2, windowY + windowHeight,
|
||||
|
@ -3190,6 +3241,18 @@ public class TApplication implements Runnable {
|
|||
// visible on screen.
|
||||
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) {
|
||||
|
||||
window.stopMovements();
|
||||
|
@ -3380,6 +3443,15 @@ public class TApplication implements Runnable {
|
|||
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;
|
||||
|
||||
/**
|
||||
* The window open effect timer.
|
||||
*/
|
||||
private TTimer openEffectTimer = null;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors -----------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -339,9 +344,6 @@ public class TWindow extends TWidget {
|
|||
// Center window if specified
|
||||
center();
|
||||
|
||||
// Add me to the application
|
||||
application.addWindowToApplication(this);
|
||||
|
||||
// Set default borders
|
||||
setBorderStyleForeground(null);
|
||||
setBorderStyleInactive(null);
|
||||
|
@ -358,6 +360,9 @@ public class TWindow extends TWidget {
|
|||
// SQUASH
|
||||
}
|
||||
setAlpha(opacity * 255 / 100);
|
||||
|
||||
// Add me to the application
|
||||
application.addWindowToApplication(this);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -1860,4 +1865,15 @@ public class TWindow extends TWidget {
|
|||
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) {
|
||||
// Collect all the encoded images.
|
||||
while (imageResults.size() > 0) {
|
||||
Future<String> image = imageResults.get(0);
|
||||
try {
|
||||
Future<String> image = imageResults.get(0);
|
||||
sb.append(image.get());
|
||||
imageResults.remove(0);
|
||||
} catch (InterruptedException e) {
|
||||
// SQUASH
|
||||
// e.printStackTrace();
|
||||
|
@ -1942,6 +1941,7 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
// SQUASH
|
||||
// e.printStackTrace();
|
||||
}
|
||||
imageResults.remove(0);
|
||||
}
|
||||
imageExecutor.shutdown();
|
||||
}
|
||||
|
|
|
@ -1354,6 +1354,38 @@ public class LogicalScreen implements Screen {
|
|||
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.
|
||||
*
|
||||
|
@ -1468,6 +1500,8 @@ public class LogicalScreen implements Screen {
|
|||
return;
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
/*
|
||||
* We need to blend the background colors of other's cells over the
|
||||
* cells of this screen (foreground and background), honoring our
|
||||
|
@ -1480,6 +1514,8 @@ public class LogicalScreen implements Screen {
|
|||
BufferedImage.TYPE_INT_ARGB);
|
||||
BufferedImage thisBackground = new BufferedImage(width, height,
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
BufferedImage overForeground = new BufferedImage(width, height,
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
BufferedImage overBackground = new BufferedImage(width, height,
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
BufferedImage thisOldBackground = new BufferedImage(width, height,
|
||||
|
@ -1515,6 +1551,16 @@ public class LogicalScreen implements Screen {
|
|||
}
|
||||
|
||||
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();
|
||||
if (overBg < 0) {
|
||||
if (backend != null) {
|
||||
|
@ -1526,18 +1572,23 @@ public class LogicalScreen implements Screen {
|
|||
thisFg |= OPAQUE;
|
||||
thisBg |= OPAQUE;
|
||||
overBg |= OPAQUE;
|
||||
overFg |= OPAQUE;
|
||||
|
||||
thisForeground.setRGB(col - x, row - y, thisFg);
|
||||
thisBackground.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);
|
||||
}
|
||||
}
|
||||
|
||||
// The three bitmaps are ready. We have skipped over
|
||||
// cells/pixels that cannot overlap. Now blit overBackground
|
||||
// over both thisForeground and thisBackground, and then assign
|
||||
// cell colors and cell chars/images.
|
||||
// The four bitmaps are ready. We have skipped over cells/pixels
|
||||
// that cannot overlap. Now blit overBackground over both
|
||||
// thisForeground and thisBackground, and then assign cell colors
|
||||
// and cell chars/images.
|
||||
//
|
||||
// Also blit overForeground over thisBackground to handle the new
|
||||
// layer's glyph opacity.
|
||||
float fAlpha = (float) (alpha / 255.0);
|
||||
Graphics2D g2d = thisForeground.createGraphics();
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
|
||||
|
@ -1551,6 +1602,15 @@ public class LogicalScreen implements Screen {
|
|||
g2d.drawImage(overBackground, 0, 0, null);
|
||||
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++) {
|
||||
if (row < 0) {
|
||||
continue;
|
||||
|
@ -1565,6 +1625,7 @@ public class LogicalScreen implements Screen {
|
|||
int thisBg = thisBackground.getRGB(col - x, row - y);
|
||||
int thisOldBg = thisOldBackground.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.setForeColorRGB(thisFg | OPAQUE);
|
||||
|
@ -1595,6 +1656,7 @@ public class LogicalScreen implements Screen {
|
|||
if (imageId > 0) {
|
||||
thisCell.setImage(newImage, imageId);
|
||||
thisCell.mixImageId(overBg);
|
||||
thisCell.mixImageId(alpha);
|
||||
} else {
|
||||
thisCell.setImage(newImage);
|
||||
}
|
||||
|
@ -1632,17 +1694,13 @@ public class LogicalScreen implements Screen {
|
|||
|
||||
// The overlaying cell has a character, use it.
|
||||
thisCell.setChar(overCell.getChar());
|
||||
int fg = overCell.getForeColorRGB();
|
||||
if (fg < 0) {
|
||||
thisCell.setForeColor(overCell.getForeColor());
|
||||
} else {
|
||||
thisCell.setForeColorRGB(fg);
|
||||
}
|
||||
thisCell.setForeColorRGB(overFg);
|
||||
thisCell.setBold(overCell.isBold());
|
||||
thisCell.setBlink(overCell.isBlink());
|
||||
thisCell.setUnderline(overCell.isUnderline());
|
||||
thisCell.setProtect(overCell.isProtect());
|
||||
thisCell.setAnimations(overCell.getAnimations());
|
||||
thisCell.setPulse(false, false, 0);
|
||||
|
||||
if (!overCell.isImage()) {
|
||||
// If we had an image, destroy it. Text ALWAYS
|
||||
|
@ -1678,6 +1736,7 @@ public class LogicalScreen implements Screen {
|
|||
if (imageId > 0) {
|
||||
thisCell.setImage(newImage, imageId);
|
||||
thisCell.mixImageId(thisOldBg);
|
||||
thisCell.mixImageId(alpha);
|
||||
} else {
|
||||
thisCell.setImage(newImage);
|
||||
}
|
||||
|
@ -1713,6 +1772,7 @@ public class LogicalScreen implements Screen {
|
|||
if (imageId > 0) {
|
||||
thisCell.setImage(newImage, imageId);
|
||||
thisCell.mixImageId(overCell);
|
||||
thisCell.mixImageId(alpha);
|
||||
} else {
|
||||
thisCell.setImage(newImage);
|
||||
}
|
||||
|
@ -1747,6 +1807,7 @@ public class LogicalScreen implements Screen {
|
|||
thisCell.setImage(newImage, imageId);
|
||||
thisCell.mixImageId(overCell);
|
||||
thisCell.mixImageId(overBg);
|
||||
thisCell.mixImageId(alpha);
|
||||
} else {
|
||||
thisCell.setImage(newImage);
|
||||
}
|
||||
|
@ -1782,6 +1843,7 @@ public class LogicalScreen implements Screen {
|
|||
thisCell.setImage(newImage, imageId);
|
||||
thisCell.mixImageId(overBg);
|
||||
thisCell.mixImageId(thisOldBg);
|
||||
thisCell.mixImageId(alpha);
|
||||
} else {
|
||||
thisCell.setImage(newImage);
|
||||
}
|
||||
|
|
|
@ -511,6 +511,20 @@ public interface Screen {
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
|
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