summaryrefslogtreecommitdiff
path: root/propertysheet/src/org/eclipse/wb/core/controls/flyout
diff options
context:
space:
mode:
Diffstat (limited to 'propertysheet/src/org/eclipse/wb/core/controls/flyout')
-rw-r--r--propertysheet/src/org/eclipse/wb/core/controls/flyout/FlyoutControlComposite.java1007
-rw-r--r--propertysheet/src/org/eclipse/wb/core/controls/flyout/IFlyoutListener.java25
-rw-r--r--propertysheet/src/org/eclipse/wb/core/controls/flyout/IFlyoutMenuContributor.java23
-rw-r--r--propertysheet/src/org/eclipse/wb/core/controls/flyout/IFlyoutPreferences.java78
-rw-r--r--propertysheet/src/org/eclipse/wb/core/controls/flyout/MemoryFlyoutPreferences.java63
-rw-r--r--propertysheet/src/org/eclipse/wb/core/controls/flyout/PluginFlyoutPreferences.java81
-rw-r--r--propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_bottom.gifbin0 -> 829 bytes
-rw-r--r--propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_left.gifbin0 -> 55 bytes
-rw-r--r--propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_right.gifbin0 -> 54 bytes
-rw-r--r--propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_top.gifbin0 -> 828 bytes
-rw-r--r--propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/pin.gifbin0 -> 854 bytes
11 files changed, 1277 insertions, 0 deletions
diff --git a/propertysheet/src/org/eclipse/wb/core/controls/flyout/FlyoutControlComposite.java b/propertysheet/src/org/eclipse/wb/core/controls/flyout/FlyoutControlComposite.java
new file mode 100644
index 0000000..23d2f83
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/core/controls/flyout/FlyoutControlComposite.java
@@ -0,0 +1,1007 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * 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:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.core.controls.flyout;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.MouseTrackAdapter;
+import org.eclipse.swt.graphics.Font;
+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.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Sash;
+import org.eclipse.swt.widgets.Tracker;
+import org.eclipse.wb.core.controls.Messages;
+import org.eclipse.wb.draw2d.IColorConstants;
+import org.eclipse.wb.draw2d.ICursorConstants;
+import org.eclipse.wb.internal.core.utils.ui.DrawUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * {@link FlyoutControlComposite} is container for two {@link Control}'s. One (client control) is
+ * used to fill client area. Second (flyout control) can be docked to any enabled position or
+ * temporary hidden.
+ *
+ * @author scheglov_ke
+ * @coverage core.control
+ */
+public final class FlyoutControlComposite extends Composite {
+ private static final int RESIZE_WIDTH = 5;
+ private static final int TITLE_LINES = 30;
+ private static final int TITLE_MARGIN = 5;
+ private static final Font TITLE_FONT = JFaceResources.getFontRegistry().getBold(
+ JFaceResources.DEFAULT_FONT);
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Images
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private static final Image PIN = loadImage("icons/pin.gif");
+ private static final Image ARROW_LEFT = loadImage("icons/arrow_left.gif");
+ private static final Image ARROW_RIGHT = loadImage("icons/arrow_right.gif");
+ private static final Image ARROW_TOP = loadImage("icons/arrow_top.gif");
+ private static final Image ARROW_BOTTOM = loadImage("icons/arrow_bottom.gif");
+
+ private static Image loadImage(String path) {
+ return DrawUtils.loadImage(FlyoutControlComposite.class, path);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Instance fields
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private final IFlyoutPreferences m_preferences;
+ private final FlyoutContainer m_flyoutContainer;
+ private int m_minWidth = 150;
+ private int m_validDockLocations = -1;
+ private final List<IFlyoutMenuContributor> m_menuContributors =
+ new ArrayList<IFlyoutMenuContributor>();
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public FlyoutControlComposite(Composite parent, int style, IFlyoutPreferences preferences) {
+ super(parent, style);
+ m_preferences = preferences;
+ // add listeners
+ addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ if (getShell().getMinimized()) {
+ return;
+ }
+ layout();
+ }
+ });
+ // create container for flyout control
+ m_flyoutContainer = new FlyoutContainer(this, SWT.NO_BACKGROUND);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Parents
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the parent {@link Composite} for flyout {@link Control}.
+ */
+ public Composite getFlyoutParent() {
+ return m_flyoutContainer;
+ }
+
+ /**
+ * @return the parent {@link Composite} for client {@link Control}.
+ */
+ public Composite getClientParent() {
+ return this;
+ }
+
+ /**
+ * Sets the bit set with valid docking locations.
+ */
+ public void setValidDockLocations(int validDockLocations) {
+ m_validDockLocations = validDockLocations;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Sets the minimal width of flyout.
+ */
+ public void setMinWidth(int minWidth) {
+ m_minWidth = minWidth;
+ }
+
+ /**
+ * Sets the text of title.
+ */
+ public void setTitleText(String text) {
+ m_flyoutContainer.setTitleText(text);
+ }
+
+ /**
+ * Adds new {@link IFlyoutMenuContributor}.
+ */
+ public void addMenuContributor(IFlyoutMenuContributor contributor) {
+ if (!m_menuContributors.contains(contributor)) {
+ m_menuContributors.add(contributor);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Layout
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public void layout() {
+ Rectangle clientArea = getClientArea();
+ int state = m_preferences.getState();
+ Control client = getChildren()[1];
+ // check, may be "clientArea" is empty, for example because CTabFolder page is not visible
+ if (clientArea.width == 0 || clientArea.height == 0) {
+ return;
+ }
+ // check, maybe flyout has no Control, so "client" should fill client area
+ if (m_flyoutContainer.getControl() == null
+ // BEGIN ADT MODIFICATIONS
+ || !m_flyoutContainer.getControl().getVisible()
+ // END ADT MODIFICATIONS
+ ) {
+ m_flyoutContainer.setBounds(0, 0, 0, 0);
+ client.setBounds(clientArea);
+ return;
+ }
+ // prepare width to display
+ int width;
+ int offset;
+ if (state == IFlyoutPreferences.STATE_OPEN) {
+ width = m_preferences.getWidth();
+ // limit maximum value
+ if (isHorizontal()) {
+ width = Math.min(clientArea.width / 2, width);
+ } else {
+ width = Math.min(clientArea.height / 2, width);
+ }
+ // limit minimum value
+ width = Math.max(width, m_minWidth);
+ width = Math.max(width, 2 * m_flyoutContainer.m_titleHeight + m_flyoutContainer.m_titleWidth);
+ // remember actual width
+ m_preferences.setWidth(width);
+ //
+ offset = width;
+ } else if (state == IFlyoutPreferences.STATE_EXPANDED) {
+ offset = m_flyoutContainer.m_titleHeight;
+ width = m_preferences.getWidth();
+ } else {
+ width = m_flyoutContainer.m_titleHeight;
+ offset = width;
+ }
+ // change bounds for flyout container and client control
+ {
+ if (isWest()) {
+ m_flyoutContainer.setBounds(0, 0, width, clientArea.height);
+ client.setBounds(offset, 0, clientArea.width - offset, clientArea.height);
+ } else if (isEast()) {
+ m_flyoutContainer.setBounds(clientArea.width - width, 0, width, clientArea.height);
+ client.setBounds(0, 0, clientArea.width - offset, clientArea.height);
+ } else if (isNorth()) {
+ m_flyoutContainer.setBounds(0, 0, clientArea.width, width);
+ client.setBounds(0, offset, clientArea.width, clientArea.height - offset);
+ } else if (isSouth()) {
+ m_flyoutContainer.setBounds(0, clientArea.height - width, clientArea.width, width);
+ client.setBounds(0, 0, clientArea.width, clientArea.height - offset);
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Internal utils
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private boolean isHorizontal() {
+ return isWest() || isEast();
+ }
+
+ private boolean isWest() {
+ return getDockLocation() == IFlyoutPreferences.DOCK_WEST;
+ }
+
+ private boolean isEast() {
+ return getDockLocation() == IFlyoutPreferences.DOCK_EAST;
+ }
+
+ private boolean isNorth() {
+ return getDockLocation() == IFlyoutPreferences.DOCK_NORTH;
+ }
+
+ private boolean isSouth() {
+ return getDockLocation() == IFlyoutPreferences.DOCK_SOUTH;
+ }
+
+ /**
+ * @return <code>true</code> if given docking location is valid.
+ */
+ private boolean isValidDockLocation(int location) {
+ return (location & m_validDockLocations) == location;
+ }
+
+ /**
+ * @return current docking location.
+ */
+ private int getDockLocation() {
+ return m_preferences.getDockLocation();
+ }
+
+ /**
+ * Sets new docking location.
+ */
+ private void setDockLocation(int dockLocation) {
+ m_preferences.setDockLocation(dockLocation);
+ layout();
+ }
+
+ // BEGIN ADT MODIFICATIONS
+ /** If the flyout hover is showing, dismiss it */
+ public void dismissHover() {
+ if (m_flyoutContainer != null) {
+ m_flyoutContainer.dismissHover();
+ }
+ }
+
+ /** Sets a listener to be modified when windows are opened, collapsed and expanded */
+ public void setListener(IFlyoutListener listener) {
+ assert m_listener == null; // Only one listener supported
+ m_listener = listener;
+ }
+ private IFlyoutListener m_listener;
+ // END ADT MODIFICATIONS
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // FlyoutContainer
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Container for flyout {@link Control}.
+ *
+ * @author scheglov_ke
+ */
+ private final class FlyoutContainer extends Composite {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Container
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public FlyoutContainer(Composite parent, int style) {
+ super(parent, style);
+ configureMenu();
+ updateTitleImage("Flyout");
+ // add listeners
+ addListener(SWT.Dispose, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ if (m_titleImage != null) {
+ m_titleImage.dispose();
+ m_titleImageRotated.dispose();
+ m_titleImage = null;
+ m_titleImageRotated = null;
+ }
+ if (m_backImage != null) {
+ m_backImage.dispose();
+ m_backImage = null;
+ }
+ }
+ });
+ {
+ Listener listener = new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ layout();
+ }
+ };
+ addListener(SWT.Move, listener);
+ addListener(SWT.Resize, listener);
+ }
+ addListener(SWT.Paint, new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ handlePaint(event.gc);
+ }
+ });
+ // mouse listeners
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseDown(MouseEvent event) {
+ if (event.button == 1) {
+ handle_mouseDown(event);
+ }
+ }
+
+ @Override
+ public void mouseUp(MouseEvent event) {
+ if (event.button == 1) {
+ handle_mouseUp(event);
+ }
+ }
+ });
+ addMouseTrackListener(new MouseTrackAdapter() {
+ @Override
+ public void mouseExit(MouseEvent e) {
+ m_stateHover = false;
+ redraw();
+ setCursor(null);
+ }
+
+ @Override
+ public void mouseHover(MouseEvent e) {
+ handle_mouseHover();
+ }
+ });
+ addMouseMoveListener(new MouseMoveListener() {
+ @Override
+ public void mouseMove(MouseEvent event) {
+ handle_mouseMove(event);
+ }
+ });
+ }
+
+ // BEGIN ADT MODIFICATIONS
+ private void dismissHover() {
+ int state = m_preferences.getState();
+ if (state == IFlyoutPreferences.STATE_EXPANDED) {
+ state = IFlyoutPreferences.STATE_COLLAPSED;
+ m_preferences.setState(state);
+ redraw();
+ FlyoutControlComposite.this.layout();
+ if (m_listener != null) {
+ m_listener.stateChanged(IFlyoutPreferences.STATE_EXPANDED, state);
+ }
+ }
+ }
+ // END END MODIFICATIONS
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Events: mouse
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private boolean m_resize;
+ private boolean m_stateHover;
+
+ /**
+ * Handler for {@link SWT#MouseDown} event.
+ */
+ private void handle_mouseDown(MouseEvent event) {
+ if (m_stateHover) {
+ int state = m_preferences.getState();
+ // BEGIN ADT MODIFICATIONS
+ int oldState = state;
+ // END ADT MODIFICATIONS
+ if (state == IFlyoutPreferences.STATE_OPEN) {
+ state = IFlyoutPreferences.STATE_COLLAPSED;
+ } else {
+ state = IFlyoutPreferences.STATE_OPEN;
+ }
+ m_preferences.setState(state);
+ redraw();
+ FlyoutControlComposite.this.layout();
+ // BEGIN ADT MODIFICATIONS
+ if (m_listener != null) {
+ m_listener.stateChanged(oldState, state);
+ }
+ // END ADT MODIFICATIONS
+ } else if (getCursor() == ICursorConstants.SIZEWE || getCursor() == ICursorConstants.SIZENS) {
+ m_resize = true;
+ } else if (getCursor() == ICursorConstants.SIZEALL) {
+ handleDocking();
+ }
+ }
+
+ /**
+ * Handler for {@link SWT#MouseUp} event.
+ */
+ private void handle_mouseUp(MouseEvent event) {
+ if (m_resize) {
+ m_resize = false;
+ handle_mouseMove(event);
+ }
+ }
+
+ /**
+ * Handler for {@link SWT#MouseMove} event.
+ */
+ private void handle_mouseMove(MouseEvent event) {
+ final FlyoutControlComposite container = FlyoutControlComposite.this;
+ if (m_resize) {
+ // prepare width
+ int width;
+ if (isHorizontal()) {
+ width = getSize().x;
+ } else {
+ width = getSize().y;
+ }
+ // prepare new width
+ int newWidth = width;
+ if (isWest()) {
+ newWidth = event.x + RESIZE_WIDTH / 2;
+ } else if (isEast()) {
+ newWidth = width - event.x + RESIZE_WIDTH / 2;
+ } else if (isNorth()) {
+ newWidth = event.y + RESIZE_WIDTH / 2;
+ } else if (isSouth()) {
+ newWidth = width - event.y + RESIZE_WIDTH / 2;
+ }
+ // update width
+ if (newWidth != width) {
+ m_preferences.setWidth(newWidth);
+ redraw();
+ container.layout();
+ }
+ } else {
+ Rectangle clientArea = getClientArea();
+ boolean inside = clientArea.contains(event.x, event.y);
+ int x = event.x;
+ int y = event.y;
+ if (inside) {
+ // check for state
+ {
+ boolean oldStateHover = m_stateHover;
+ if (isEast()) {
+ m_stateHover = x > clientArea.width - m_titleHeight && y < m_titleHeight;
+ } else {
+ m_stateHover = x < m_titleHeight && y < m_titleHeight;
+ }
+ if (m_stateHover != oldStateHover) {
+ redraw();
+ }
+ if (m_stateHover) {
+ setCursor(null);
+ return;
+ }
+ }
+ // check for resize band
+ if (isOpenExpanded()) {
+ if (isWest() && x >= clientArea.width - RESIZE_WIDTH) {
+ setCursor(ICursorConstants.SIZEWE);
+ } else if (isEast() && x <= RESIZE_WIDTH) {
+ setCursor(ICursorConstants.SIZEWE);
+ } else if (isNorth() && y >= clientArea.height - RESIZE_WIDTH) {
+ setCursor(ICursorConstants.SIZENS);
+ } else if (isSouth() && y <= RESIZE_WIDTH) {
+ setCursor(ICursorConstants.SIZENS);
+ } else {
+ setCursor(null);
+ }
+ }
+ // check for docking
+ if (getCursor() == null) {
+ setCursor(ICursorConstants.SIZEALL);
+ }
+ } else {
+ setCursor(null);
+ }
+ }
+ }
+
+ /**
+ * Handler for {@link SWT#MouseHover} event - temporary expands flyout and collapse again when
+ * mouse moves above client.
+ */
+ private void handle_mouseHover() {
+ if (m_preferences.getState() == IFlyoutPreferences.STATE_COLLAPSED && !m_stateHover) {
+ m_preferences.setState(IFlyoutPreferences.STATE_EXPANDED);
+ //
+ final FlyoutControlComposite container = FlyoutControlComposite.this;
+ container.layout();
+ // BEGIN ADT MODIFICATIONS
+ if (m_listener != null) {
+ m_listener.stateChanged(IFlyoutPreferences.STATE_COLLAPSED,
+ IFlyoutPreferences.STATE_EXPANDED);
+ }
+ // END ADT MODIFICATIONS
+ // add listeners
+ Listener listener = new Listener() {
+ @Override
+ public void handleEvent(Event event) {
+ if (event.type == SWT.Dispose) {
+ getDisplay().removeFilter(SWT.MouseMove, this);
+ } else {
+ Point p = ((Control) event.widget).toDisplay(event.x, event.y);
+ // during resize mouse can be temporary outside of flyout - ignore
+ if (m_resize) {
+ return;
+ }
+ // mouse in in flyout container - ignore
+ if (getClientArea().contains(toControl(p.x, p.y))) {
+ return;
+ }
+ // mouse is in full container - collapse
+ if (container.getClientArea().contains(container.toControl(p.x, p.y))) {
+ getDisplay().removeFilter(SWT.MouseMove, this);
+ // it is possible, that user restored (OPEN) flyout, so collapse only if we still in expand state
+ if (m_preferences.getState() == IFlyoutPreferences.STATE_EXPANDED) {
+ m_preferences.setState(IFlyoutPreferences.STATE_COLLAPSED);
+ container.layout();
+ // BEGIN ADT MODIFICATIONS
+ if (m_listener != null) {
+ m_listener.stateChanged(IFlyoutPreferences.STATE_EXPANDED,
+ IFlyoutPreferences.STATE_COLLAPSED);
+ }
+ // END ADT MODIFICATIONS
+ }
+ }
+ }
+ }
+ };
+ addListener(SWT.Dispose, listener);
+ getDisplay().addFilter(SWT.MouseMove, listener);
+ }
+ }
+
+ /**
+ * Handler for docking.
+ */
+ private void handleDocking() {
+ final FlyoutControlComposite container = FlyoutControlComposite.this;
+ final int width = m_preferences.getWidth();
+ final int oldDockLocation = getDockLocation();
+ final int[] newDockLocation = new int[]{oldDockLocation};
+ final Tracker dockingTracker = new Tracker(container, SWT.NONE);
+ dockingTracker.setRectangles(new Rectangle[]{getBounds()});
+ dockingTracker.setStippled(true);
+ dockingTracker.addListener(SWT.Move, new Listener() {
+ @Override
+ public void handleEvent(Event event2) {
+ Rectangle clientArea = container.getClientArea();
+ Point location = container.toControl(event2.x, event2.y);
+ int h3 = clientArea.height / 3;
+ // check locations
+ if (location.y < h3 && isValidDockLocation(IFlyoutPreferences.DOCK_NORTH)) {
+ dockingTracker.setRectangles(new Rectangle[]{new Rectangle(0,
+ 0,
+ clientArea.width,
+ width)});
+ newDockLocation[0] = IFlyoutPreferences.DOCK_NORTH;
+ } else if (location.y > 2 * h3 && isValidDockLocation(IFlyoutPreferences.DOCK_SOUTH)) {
+ dockingTracker.setRectangles(new Rectangle[]{new Rectangle(0,
+ clientArea.height - width,
+ clientArea.width,
+ width)});
+ newDockLocation[0] = IFlyoutPreferences.DOCK_SOUTH;
+ } else if (location.x < clientArea.width / 2
+ && isValidDockLocation(IFlyoutPreferences.DOCK_WEST)) {
+ dockingTracker.setRectangles(new Rectangle[]{new Rectangle(0,
+ 0,
+ width,
+ clientArea.height)});
+ newDockLocation[0] = IFlyoutPreferences.DOCK_WEST;
+ } else if (isValidDockLocation(IFlyoutPreferences.DOCK_EAST)) {
+ dockingTracker.setRectangles(new Rectangle[]{new Rectangle(clientArea.width - width,
+ 0,
+ width,
+ clientArea.height)});
+ newDockLocation[0] = IFlyoutPreferences.DOCK_EAST;
+ } else {
+ dockingTracker.setRectangles(new Rectangle[]{getBounds()});
+ newDockLocation[0] = oldDockLocation;
+ }
+ }
+ });
+ // start tracking
+ if (dockingTracker.open()) {
+ setDockLocation(newDockLocation[0]);
+ }
+ // dispose tracker
+ dockingTracker.dispose();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the {@link Control} installed on this {@link FlyoutControlComposite}, or
+ * <code>null</code> if there are no any {@link Control}.
+ */
+ private Control getControl() {
+ Control[] children = getChildren();
+ return children.length == 1 ? children[0] : null;
+ }
+
+ /**
+ * Sets the text of title.
+ */
+ public void setTitleText(String text) {
+ updateTitleImage(text);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Layout
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public void layout() {
+ Control control = getControl();
+ if (control == null) {
+ return;
+ }
+ // OK, we have control, so can continue layout
+ Rectangle clientArea = getClientArea();
+ if (isOpenExpanded()) {
+ if (isWest()) {
+ int y = m_titleHeight;
+ control.setBounds(0, y, clientArea.width - RESIZE_WIDTH, clientArea.height - y);
+ } else if (isEast()) {
+ int y = m_titleHeight;
+ control.setBounds(RESIZE_WIDTH, y, clientArea.width - RESIZE_WIDTH, clientArea.height - y);
+ } else if (isNorth()) {
+ int y = m_titleHeight;
+ control.setBounds(0, y, clientArea.width, clientArea.height - y - RESIZE_WIDTH);
+ } else if (isSouth()) {
+ int y = RESIZE_WIDTH + m_titleHeight;
+ control.setBounds(0, y, clientArea.width, clientArea.height - y);
+ }
+ } else {
+ control.setBounds(0, 0, 0, 0);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Paint
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private Image m_backImage;
+
+ /**
+ * Handler for {@link SWT#Paint} event.
+ */
+ private void handlePaint(GC paintGC) {
+ Rectangle clientArea = getClientArea();
+ // prepare back image
+ GC gc;
+ {
+ if (m_backImage == null || !m_backImage.getBounds().equals(clientArea)) {
+ if (m_backImage != null) {
+ m_backImage.dispose();
+ }
+ m_backImage = new Image(getDisplay(), clientArea.width, clientArea.height);
+ }
+ // prepare GC
+ gc = new GC(m_backImage);
+ gc.setBackground(paintGC.getBackground());
+ gc.setForeground(paintGC.getForeground());
+ gc.fillRectangle(clientArea);
+ }
+ //
+ if (isOpenExpanded()) {
+ // draw header
+ {
+ // draw title
+ if (isWest()) {
+ drawStateImage(gc, 0, 0);
+ gc.drawImage(m_titleImage, m_titleHeight, 0);
+ } else if (isEast()) {
+ int x = clientArea.width - m_titleHeight;
+ drawStateImage(gc, x, 0);
+ gc.drawImage(m_titleImage, x - m_titleWidth, 0);
+ } else if (isNorth()) {
+ drawStateImage(gc, 0, 0);
+ gc.drawImage(m_titleImage, m_titleHeight, 0);
+ } else if (isSouth()) {
+ int y = RESIZE_WIDTH;
+ drawStateImage(gc, 0, y);
+ gc.drawImage(m_titleImage, m_titleHeight, y);
+ }
+ }
+ // draw resize band
+ drawResizeBand(gc);
+ } else {
+ if (isHorizontal()) {
+ drawStateImage(gc, 0, 0);
+ gc.drawImage(m_titleImageRotated, 0, m_titleHeight);
+ } else {
+ drawStateImage(gc, 0, 0);
+ gc.drawImage(m_titleImage, m_titleHeight, 0);
+ }
+ DrawUtils.drawHighlightRectangle(gc, 0, 0, clientArea.width, clientArea.height);
+ }
+ // flush back image
+ {
+ gc.dispose();
+ paintGC.drawImage(m_backImage, 0, 0);
+ }
+ }
+
+ /**
+ * Draws the state image (arrow) at given location.
+ */
+ private void drawStateImage(GC gc, int x, int y) {
+ DrawUtils.drawImageCHCV(gc, getStateImage(), x, y, m_titleHeight, m_titleHeight);
+ if (m_stateHover) {
+ DrawUtils.drawHighlightRectangle(gc, x, y, m_titleHeight, m_titleHeight);
+ }
+ }
+
+ /**
+ * @return the {@link Image} corresponding to current state (open or collapsed).
+ */
+ private Image getStateImage() {
+ int location = getDockLocation();
+ int state = m_preferences.getState();
+ if (state == IFlyoutPreferences.STATE_OPEN) {
+ switch (location) {
+ case IFlyoutPreferences.DOCK_WEST :
+ return ARROW_LEFT;
+ case IFlyoutPreferences.DOCK_EAST :
+ return ARROW_RIGHT;
+ case IFlyoutPreferences.DOCK_NORTH :
+ return ARROW_TOP;
+ case IFlyoutPreferences.DOCK_SOUTH :
+ return ARROW_BOTTOM;
+ }
+ } else if (state == IFlyoutPreferences.STATE_EXPANDED) {
+ return PIN;
+ } else {
+ switch (location) {
+ case IFlyoutPreferences.DOCK_WEST :
+ return ARROW_RIGHT;
+ case IFlyoutPreferences.DOCK_EAST :
+ return ARROW_LEFT;
+ case IFlyoutPreferences.DOCK_NORTH :
+ return ARROW_BOTTOM;
+ case IFlyoutPreferences.DOCK_SOUTH :
+ return ARROW_TOP;
+ }
+ }
+ //
+ return null;
+ }
+
+ /**
+ * Draws that resize band, {@link Sash} like.
+ */
+ private void drawResizeBand(GC gc) {
+ Rectangle clientArea = getClientArea();
+ // prepare locations
+ int x, y, width, height;
+ if (isHorizontal()) {
+ if (isWest()) {
+ x = clientArea.width - RESIZE_WIDTH;
+ } else {
+ x = 0;
+ }
+ y = 0;
+ width = RESIZE_WIDTH;
+ height = clientArea.height;
+ } else {
+ x = 0;
+ if (isNorth()) {
+ y = clientArea.height - RESIZE_WIDTH;
+ } else {
+ y = 0;
+ }
+ width = clientArea.width;
+ height = RESIZE_WIDTH;
+ }
+ // draw band
+ DrawUtils.drawHighlightRectangle(gc, x, y, width, height);
+ }
+
+ /**
+ * @return <code>true</code> if flyout is open or expanded.
+ */
+ private boolean isOpenExpanded() {
+ int state = m_preferences.getState();
+ return state == IFlyoutPreferences.STATE_OPEN || state == IFlyoutPreferences.STATE_EXPANDED;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Title image
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private int m_titleWidth;
+ private int m_titleHeight;
+ private Image m_titleImage;
+ private Image m_titleImageRotated;
+
+ /**
+ * Creates {@link Image} for given title text.
+ */
+ private void updateTitleImage(String text) {
+ // prepare size of text
+ Point textSize;
+ {
+ GC gc = new GC(this);
+ gc.setFont(TITLE_FONT);
+ textSize = gc.textExtent(text);
+ gc.dispose();
+ }
+ // dispose existing image
+ if (m_titleImage != null) {
+ m_titleImage.dispose();
+ m_titleImageRotated.dispose();
+ }
+ // prepare new image
+ {
+ m_titleWidth = textSize.x + 2 * TITLE_LINES + 4 * TITLE_MARGIN;
+ m_titleHeight = textSize.y;
+ m_titleImage = new Image(getDisplay(), m_titleWidth, m_titleHeight);
+ GC gc = new GC(m_titleImage);
+ try {
+ gc.setBackground(getBackground());
+ gc.fillRectangle(0, 0, m_titleWidth, m_titleHeight);
+ int x = 0;
+ // draw left lines
+ {
+ x += TITLE_MARGIN;
+ drawTitleLines(gc, x, m_titleHeight, TITLE_LINES);
+ x += TITLE_LINES + TITLE_MARGIN;
+ }
+ // draw text
+ {
+ gc.setForeground(IColorConstants.black);
+ gc.setFont(TITLE_FONT);
+ gc.drawText(text, x, 0);
+ x += textSize.x;
+ }
+ // draw right lines
+ {
+ x += TITLE_MARGIN;
+ drawTitleLines(gc, x, m_titleHeight, TITLE_LINES);
+ }
+ } finally {
+ gc.dispose();
+ }
+ }
+ // prepare rotated image
+ m_titleImageRotated = DrawUtils.createRotatedImage(m_titleImage);
+ }
+
+ /**
+ * Draws two title lines.
+ */
+ private void drawTitleLines(GC gc, int x, int height, int width) {
+ drawTitleLine(gc, x, height / 3, width);
+ drawTitleLine(gc, x, 2 * height / 3, width);
+ }
+
+ /**
+ * Draws single title line.
+ */
+ private void drawTitleLine(GC gc, int x, int y, int width) {
+ int right = x + TITLE_LINES;
+ //
+ gc.setForeground(IColorConstants.buttonLightest);
+ gc.drawLine(x, y, right - 2, y);
+ gc.drawLine(x, y + 1, right - 2, y + 1);
+ //
+ gc.setForeground(IColorConstants.buttonDarker);
+ gc.drawLine(right - 2, y, right - 1, y);
+ gc.drawLine(x + 2, y + 1, right - 2, y + 1);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Menu
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private void configureMenu() {
+ final MenuManager manager = new MenuManager();
+ manager.setRemoveAllWhenShown(true);
+ manager.addMenuListener(new IMenuListener() {
+ @Override
+ public void menuAboutToShow(IMenuManager menuMgr) {
+ addDockActions();
+ for (IFlyoutMenuContributor contributor : m_menuContributors) {
+ contributor.contribute(manager);
+ }
+ }
+
+ private void addDockActions() {
+ MenuManager dockManager = new MenuManager(Messages.FlyoutControlComposite_dockManager);
+ addDockAction(
+ dockManager,
+ Messages.FlyoutControlComposite_dockLeft,
+ IFlyoutPreferences.DOCK_WEST);
+ addDockAction(
+ dockManager,
+ Messages.FlyoutControlComposite_dockRight,
+ IFlyoutPreferences.DOCK_EAST);
+ addDockAction(
+ dockManager,
+ Messages.FlyoutControlComposite_dockTop,
+ IFlyoutPreferences.DOCK_NORTH);
+ addDockAction(
+ dockManager,
+ Messages.FlyoutControlComposite_dockBottom,
+ IFlyoutPreferences.DOCK_SOUTH);
+ manager.add(dockManager);
+ }
+
+ private void addDockAction(MenuManager dockManager, String text, int location) {
+ if ((m_validDockLocations & location) != 0) {
+ dockManager.add(new DockAction(text, location));
+ }
+ }
+ });
+ // set menu
+ setMenu(manager.createContextMenu(this));
+ // dispose it later
+ addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ manager.dispose();
+ }
+ });
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // DockAction
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private class DockAction extends Action {
+ private final int m_location;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public DockAction(String text, int location) {
+ super(text, AS_RADIO_BUTTON);
+ m_location = location;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Action
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ @Override
+ public boolean isChecked() {
+ return getDockLocation() == m_location;
+ }
+
+ @Override
+ public void run() {
+ setDockLocation(m_location);
+ }
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/core/controls/flyout/IFlyoutListener.java b/propertysheet/src/org/eclipse/wb/core/controls/flyout/IFlyoutListener.java
new file mode 100644
index 0000000..ed87bb8
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/core/controls/flyout/IFlyoutListener.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Google, Inc.
+ * 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:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.core.controls.flyout;
+
+// BEGIN ADT MODIFICATIONS
+/** Interface for listeners interested in window state transitions in flyout windows */
+public interface IFlyoutListener {
+ /**
+ * The flyout has changed state from the old state to the new state (see the
+ * state constants in {@link IFlyoutPreferences})
+ *
+ * @param oldState the old state
+ * @param newState the new state
+ */
+ void stateChanged(int oldState, int newState);
+}
+// END ADT MODIFICATIONS
diff --git a/propertysheet/src/org/eclipse/wb/core/controls/flyout/IFlyoutMenuContributor.java b/propertysheet/src/org/eclipse/wb/core/controls/flyout/IFlyoutMenuContributor.java
new file mode 100644
index 0000000..11a9b08
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/core/controls/flyout/IFlyoutMenuContributor.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * 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:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.core.controls.flyout;
+
+import org.eclipse.jface.action.IMenuManager;
+
+/**
+ * Contributes items into {@link IMenuManager} or {@link FlyoutControlComposite}.
+ *
+ * @author scheglov_ke
+ * @coverage core.control
+ */
+public interface IFlyoutMenuContributor {
+ void contribute(IMenuManager manager);
+}
diff --git a/propertysheet/src/org/eclipse/wb/core/controls/flyout/IFlyoutPreferences.java b/propertysheet/src/org/eclipse/wb/core/controls/flyout/IFlyoutPreferences.java
new file mode 100644
index 0000000..d24edb5
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/core/controls/flyout/IFlyoutPreferences.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * 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:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.core.controls.flyout;
+
+/**
+ * Provider for preferences of flyout control of {@link FlyoutControlComposite}.
+ *
+ * @author scheglov_ke
+ * @coverage core.control
+ */
+public interface IFlyoutPreferences {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Docking constants
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ int DOCK_WEST = 1;
+ int DOCK_EAST = 2;
+ int DOCK_NORTH = 4;
+ int DOCK_SOUTH = 8;
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // State constants
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ int STATE_OPEN = 0;
+ int STATE_COLLAPSED = 1;
+ int STATE_EXPANDED = 2;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * @return the docking location - {@link #DOCK_WEST}, {@link #DOCK_EAST}, {@link #DOCK_NORTH} or
+ * {@link #DOCK_SOUTH}.
+ */
+ int getDockLocation();
+
+ /**
+ * @return the state of flyout - {@link #STATE_OPEN} or {@link #STATE_COLLAPSED}.
+ */
+ int getState();
+
+ /**
+ * @return the width of flyout.
+ */
+ int getWidth();
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Modification
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Sets the docking location.
+ */
+ void setDockLocation(int location);
+
+ /**
+ * Sets the state of flyout - {@link #STATE_OPEN} or {@link #STATE_COLLAPSED}.
+ */
+ void setState(int state);
+
+ /**
+ * Sets the width of flyout.
+ */
+ void setWidth(int width);
+}
diff --git a/propertysheet/src/org/eclipse/wb/core/controls/flyout/MemoryFlyoutPreferences.java b/propertysheet/src/org/eclipse/wb/core/controls/flyout/MemoryFlyoutPreferences.java
new file mode 100644
index 0000000..8591589
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/core/controls/flyout/MemoryFlyoutPreferences.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * 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:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.core.controls.flyout;
+
+/**
+ * Implementation of {@link IFlyoutPreferences} for keeping settings in memory.
+ *
+ * @author scheglov_ke
+ * @coverage core.control
+ */
+public final class MemoryFlyoutPreferences implements IFlyoutPreferences {
+ private int m_dockLocation;
+ private int m_state;
+ private int m_width;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public MemoryFlyoutPreferences(int dockLocation, int state, int width) {
+ m_dockLocation = dockLocation;
+ m_state = state;
+ m_width = width;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // IFlyoutPreferences
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public int getDockLocation() {
+ return m_dockLocation;
+ }
+
+ public int getState() {
+ return m_state;
+ }
+
+ public int getWidth() {
+ return m_width;
+ }
+
+ public void setDockLocation(int location) {
+ m_dockLocation = location;
+ }
+
+ public void setState(int state) {
+ m_state = state;
+ }
+
+ public void setWidth(int width) {
+ m_width = width;
+ }
+} \ No newline at end of file
diff --git a/propertysheet/src/org/eclipse/wb/core/controls/flyout/PluginFlyoutPreferences.java b/propertysheet/src/org/eclipse/wb/core/controls/flyout/PluginFlyoutPreferences.java
new file mode 100644
index 0000000..270dba0
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/core/controls/flyout/PluginFlyoutPreferences.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * 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:
+ * Google, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wb.core.controls.flyout;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+
+/**
+ * Implementation of {@link IFlyoutPreferences} for {@link IPreferenceStore}.
+ *
+ * @author scheglov_ke
+ * @coverage core.control
+ */
+public final class PluginFlyoutPreferences implements IFlyoutPreferences {
+ private final IPreferenceStore m_store;
+ private final String m_dockLocationKey;
+ private final String m_stateKey;
+ private final String m_widthKey;
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Constructor
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public PluginFlyoutPreferences(IPreferenceStore store, String prefix) {
+ m_store = store;
+ m_dockLocationKey = prefix + ".flyout.dockLocation";
+ m_stateKey = prefix + ".flyout.state";
+ m_widthKey = prefix + ".flyout.width";
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Access
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /**
+ * Initializes defaults using given values.
+ */
+ public void initializeDefaults(int location, int state, int width) {
+ m_store.setDefault(m_dockLocationKey, location);
+ m_store.setDefault(m_stateKey, state);
+ m_store.setDefault(m_widthKey, width);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // IFlyoutPreferences
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ public int getDockLocation() {
+ return m_store.getInt(m_dockLocationKey);
+ }
+
+ public int getState() {
+ return m_store.getInt(m_stateKey);
+ }
+
+ public int getWidth() {
+ return m_store.getInt(m_widthKey);
+ }
+
+ public void setDockLocation(int location) {
+ m_store.setValue(m_dockLocationKey, location);
+ }
+
+ public void setState(int state) {
+ m_store.setValue(m_stateKey, state);
+ }
+
+ public void setWidth(int width) {
+ m_store.setValue(m_widthKey, width);
+ }
+}
diff --git a/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_bottom.gif b/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_bottom.gif
new file mode 100644
index 0000000..4a2df3f
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_bottom.gif
Binary files differ
diff --git a/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_left.gif b/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_left.gif
new file mode 100644
index 0000000..9f7018e
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_left.gif
Binary files differ
diff --git a/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_right.gif b/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_right.gif
new file mode 100644
index 0000000..56fb7de
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_right.gif
Binary files differ
diff --git a/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_top.gif b/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_top.gif
new file mode 100644
index 0000000..eb4e5c2
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/arrow_top.gif
Binary files differ
diff --git a/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/pin.gif b/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/pin.gif
new file mode 100644
index 0000000..61bb170
--- /dev/null
+++ b/propertysheet/src/org/eclipse/wb/core/controls/flyout/icons/pin.gif
Binary files differ