+++ /dev/null
-/*
- * Jexer - Java Text User Interface
- *
- * The MIT License (MIT)
- *
- * 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"),
- * 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 Kevin Lamonte [kevin.lamonte@gmail.com]
- * @version 1
- */
-package jexer.bits;
-
-import java.awt.Color;
-import java.awt.image.BufferedImage;
-
-/**
- * This class represents a single text cell or bit of image on the screen.
- */
-public final class Cell extends CellAttributes {
-
- // ------------------------------------------------------------------------
- // Constants --------------------------------------------------------------
- // ------------------------------------------------------------------------
-
- /**
- * How this cell needs to be displayed if it is part of a larger glyph.
- */
- public enum Width {
- /**
- * This cell is an entire glyph on its own.
- */
- SINGLE,
-
- /**
- * This cell is the left half of a wide glyph.
- */
- LEFT,
-
- /**
- * This cell is the right half of a wide glyph.
- */
- RIGHT,
- }
-
- /**
- * The special "this cell is unset" (null) value. This is the Unicode
- * "not a character" value.
- */
- private static final char UNSET_VALUE = (char) 65535;
-
- // ------------------------------------------------------------------------
- // Variables --------------------------------------------------------------
- // ------------------------------------------------------------------------
-
- /**
- * The character at this cell.
- */
- private char ch;
-
- /**
- * The display width of this cell.
- */
- private Width width = Width.SINGLE;
-
- /**
- * The image at this cell.
- */
- private BufferedImage image = null;
-
- /**
- * The image at this cell, inverted.
- */
- private BufferedImage invertedImage = null;
-
- /**
- * The background color used for the area the image portion might not
- * cover.
- */
- private Color background = null;
-
- /**
- * hashCode() needs to call image.hashCode(), which can get quite
- * expensive.
- */
- private int imageHashCode = 0;
-
- /**
- * hashCode() needs to call background.hashCode(), which can get quite
- * expensive.
- */
- private int backgroundHashCode = 0;
-
- // ------------------------------------------------------------------------
- // Constructors -----------------------------------------------------------
- // ------------------------------------------------------------------------
-
- /**
- * Public constructor sets default values of the cell to blank.
- *
- * @see #isBlank()
- * @see #reset()
- */
- public Cell() {
- reset();
- }
-
- /**
- * Public constructor sets the character. Attributes are the same as
- * default.
- *
- * @param ch character to set to
- * @see #reset()
- */
- public Cell(final char ch) {
- reset();
- this.ch = ch;
- }
-
- /**
- * Public constructor creates a duplicate.
- *
- * @param cell the instance to copy
- */
- public Cell(final Cell cell) {
- setTo(cell);
- }
-
- // ------------------------------------------------------------------------
- // Cell -------------------------------------------------------------------
- // ------------------------------------------------------------------------
-
- /**
- * Set the image data for this cell.
- *
- * @param image the image for this cell
- */
- public void setImage(final BufferedImage image) {
- this.image = image;
- imageHashCode = image.hashCode();
- width = Width.SINGLE;
- }
-
- /**
- * Get the image data for this cell.
- *
- * @return the image for this cell
- */
- public BufferedImage getImage() {
- if (invertedImage != null) {
- return invertedImage;
- }
- return image;
- }
-
- /**
- * Get the bitmap image background color for this cell.
- *
- * @return the bitmap image background color
- */
- public Color getBackground() {
- return background;
- }
-
- /**
- * If true, this cell has image data.
- *
- * @return true if this cell is an image rather than a character with
- * attributes
- */
- public boolean isImage() {
- if (image != null) {
- return true;
- }
- return false;
- }
-
- /**
- * Restore the image in this cell to its normal version, if it has one.
- */
- public void restoreImage() {
- invertedImage = null;
- }
-
- /**
- * If true, this cell has image data, and that data is inverted.
- *
- * @return true if this cell is an image rather than a character with
- * attributes, and the data is inverted
- */
- public boolean isInvertedImage() {
- if ((image != null) && (invertedImage != null)) {
- return true;
- }
- return false;
- }
-
- /**
- * Invert the image in this cell, if it has one.
- */
- public void invertImage() {
- if (image == null) {
- return;
- }
- if (invertedImage == null) {
- invertedImage = new BufferedImage(image.getWidth(),
- image.getHeight(), BufferedImage.TYPE_INT_ARGB);
-
- int [] rgbArray = image.getRGB(0, 0,
- image.getWidth(), image.getHeight(), null, 0, image.getWidth());
-
- for (int i = 0; i < rgbArray.length; i++) {
- // Set the colors to fully inverted.
- if (rgbArray[i] != 0x00FFFFFF) {
- rgbArray[i] ^= 0x00FFFFFF;
- }
- // Also set alpha to non-transparent.
- rgbArray[i] |= 0xFF000000;
- }
- invertedImage.setRGB(0, 0, image.getWidth(), image.getHeight(),
- rgbArray, 0, image.getWidth());
- }
- }
-
- /**
- * Getter for cell character.
- *
- * @return cell character
- */
- public char getChar() {
- return ch;
- }
-
- /**
- * Setter for cell character.
- *
- * @param ch new cell character
- */
- public void setChar(final char ch) {
- this.ch = ch;
- }
-
- /**
- * Getter for cell width.
- *
- * @return Width.SINGLE, Width.LEFT, or Width.RIGHT
- */
- public Width getWidth() {
- return width;
- }
-
- /**
- * Setter for cell width.
- *
- * @param width new cell width, one of Width.SINGLE, Width.LEFT, or
- * Width.RIGHT
- */
- public void setWidth(final Width width) {
- this.width = width;
- }
-
- /**
- * Reset this cell to a blank.
- */
- @Override
- public void reset() {
- super.reset();
- ch = ' ';
- width = Width.SINGLE;
- image = null;
- imageHashCode = 0;
- invertedImage = null;
- background = Color.BLACK;
- backgroundHashCode = 0;
- }
-
- /**
- * UNset this cell. It will not be equal to any other cell until it has
- * been assigned attributes and a character.
- */
- public void unset() {
- super.reset();
- ch = UNSET_VALUE;
- width = Width.SINGLE;
- image = null;
- imageHashCode = 0;
- invertedImage = null;
- background = Color.BLACK;
- backgroundHashCode = 0;
- }
-
- /**
- * Check to see if this cell has default attributes: white foreground,
- * black background, no bold/blink/reverse/underline/protect, and a
- * character value of ' ' (space).
- *
- * @return true if this cell has default attributes.
- */
- public boolean isBlank() {
- if ((ch == UNSET_VALUE) || (image != null)) {
- return false;
- }
- if ((getForeColor().equals(Color.WHITE))
- && (getBackColor().equals(Color.BLACK))
- && !isBold()
- && !isBlink()
- && !isReverse()
- && !isUnderline()
- && !isProtect()
- && !isRGB()
- && !isImage()
- && (width == Width.SINGLE)
- && (ch == ' ')
- ) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Comparison check. All fields must match to return true.
- *
- * @param rhs another Cell instance
- * @return true if all fields are equal
- */
- @Override
- public boolean equals(final Object rhs) {
- if (!(rhs instanceof Cell)) {
- return false;
- }
-
- Cell that = (Cell) rhs;
-
- // Unsetted cells can never be equal.
- if ((ch == UNSET_VALUE) || (that.ch == UNSET_VALUE)) {
- return false;
- }
-
- // If this or rhs has an image and the other doesn't, these are not
- // equal.
- if ((image != null) && (that.image == null)) {
- return false;
- }
- if ((image == null) && (that.image != null)) {
- return false;
- }
- // If this and rhs have images, both must match.
- if ((image != null) && (that.image != null)) {
- if ((invertedImage == null) && (that.invertedImage != null)) {
- return false;
- }
- if ((invertedImage != null) && (that.invertedImage == null)) {
- return false;
- }
- // Either both objects have their image inverted, or neither do.
- // Now if the images are identical the cells are the same
- // visually.
- if (image.equals(that.image)
- && (background.equals(that.background))
- ) {
- return true;
- } else {
- return false;
- }
- }
-
- // Normal case: character and attributes must match.
- if ((ch == that.ch) && (width == that.width)) {
- return super.equals(rhs);
- }
- return false;
- }
-
- /**
- * Hashcode uses all fields in equals().
- *
- * @return the hash
- */
- @Override
- public int hashCode() {
- int A = 13;
- int B = 23;
- int hash = A;
- hash = (B * hash) + super.hashCode();
- hash = (B * hash) + (int)ch;
- hash = (B * hash) + width.hashCode();
- if (image != null) {
- /*
- hash = (B * hash) + image.hashCode();
- hash = (B * hash) + background.hashCode();
- */
- hash = (B * hash) + imageHashCode;
- hash = (B * hash) + backgroundHashCode;
- }
- if (invertedImage != null) {
- hash = (B * hash) + invertedImage.hashCode();
- }
- return hash;
- }
-
- /**
- * Set my field values to that's field.
- *
- * @param rhs an instance of either Cell or CellAttributes
- */
- @Override
- public void setTo(final Object rhs) {
- // Let this throw a ClassCastException
- CellAttributes thatAttr = (CellAttributes) rhs;
- this.image = null;
- this.imageHashCode = 0;
- this.backgroundHashCode = 0;
- this.width = Width.SINGLE;
- super.setTo(thatAttr);
-
- if (rhs instanceof Cell) {
- Cell that = (Cell) rhs;
- this.ch = that.ch;
- this.width = that.width;
- this.image = that.image;
- this.invertedImage = that.invertedImage;
- this.background = that.background;
- this.imageHashCode = that.imageHashCode;
- this.backgroundHashCode = that.backgroundHashCode;
- }
- }
-
- /**
- * Set my field attr values to that's field.
- *
- * @param that a CellAttributes instance
- */
- public void setAttr(final CellAttributes that) {
- image = null;
- super.setTo(that);
- }
-
- /**
- * Make human-readable description of this Cell.
- *
- * @return displayable String
- */
- @Override
- public String toString() {
- return String.format("fore: %s back: %s bold: %s blink: %s ch %c",
- getForeColor(), getBackColor(), isBold(), isBlink(), ch);
- }
-}