package com.vitco.layout.bars; import com.jidesoft.action.CommandMenuBar; import com.jidesoft.swing.JideButton; import com.vitco.manager.action.ActionManager; import com.vitco.settings.VitcoSettings; import com.vitco.util.misc.SaveResourceLoader; import org.springframework.beans.factory.annotation.Autowired; import javax.swing.*; import java.awt.*; import java.awt.event.*; /** * the main menu, uses menu generator to load content from file * * defines interactions */ public class MainMenuLinkage extends BarLinkagePrototype { // true if the frame is currently maximized private boolean maximized = false; // fullscreen button private JideButton fullscreenButton; private final Icon enable_fullscreen = new SaveResourceLoader( "resource/img/icons/application/enable_fullscreen.png" ).asIconImage(); private final Icon disable_fullscreen = new SaveResourceLoader( "resource/img/icons/application/disable_fullscreen.png" ).asIconImage(); // var & setter private ActionManager actionManager; @Autowired public final void setActionManager(ActionManager actionManager) { this.actionManager = actionManager; } private void setMaximized(Frame frame, boolean state) { if (state) { // find out which screen we have the most overlap Rectangle maximizedBounds = null; int overlap = -1; Rectangle frameBounds = frame.getBounds(); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); for (GraphicsDevice gd : ge.getScreenDevices()) { GraphicsConfiguration defaultConfiguration = gd.getDefaultConfiguration(); Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(defaultConfiguration); Rectangle usableScreenArea = defaultConfiguration.getBounds(); Rectangle withoutTaskBarOnScreen = new Rectangle( screenInsets.left, screenInsets.top, usableScreenArea.width - screenInsets.right, usableScreenArea.height - screenInsets.bottom ); Rectangle overlapRect = usableScreenArea.intersection(frameBounds); int cOverlap = overlapRect.width * overlapRect.height; if (overlap < cOverlap) { maximizedBounds = withoutTaskBarOnScreen; overlap = cOverlap; } } // restrict maximize to that screen (coordinates on the particular screen!) frame.setMaximizedBounds(maximizedBounds); frame.setExtendedState(frame.getExtendedState()|JFrame.MAXIMIZED_BOTH); } else { frame.setExtendedState(JFrame.NORMAL); } } private boolean isMaximized(Frame frame) { int state = frame.getExtendedState(); return (state & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH; } @Override public CommandMenuBar buildBar(String key, final Frame frame) { final CommandMenuBar bar = new CommandMenuBar(key); // build the menu menuGenerator.buildMenuFromXML(bar, "com/vitco/layout/bars/main_menu.xml"); // add buttons to the titlebar bar.addExpansion(); JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.setOpaque(false); JideButton minimize = new JideButton(new SaveResourceLoader( "resource/img/icons/application/minimize.png" ).asIconImage()); minimize.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); minimize.addActionListener(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { frame.setState(Frame.ICONIFIED); } }); panel.add(minimize, BorderLayout.WEST); fullscreenButton = new JideButton(); fullscreenButton.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); fullscreenButton.addActionListener(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { setMaximized(frame, !isMaximized(frame)); } }); panel.add(fullscreenButton, BorderLayout.CENTER); JideButton close = new JideButton(new SaveResourceLoader( "resource/img/icons/application/close.png" ).asIconImage()); close.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 15)); close.addActionListener(new AbstractAction() { @Override public void actionPerformed(final ActionEvent e) { // execute closing action actionManager.performWhenActionIsReady("close_program_action", new Runnable() { @Override public void run() { actionManager.getAction("close_program_action").actionPerformed( new ActionEvent(e.getSource(), e.getID(), e.paramString()) ); } }); } }); panel.add(close, BorderLayout.EAST); bar.add(panel); // make borderless frame.setUndecorated(true); // make menu bar draggable new MoveMouseAdapter(bar, frame); // listen to border events new ResizeMouseAdapter(frame); // add listener to react to MAXIMIZED changes frame.addComponentListener( new ComponentAdapter() { public void componentResized(ComponentEvent e) { if (isMaximized(frame)) { ((JFrame)frame).getRootPane().setBorder(BorderFactory.createEmptyBorder()); fullscreenButton.setIcon(disable_fullscreen); maximized = true; } else { ((JFrame)frame).getRootPane().setBorder(VitcoSettings.FRAME_BORDER); fullscreenButton.setIcon(enable_fullscreen); maximized = false; } } } ); // register the logic for this menu menuLogic.registerLogic(frame); return bar; } // listen to border events private final class ResizeMouseAdapter extends MouseAdapter { // the default mouse cursor private final Cursor DEFAULT_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR); // border (outside and inside the rect) private static final int BORDER_DIST_DOUBLE = VitcoSettings.FRAME_BORDER_SIZE * 2; // border size outside (or inside) the rect private static final int BORDER_DIST = VitcoSettings.FRAME_BORDER_SIZE; // the related frame private final Frame frame; private final int locations[] = { SwingConstants.NORTH_WEST, SwingConstants.NORTH_EAST, SwingConstants.SOUTH_WEST, SwingConstants.SOUTH_EAST, SwingConstants.NORTH, SwingConstants.SOUTH, SwingConstants.WEST, SwingConstants.EAST }; private final Cursor cursors[] = { new Cursor(Cursor.NW_RESIZE_CURSOR), new Cursor(Cursor.NE_RESIZE_CURSOR), new Cursor(Cursor.SW_RESIZE_CURSOR), new Cursor(Cursor.SE_RESIZE_CURSOR), new Cursor(Cursor.N_RESIZE_CURSOR), new Cursor(Cursor.S_RESIZE_CURSOR), new Cursor(Cursor.W_RESIZE_CURSOR), new Cursor(Cursor.E_RESIZE_CURSOR) }; // constructor public ResizeMouseAdapter(Frame frame) { this.frame = frame; frame.addMouseListener(this); frame.addMouseMotionListener(this); } // helper - get the rectangle for border so we can check for containment private Rectangle getRectangle(int x, int y, int w, int h, int location) { switch (location) { case SwingConstants.NORTH: return new Rectangle(x, y, w, BORDER_DIST_DOUBLE); case SwingConstants.SOUTH: return new Rectangle(x, y + h - BORDER_DIST_DOUBLE, w, BORDER_DIST_DOUBLE); case SwingConstants.WEST: return new Rectangle(x, y, BORDER_DIST_DOUBLE, h); case SwingConstants.EAST: return new Rectangle(x + w - BORDER_DIST_DOUBLE, y, BORDER_DIST_DOUBLE, h); case SwingConstants.NORTH_WEST: return new Rectangle(x, y, BORDER_DIST_DOUBLE, BORDER_DIST_DOUBLE); case SwingConstants.NORTH_EAST: return new Rectangle(x + w - BORDER_DIST_DOUBLE, y, BORDER_DIST_DOUBLE, BORDER_DIST_DOUBLE); case SwingConstants.SOUTH_WEST: return new Rectangle(x, y + h - BORDER_DIST_DOUBLE, BORDER_DIST_DOUBLE, BORDER_DIST_DOUBLE); case SwingConstants.SOUTH_EAST: return new Rectangle(x + w - BORDER_DIST_DOUBLE, y + h - BORDER_DIST_DOUBLE, BORDER_DIST_DOUBLE, BORDER_DIST_DOUBLE); } return null; } // get the appropriate cursor for a request point (w.r.t. drag type) public final Cursor getCursor(Point p) { if (!maximized) { for (int i = 0; i < locations.length; i++) { Rectangle rect = getRectangle( -BORDER_DIST, -BORDER_DIST, frame.getWidth() + BORDER_DIST_DOUBLE, frame.getHeight() + BORDER_DIST_DOUBLE, locations[i]); if (rect.contains(p)) { return cursors[i]; } } } return DEFAULT_CURSOR; } // get the appropriate drag type for a request point public final int getDragType(Point p) { if (!maximized) { for (int location : locations) { Rectangle rect = getRectangle( -BORDER_DIST, -BORDER_DIST, frame.getWidth() + BORDER_DIST_DOUBLE, frame.getHeight() + BORDER_DIST_DOUBLE, location); if (rect.contains(p)) { return location; } } } return -1; } // ============ // current drag type private int dragType = -1; // current drag position private Point pos = new Point(0, 0); // get current location on screen private Point getScreenLocation(MouseEvent e) { Point cursor = e.getPoint(); Point target_location = frame.getLocationOnScreen(); return new Point((int) (target_location.getX() + cursor.getX()), (int) (target_location.getY() + cursor.getY())); } @Override public void mousePressed(MouseEvent e) { super.mousePressed(e); // initialize position and drag type pos = this.getScreenLocation(e); dragType = getDragType(e.getPoint()); } @Override public void mouseDragged(MouseEvent e) { super.mouseDragged(e); // executing dragging event (resize) if (dragType != -1) { Point newPos = this.getScreenLocation(e); int xdiff = newPos.x - pos.x; int ydiff = newPos.y - pos.y; switch (dragType) { case SwingConstants.NORTH_WEST: frame.setBounds(frame.getX() + xdiff, frame.getY() + ydiff, frame.getWidth() - xdiff, frame.getHeight() - ydiff); break; case SwingConstants.NORTH_EAST: frame.setBounds(frame.getX(), frame.getY() + ydiff, frame.getWidth() + xdiff, frame.getHeight() - ydiff); break; case SwingConstants.SOUTH_WEST: frame.setBounds(frame.getX() + xdiff, frame.getY(), frame.getWidth() - xdiff, frame.getHeight() + ydiff); break; case SwingConstants.SOUTH_EAST: frame.setBounds(frame.getX(), frame.getY(), frame.getWidth() + xdiff, frame.getHeight() + ydiff); break; case SwingConstants.NORTH: frame.setBounds(frame.getX(), frame.getY() + ydiff, frame.getWidth(), frame.getHeight() - ydiff); break; case SwingConstants.SOUTH: frame.setBounds(frame.getX(), frame.getY(), frame.getWidth(), frame.getHeight() + ydiff); break; case SwingConstants.WEST: frame.setBounds(frame.getX() + xdiff, frame.getY(), frame.getWidth() - xdiff, frame.getHeight()); break; case SwingConstants.EAST: frame.setBounds(frame.getX(), frame.getY(), frame.getWidth() + xdiff, frame.getHeight()); break; default: frame.setBounds(frame.getX() + xdiff, frame.getY() + ydiff, frame.getWidth(), frame.getHeight()); break; } pos = newPos; } } @Override public void mouseMoved(MouseEvent e) { super.mouseMoved(e); if (!maximized) { frame.setCursor(getCursor(e.getPoint())); } } @Override public void mouseExited(MouseEvent e) { super.mouseExited(e); frame.setCursor(DEFAULT_CURSOR); } } // helper class to drag frame private final class MoveMouseAdapter extends MouseAdapter { // the frame that is dragged private final Frame frame; // the component that is used for dragging private JComponent target; // locations private Point start_drag; private Point start_loc; // constructor public MoveMouseAdapter(JComponent target, Frame frame) { this.target = target; this.frame = frame; // add listener target.addMouseListener(this); target.addMouseMotionListener(this); } // -------- // get current location on screen private Point getScreenLocation(MouseEvent e) { Point cursor = e.getPoint(); Point target_location = this.target.getLocationOnScreen(); return new Point((int) (target_location.getX() + cursor.getX()), (int) (target_location.getY() + cursor.getY())); } // initialize locations public void mousePressed(MouseEvent e) { this.start_drag = this.getScreenLocation(e); this.start_loc = frame.getLocation(); } public void mouseReleased(MouseEvent e) { // change maximized state on dbl click if (e.getClickCount() == 2) { setMaximized(frame, !isMaximized(frame)); } } // update frame public void mouseDragged(MouseEvent e) { // no longer maximised if (isMaximized(frame)) { setMaximized(frame, false); } // update position Point current = this.getScreenLocation(e); Point offset = new Point( current.x - start_drag.x, current.y - start_drag.y ); Point new_location = new Point( this.start_loc.x + offset.x, this.start_loc.y + offset.y ); frame.setLocation(new_location); } } }