package jp.crwdev.app.gui; import java.awt.Color; import java.awt.Dimension; import java.awt.DisplayMode; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.image.BufferStrategy; import java.awt.image.BufferedImage; import java.util.LinkedList; import javax.swing.AbstractAction; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.KeyStroke; import jp.crwdev.app.BufferedImageIO; import jp.crwdev.app.EventObserver; import jp.crwdev.app.EventObserver.OnEventListener; import jp.crwdev.app.imagefilter.PreviewImageFilter; import jp.crwdev.app.imagefilter.ResizeFilter; import jp.crwdev.app.interfaces.IImageFileInfo; import jp.crwdev.app.setting.ImageFilterParamSet; import jp.crwdev.app.util.ImageCache; import jp.crwdev.app.util.ImageCache.ImageData; import jp.crwdev.app.util.InifileProperty; @SuppressWarnings("serial") public class FullscreenWindow extends JFrame implements MouseListener, MouseMotionListener, MouseWheelListener, OnEventListener { public static boolean mEnableFullScreen = false; public int windowWidth = 640; public int windowHeight = 480; public float mZoomScale = 1.75f; private int mPreviewMargin = 20; private GraphicsDevice mDevice; private BufferStrategy mBufferStrategy; private int mScreenWidth = 640; private int mScreenHeight = 480; private Rectangle mImageArea = new Rectangle(); public FullscreenWindow(){ setTitle("FullscreenView"); setBounds(0, 0, 640, 480); setResizable(false); //setIgnoreRepaint(true); // paintイベントを無効化 mEnableFullScreen = InifileProperty.getInstance().isEnableFullScreen(); addMouseListener(this); addMouseMotionListener(this); addMouseWheelListener(this); // ESCキーで終了 InputMap imap = getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); imap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escape"); getRootPane().getActionMap().put("escape", new AbstractAction(){ @Override public void actionPerformed(ActionEvent e) { closeWindow(); } }); initFullScreen(); // setUndecorated(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); createBufferStrategy(2); mBufferStrategy = getBufferStrategy(); repaintEvent(); screenUpdate(); } private void initFullScreen() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); mDevice = ge.getDefaultScreenDevice(); // GraphicsDeviceの取得 DisplayMode mode = mDevice.getDisplayMode(); int width = mode.getWidth(); int height = mode.getHeight(); int depth = mode.getBitDepth(); if(mEnableFullScreen){ setUndecorated(true); // タイトルバー・ボーダー非表示 setIgnoreRepaint(false); if (!mDevice.isFullScreenSupported()) { System.out.println("フルスクリーンモードはサポートされていません。"); System.exit(0); } // フルスクリーン化! mDevice.setFullScreenWindow(this); setDisplayMode(width, height, depth); mScreenWidth = width; mScreenHeight = height; } else{ setUndecorated(true); // タイトルバー・ボーダー非表示 setIgnoreRepaint(true); if(InifileProperty.getInstance().isShowDebugWindow()){ mScreenWidth = windowWidth; mScreenHeight = windowHeight; }else{ mScreenWidth = width; mScreenHeight = height; } setBounds(0, 0, mScreenWidth, mScreenHeight); } } /** * ディスプレイモードを設定 * * @param width * @param height * @param bitDepth */ private void setDisplayMode(int width, int height, int bitDepth) { if (!mDevice.isDisplayChangeSupported()) { System.out.println("ディスプレイモードの変更はサポートされていません。"); return; } DisplayMode dm = new DisplayMode(width, height, bitDepth, DisplayMode.REFRESH_RATE_UNKNOWN); mDevice.setDisplayMode(dm); } /** * Same as ImagePanel */ private PreviewImageFilter mImageFilter = new PreviewImageFilter(); private PreviewImageFilter mPreviewZoomFilter = new PreviewImageFilter(); private BufferedImage mPreviewZoomImage = null; private Object mLockZoomImage = new Object(); private IImageFileInfo mFileInfo = null; private int mInfoIndex = 0; private BufferedImage mOriginalImage = null; private BufferedImage mDisplayImage = null; private boolean mIsZoomDrag = false; private Point mZoomPoint = new Point(); private boolean mFitZoom = false; private EventObserver mEventSender = null; public void setEventObserver(EventObserver observer){ mEventSender = observer; } public void setFitZoom(boolean fitZoom){ mFitZoom = fitZoom; } public void setImageFilterParam(ImageFilterParamSet params){ mImageFilter.setImageFilterParam(params); mImageFilter.setPreviewSize(getWidth(), getHeight()); mPreviewZoomFilter.setImageFilterParam(params); mPreviewZoomFilter.setPreviewSize((int)(getWidth()*mZoomScale), (int)(getHeight()*mZoomScale)); } public void setImage(BufferedImage image, IImageFileInfo info, int rowIndex){ //AddSpaceFilter filter = new AddSpaceFilter(); //mOriginalImage = filter.filter(image, info.getFilterParam()); mOriginalImage = image; mFileInfo = info; mInfoIndex = rowIndex; if(mOriginalImage != null){ updateDisplayImage(true); } } public void updateDisplayImage(boolean async){ if(mOriginalImage == null){ return; } if(async){ startRenderImage(); } else{ updateDisplayImageInternal(); } } private LinkedList<Integer> mQueue = new LinkedList<Integer>(); private Object mThreadLock = new Object(); private Thread mThread = null; private boolean mThreadFinish = false; public void startRenderImage(){ if(mThread == null){ mThread = new Thread(){ @Override public void run(){ while(!mThreadFinish){ synchronized(mThreadLock){ if(mQueue.isEmpty()){ try { mThreadLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } if(!mQueue.isEmpty()){ mQueue.pop(); } } try { boolean loop = true; while(loop && !mThreadFinish){ updateDisplayImageInternal(); synchronized(mQueue){ loop = !mQueue.isEmpty(); if(loop){ mQueue.pop(); } } } }catch(Exception e){ mEventSender.setProgressMessage(e.getMessage()); }catch(OutOfMemoryError e){ mEventSender.setProgressMessage(e.getMessage()); } } mThread = null; } }; mThread.setPriority(Thread.MAX_PRIORITY); mThread.start(); } synchronized(mThreadLock){ while(mQueue.size() > 0){ mQueue.remove(); } mQueue.push(0); mThreadLock.notify(); } } // private void finalizeThread(){ // if(mThread != null){ // mThreadFinish = true; // synchronized(mThreadLock){ // mThreadLock.notify(); // } // mThread = null; // } // } public void updateDisplayImageInternal(){ if(mImageFilter != null){ try { if(ImageCache.enable){ ImageData data = ImageCache.getInstance().getImageData(mInfoIndex); mDisplayImage = data.getDisplayImage(mImageFilter, false); mPreviewZoomImage = null; new Thread(){ @Override public void run(){ createZoomImage(); } }.start(); } else{ BufferedImage filtered = mImageFilter.filter(BufferedImageIO.copyBufferedImage(mOriginalImage), mFileInfo.getFilterParam()); mDisplayImage = filtered; mPreviewZoomImage = null; new Thread(){ @Override public void run(){ createZoomImage(); } }.start(); } }catch(OutOfMemoryError e){ mEventSender.setProgressMessage(e.getMessage()); e.printStackTrace(); } } repaintEvent(); screenUpdate(); // repaint(); } private void createZoomImage(){ synchronized(mLockZoomImage){ if(mPreviewZoomImage == null){ if(ImageCache.enable){ if(mPreviewZoomImage == null){ ImageData data = ImageCache.getInstance().getImageData(mInfoIndex); mPreviewZoomImage = data.getZoomImage(mPreviewZoomFilter); } }else{ if(mPreviewZoomImage == null){ BufferedImage filtered = mPreviewZoomFilter.filter(BufferedImageIO.copyBufferedImage(mOriginalImage), mFileInfo.getFilterParam()); mPreviewZoomImage = filtered; } } if(mEnableFullScreen){ repaintEvent(); screenUpdate(); } } } } @Override public void paint(Graphics g){ //super.paint(g); repaintEvent(g); } private void repaintEvent(){ if(mEnableFullScreen){ repaintEvent(mBufferStrategy.getDrawGraphics()); }else{ repaint(); } } private void repaintEvent(Graphics g){ // 背景 g.setColor(Color.DARK_GRAY);//BLACK); g.fillRect(0, 0, mScreenWidth, mScreenHeight); int w = getWidth(); int h = getHeight(); if (mDisplayImage != null){ int imageW = mDisplayImage.getWidth(); int imageH = mDisplayImage.getHeight(); int x = (w - imageW)/2; int y = (h - imageH)/2; mImageArea.setBounds(x, y, imageW, imageH); if(!mIsZoomDrag){ if(mFitZoom){ int width = w - mPreviewMargin; int height = h - mPreviewMargin; int ow = mDisplayImage.getWidth(); int oh = mDisplayImage.getHeight(); if(width > ow && height > oh){ int scale = 1; do{ scale *= 2; }while(!(ow * scale >= width && oh * scale >= height)); Dimension size = ResizeFilter.getResizeDimension(ow*scale, oh*scale, width, height); int zw = size.width; int zh = size.height; int zx = width / 2 - zw / 2 + mPreviewMargin / 2; int zy = height / 2 - zh / 2 + mPreviewMargin / 2; Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);//RenderingHints.VALUE_INTERPOLATION_BICUBIC); g.drawImage(mDisplayImage, zx, zy, zx+zw, zy+zh, 0, 0, ow, oh, null); mImageArea.setBounds(zx, zy, zw, zh); } else{ g.drawImage(mDisplayImage, x, y, this); } } else{ g.drawImage(mDisplayImage, x, y, this); } } else if(mIsZoomDrag){ //createZoomImage(); float scale = mZoomScale; int mx = mZoomPoint.x; int my = mZoomPoint.y; int cx = w / 2; int cy = h / 2; mx += (mx - cx); my += (my - cy); int dw = (int)(imageW); int dh = (int)(imageH); int zw = (int)(dw * scale); int zh = (int)(dh * scale); int pw = mPreviewZoomImage.getWidth(); int ph = mPreviewZoomImage.getHeight(); if(mPreviewZoomImage != null){ if(zw < pw || zh < ph){ zw = pw; zh = ph; } } float panX = (float)(mx - cx) / (float)dw; float panY = (float)(my - cy) / (float)dh; int zx = mx - (int)(zw * (0.5f + panX)); int zy = my - (int)(zh * (0.5f + panY)); if(zx > 0){ g.fillRect(0, 0, zx, h); } if(zx+zw < w){ g.fillRect(zx+zw, 0, w, h); } if(zy > 0){ g.fillRect(zx, 0, zw, zy); } if(zy+zh < h){ g.fillRect(zx, zy+zh, zw, h); } if(mPreviewZoomImage != null){ if(zw != pw || zh != ph){ Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);//RenderingHints.VALUE_INTERPOLATION_BICUBIC); } g.drawImage(mPreviewZoomImage, zx, zy, zx+zw, zy+zh, 0, 0, pw, ph, null); }else{ if(zw != imageW || zh != imageH){ Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);//RenderingHints.VALUE_INTERPOLATION_BICUBIC); } g.drawImage(mDisplayImage, zx, zy, zx+zw, zy+zh, 0, 0, imageW, imageH, null); } } else{ g.fillRect(0, 0, w, h); g.drawImage(mDisplayImage, x, y, this); } } else{ mImageArea.setBounds(0,0,0,0); } if(mEnableFullScreen){ g.dispose(); } } /** * スクリーンの更新(BufferStrategyを使用) * */ private void screenUpdate() { if(mEnableFullScreen){ if (!mBufferStrategy.contentsLost()) { mBufferStrategy.show(); } else { System.out.println("Contents Lost"); } Toolkit.getDefaultToolkit().sync(); } } private void closeWindow(){ if(mEnableFullScreen){ mDevice.setFullScreenWindow(null); } mEventSender.sendEvent(EventObserver.EventTarget_Main, EventObserver.EventType_EndFullscreen, 0); } @Override public void mouseClicked(MouseEvent e) { if(javax.swing.SwingUtilities.isRightMouseButton(e)){ if(e.getClickCount() >= 2){ closeWindow(); } else{ mEventSender.sendEvent(EventObserver.EventTarget_Table, EventObserver.EventType_MoveInfo, -1); } } else{ if(!mImageArea.contains(e.getX(), e.getY())){ mEventSender.sendEvent(EventObserver.EventTarget_Table, EventObserver.EventType_MoveInfo, 1); } } } @Override public void mousePressed(MouseEvent e) { int x = e.getX(); int y = e.getY(); if(javax.swing.SwingUtilities.isRightMouseButton(e)){ } else{ // Zoom start if(mImageArea.contains(x, y)){ mIsZoomDrag = true; mZoomPoint.setLocation(x, y); repaintEvent(); screenUpdate(); } } } @Override public void mouseReleased(MouseEvent e) { if(mFileInfo == null){ return; } if(javax.swing.SwingUtilities.isRightMouseButton(e)){ } else { // Zoom end if(mIsZoomDrag){ mIsZoomDrag = false; repaintEvent(); screenUpdate(); } } } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mouseDragged(MouseEvent e) { int x = e.getX(); int y = e.getY(); if(javax.swing.SwingUtilities.isRightMouseButton(e)){ } else{ // Zoom mZoomPoint.setLocation(x, y); repaintEvent(); screenUpdate(); } } @Override public void mouseMoved(MouseEvent e) { // repaintEvent(); // screenUpdate(); } @Override public void mouseWheelMoved(MouseWheelEvent e) { int step = 1; if(e.getWheelRotation() < 0){ step = -1; } mEventSender.sendEvent(EventObserver.EventTarget_Table, EventObserver.EventType_MoveInfo, step); } @Override public void onEventReceived(int type, int arg1, int arg2, Object obj) { switch(type){ case EventObserver.EventType_PreviewSize: //Dimension size = (Dimension)obj; //setOutputSizePreview(arg1 == 1, size.width, size.height); break; default: break; } } }