/* * Copyright (C) 2014 Shashank Tulsyan * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package neembuu.release1.ui.frame; import java.awt.Cursor; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import neembuu.util.Throwables; /** * * @author Shashank Tulsyan */ public class MouseHandler implements MouseListener,MouseMotionListener { private final ComponentInterface component; private Point p_initial = null; private Point p_previous_absolute = null; private MouseLocation mouseLocation = MouseLocation.C; private volatile long lastME; private volatile Thread th; public MouseHandler(ComponentInterface component) { this.component = component; th = Throwables.start(new Runnable() { @Override public void run() { resetMouseThread(); } },"Mouse cursor reset thread",true); } @Override public void mouseDragged(MouseEvent mouseevent) { lastME = System.currentTimeMillis(); if(mouseevent.isConsumed())return; final Point p_final = mouseevent.getLocationOnScreen(); //global location of mouse pointer int dw = p_final.x - p_previous_absolute.x; int dh = p_final.y - p_previous_absolute.y; Rectangle wp = component.getBounds(); switch (mouseLocation) { case NW: carefulSetBounds(wp.x+dw, wp.y+dh, wp.width-dw, wp.height-dh,wp);break; case W: carefulSetBounds(wp.x+dw, wp.y, wp.width-dw, wp.height,wp);break; case SW: carefulSetBounds(wp.x+dw, wp.y, wp.width-dw, wp.height+dh,wp);break; case S: carefulSetBounds(wp.x, wp.y, wp.width, wp.height+dh,wp);break; case SE: carefulSetBounds(wp.x, wp.y, wp.width+dw, wp.height+dh,wp);break; case E: carefulSetBounds(wp.x, wp.y, wp.width+dw, wp.height,wp);break; case NE: carefulSetBounds(wp.x, wp.y + dh, wp.width+dw, wp.height-dh,wp);break; case N: carefulSetBounds(wp.x, wp.y + dh, wp.width, wp.height-dh,wp);break; case C: component.setLocation(-p_initial.x + p_final.x, -p_initial.y + p_final.y); break; default: throw new AssertionError(); } p_previous_absolute = p_final; } @Override public void mouseMoved(MouseEvent e) { lastME = System.currentTimeMillis(); int mx = e.getX(), my=e.getY(); int h = component.getHeight(), w=component.getWidth(); //System.out.println("loc="+mouseLocation+" "+e); //System.out.println("w="+w+" h="+h); final int xa=8,yb=8; int a = 8; int b = 8; if(component.resizable()){ if(mx>xa && mx<w-xa && my > yb && my < h-yb ){ //if(mouseLocation!=MouseLocation.C){ mouseLocation=MouseLocation.C; component.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); //} }if(atCornerBorder(mx, my, a, b, MouseLocation.NW) ){ //if(mouseLocation!=MouseLocation.NW){ mouseLocation=MouseLocation.NW; component.setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR)); }if(mx<xa && my > b && my < h-b){ //if(mouseLocation!=MouseLocation.W){ mouseLocation=MouseLocation.W; component.setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)); }if(atCornerBorder(mx, my, a, h-b, MouseLocation.SW) ){ //if(mouseLocation!=MouseLocation.SW){ mouseLocation=MouseLocation.SW; component.setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR)); }if(mx>a && mx<w-a && my >= h-yb){ //if(mouseLocation!=MouseLocation.S){ mouseLocation=MouseLocation.S; component.setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)); }if(atCornerBorder(mx, my, w-a, h-b, MouseLocation.SE)){ //if(mouseLocation!=MouseLocation.SE){ mouseLocation=MouseLocation.SE; component.setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR)); }if(mx>=w-xa && my > b && my < h-b){ //if(mouseLocation!=MouseLocation.E){ mouseLocation=MouseLocation.E; component.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)); }if(atCornerBorder(mx, my, w-a, b, MouseLocation.NE)){ //if(mouseLocation!=MouseLocation.NE){ mouseLocation=MouseLocation.NE; component.setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR)); }if(mx>a && mx<w-a && my < yb ){ //if(mouseLocation!=MouseLocation.N){ mouseLocation=MouseLocation.N; component.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)); } } //System.out.println("("+mx+","+my+")"+" "+h+" "+w+" " +mouseLocation); } private void carefulSetBounds(int x, int y, int w, int h, Rectangle previousDimension){ if(!component.resizable())return; if(w<component.minimumWidth()){w=previousDimension.width;x=previousDimension.x;} if(h<component.minimumHeight()){h=previousDimension.height;y=previousDimension.y;} component.setBounds(x, y, w, h); } private boolean atCornerBorder( int x, int y, int x_limit, int y_limit, MouseLocation checkOfCorner ){ boolean atCorner = false; int a = 10, b = 10; switch (checkOfCorner) { case NW: atCorner = x<a && y <b; break; case SW: atCorner = x<a && y >=component.getHeight()-b; break; case SE: atCorner = x>=component.getWidth()-a && y >=component.getHeight()-b; break; case NE: atCorner = x>=component.getWidth()-a && y <b; break; default: throw new AssertionError(); } return atCorner; } @Override public void mouseClicked(MouseEvent e) { lastME = System.currentTimeMillis(); } @Override public void mouseEntered(MouseEvent e) { lastME = System.currentTimeMillis(); } @Override public void mouseExited(MouseEvent e) { lastME = System.currentTimeMillis(); /*final long thisME = lastME; Throwables.start(new Runnable() { @Override public void run() { try{Thread.sleep(1000);}catch(Exception a){} if(thisME < lastME)return; mouseLocation = MouseLocation.C; component.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } },"Mouse exited event");*/ } @Override public void mousePressed(MouseEvent e) { lastME = System.currentTimeMillis(); if(e.isConsumed())return; p_initial = e.getPoint(); p_previous_absolute = e.getLocationOnScreen(); /*component.setVisible(false); component.setVisible(true);*/ } @Override public void mouseReleased(MouseEvent mouseEvent) { lastME = System.currentTimeMillis(); /*if(mouseEvent.isConsumed())return; final Dimension screendim = Toolkit.getDefaultToolkit ().getScreenSize(); final int x= component.getLocation_x(),y=component.getLocation_y(); final int ht = component.getHeight(), wd=component.getWidth(); final int swd = screendim.width, sht = screendim.height;*/ /*component.setVisible(false); component.setVisible(true);*/ } enum MouseLocation { N,S, // | W,E, // - NW,SE, // \ NE,SW, // / C } public MouseHandler normalize(final int x_offset,final int y_offset){ return new MouseHandler(component){ @Override public void mouseClicked(MouseEvent e) { e.translatePoint(x_offset, y_offset); MouseHandler.this.mouseClicked(e); } @Override public void mouseDragged(MouseEvent e) { e.translatePoint(x_offset, y_offset); MouseHandler.this.mouseDragged(e); } @Override public void mouseEntered(MouseEvent e) { e.translatePoint(x_offset, y_offset); MouseHandler.this.mouseEntered(e); } @Override public void mouseExited(MouseEvent e) { e.translatePoint(x_offset, y_offset); //MouseHandler.this.mouseExited(e); } @Override public void mouseMoved(MouseEvent e) { e.translatePoint(x_offset, y_offset); MouseHandler.this.mouseMoved(e); } @Override public void mousePressed(MouseEvent e) { e.translatePoint(x_offset, y_offset); MouseHandler.this.mousePressed(e); } @Override public void mouseReleased(MouseEvent e) { e.translatePoint(x_offset, y_offset); MouseHandler.this.mouseReleased(e); } }; } private void resetMouseThread(){ while(Thread.currentThread()==th){ long diff = System.currentTimeMillis() - lastME; if(diff > 5000){ lastME += diff; try{ Cursor d = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); mouseLocation=MouseLocation.C; if(component.getCursor()!=d) component.setCursor(d); }catch(Exception a){ Throwables.addStartingThrowableAsSuppressed(a); a.printStackTrace(); } } try{Thread.sleep(300);}catch(Exception a){} } } }