Package org.sf.feeling.swt.win32.extension.widgets

Source Code of org.sf.feeling.swt.win32.extension.widgets.SizeBorder

/*******************************************************************************
* Copyright (c) 2007 cnfree.
* 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:
*  cnfree  - initial API and implementation
*******************************************************************************/

package org.sf.feeling.swt.win32.extension.widgets;

import java.util.Timer;
import java.util.TimerTask;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;


/**
* A border for a resizable container. This border control usually fills the
* entire container, with a content pane above it (not covering the actual
* border area).
*
* <p>If the style SWT.BORDER ist set, a beveled border (as used on Windows
* Classic window decorations) will be drawn. Without this style, no drawing
* is done.</p>
*
* @author <a href="mailto:cnfree2000@hotmail.com">cnfree</a>
*/

public class SizeBorder extends Canvas
{
  private static final long UPDATE_DELAY = 25;
 
  private static final int AREA_NONE = 0;
  private static final int AREA_N    = 1;
  private static final int AREA_S    = 2;
  private static final int AREA_E    = 4;
  private static final int AREA_W    = 8;
  private static final int AREA_NW   = 9;
  private static final int AREA_NE   = 5;
  private static final int AREA_SE   = 6;
  private static final int AREA_SW   = 10;
 
  private Rectangle snapBack;
  private boolean cancelled = true;
  private volatile long lastUpdate;
  private Timer timer = new Timer(true);
  private TimerTask timerTask;
  private Composite resizableParent;
  private Point minSize, mouseDownOffset;
  private int borderWidth = 4, cornerSize = 16;
  private Display display;
  private Cursor cursor, cursorNWSE, cursorNESW, cursorWE, cursorNS;
  private int currentArea;


  public SizeBorder(Composite parent, int style)
  {
    this(parent, parent.getShell(), style);
  }

 
  public SizeBorder(Composite parent, final Composite resizableParent, int style)
  {
    super(parent, checkStyle (style));
    this.resizableParent = resizableParent;
    this.display = getDisplay();

    cursorNWSE = new Cursor(getDisplay(), SWT.CURSOR_SIZENWSE);
    cursorNESW = new Cursor(getDisplay(), SWT.CURSOR_SIZENESW);
    cursorWE = new Cursor(getDisplay(), SWT.CURSOR_SIZEWE);
    cursorNS = new Cursor(getDisplay(), SWT.CURSOR_SIZENS);

    addListener(SWT.Dispose, new Listener()
    {
      public void handleEvent(Event e)
      {
        cursorNWSE.dispose();
        cursorNESW.dispose();
        cursorWE.dispose();
        cursorNS.dispose();
      }
    });

    if((style & SWT.BORDER) != 0)
    {
      final Color highlightShadowColor = display.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
      final Color lightShadowColor = display.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW);
      final Color normalShadowColor = display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
      final Color darkShadowColor = display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW);
 
