view ScreenAdjuster.java @ 1:c5bdb7bee4a7

Refactor displayMessage. Enable holding messages. Cleanup.
author Tom Fredrik Blenning Klaussen <bfg@bfgconsult.no>
date Wed, 08 Jan 2014 19:00:08 +0100
parents 855307f4bf5e
children 77e2655ac09d
line wrap: on
line source

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.util.*;

class ScreenAdjuster extends JFrame implements ActionListener
{
    final float TIMEOUT_IN_SECONDS = 2.5f;
    int frameNumber = -1;
    Vector<String> messageText = null;
    Color backgroundColor = Color.BLACK;
    Color foregroundColor;
    Color outlineColor;
    boolean messageVisible = false;
    boolean messageOutline = false;
    boolean messageBBox = false;

    enum MessageStatus { TIMEOUT, SHOW, HIDE };

    javax.swing.Timer messageTimeout =
	new javax.swing.Timer((int)(TIMEOUT_IN_SECONDS * 1000), this);

    ScreenAdjuster(boolean fullScreen)
    {
	messageTimeout.setRepeats(false);

	nextFrame();

	if (fullScreen) {
	    setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	    setUndecorated(true);
	    //setResizable(false);
	    /*
	    Rectangle bounds = getBounds();
	    setBounds(bounds.x,bounds.y,200,200);
	    setVisible(true);
	    */
	    /*
	      fullscreenFrame.add(new JLabel("Press ALT+F4 to exit fullscreen.",
	      SwingConstants.CENTER),
	      BorderLayout.CENTER);
	    */
	    validate();
	
	    setVisible(true);
	    GraphicsEnvironment.getLocalGraphicsEnvironment()
		.getDefaultScreenDevice().setFullScreenWindow(this);
	}
	else {
	    Rectangle bounds = getBounds();
	    setBounds(bounds.x,bounds.y,200,200);
	    setVisible(true);

	}
	enableEvents(AWTEvent.KEY_EVENT_MASK);

    }

    public void actionPerformed(ActionEvent evt)
    {
	messageVisible = false;
	repaint();
    }

