/******************************************************************************* * Copyright (c) 2007, 2014 compeople AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * compeople AG - initial API and implementation *******************************************************************************/ package org.eclipse.riena.ui.swt; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.MouseTrackListener; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.riena.ui.swt.facades.SWTFacade; import org.eclipse.riena.ui.swt.lnf.LnfKeyConstants; import org.eclipse.riena.ui.swt.lnf.LnfManager; import org.eclipse.riena.ui.swt.lnf.renderer.AbstractTitleBarRenderer; import org.eclipse.riena.ui.swt.utils.ShellHelper; import org.eclipse.riena.ui.swt.utils.SwtUtilities; /** * TODO After any mouse operation a method of this listener is called. */ public abstract class AbstractTitleBarMouseListener implements MouseListener, MouseTrackListener, MouseMoveListener { private final static ShellHelper SHELL_HELPER = new ShellHelper(); enum BtnState { NONE, HOVER, HOVER_SELECTED; } private Cursor handCursor; private Cursor grabCursor; private Cursor defaultCursor; private final static int BTN_COUNT = 3; private final static int CLOSE_BTN_INDEX = 0; private final static int MAX_BTN_INDEX = 1; private final static int MIN_BTN_INDEX = 2; private final BtnState[] btnStates = new BtnState[BTN_COUNT]; private boolean mouseDownOnButton; private boolean moveInside; private boolean move; private Point moveStartPoint; public AbstractTitleBarMouseListener() { resetBtnStates(); mouseDownOnButton = false; move = false; updateRenderer(); } /** * Returns the renderer of the title bar. * * @return renderer */ protected abstract AbstractTitleBarRenderer getTitleBarRenderer(); /** * Resets the states of the buttons. */ private void resetBtnStates() { for (int i = 0; i < btnStates.length; i++) { changeBtnState(BtnState.NONE, i); } } /** * Sets the state of a button (and resets the others). * * @param newState * state to set * @param btnIndex * button index */ private void changeBtnState(final BtnState newState, final int btnIndex) { if (newState != BtnState.NONE) { resetBtnStates(); } btnStates[btnIndex] = newState; } /** * Updates the states of the buttons. * * @param e * mouse event */ private void updateButtonStates(final MouseEvent e) { final Point pointer = new Point(e.x, e.y); boolean insideAButton = false; resetBtnStates(); if (getTitleBarRenderer().isInsideCloseButton(pointer)) { if (mouseDownOnButton) { changeBtnState(BtnState.HOVER_SELECTED, CLOSE_BTN_INDEX); } else { changeBtnState(BtnState.HOVER, CLOSE_BTN_INDEX); } insideAButton = true; } else if (getTitleBarRenderer().isInsideMaximizeButton(pointer)) { if (mouseDownOnButton) { changeBtnState(BtnState.HOVER_SELECTED, MAX_BTN_INDEX); } else { changeBtnState(BtnState.HOVER, MAX_BTN_INDEX); } insideAButton = true; } else if (getTitleBarRenderer().isInsideMinimizeButton(pointer)) { if (mouseDownOnButton) { changeBtnState(BtnState.HOVER_SELECTED, MIN_BTN_INDEX); } else { changeBtnState(BtnState.HOVER, MIN_BTN_INDEX); } insideAButton = true; } if (!insideAButton) { mouseDownOnButton = false; } final boolean redraw = updateRenderer(); if (redraw) { redrawButtons(e); } } private void redrawButtons(final MouseEvent e) { final Control control = (Control) e.getSource(); if (!control.isDisposed()) { final Rectangle buttonBounds = getTitleBarRenderer().getAllButtonsBounds(); control.redraw(buttonBounds.x, buttonBounds.y, buttonBounds.width, buttonBounds.height, false); } } private boolean updateRenderer() { boolean changed = false; for (int i = 0; i < btnStates.length; i++) { final boolean hover = btnStates[i] == BtnState.HOVER; final boolean pressed = btnStates[i] == BtnState.HOVER_SELECTED && mouseDownOnButton; switch (i) { case CLOSE_BTN_INDEX: if (getTitleBarRenderer().isCloseButtonHover() != hover) { getTitleBarRenderer().setCloseButtonHover(hover); changed = true; } if (getTitleBarRenderer().isCloseButtonPressed() != pressed) { getTitleBarRenderer().setCloseButtonPressed(pressed); changed = true; } break; case MAX_BTN_INDEX: if (getTitleBarRenderer().isMaximizedButtonHover() != hover) { getTitleBarRenderer().setMaximizedButtonHover(hover); changed = true; } if (getTitleBarRenderer().isMaximizedButtonPressed() != pressed) { getTitleBarRenderer().setMaximizedButtonPressed(pressed); changed = true; } break; case MIN_BTN_INDEX: if (getTitleBarRenderer().isMinimizedButtonHover() != hover) { getTitleBarRenderer().setMinimizedButtonHover(hover); changed = true; } if (getTitleBarRenderer().isMinimizedButtonPressed() != pressed) { getTitleBarRenderer().setMinimizedButtonPressed(pressed); changed = true; } break; default: throw new AssertionError("Illegal button index: " + i); //$NON-NLS-1$ } } return changed; } private void updateCursor(final MouseEvent e) { final Control control = (Control) e.getSource(); // avoids widget is disposed exception on close if (!control.isDisposed()) { final Point pointer = new Point(e.x, e.y); if (moveInside && getTitleBarRenderer().isInsideMoveArea(pointer)) { if (move) { showGrabCursor(control); } else { showHandCursor(control); } } else { if (!move) { showDefaultCursor(control); } } } } public void mouseDoubleClick(final MouseEvent e) { // unused } public void mouseDown(final MouseEvent e) { mouseDownOnButton = true; updateButtonStates(e); if (!mouseDownOnButton) { final Point pointer = new Point(e.x, e.y); if (getTitleBarRenderer().isInsideMoveArea(pointer)) { move = true; moveStartPoint = pointer; } else { move = false; } } updateCursor(e); } /** * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent) */ public void mouseUp(final MouseEvent e) { final Point pointer = new Point(e.x, e.y); if (mouseDownOnButton && (e.getSource() instanceof Control)) { final Control control = (Control) e.getSource(); final Shell shell = getShell(control); if (shell != null) { if (getTitleBarRenderer().isInsideCloseButton(pointer)) { if (btnStates[CLOSE_BTN_INDEX] == BtnState.HOVER_SELECTED) { shell.close(); } } else if (getTitleBarRenderer().isInsideMaximizeButton(pointer)) { if (btnStates[MAX_BTN_INDEX] == BtnState.HOVER_SELECTED) { SHELL_HELPER.maximizeRestore(shell); } } else if (getTitleBarRenderer().isInsideMinimizeButton(pointer)) { if (btnStates[MIN_BTN_INDEX] == BtnState.HOVER_SELECTED) { shell.setMinimized(true); } } } } mouseDownOnButton = false; updateButtonStates(e); move = false; updateCursor(e); } public void mouseEnter(final MouseEvent e) { updateButtonStates(e); moveInside = true; move = false; updateCursor(e); } public void mouseExit(final MouseEvent e) { updateButtonStates(e); moveInside = false; move = false; updateCursor(e); } public void mouseHover(final MouseEvent e) { // unused } public void mouseMove(final MouseEvent e) { updateButtonStates(e); if (move) { move(e); } updateCursor(e); } private void move(final MouseEvent e) { final Point moveEndPoint = new Point(e.x, e.y); final Control control = (Control) e.getSource(); final Shell shell = getShell(control); final boolean wasMaximized = ShellHelper.isMaximzed(shell); final int xMove = moveStartPoint.x - moveEndPoint.x; final int yMove = moveStartPoint.y - moveEndPoint.y; final int x = shell.getLocation().x - xMove; final int y = shell.getLocation().y - yMove; shell.setLocation(x, y); if (wasMaximized != ShellHelper.isMaximzed(shell)) { redrawButtons(e); } } private Shell getShell(Control control) { Shell result = null; while (control != null && result == null) { if (control instanceof Shell) { result = (Shell) control; } else { control = control.getParent(); } } return result; } /** * Sets the hand cursor for the given control. * * @param control */ private void showHandCursor(final Control control) { if (handCursor == null) { handCursor = createHandCursor(control.getDisplay()); } setCursor(control, handCursor); } /** * Sets the grab cursor for the given control. * * @param control */ private void showGrabCursor(final Control control) { if (grabCursor == null) { grabCursor = createGrabCursor(control.getDisplay()); } setCursor(control, grabCursor); } /** * Sets the default cursor for the given control. * * @param shell */ private void showDefaultCursor(final Control control) { if (defaultCursor == null) { defaultCursor = new Cursor(control.getDisplay(), SWT.CURSOR_ARROW); } setCursor(control, defaultCursor); } /** * Sets the given cursor for the control * * @param control * @param cursor * new cursor */ private void setCursor(final Control control, final Cursor cursor) { if (!SwtUtilities.isDisposed(control)) { if ((cursor != null) && (control.getCursor() != cursor)) { control.setCursor(cursor); } } } private Cursor createHandCursor(final Display display) { final String key = LnfKeyConstants.TITLELESS_SHELL_HAND_IMAGE; final Image image = LnfManager.getLnf().getImage(key); return SWTFacade.getDefault().createCursor(display, image, SWT.CURSOR_HAND); } private Cursor createGrabCursor(final Display display) { final String key = LnfKeyConstants.TITLELESS_SHELL_GRAB_IMAGE; final Image image = LnfManager.getLnf().getImage(key); return SWTFacade.getDefault().createCursor(display, image, SWT.CURSOR_HAND); } public void dispose() { SwtUtilities.dispose(handCursor); SwtUtilities.dispose(grabCursor); SwtUtilities.dispose(defaultCursor); } }