      addListener(SWT.Paint, new Listener()
      {
        public void handleEvent(Event event)
        {
          Rectangle r = getClientArea();
          if(r.width == 0 || r.height == 0) return;
          drawBevelRect(event.gc, r.x, r.y, r.width-1, r.height-1, lightShadowColor, darkShadowColor);
          drawBevelRect(event.gc, r.x+1, r.y+1, r.width-3, r.height-3, highlightShadowColor, normalShadowColor);
        }
      });
    }

    addListener(SWT.MouseDown, new Listener()
    {
      public void handleEvent(Event event)
      {
        if(event.button == 1)
        {
          currentArea = areaAtPoint(event.x, event.y);
          if(currentArea == AREA_NONE) return;
          if(resizableParent instanceof Shell)
            mouseDownOffset = toDisplay(event.x, event.y);
          else
            mouseDownOffset = display.map(SizeBorder.this, resizableParent.getParent(), event.x, event.y);
          snapBack = resizableParent.getBounds();
          cancelled = false;
        }
        else if(event.button == 3 && (event.stateMask & SWT.BUTTON1) != 0) // chord click
        {
          if(snapBack != null)
          {
            resizableParent.setBounds(snapBack);
            snapBack = null;
            cancelled = true;
          }
        }
      }
    });

    addListener(SWT.MouseMove, new Listener()
    {
      public void handleEvent(final Event event)
      {
        if((event.stateMask & SWT.BUTTON1) == 0) updateCursor(areaAtPoint(event.x, event.y));

        if(!cancelled && (event.stateMask & SWT.BUTTON1) != 0)
        {
          if(timerTask != null)
          {
            timerTask.cancel();
            timerTask = null;
          }
          long now = System.currentTimeMillis();
          if(lastUpdate + UPDATE_DELAY < now)
          {
            performResize(event);
            lastUpdate = now;
          }
          else
          {
            timerTask = new TimerTask()
            {
              public void run()
              {
                final TimerTask executingTask = this;
                event.display.asyncExec(new Runnable()
                {
                  public void run()
                  {
                    if(executingTask != timerTask) return;
                    performResize(event);
                  }
                });
              }
            };
            timer.schedule(timerTask, UPDATE_DELAY);
          }
        }
      }
    });
   
    addListener(SWT.MouseUp, new Listener()
    {
      public void handleEvent(Event event)
      {
        if(timerTask != null)
        {
          timerTask.cancel();
          timerTask = null;
        }
        if(!cancelled && (event.stateMask & SWT.BUTTON1) != 0)
        {
          performResize(event);
        }
      }
    });
   
    addListener(SWT.Show, new Listener()
    {
      public void handleEvent(Event event)
      {
        Point p = toControl(display.getCursorLocation());
        updateCursor(areaAtPoint(p.x, p.y));
      }
    });

    addListener(SWT.Dispose, new Listener()
    {
      public void handleEvent(Event event)
      {
        timer.cancel();
      }
    });
  }


  private static int checkStyle(int style)
  {
    //int mask = SWT.NONE;
    //style &= mask;
    style = SWT.NO_FOCUS;
    return style;
  }


  private void performResize(Event event)
  {
    // Make sure we stay within the container parent's client area
    Rectangle ca;
    if(resizableParent instanceof Shell) ca = getDisplay().getClientArea();
    else ca = getDisplay().map(resizableParent.getParent(), null, resizableParent.getParent().getClientArea());
    Point caOffset = toControl(ca.x, ca.y);
    event.x = Math.max(Math.min(event.x, caOffset.x + ca.width - 1), caOffset.x);
    event.y = Math.max(Math.min(event.y, caOffset.y + ca.height - 1), caOffset.y);

    // Compute movement relative to position at MouseDown event
    Point movement = (resizableParent instanceof Shell)
      ? toDisplay(event.x, event.y)
      : display.map(this, resizableParent.getParent(), event.x, event.y);
    movement.x -= mouseDownOffset.x;
    movement.y -= mouseDownOffset.y;
   
    // Compute new size and position
    int newW = snapBack.width, newH = snapBack.height, newX = snapBack.x, newY = snapBack.y;
    if((currentArea & AREA_E) != 0) newW += movement.x;
    else if((currentArea & AREA_W) != 0) { newW -= movement.x; newX += snapBack.width - newW; }
    if((currentArea & AREA_S) != 0) newH += movement.y;
    else if((currentArea & AREA_N) != 0) { newH -= movement.y; newY += snapBack.height - newH; }

    // Do not go below the container's minimum size
    int minW, minH;
    if(minSize != null) { minW = minSize.x; minH = minSize.y; }
    else { minW = 0; minH = 0; }
    int maxX = snapBack.x + snapBack.width - minW;
    int maxY = snapBack.y + snapBack.height - minH;

    newW = Math.max(minW, newW);
    newH = Math.max(minH, newH);
    newX = Math.min(maxX, newX);
    newY = Math.min(maxY, newY);

    resizableParent.setBounds(newX, newY, newW, newH);
  }
 
 
  private void updateCursor(int area)
  {
    Cursor c = null;
    switch(area)
    {
      case AREA_N:  case AREA_S:  c = cursorNS;   break;
      case AREA_W:  case AREA_E:  c = cursorWE;   break;
      case AREA_NW: case AREA_SE: c = cursorNWSE; break;
      case AREA_NE: case AREA_SW: c = cursorNESW; break;
    }
    if(cursor == c) return;
    cursor = c;
    setCursor(c);
  }
 
 
  private int areaAtPoint(int x, int y)
  {
    Point size = getSize();
    if(x < borderWidth) // left edge
    {
      if(y < cornerSize) return AREA_NW;
      else if(y >= size.y-cornerSize) return AREA_SW;
      else return AREA_W;
    }
    else if(x >= size.x-borderWidth) // right edge
    {
      if(y >= size.y-cornerSize) return AREA_SE;
      else if(y < cornerSize) return AREA_NE;
      else return AREA_E;
    }
    else if(y < borderWidth) // top edge
    {
      if(x < cornerSize) return AREA_NW;
      else if(x >= size.x-cornerSize) return AREA_NE;
      else return AREA_N;
    }
    else if(y >= size.y-borderWidth) // bottom edge
    {
      if(x >= size.x-cornerSize) return AREA_SE;
      else if(x < cornerSize) return AREA_SW;
      else return AREA_S;
    }
    else return AREA_NONE;
  }
 
 
  public Point computeSize(int wHint, int hHint, boolean changed)
  {
    checkWidget();
    if(wHint == SWT.DEFAULT) wHint = 0;
    if(hHint == SWT.DEFAULT) hHint = 0;
    return new Point(wHint, hHint);
  }


  public boolean setFocus()
  {
    checkWidget();
    return false;
  }


  public boolean isReparentable ()
  {
    checkWidget();
    return false;
  }


  /**
   * Set the allowed minimum size for the shell. The SizeGrip will
   * not resize the shell to a smaller size.
   * <p>
   * Note: This does <em>not</em> affect other ways of resizing the shell,
   * like using the size controls which are placed on the trimmings by
   * the window manager.
   * </p>
   */

  public void setMinimumShellSize(Point p)
  {
    checkWidget();
    this.minSize = p;
  }


  /**
   * Set the allowed minimum size for the shell. The SizeGrip will
   * not resize the shell to a smaller size.
   * <p>
   * Note: This does <em>not</em> affect other ways of resizing the shell,
   * like using the size controls which are placed on the trimmings by
   * the window manager.
   * </p>
   */

  public void setMinimumShellSize(int width, int height)
  {
    checkWidget();
    this.minSize = new Point(width, height);
  }
 
 
  public void setBorderWidth(int width)
  {
    checkWidget();
    borderWidth = width;
    Point p = toControl(display.getCursorLocation());
    updateCursor(areaAtPoint(p.x, p.y));
  }
 
 
  public void setCornerSize(int size)
  {
    checkWidget();
    cornerSize = size;
    Point p = toControl(display.getCursorLocation());
    updateCursor(areaAtPoint(p.x, p.y));
  }

 
  private static void drawBevelRect(GC gc, int x, int y, int w, int h, Color topleft, Color bottomright)
  {
    gc.setForeground(bottomright);
    gc.drawLine(x + w, y, x + w, y + h);
    gc.drawLine(x, y + h, x + w, y + h);

    gc.setForeground(topleft);
    gc.drawLine(x, y, x + w - 1, y);
    gc.drawLine(x, y, x, y + h - 1);
  }
}
TOP

Related Classes of org.sf.feeling.swt.win32.extension.widgets.SizeBorder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.