    protected void processKeyEvent(KeyEvent e)
    {
	int increase = 1;
	MessageStatus messageStatus = MessageStatus.TIMEOUT;
	if (e.getID() == KeyEvent.KEY_PRESSED) {
	    Log.DEFAULT.println(e.paramString());
	    if (e.getKeyCode() == KeyEvent.VK_Q) {
		System.exit(0);
	    }
	    if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
		increase = -1;
	    }
	    else if (e.getKeyCode() == KeyEvent.VK_S) {
		messageTimeout.stop();
		increase = 0;
		messageStatus = MessageStatus.SHOW;
	    }
	    else if (e.getKeyCode() == KeyEvent.VK_H) {
		messageTimeout.stop();
		increase = 0;
		messageStatus = MessageStatus.HIDE;
	    }
	    Log.DEFAULT.println(e.getKeyText(e.getKeyCode()));
	    displayFrame(increase, messageStatus);
	}
    }

    static Color complementary(Color in)
    {
	if (in != null) {
	    float hsb [] = Color.RGBtoHSB(in.getRed(),
					  in.getGreen(),
					  in.getBlue(), null);
	    return Color.getHSBColor(hsb[0], hsb[1], 1 - hsb[2]);
	}
	return Color.BLACK;
    }

    void nextFrame()
    {
	displayFrame(1, MessageStatus.TIMEOUT);
    }

    void displayFrame(int increase, MessageStatus messageStatus)
    {
	int numFrames = this.numFrames();
	frameNumber = (frameNumber + increase + numFrames) % numFrames;
	foregroundColor = null;
	backgroundColor = null;
	outlineColor = null;
	messageText = new Vector<String>(0);
	messageBBox = false;

	switch (frameNumber) {
	case 0:
	    messageText.add("This screen should appear all BLACK!");
	    messageText.add("Please check for any dead pixels.");
	    messageText.add("");
	    messageText.add("Appart from this, please use this opportunity to clean your screen.");
	    backgroundColor = Color.BLACK;
	    break;
	case 1:
	    messageText.add("This screen should appear all WHITE!");
	    messageText.add("Please check for any dead pixels.");
	    messageText.add("");
	    messageText.add("Appart from this, please use this opportunity to clean your screen.");
	    backgroundColor = Color.WHITE;
	    break;
	case 2:
	    messageText.add("This screen should appear all RED!");
	    messageText.add("Please check for any dead pixels.");
	    backgroundColor = Color.RED;
	    break;
	case 3:
	    messageText.add("This screen should appear all GREEN!");
	    messageText.add("Please check for any dead pixels.");
	    backgroundColor = Color.GREEN;
	    break;
	case 4:
	    messageText.add("This screen should appear all BLUE!");
	    messageText.add("Please check for any dead pixels.");
	    backgroundColor = Color.BLUE;
	    break;
	case 5:
	    messageText.add("This screen contains vertical stripes");
	    messageText.add("Please adjust your screen so they are perfectly vertical");
	    messageText.add("");
	    messageText.add("(Primarily applies to CRT screens)");
	    foregroundColor = Color.BLACK;
	    break;
	case 6:
	    messageText.add("This screen contains horizontal stripes");
	    messageText.add("Please adjust your screen so they are perfectly horizontal");
	    messageText.add("");
	    messageText.add("(Primarily applies to CRT screens)");
	    foregroundColor = Color.BLACK;
	    break;
	case 7:
	    messageText.add("This screen contains a chess pattern");
	    messageText.add("Please adjust your screen so the pattern is perfectly horizontal and vertical");
	    messageText.add("");
	    messageText.add("(Primarily applies to CRT screens)");
	    foregroundColor = Color.BLACK;
	    break;
	case 8:
	    messageText.add("This screen should be all black, with a hairline yellow border");
	    messageText.add("Please adjust your screen so the border is perfectly aligned with the sides of your screen");
	    backgroundColor = Color.BLACK;
	    break;
	case 9:
	    messageText.add("This screen contains a round circle");
	    messageText.add("Please adjust your screen so that the aspect ratio makes this perfectly round.");
	    foregroundColor = Color.WHITE;
	    backgroundColor = Color.WHITE;
	    outlineColor = Color.BLACK;
	    break;
	case 10:
	    messageText.add("This screen contains a medium size chess pattern");
	    messageText.add("Please adjust your brightness and contrast.");
	    foregroundColor = Color.RED;
	    backgroundColor = Color.WHITE;
	    outlineColor = Color.BLACK;
	    messageBBox = true;
	    break;
	case 11:
	    messageText.add("This screen contains a pixel size chess pattern");
	    messageText.add("Please adjust your brightness and contrast.");
	    foregroundColor = Color.RED;
	    backgroundColor = Color.WHITE;
	    outlineColor = Color.BLACK;
	    messageBBox = true;
	    break;
	}
	messageTimeout.stop();
	messageVisible = !(messageStatus == MessageStatus.HIDE);

	if (messageStatus == MessageStatus.TIMEOUT)
	    messageTimeout.start();

	if (foregroundColor == null)
	    foregroundColor = complementary(backgroundColor);
	//messageText.setForeground(foregroundColor);

	repaint();
    }

    int numFrames()
    {
	return 12;
    }

    public static final void main(final String[] args) throws Exception
    {
	UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

	Log.DEFAULT = new Log(new VoidStream());

	boolean fullscreen = true;

	if (args.length >= 1) {
	    fullscreen = false;
	}
	//fullscreen = false;
 
	final JFrame fullscreenFrame = new ScreenAdjuster(fullscreen);
	
    }

    public static void paintCheckers(Graphics g, Rectangle bounds, int size, int numColors, int mode, boolean alternativeColors)
    {
	Rectangle cbounds = g.getClipBounds();

	g.setColor(Color.WHITE);
	//g.fillRect(cbounds.x, cbounds.y, cbounds.width, cbounds.height);
	g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
	
	//Offset xmin by 1, if cliparea is on an odd boundary
	int xmin = bounds.x;
	int xmax = bounds.x + bounds.width;
	int ymin = bounds.y;
	int ymax = bounds.y + bounds.height;
	int hcolor = -1;

	Color colors[] = { Color.BLACK, Color.RED,
			   Color.GREEN, Color.BLUE, Color.WHITE  };

	if (numColors <= 2) {
	    if (alternativeColors) {
		colors[0] = Color.YELLOW;
		colors[1] = Color.BLUE;
	    }
	    else {
		colors[1] = Color.WHITE;
	    }
	}

	g.setColor(Color.BLACK);
	for (int x = xmin; x < xmax; x += size) {
	    if ((mode & 0x1) > 0)
		hcolor = (hcolor + 1) % numColors;
	    int color = hcolor;
	    for (int y = ymin; y < ymax; y += size) {
		if ((mode & 0x2) > 0)
		    color = (color + 1) % numColors;
		g.setColor(colors[color]);
		g.fillRect(x, y, size, size);
	    }
	}
    }

    public void paint(Graphics g)
    {
	super.paint(g);
	Graphics2D g2 = (Graphics2D) g;
	Rectangle cbounds = g.getClipBounds();
	Rectangle bounds = getBounds();

	Log.DEFAULT.println(frameNumber);


	if (backgroundColor != null) {
	    g.setColor(backgroundColor);
	    g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
	}

	switch (frameNumber) {
	case 0:
	case 1:
	case 2:
	case 3:
	case 4:
	    break;
	case 11: {
	    g.setColor(Color.BLACK);
	    //Offset xmin by 1, if cliparea is on an odd boundary
	    int xmin = cbounds.x + ((cbounds.x - bounds.x) & 0x1);
	    int xmax = cbounds.x + cbounds.width;
	    for (int x = xmin; x < xmax; x += 2) {
		g.drawLine(x, bounds.y, x, bounds.y + bounds.height);
	    }
	    for (int y = bounds.y; y < bounds.y + bounds.height; y += 2) {
		g.drawLine(bounds.x, y, bounds.x + bounds.width, y);
	    }
	    break;
	}
	case 7: {
	    paintCheckers(g, bounds, 50, 2, 3, true);
	    break;
	}
	case 10: {
	    paintCheckers(g, bounds, 5, 2, 3, false);
	    break;
	}
	case 9: {
	    int x = bounds.x;
	    int y = bounds.y;
	    int height = bounds.height - y;
	    int width = bounds.width - x;
	    int diameter;
	    if (height < width) {
		diameter = height;
		x += (width - height) /2;
	    }
	    else {
		diameter = width;
		y += (height - width) /2;
	    }
	    Log.DEFAULT.println("Geometry:"+bounds.x+"x"+bounds.y+":"+bounds.width + "x" + bounds.height);
	    g.setColor(Color.BLACK);
	    g.fillOval(x, y, diameter, diameter);
	    
	    break;
	}
	case 8: {
	    g.setColor(Color.YELLOW);
	    g.drawRect(bounds.x+1, bounds.y+1, bounds.width-2, bounds.height-2);
	    break;
	}
	case 5: {
	    paintCheckers(g, bounds, 50, 2, 2, true);
	    break;
	}
	case 6: {
	    paintCheckers(g, bounds, 50, 2, 1, true);
	    break;
	}
	};
	/*
	if (messageText.isVisible())
	    messageText.paint(g);
	*/
	if (messageVisible) {
	    drawMessage(g2);
	}		
    }

    void drawMessage(Graphics2D g2)
    {
	Font font = g2.getFont();
	Rectangle bounds = getBounds();

	font = new Font(font.getFontName(),
			font.getStyle(),
			(int)(font.getSize2D() * 2));
	double fontHeight = font.getMaxCharBounds(g2.getFontRenderContext()).getHeight();
	double totalHeight = fontHeight * messageText.size();
	double y = (bounds.height - totalHeight) /2.0;

	for (int i = 0; i < messageText.size(); ++i) {
	    String text = messageText.get(i);
	    if (text.length() > 0 ) {
		TextLayout tl = 
		    new TextLayout(messageText.get(i),
				   font, g2.getFontRenderContext());
		double textWidth = tl.getBounds().getWidth();
		double x = (bounds.width - textWidth) /2.0;

		Shape outline =
		    tl.getOutline(AffineTransform.getTranslateInstance(x,y));
		
		Rectangle tBounds = outline.getBounds();

		if (messageBBox) {
		    g2.setColor(backgroundColor);
		    g2.fillRect(tBounds.x, tBounds.y, tBounds.width, tBounds.height);
		}
		g2.setColor(foregroundColor);
		g2.fill(outline);
		if (outlineColor != null) {
		    g2.setColor(outlineColor);
		}
		g2.draw(outline);
	    }
	    y += fontHeight;
	}

    }
 
}