/******************************************************************************* * 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.lnf.renderer; import org.eclipse.core.runtime.Assert; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.riena.ui.swt.lnf.AbstractLnfRenderer; import org.eclipse.riena.ui.swt.lnf.LnfManager; import org.eclipse.riena.ui.swt.utils.ShellHelper; import org.eclipse.riena.ui.swt.utils.SwtUtilities; /** * Renderer of the buttons (min.,max. and close), the title , the image and background of title bar. */ public abstract class AbstractTitleBarRenderer extends AbstractLnfRenderer { private final static int DEFAULT_HEIGHT = 26; private final static int BUTTON_RIGHT_GAP = SwtUtilities.convertXToDpiTruncate(2); private final static int BUTTON_BUTTON_GAP = SwtUtilities.convertXToDpiTruncate(2); protected final static int BTN_COUNT = 3; protected final static int CLOSE_BTN_INDEX = 0; protected final static int MAX_BTN_INDEX = 1; protected final static int MIN_BTN_INDEX = 2; protected final static int RESTORE_BTN_INDEX = 3; private boolean closeable; private boolean maximizable; private boolean minimizable; private final boolean[] pressed = new boolean[BTN_COUNT]; private final boolean[] hover = new boolean[BTN_COUNT]; private boolean active; private boolean maximized; private Rectangle imageBounds; private Rectangle textBounds; private final Rectangle[] btnBounds = new Rectangle[BTN_COUNT]; private Shell shell; /** * Creates a new instance of <code>AbstractTitleBarRenderer</code> and initializes the bounds of the buttons, the text etc. */ public AbstractTitleBarRenderer() { super(); resetBounds(); } /** * Resets the bounds of the buttons, the text etc. */ private void resetBounds() { for (int i = 0; i < btnBounds.length; i++) { btnBounds[i] = new Rectangle(0, 0, 0, 0); } imageBounds = new Rectangle(0, 0, 0, 0); textBounds = new Rectangle(0, 0, 0, 0); } /** * Set the Shell used by this renderer. * * @param shell * the shell to set (non-null) */ public void setShell(final Shell shell) { Assert.isNotNull(shell); this.shell = shell; } protected Shell getShell() { return shell; } /** * @see org.eclipse.riena.ui.swt.lnf.AbstractLnfRenderer#paint(org.eclipse.swt.graphics.GC, java.lang.Object) */ @Override public void paint(final GC gc, final Object value) { // Assert.isNotNull(shell); if (shell == null) { shell = Display.getDefault().getActiveShell(); } setActive(true); setMaximized(ShellHelper.isMaximzed(shell)); resetBounds(); paintBackground(gc); imageBounds = paintImage(gc); for (int i = 0; i < BTN_COUNT; i++) { paintButton(gc, i); } textBounds = paintTitle(gc); } /** * Paints the background of the title bar. * * @param gc * graphics context */ abstract protected void paintBackground(GC gc); /** * Paints the title.<br> * <i>To paint the title correct the bounds of the buttons and the image must be set before.</i> * * @param gc * graphics context * @return the bounds of the text */ abstract protected Rectangle paintTitle(GC gc); /** * Paints the image. * * @param gc * graphics context * @return the bounds of the image */ abstract protected Rectangle paintImage(GC gc); /** * Sets the bounds for a button and paints it. * * @param gc * graphics context * @param btnIndex * index of the button */ protected void paintButton(final GC gc, final int btnIndex) { Image image = null; if (getBtnShow()[btnIndex]) { int index = btnIndex; if ((index == MAX_BTN_INDEX) && isMaximized()) { index = RESTORE_BTN_INDEX; } if (isActive()) { if (isPressed(btnIndex)) { image = LnfManager.getLnf().getImage(getBtnHoverSelectedImageKeys()[index]); } else if (isHover(btnIndex)) { image = LnfManager.getLnf().getImage(getBtnHoverImageKeys()[index]); } else { image = LnfManager.getLnf().getImage(getBtnImageKeys()[index]); } } else { image = LnfManager.getLnf().getImage(getBtnInactiveImageKeys()[index]); } if (image == null) { image = LnfManager.getLnf().getImage(getBtnImageKeys()[index]); } } int x = SwtUtilities.convertXToDpi(BUTTON_RIGHT_GAP); x = getBounds().x + getBounds().width - x; if (btnIndex > 0) { x = btnBounds[btnIndex - 1].x; if (btnBounds[btnIndex - 1].width > 0) { x -= SwtUtilities.convertXToDpi(BUTTON_BUTTON_GAP); } } int y = 0; if (image != null) { final Rectangle imgBounds = image.getBounds(); y = getBounds().height / 2 - imgBounds.height / 2; y -= 2; x -= imgBounds.width; gc.drawImage(image, x, y); btnBounds[btnIndex].width = imgBounds.width; btnBounds[btnIndex].height = imgBounds.height; } btnBounds[btnIndex].x = x; btnBounds[btnIndex].y = y; } /** * @see org.eclipse.riena.navigation.ui.swt.lnf.ILnfRenderer#dispose() */ public void dispose() { // nothing to do } /** * @return the pressed */ protected boolean isPressed(final int btnIndex) { return pressed[btnIndex]; } /** * @param pressed * the pressed to set */ protected void setPressed(final int btnIndex, final boolean pressed) { this.pressed[btnIndex] = pressed; } /** * @return the hover */ protected boolean isHover(final int btnIndex) { return hover[btnIndex]; } /** * @param hover * the hover to set */ protected void setHover(final int btnIndex, final boolean hover) { this.hover[btnIndex] = hover; } /** * @return the active */ protected boolean isActive() { return active; } /** * @param active * the active to set */ protected void setActive(final boolean active) { this.active = active; } /** * @return the maximized */ protected boolean isMaximized() { return maximized; } /** * @param maximiz * the maximized to set */ protected void setMaximized(final boolean maximized) { this.maximized = maximized; } /** * Returns <code>true</code> if the given point is inside the bounds of the close button, and <code>false</code> otherwise. * * @param pt * the point to test * @return <code>true</code> if the close button bounds contains the point and <code>false</code> otherwise */ public boolean isInsideCloseButton(final Point pt) { return isInsideButton(pt, CLOSE_BTN_INDEX); } /** * Returns <code>true</code> if the given point is inside the bounds of the minimize button, and <code>false</code> otherwise. * * @param pt * the point to test * @return <code>true</code> if the minimize button bounds contains the point and <code>false</code> otherwise */ public boolean isInsideMinimizeButton(final Point pt) { return isInsideButton(pt, MIN_BTN_INDEX); } /** * Returns <code>true</code> if the given point is inside the bounds of the maximize/restore button, and <code>false</code> otherwise. * * @param pt * the point to test * @return <code>true</code> if the maximize/restore button bounds contains the point and <code>false</code> otherwise */ public boolean isInsideMaximizeButton(final Point pt) { return isInsideButton(pt, MAX_BTN_INDEX); } /** * Returns <code>true</code> if the given point is inside the bounds of the button, and <code>false</code> otherwise. * * @param pt * the point to test * @param btnIndex * index of button * @return <code>true</code> if the button bounds contains the point and <code>false</code> otherwise */ private boolean isInsideButton(final Point pt, final int btnIndex) { return btnBounds[btnIndex].contains(pt); } /** * Returns <code>true</code> if the given point is inside the bounds of the move area, and <code>false</code> otherwise.<br> * The move area is the area of the shell less the bounds of the buttons. * * @param pt * the point to test * @return <code>true</code> if the move area bounds contains the point and <code>false</code> otherwise */ public boolean isInsideMoveArea(final Point pt) { boolean result = false; final Rectangle bounds = getBounds(); if (bounds != null) { final Rectangle moveArea = new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height); int minX = bounds.x + bounds.width; int maxHeight = textBounds.y + textBounds.height; for (final Rectangle btnBound : btnBounds) { minX = Math.min(minX, btnBound.x); maxHeight = Math.max(maxHeight, btnBound.y + btnBound.height); } int width = minX - bounds.x; if (width < 0) { width = 0; } moveArea.width = width; moveArea.height = maxHeight; result = moveArea.contains(pt); } return result; } /** * Returns the bounds of all buttons. * * @return bounds of buttons */ public Rectangle getAllButtonsBounds() { final Rectangle bounds = new Rectangle(btnBounds[0].x, btnBounds[0].y, btnBounds[0].width, btnBounds[0].height); for (int i = 1; i < btnBounds.length; i++) { bounds.add(btnBounds[i]); } return bounds; } protected Rectangle getImageBounds() { return imageBounds; } /** * Returns a array with the bounds of every single button. * * @return bounds of buttons */ protected Rectangle[] getButtonsBounds() { return btnBounds; } /** * @return the pressed */ public boolean isCloseButtonPressed() { return isPressed(CLOSE_BTN_INDEX); } /** * @param pressed * the pressed to set */ public void setCloseButtonPressed(final boolean pressed) { setPressed(CLOSE_BTN_INDEX, pressed); } /** * @return the hover */ public boolean isCloseButtonHover() { return isHover(CLOSE_BTN_INDEX); } /** * @param hover * the hover to set */ public void setCloseButtonHover(final boolean hover) { setHover(CLOSE_BTN_INDEX, hover); } /** * @return the pressed */ public boolean isMaximizedButtonPressed() { return isPressed(MAX_BTN_INDEX); } /** * @param pressed * the pressed to set */ public void setMaximizedButtonPressed(final boolean pressed) { setPressed(MAX_BTN_INDEX, pressed); } /** * @return the hover */ public boolean isMaximizedButtonHover() { return isHover(MAX_BTN_INDEX); } /** * @param hover * the hover to set */ public void setMaximizedButtonHover(final boolean hover) { setHover(MAX_BTN_INDEX, hover); } /** * @return the pressed */ public boolean isMinimizedButtonPressed() { return isPressed(MIN_BTN_INDEX); } /** * @param pressed * the pressed to set */ public void setMinimizedButtonPressed(final boolean pressed) { setPressed(MIN_BTN_INDEX, pressed); } /** * @return the hover */ public boolean isMinimizedButtonHover() { return isHover(MIN_BTN_INDEX); } /** * @param hover * the hover to set */ public void setMinimizedButtonHover(final boolean hover) { setHover(MIN_BTN_INDEX, hover); } abstract protected String[] getBtnImageKeys(); abstract protected String[] getBtnHoverSelectedImageKeys(); abstract protected String[] getBtnHoverImageKeys(); abstract protected String[] getBtnInactiveImageKeys(); private boolean[] getBtnShow() { final boolean[] btnShow = new boolean[BTN_COUNT]; btnShow[CLOSE_BTN_INDEX] = isCloseable(); btnShow[MAX_BTN_INDEX] = isMaximizable(); btnShow[MIN_BTN_INDEX] = isMinimizable(); return btnShow; } public void setCloseable(final boolean closeable) { this.closeable = closeable; } public boolean isCloseable() { return closeable; } public void setMaximizable(final boolean maximizable) { this.maximizable = maximizable; } public boolean isMaximizable() { return maximizable; } public void setMinimizable(final boolean minimizable) { this.minimizable = minimizable; } public boolean isMinimizable() { return minimizable; } /** * Returns the height of the title bar. * * @return height of title bar */ public int getHeight() { int height = 0; if (getBounds() != null) { height = getBounds().height; } if (height <= 0) { height = SwtUtilities.convertYToDpi(DEFAULT_HEIGHT); } return height; } }