changeset 190:df4e66472aff

novocode line endings, indention
author Frank Benoit <benoit@tionex.de>
date Sun, 26 Oct 2008 15:04:41 +0100
parents 71ca5bcf2307
children 1ef729510ed6
files dwtx/novocode/CustomSeparator.d dwtx/novocode/ScaledImage.d dwtx/novocode/SizeBorder.d dwtx/novocode/SizeGrip.d dwtx/novocode/ishell/DesktopForm.d dwtx/novocode/ishell/InternalShell.d dwtx/novocode/ishell/internal/CustomDrawnButton.d dwtx/novocode/ishell/internal/DesktopListener.d dwtx/novocode/ishell/internal/TitleBar.d dwtx/novocode/ishell/internal/TitleBarButton.d
diffstat 10 files changed, 2672 insertions(+), 2672 deletions(-) [+]
line wrap: on
line diff
--- a/dwtx/novocode/CustomSeparator.d	Sun Oct 26 14:57:25 2008 +0100
+++ b/dwtx/novocode/CustomSeparator.d	Sun Oct 26 15:04:41 2008 +0100
@@ -1,139 +1,139 @@
-/**
-        Original: com.novocode.naf.swt.custom.CustomSeparator
-***/
-
-/*******************************************************************************
- * Copyright (c) 2004 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
- * 
- * Contributors:
- *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
- *******************************************************************************/
-
-module dwtx.novocode.CustomSeparator;
-
-import dwt.DWT;
-/**import dwt.events.PaintEvent;**/
-/**import dwt.events.PaintListener;**/
-import dwt.graphics.Color;
-import dwt.graphics.Point;
-import dwt.graphics.Rectangle;
-import dwt.widgets.Canvas;
-import dwt.widgets.Composite;
-import dwt.widgets.Display;
-import dwt.widgets.Event;
-import dwt.widgets.Listener;
-
-
-/**
- * Instances of this class are non-native separator lines.
- * <dl>
- * <dt><b>Styles:</b></dt>
- * <dd>SHADOW_IN, SHADOW_OUT, SHADOW_NONE, HORIZONTAL, VERTICAL</dd>
- * <dt><b>Events:</b></dt>
- * <dd>(none)</dd>
- * </dl>
- * <p>
- * Note: Only one of SHADOW_IN, SHADOW_OUT and SHADOW_NONE may be specified.
- * If neither ist specified, the default value SHADOW_IN is used. If SHADOW_NONE
- * is specified, a single line is drawn with the control's foreground color.
- * Only one of HORIZONTAL and VERTICAL may be specified. The default is VERTICAL.
- * </p>
- *
- * @author Stefan Zeiger (szeiger@novocode.com)
- * @since Feb 12, 2004
- * @version $Id: CustomSeparator.java 199 2004-10-08 13:20:36 +0000 (Fri, 08 Oct 2004) szeiger $
- */
-
-class CustomSeparator : Canvas
-{
-  private int lineSize;
-  private int style;
-
-
-  this(Composite parent, int style)
-  {
-    super(parent, style = checkStyle (style));
-
-    this.style = style;
-
-    if((style & DWT.SHADOW_IN) !is 0 || (style & DWT.SHADOW_OUT) !is 0) lineSize = 2;
-    else lineSize = 1;
-
-    /**addPaintListener(new class() PaintListener
-    {
-      public void paintControl(PaintEvent event) { onPaint(event); }
-    });*/
-    addListener(DWT.Paint, dgListener(&onPaint));
-  }
-
-
-  private int checkStyle(int style)
-  {
-    int mask = DWT.SHADOW_IN | DWT.SHADOW_OUT| DWT.SHADOW_NONE | DWT.HORIZONTAL | DWT.VERTICAL;
-    style &= mask;
-    if((style & (DWT.SHADOW_IN | DWT.SHADOW_OUT| DWT.SHADOW_NONE)) is 0) style |= DWT.SHADOW_IN;
-    if((style & (DWT.HORIZONTAL | DWT.VERTICAL)) is 0) style |= DWT.VERTICAL;
-    return style;
-  }
-
-
-  public Point computeSize(int wHint, int hHint, bool changed)
-  {
-    checkWidget();
-    if(wHint is DWT.DEFAULT) wHint = lineSize;
-    if(hHint is DWT.DEFAULT) hHint = lineSize;
-    return new Point(wHint, hHint);
-  }
-  
-
-  public bool setFocus()
-  {
-    checkWidget();
-    return false;
-  }
-
-
-  private void onPaint(PaintEvent event)
-  {
-    Rectangle r = getClientArea();
-    if(r.width is 0 || r.height is 0) return;
-    bool horiz = ((style & DWT.HORIZONTAL) !is 0);
-    int mid = horiz ? r.y + (r.height/2) : r.x + (r.width/2);
-
-    Display disp = getDisplay();
-    event.gc.setLineWidth(1);
-
-    if((style & DWT.SHADOW_IN) !is 0)
-    {
-      Color shadow = disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
-      Color highlight = disp.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
-      event.gc.setForeground(shadow);
-      if(horiz) event.gc.drawLine(r.x, mid-1, r.x+r.width-1, mid-1);
-      else event.gc.drawLine(mid-1, r.y, mid-1, r.y+r.height-1);
-      event.gc.setForeground(highlight);
-      if(horiz) event.gc.drawLine(r.x, mid, r.x+r.width-1, mid);
-      else event.gc.drawLine(mid, r.y, mid, r.y+r.height-1);
-    }
-    else if((style & DWT.SHADOW_OUT) !is 0)
-    {
-      Color shadow = disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
-      Color highlight = disp.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
-      event.gc.setForeground(highlight);
-      if(horiz) event.gc.drawLine(r.x, mid-1, r.x+r.width-1, mid-1);
-      else event.gc.drawLine(mid-1, r.y, mid-1, r.y+r.height-1);
-      event.gc.setForeground(shadow);
-      if(horiz) event.gc.drawLine(r.x, mid, r.x+r.width-1, mid);
-      else event.gc.drawLine(mid, r.y, mid, r.y+r.height-1);
-    }
-    else
-    {
-      event.gc.setForeground(getForeground());
-      if(horiz) event.gc.drawLine(r.x, mid, r.x+r.width-1, mid);
-      else event.gc.drawLine(mid, r.y, mid, r.y+r.height-1);
-    }
-  }
-}
+/**
+Original: com.novocode.naf.swt.custom.CustomSeparator
+ ***/
+
+/*******************************************************************************
+ * Copyright (c) 2004 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
+ *******************************************************************************/
+
+module dwtx.novocode.CustomSeparator;
+
+import dwt.DWT;
+/**import dwt.events.PaintEvent;**/
+/**import dwt.events.PaintListener;**/
+import dwt.graphics.Color;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Canvas;
+import dwt.widgets.Composite;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+
+
+/**
+ * Instances of this class are non-native separator lines.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>SHADOW_IN, SHADOW_OUT, SHADOW_NONE, HORIZONTAL, VERTICAL</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of SHADOW_IN, SHADOW_OUT and SHADOW_NONE may be specified.
+ * If neither ist specified, the default value SHADOW_IN is used. If SHADOW_NONE
+ * is specified, a single line is drawn with the control's foreground color.
+ * Only one of HORIZONTAL and VERTICAL may be specified. The default is VERTICAL.
+ * </p>
+ *
+ * @author Stefan Zeiger (szeiger@novocode.com)
+ * @since Feb 12, 2004
+ * @version $Id: CustomSeparator.java 199 2004-10-08 13:20:36 +0000 (Fri, 08 Oct 2004) szeiger $
+ */
+
+class CustomSeparator : Canvas
+{
+    private int lineSize;
+    private int style;
+
+
+    this(Composite parent, int style)
+    {
+        super(parent, style = checkStyle (style));
+
+        this.style = style;
+
+        if((style & DWT.SHADOW_IN) !is 0 || (style & DWT.SHADOW_OUT) !is 0) lineSize = 2;
+        else lineSize = 1;
+
+        /**addPaintListener(new class() PaintListener
+          {
+          public void paintControl(PaintEvent event) { onPaint(event); }
+          });*/
+        addListener(DWT.Paint, dgListener(&onPaint));
+    }
+
+
+    private int checkStyle(int style)
+    {
+        int mask = DWT.SHADOW_IN | DWT.SHADOW_OUT| DWT.SHADOW_NONE | DWT.HORIZONTAL | DWT.VERTICAL;
+        style &= mask;
+        if((style & (DWT.SHADOW_IN | DWT.SHADOW_OUT| DWT.SHADOW_NONE)) is 0) style |= DWT.SHADOW_IN;
+        if((style & (DWT.HORIZONTAL | DWT.VERTICAL)) is 0) style |= DWT.VERTICAL;
+        return style;
+    }
+
+
+    public Point computeSize(int wHint, int hHint, bool changed)
+    {
+        checkWidget();
+        if(wHint is DWT.DEFAULT) wHint = lineSize;
+        if(hHint is DWT.DEFAULT) hHint = lineSize;
+        return new Point(wHint, hHint);
+    }
+
+
+    public bool setFocus()
+    {
+        checkWidget();
+        return false;
+    }
+
+
+    private void onPaint(PaintEvent event)
+    {
+        Rectangle r = getClientArea();
+        if(r.width is 0 || r.height is 0) return;
+        bool horiz = ((style & DWT.HORIZONTAL) !is 0);
+        int mid = horiz ? r.y + (r.height/2) : r.x + (r.width/2);
+
+        Display disp = getDisplay();
+        event.gc.setLineWidth(1);
+
+        if((style & DWT.SHADOW_IN) !is 0)
+        {
+            Color shadow = disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
+            Color highlight = disp.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
+            event.gc.setForeground(shadow);
+            if(horiz) event.gc.drawLine(r.x, mid-1, r.x+r.width-1, mid-1);
+            else event.gc.drawLine(mid-1, r.y, mid-1, r.y+r.height-1);
+            event.gc.setForeground(highlight);
+            if(horiz) event.gc.drawLine(r.x, mid, r.x+r.width-1, mid);
+            else event.gc.drawLine(mid, r.y, mid, r.y+r.height-1);
+        }
+        else if((style & DWT.SHADOW_OUT) !is 0)
+        {
+            Color shadow = disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
+            Color highlight = disp.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
+            event.gc.setForeground(highlight);
+            if(horiz) event.gc.drawLine(r.x, mid-1, r.x+r.width-1, mid-1);
+            else event.gc.drawLine(mid-1, r.y, mid-1, r.y+r.height-1);
+            event.gc.setForeground(shadow);
+            if(horiz) event.gc.drawLine(r.x, mid, r.x+r.width-1, mid);
+            else event.gc.drawLine(mid, r.y, mid, r.y+r.height-1);
+        }
+        else
+        {
+            event.gc.setForeground(getForeground());
+            if(horiz) event.gc.drawLine(r.x, mid, r.x+r.width-1, mid);
+            else event.gc.drawLine(mid, r.y, mid, r.y+r.height-1);
+        }
+    }
+}
--- a/dwtx/novocode/ScaledImage.d	Sun Oct 26 14:57:25 2008 +0100
+++ b/dwtx/novocode/ScaledImage.d	Sun Oct 26 15:04:41 2008 +0100
@@ -1,271 +1,271 @@
-/*******************************************************************************
- * Copyright (c) 2004 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
- * 
- * Contributors:
- *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
- *     IBM Corporation - original SWT CLabel implementation on which this class is based
- *******************************************************************************/
-
-module dwtx.novocode.ScaledImage;
-
-import dwt.DWT;
-import dwt.graphics.Color;
-import dwt.graphics.GC;
-import dwt.graphics.Image;
-import dwt.graphics.Point;
-import dwt.graphics.Rectangle;
-import dwt.widgets.Canvas;
-import dwt.widgets.Composite;
-import dwt.widgets.Event;
-import dwt.widgets.Listener;
-
-
-/**
- * An image / gradient component. Under development.
- *
- * @author Stefan Zeiger (szeiger@novocode.com)
- * @since Mar 21, 2005
- * @version $Id: ScaledImage.java 346 2005-07-11 20:15:57 +0000 (Mon, 11 Jul 2005) szeiger $
- */
-
-class ScaledImage : Canvas
-{
-  private const Rectangle DEFAULT_BOUNDS;
-  
-  public static const int IMAGE_PLACEMENT_STRETCH = 0;
-  public static const int IMAGE_PLACEMENT_TILE    = 1;
-
-  private Image image;
-
-  private Color[] gradientColors;
-
-  private int[] gradientPercents;
-
-  private bool gradientVertical;
-  
-  private int imagePlacement = IMAGE_PLACEMENT_STRETCH;
-
-
-  this(Composite parent, int style)
-  {
-    super(parent, style | DWT.NO_BACKGROUND);
-    this.DEFAULT_BOUNDS = new Rectangle(0, 0, 32, 32);
-
-    addListener(DWT.Paint, dgListener(&onPaint));
-  }
-
-
-  private void onPaint(Event event)
-  {
-        Rectangle rect = getClientArea();
-        GC gc = event.gc;
-        if(image is null
-          || image.getImageData().getTransparencyType() !is DWT.TRANSPARENCY_NONE)
-        {
-
-          if(gradientColors !is null)
-          {
-            // draw a gradient behind the text
-            Color oldBackground = gc.getBackground();
-            if(gradientColors.length is 1)
-            {
-              if(gradientColors[0] !is null) gc.setBackground(gradientColors[0]);
-              gc.fillRectangle(0, 0, rect.width, rect.height);
-            }
-            else
-            {
-              Color oldForeground = gc.getForeground();
-              Color lastColor = gradientColors[0];
-              if(lastColor is null) lastColor = oldBackground;
-              int pos = 0;
-              for(int i = 0; i < gradientPercents.length; ++i)
-              {
-                gc.setForeground(lastColor);
-                lastColor = gradientColors[i + 1];
-                if(lastColor is null) lastColor = oldBackground;
-                gc.setBackground(lastColor);
-                if(gradientVertical)
-                {
-                  int gradientHeight = (gradientPercents[i] * rect.height / 100)
-                    - pos;
-                  gc.fillGradientRectangle(0, pos, rect.width, gradientHeight,
-                    true);
-                  pos += gradientHeight;
-                }
-                else
-                {
-                  int gradientWidth = (gradientPercents[i] * rect.width / 100)
-                    - pos;
-                  gc.fillGradientRectangle(pos, 0, gradientWidth, rect.height,
-                    false);
-                  pos += gradientWidth;
-                }
-              }
-              if(gradientVertical && pos < rect.height)
-              {
-                gc.setBackground(getBackground());
-                gc.fillRectangle(0, pos, rect.width, rect.height - pos);
-              }
-              if(!gradientVertical && pos < rect.width)
-              {
-                gc.setBackground(getBackground());
-                gc.fillRectangle(pos, 0, rect.width - pos, rect.height);
-              }
-              gc.setForeground(oldForeground);
-            }
-            gc.setBackground(oldBackground);
-          }
-          else
-          {
-            if((getStyle() & DWT.NO_BACKGROUND) !is 0)
-            {
-              gc.setBackground(getBackground());
-              gc.fillRectangle(rect);
-            }
-          }
-
-        }
-        if(image !is null)
-        {
-          Rectangle ib = image.getBounds();
-          if(imagePlacement is IMAGE_PLACEMENT_TILE)
-          {
-            int maxStartX = rect.x + rect.width;
-            int maxStartY = rect.y + rect.height;
-            for(int x = rect.x; x < maxStartX; x += ib.width)
-              for(int y = rect.y; y < maxStartY; y += ib.height)
-                event.gc.drawImage(image, x, y);
-          }
-          else // IMAGE_PLACEMENT_STRETCH
-          {
-            event.gc.drawImage(image, ib.x, ib.y, ib.width, ib.height, rect.x,
-              rect.y, rect.width, rect.height);
-          }
-        }
-  }
-
-
-  public void setImage(Image image)
-  {
-    this.image = image;
-    redraw();
-  }
-  
-  
-  public void setImagePlacement(int imagePlacement)
-  {
-    this.imagePlacement = imagePlacement;
-    redraw();
-  }
-
-
-  public Point computeSize(int wHint, int hHint, bool changed)
-  {
-    checkWidget();
-    Rectangle ib = image !is null ? image.getBounds() : DEFAULT_BOUNDS;
-    if(wHint == DWT.DEFAULT) wHint = ib.width;
-    if(hHint == DWT.DEFAULT) hHint = ib.height;
-    return new Point(wHint, hHint);
-  }
-
-
-  public void setBackground(Color color)
-  {
-    super.setBackground(color);
-    // Are these settings the same as before?
-    if(color !is null && gradientColors is null && gradientPercents is null)
-    {
-      Color background = getBackground();
-      if(color is background)
-      {
-        return;
-      }
-    }
-    gradientColors = null;
-    gradientPercents = null;
-    redraw();
-  }
-
-
-  public void setBackground(Color[] colors, int[] percents)
-  {
-    setBackground(colors, percents, false);
-  }
-
-
-  public void setBackground(Color[] colors, int[] percents, bool vertical)
-  {
-    checkWidget();
-    if(colors !is null)
-    {
-      if(percents is null || percents.length !is colors.length - 1)
-      {
-        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-      }
-      if(getDisplay().getDepth() < 15)
-      {
-        // Don't use gradients on low color displays
-        colors = [ colors[colors.length - 1] ];
-        percents = [];
-      }
-      for(int i = 0; i < percents.length; i++)
-      {
-        if(percents[i] < 0 || percents[i] > 100)
-        {
-          DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }
-        if(i > 0 && percents[i] < percents[i - 1])
-        {
-          DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }
-      }
-    }
-
-    // Are these settings the same as before?
-    Color background = getBackground();
-    if((gradientColors !is null) && (colors !is null)
-      && (gradientColors.length is colors.length))
-    {
-      bool same = false;
-      for(int i = 0; i < gradientColors.length; i++)
-      {
-        same = (gradientColors[i] is colors[i])
-          || ((gradientColors[i] is null) && (colors[i] is background))
-          || ((gradientColors[i] is background) && (colors[i] is null));
-        if(!same) break;
-      }
-      if(same)
-      {
-        for(int i = 0; i < gradientPercents.length; i++)
-        {
-          same = gradientPercents[i] is percents[i];
-          if(!same) break;
-        }
-      }
-      if(same && this.gradientVertical is vertical) return;
-    }
-    // Store the new settings
-    if(colors is null)
-    {
-      gradientColors = null;
-      gradientPercents = null;
-      gradientVertical = false;
-    }
-    else
-    {
-      gradientColors = new Color[colors.length];
-      for(int i = 0; i < colors.length; ++i)
-        gradientColors[i] = (colors[i] !is null) ? colors[i] : background;
-      gradientPercents = new int[percents.length];
-      for(int i = 0; i < percents.length; ++i)
-        gradientPercents[i] = percents[i];
-      gradientVertical = vertical;
-    }
-    // Refresh with the new settings
-    redraw();
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2004 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
+ *     IBM Corporation - original SWT CLabel implementation on which this class is based
+ *******************************************************************************/
+
+module dwtx.novocode.ScaledImage;
+
+import dwt.DWT;
+import dwt.graphics.Color;
+import dwt.graphics.GC;
+import dwt.graphics.Image;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Canvas;
+import dwt.widgets.Composite;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+
+
+/**
+ * An image / gradient component. Under development.
+ *
+ * @author Stefan Zeiger (szeiger@novocode.com)
+ * @since Mar 21, 2005
+ * @version $Id: ScaledImage.java 346 2005-07-11 20:15:57 +0000 (Mon, 11 Jul 2005) szeiger $
+ */
+
+class ScaledImage : Canvas
+{
+    private const Rectangle DEFAULT_BOUNDS;
+
+    public static const int IMAGE_PLACEMENT_STRETCH = 0;
+    public static const int IMAGE_PLACEMENT_TILE    = 1;
+
+    private Image image;
+
+    private Color[] gradientColors;
+
+    private int[] gradientPercents;
+
+    private bool gradientVertical;
+
+    private int imagePlacement = IMAGE_PLACEMENT_STRETCH;
+
+
+    this(Composite parent, int style)
+    {
+        super(parent, style | DWT.NO_BACKGROUND);
+        this.DEFAULT_BOUNDS = new Rectangle(0, 0, 32, 32);
+
+        addListener(DWT.Paint, dgListener(&onPaint));
+    }
+
+
+    private void onPaint(Event event)
+    {
+        Rectangle rect = getClientArea();
+        GC gc = event.gc;
+        if(image is null
+                || image.getImageData().getTransparencyType() !is DWT.TRANSPARENCY_NONE)
+        {
+
+            if(gradientColors !is null)
+            {
+                // draw a gradient behind the text
+                Color oldBackground = gc.getBackground();
+                if(gradientColors.length is 1)
+                {
+                    if(gradientColors[0] !is null) gc.setBackground(gradientColors[0]);
+                    gc.fillRectangle(0, 0, rect.width, rect.height);
+                }
+                else
+                {
+                    Color oldForeground = gc.getForeground();
+                    Color lastColor = gradientColors[0];
+                    if(lastColor is null) lastColor = oldBackground;
+                    int pos = 0;
+                    for(int i = 0; i < gradientPercents.length; ++i)
+                    {
+                        gc.setForeground(lastColor);
+                        lastColor = gradientColors[i + 1];
+                        if(lastColor is null) lastColor = oldBackground;
+                        gc.setBackground(lastColor);
+                        if(gradientVertical)
+                        {
+                            int gradientHeight = (gradientPercents[i] * rect.height / 100)
+                                - pos;
+                            gc.fillGradientRectangle(0, pos, rect.width, gradientHeight,
+                                    true);
+                            pos += gradientHeight;
+                        }
+                        else
+                        {
+                            int gradientWidth = (gradientPercents[i] * rect.width / 100)
+                                - pos;
+                            gc.fillGradientRectangle(pos, 0, gradientWidth, rect.height,
+                                    false);
+                            pos += gradientWidth;
+                        }
+                    }
+                    if(gradientVertical && pos < rect.height)
+                    {
+                        gc.setBackground(getBackground());
+                        gc.fillRectangle(0, pos, rect.width, rect.height - pos);
+                    }
+                    if(!gradientVertical && pos < rect.width)
+                    {
+                        gc.setBackground(getBackground());
+                        gc.fillRectangle(pos, 0, rect.width - pos, rect.height);
+                    }
+                    gc.setForeground(oldForeground);
+                }
+                gc.setBackground(oldBackground);
+            }
+            else
+            {
+                if((getStyle() & DWT.NO_BACKGROUND) !is 0)
+                {
+                    gc.setBackground(getBackground());
+                    gc.fillRectangle(rect);
+                }
+            }
+
+        }
+        if(image !is null)
+        {
+            Rectangle ib = image.getBounds();
+            if(imagePlacement is IMAGE_PLACEMENT_TILE)
+            {
+                int maxStartX = rect.x + rect.width;
+                int maxStartY = rect.y + rect.height;
+                for(int x = rect.x; x < maxStartX; x += ib.width)
+                    for(int y = rect.y; y < maxStartY; y += ib.height)
+                        event.gc.drawImage(image, x, y);
+            }
+            else // IMAGE_PLACEMENT_STRETCH
+            {
+                event.gc.drawImage(image, ib.x, ib.y, ib.width, ib.height, rect.x,
+                        rect.y, rect.width, rect.height);
+            }
+        }
+    }
+
+
+    public void setImage(Image image)
+    {
+        this.image = image;
+        redraw();
+    }
+
+
+    public void setImagePlacement(int imagePlacement)
+    {
+        this.imagePlacement = imagePlacement;
+        redraw();
+    }
+
+
+    public Point computeSize(int wHint, int hHint, bool changed)
+    {
+        checkWidget();
+        Rectangle ib = image !is null ? image.getBounds() : DEFAULT_BOUNDS;
+        if(wHint == DWT.DEFAULT) wHint = ib.width;
+        if(hHint == DWT.DEFAULT) hHint = ib.height;
+        return new Point(wHint, hHint);
+    }
+
+
+    public void setBackground(Color color)
+    {
+        super.setBackground(color);
+        // Are these settings the same as before?
+        if(color !is null && gradientColors is null && gradientPercents is null)
+        {
+            Color background = getBackground();
+            if(color is background)
+            {
+                return;
+            }
+        }
+        gradientColors = null;
+        gradientPercents = null;
+        redraw();
+    }
+
+
+    public void setBackground(Color[] colors, int[] percents)
+    {
+        setBackground(colors, percents, false);
+    }
+
+
+    public void setBackground(Color[] colors, int[] percents, bool vertical)
+    {
+        checkWidget();
+        if(colors !is null)
+        {
+            if(percents is null || percents.length !is colors.length - 1)
+            {
+                DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+            }
+            if(getDisplay().getDepth() < 15)
+            {
+                // Don't use gradients on low color displays
+                colors = [ colors[colors.length - 1] ];
+                percents = [];
+            }
+            for(int i = 0; i < percents.length; i++)
+            {
+                if(percents[i] < 0 || percents[i] > 100)
+                {
+                    DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+                }
+                if(i > 0 && percents[i] < percents[i - 1])
+                {
+                    DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+                }
+            }
+        }
+
+        // Are these settings the same as before?
+        Color background = getBackground();
+        if((gradientColors !is null) && (colors !is null)
+                && (gradientColors.length is colors.length))
+        {
+            bool same = false;
+            for(int i = 0; i < gradientColors.length; i++)
+            {
+                same = (gradientColors[i] is colors[i])
+                    || ((gradientColors[i] is null) && (colors[i] is background))
+                    || ((gradientColors[i] is background) && (colors[i] is null));
+                if(!same) break;
+            }
+            if(same)
+            {
+                for(int i = 0; i < gradientPercents.length; i++)
+                {
+                    same = gradientPercents[i] is percents[i];
+                    if(!same) break;
+                }
+            }
+            if(same && this.gradientVertical is vertical) return;
+        }
+        // Store the new settings
+        if(colors is null)
+        {
+            gradientColors = null;
+            gradientPercents = null;
+            gradientVertical = false;
+        }
+        else
+        {
+            gradientColors = new Color[colors.length];
+            for(int i = 0; i < colors.length; ++i)
+                gradientColors[i] = (colors[i] !is null) ? colors[i] : background;
+            gradientPercents = new int[percents.length];
+            for(int i = 0; i < percents.length; ++i)
+                gradientPercents[i] = percents[i];
+            gradientVertical = vertical;
+        }
+        // Refresh with the new settings
+        redraw();
+    }
+}
--- a/dwtx/novocode/SizeBorder.d	Sun Oct 26 14:57:25 2008 +0100
+++ b/dwtx/novocode/SizeBorder.d	Sun Oct 26 15:04:41 2008 +0100
@@ -1,406 +1,406 @@
-/*******************************************************************************
- * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
- * 
- * Contributors:
- *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
- *******************************************************************************/
-
-module dwtx.novocode.SizeBorder;
-
-import dwt.dwthelper.utils;
-import dwt.dwthelper.Runnable;
-import dwtx.dwtxhelper.Timer;
-import dwtx.dwtxhelper.TimerTask;
-
-import dwt.DWT;
-import dwt.graphics.Color;
-import dwt.graphics.Cursor;
-import dwt.graphics.GC;
-import dwt.graphics.Point;
-import dwt.graphics.Rectangle;
-import dwt.widgets.Canvas;
-import dwt.widgets.Composite;
-import dwt.widgets.Display;
-import dwt.widgets.Event;
-import dwt.widgets.Listener;
-import dwt.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 Stefan Zeiger (szeiger@novocode.com)
- * @since Jan 21, 2005
- * @version $Id: SizeBorder.java 321 2005-02-26 15:44:24 +0000 (Sat, 26 Feb 2005) szeiger $
- */
-
-class SizeBorder : Canvas
-{
-  private static const long UPDATE_DELAY = 25;
-  
-  private static const int AREA_NONE = 0;
-  private static const int AREA_N    = 1;
-  private static const int AREA_S    = 2;
-  private static const int AREA_E    = 4;
-  private static const int AREA_W    = 8;
-  private static const int AREA_NW   = 9;
-  private static const int AREA_NE   = 5;
-  private static const int AREA_SE   = 6;
-  private static const int AREA_SW   = 10;
-  
-  private Rectangle snapBack;
-  private bool cancelled = true;
-  private /**volatile*/ long lastUpdate;
-  private Timer timer;
-  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;
-  private Color highlightShadowColor, lightShadowColor, normalShadowColor,darkShadowColor;
-
-
-  this(Composite parent, int style)
-  {
-    this(parent, parent.getShell(), style);
-  }
-
-  
-  this(Composite parent, Composite resizableParent, int style)
-  {
-    super(parent, checkStyle (style));
-    this.timer = new Timer(true);
-    this.resizableParent = resizableParent;
-    this.display = getDisplay();
-
-    cursorNWSE = new Cursor(getDisplay(), DWT.CURSOR_SIZENWSE);
-    cursorNESW = new Cursor(getDisplay(), DWT.CURSOR_SIZENESW);
-    cursorWE = new Cursor(getDisplay(), DWT.CURSOR_SIZEWE);
-    cursorNS = new Cursor(getDisplay(), DWT.CURSOR_SIZENS);
-
-    addListener(DWT.Dispose, dgListener(&onDispose));
-
-    if((style & DWT.BORDER) !is 0)
-    {
-      highlightShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
-      lightShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_LIGHT_SHADOW);
-      normalShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
-      darkShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_DARK_SHADOW);
-  
-      addListener(DWT.Paint, dgListener(&onPaint));
-    }
-
-    addListener(DWT.MouseDown, dgListener(&onMouseDown));
-
-    addListener(DWT.MouseMove, dgListener(&onMouseMove));
-    
-    addListener(DWT.MouseUp, dgListener(&onMouseUp));
-    
-    addListener(DWT.Show, dgListener(&onShow));
-  }
-
-  private void onDispose(Event event)
-  {
-        cursorNWSE.dispose();
-        cursorNESW.dispose();
-        cursorWE.dispose();
-        cursorNS.dispose();
-
-        timer.cancel();
-  }
-
-
-  private void onPaint(Event event)
-  {
-          Rectangle r = getClientArea();
-          if(r.width is 0 || r.height is 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);
-  }
-
-
-  private void onMouseDown(Event event)
-  {
-        if(event.button is 1)
-        {
-          currentArea = areaAtPoint(event.x, event.y);
-          if(currentArea is AREA_NONE) return;
-          if(cast(Shell)resizableParent !is null)
-            mouseDownOffset = toDisplay(event.x, event.y);
-          else
-            mouseDownOffset = display.map(/**SizeBorder.this*/getSizeBorder(), resizableParent.getParent(), event.x, event.y);
-          snapBack = resizableParent.getBounds();
-          cancelled = false;
-        }
-        else if(event.button is 3 && (event.stateMask & DWT.BUTTON1) !is 0) // chord click
-        {
-          if(snapBack !is null)
-          {
-            resizableParent.setBounds(snapBack);
-            snapBack = null;
-            cancelled = true;
-          }
-        }
-  }
-
-
-  private void onMouseMove(Event event)
-  {
-        if((event.stateMask & DWT.BUTTON1) is 0) updateCursor(areaAtPoint(event.x, event.y));
-
-        if(!cancelled && (event.stateMask & DWT.BUTTON1) !is 0)
-        {
-          if(timerTask !is null)
-          {
-            timerTask.cancel();
-            timerTask = null;
-          }
-          long now = System.currentTimeMillis();
-          if(lastUpdate + UPDATE_DELAY < now)
-          {
-            performResize(event);
-            lastUpdate = now;
-          }
-          else
-          {
-            timerTask = new class() TimerTask
-            {
-              public void run()
-              {
-                TimerTask executingTask = this;
-                event.display.asyncExec(new class() Runnable
-                {
-                  public void run()
-                  {
-                    if(executingTask !is timerTask) return;
-                    performResize(event);
-                  }
-                });
-              }
-            };
-            timer.schedule(timerTask, UPDATE_DELAY);
-          }
-        }
-  }
-
-
-  private void onMouseUp(Event event)
-  {
-        if(timerTask !is null)
-        {
-          timerTask.cancel();
-          timerTask = null;
-        }
-        if(!cancelled && (event.stateMask & DWT.BUTTON1) !is 0)
-        {
-          performResize(event);
-        }
-  }
-
-
-  private void onShow(Event event)
-  {
-        Point p = toControl(display.getCursorLocation());
-        updateCursor(areaAtPoint(p.x, p.y));
-  }
-
-
-  private SizeBorder getSizeBorder()
-  {
-      return this;
-  }
-
-  private static int checkStyle(int style)
-  {
-    //int mask = DWT.NONE;
-    //style &= mask;
-    style = DWT.NO_FOCUS;
-    return style;
-  }
-
-
-  private void performResize(Event event)
-  {
-    // Make sure we stay within the container parent's client area
-    Rectangle ca;
-    if(cast(Shell)resizableParent !is null) 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 = (cast(Shell)resizableParent !is null)
-      ? 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) !is 0) newW += movement.x;
-    else if((currentArea & AREA_W) !is 0) { newW -= movement.x; newX += snapBack.width - newW; }
-    if((currentArea & AREA_S) !is 0) newH += movement.y;
-    else if((currentArea & AREA_N) !is 0) { newH -= movement.y; newY += snapBack.height - newH; }
-
-    // Do not go below the container's minimum size
-    int minW, minH;
-    if(minSize !is 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 is 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, bool changed)
-  {
-    checkWidget();
-    if(wHint == DWT.DEFAULT) wHint = 0;
-    if(hHint == DWT.DEFAULT) hHint = 0;
-    return new Point(wHint, hHint);
-  }
-
-
-  public bool setFocus()
-  {
-    checkWidget();
-    return false;
-  }
-
-
-  public bool 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);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
+ *******************************************************************************/
+
+module dwtx.novocode.SizeBorder;
+
+import dwt.dwthelper.utils;
+import dwt.dwthelper.Runnable;
+import dwtx.dwtxhelper.Timer;
+import dwtx.dwtxhelper.TimerTask;
+
+import dwt.DWT;
+import dwt.graphics.Color;
+import dwt.graphics.Cursor;
+import dwt.graphics.GC;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Canvas;
+import dwt.widgets.Composite;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.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 Stefan Zeiger (szeiger@novocode.com)
+ * @since Jan 21, 2005
+ * @version $Id: SizeBorder.java 321 2005-02-26 15:44:24 +0000 (Sat, 26 Feb 2005) szeiger $
+ */
+
+class SizeBorder : Canvas
+{
+    private static const long UPDATE_DELAY = 25;
+
+    private static const int AREA_NONE = 0;
+    private static const int AREA_N    = 1;
+    private static const int AREA_S    = 2;
+    private static const int AREA_E    = 4;
+    private static const int AREA_W    = 8;
+    private static const int AREA_NW   = 9;
+    private static const int AREA_NE   = 5;
+    private static const int AREA_SE   = 6;
+    private static const int AREA_SW   = 10;
+
+    private Rectangle snapBack;
+    private bool cancelled = true;
+    private /**volatile*/ long lastUpdate;
+    private Timer timer;
+    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;
+    private Color highlightShadowColor, lightShadowColor, normalShadowColor,darkShadowColor;
+
+
+    this(Composite parent, int style)
+    {
+        this(parent, parent.getShell(), style);
+    }
+
+
+    this(Composite parent, Composite resizableParent, int style)
+    {
+        super(parent, checkStyle (style));
+        this.timer = new Timer(true);
+        this.resizableParent = resizableParent;
+        this.display = getDisplay();
+
+        cursorNWSE = new Cursor(getDisplay(), DWT.CURSOR_SIZENWSE);
+        cursorNESW = new Cursor(getDisplay(), DWT.CURSOR_SIZENESW);
+        cursorWE = new Cursor(getDisplay(), DWT.CURSOR_SIZEWE);
+        cursorNS = new Cursor(getDisplay(), DWT.CURSOR_SIZENS);
+
+        addListener(DWT.Dispose, dgListener(&onDispose));
+
+        if((style & DWT.BORDER) !is 0)
+        {
+            highlightShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
+            lightShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_LIGHT_SHADOW);
+            normalShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
+            darkShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_DARK_SHADOW);
+
+            addListener(DWT.Paint, dgListener(&onPaint));
+        }
+
+        addListener(DWT.MouseDown, dgListener(&onMouseDown));
+
+        addListener(DWT.MouseMove, dgListener(&onMouseMove));
+
+        addListener(DWT.MouseUp, dgListener(&onMouseUp));
+
+        addListener(DWT.Show, dgListener(&onShow));
+    }
+
+    private void onDispose(Event event)
+    {
+        cursorNWSE.dispose();
+        cursorNESW.dispose();
+        cursorWE.dispose();
+        cursorNS.dispose();
+
+        timer.cancel();
+    }
+
+
+    private void onPaint(Event event)
+    {
+        Rectangle r = getClientArea();
+        if(r.width is 0 || r.height is 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);
+    }
+
+
+    private void onMouseDown(Event event)
+    {
+        if(event.button is 1)
+        {
+            currentArea = areaAtPoint(event.x, event.y);
+            if(currentArea is AREA_NONE) return;
+            if(cast(Shell)resizableParent !is null)
+                mouseDownOffset = toDisplay(event.x, event.y);
+            else
+                mouseDownOffset = display.map(/**SizeBorder.this*/getSizeBorder(), resizableParent.getParent(), event.x, event.y);
+            snapBack = resizableParent.getBounds();
+            cancelled = false;
+        }
+        else if(event.button is 3 && (event.stateMask & DWT.BUTTON1) !is 0) // chord click
+        {
+            if(snapBack !is null)
+            {
+                resizableParent.setBounds(snapBack);
+                snapBack = null;
+                cancelled = true;
+            }
+        }
+    }
+
+
+    private void onMouseMove(Event event)
+    {
+        if((event.stateMask & DWT.BUTTON1) is 0) updateCursor(areaAtPoint(event.x, event.y));
+
+        if(!cancelled && (event.stateMask & DWT.BUTTON1) !is 0)
+        {
+            if(timerTask !is null)
+            {
+                timerTask.cancel();
+                timerTask = null;
+            }
+            long now = System.currentTimeMillis();
+            if(lastUpdate + UPDATE_DELAY < now)
+            {
+                performResize(event);
+                lastUpdate = now;
+            }
+            else
+            {
+                timerTask = new class() TimerTask
+                {
+                    public void run()
+                    {
+                        TimerTask executingTask = this;
+                        event.display.asyncExec(new class() Runnable
+                            {
+                                public void run()
+                                {
+                                    if(executingTask !is timerTask) return;
+                                    performResize(event);
+                                }
+                            });
+                    }
+                };
+                timer.schedule(timerTask, UPDATE_DELAY);
+            }
+        }
+    }
+
+
+    private void onMouseUp(Event event)
+    {
+        if(timerTask !is null)
+        {
+            timerTask.cancel();
+            timerTask = null;
+        }
+        if(!cancelled && (event.stateMask & DWT.BUTTON1) !is 0)
+        {
+            performResize(event);
+        }
+    }
+
+
+    private void onShow(Event event)
+    {
+        Point p = toControl(display.getCursorLocation());
+        updateCursor(areaAtPoint(p.x, p.y));
+    }
+
+
+    private SizeBorder getSizeBorder()
+    {
+        return this;
+    }
+
+    private static int checkStyle(int style)
+    {
+        //int mask = DWT.NONE;
+        //style &= mask;
+        style = DWT.NO_FOCUS;
+        return style;
+    }
+
+
+    private void performResize(Event event)
+    {
+        // Make sure we stay within the container parent's client area
+        Rectangle ca;
+        if(cast(Shell)resizableParent !is null) 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 = (cast(Shell)resizableParent !is null)
+            ? 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) !is 0) newW += movement.x;
+        else if((currentArea & AREA_W) !is 0) { newW -= movement.x; newX += snapBack.width - newW; }
+        if((currentArea & AREA_S) !is 0) newH += movement.y;
+        else if((currentArea & AREA_N) !is 0) { newH -= movement.y; newY += snapBack.height - newH; }
+
+        // Do not go below the container's minimum size
+        int minW, minH;
+        if(minSize !is 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 is 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, bool changed)
+    {
+        checkWidget();
+        if(wHint == DWT.DEFAULT) wHint = 0;
+        if(hHint == DWT.DEFAULT) hHint = 0;
+        return new Point(wHint, hHint);
+    }
+
+
+    public bool setFocus()
+    {
+        checkWidget();
+        return false;
+    }
+
+
+    public bool 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);
+    }
+}
--- a/dwtx/novocode/SizeGrip.d	Sun Oct 26 14:57:25 2008 +0100
+++ b/dwtx/novocode/SizeGrip.d	Sun Oct 26 15:04:41 2008 +0100
@@ -11,8 +11,8 @@
  *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 /++
- + This code was take from http://www.novocode.com/swt/
- +/
++ This code was take from http://www.novocode.com/swt/
++/
 module dwtx.novocode.SizeGrip;
 
 import dwt.dwthelper.utils;
@@ -195,10 +195,10 @@
                     {
                         TimerTask executingTask = this;
                         event.display.asyncExec( dgRunnable( (Event event_, TimerTask executingTask_ )
-                        {
-                            if(executingTask_ !is timerTask) return;
-                            performResize(event_);
-                        }, event, executingTask ));
+                            {
+                                if(executingTask_ !is timerTask) return;
+                                performResize(event_);
+                            }, event, executingTask ));
                     }
                 };
                 timer.schedule(timerTask, UPDATE_DELAY);
@@ -216,7 +216,7 @@
             performResize(event);
         }
     }
-    
+
     public this(Composite parent, Composite resizableParent_, int style)
     {
         super(parent, style = checkStyle (style));
--- a/dwtx/novocode/ishell/DesktopForm.d	Sun Oct 26 14:57:25 2008 +0100
+++ b/dwtx/novocode/ishell/DesktopForm.d	Sun Oct 26 15:04:41 2008 +0100
@@ -1,512 +1,512 @@
-/*******************************************************************************
- * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
- * 
- * Contributors:
- *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
- *******************************************************************************/
-
-module dwtx.novocode.ishell.DesktopForm;
-
-import dwt.DWT;
-import dwt.graphics.Color;
-import dwt.graphics.Rectangle;
-import dwt.widgets.Composite;
-import dwt.widgets.Control;
-import dwt.widgets.Display;
-import dwt.widgets.Event;
-import dwt.widgets.Listener;
-import dwt.widgets.Shell;
-
-import dwtx.novocode.ishell.internal.DesktopListener;
-import dwtx.novocode.ishell.InternalShell;
-
-import tango.core.Array;
-
-
-/**
- * A desktop which manages internal shells.
- *
- * @author Stefan Zeiger (szeiger@novocode.com)
- * @since Jan 21, 2005
- * @version $Id: DesktopForm.java 344 2005-07-09 22:37:51 +0000 (Sat, 09 Jul 2005) szeiger $
- */
-
-class DesktopForm : Composite
-{
-  private static const InternalShell[] EMPTY_INTERNALSHELL_ARRAY/** = new InternalShell[0]*/;
-  private static const int FIRST_SHELL_LOCATION = 32;
-  private static const int SHELL_LOCATION_OFFSET = 16;
-
-  private InternalShell activeShell;
-  private DesktopListener[] desktopListeners;
-  private InternalShell[] allShells;
-  private InternalShell[] visibleShells;
-  private int nextShellLocation = FIRST_SHELL_LOCATION;
-  private bool showMaximizedTitle;
-  private bool autoMaximize = true;
-  private bool enableCtrlTab = true;
-  private bool allowDeactivate;
-  private Shell shell;
-  private InternalShell ishell;
-  private Listener mouseDownFilter, focusInFilter, traverseFilter;
-
-
-  this(Composite parent, int style)
-  {
-    super(parent, style);
-    Display display = getDisplay();
-    shell = getShell();
-
-    Color bg = display.getSystemColor(DWT.COLOR_TITLE_INACTIVE_BACKGROUND);
-    setBackground(bg);
-    int brightness = bg.getRed() + bg.getGreen() + bg.getBlue();
-    setForeground(display.getSystemColor(brightness > 400 ? DWT.COLOR_BLACK : DWT.COLOR_WHITE));
-    
-    addListener(DWT.Resize, dgListener(&onResize));
-    
-    mouseDownFilter = dgListener(&onMouseDownFilter);
-    focusInFilter = dgListener(&onFocusInFilter);
-    traverseFilter = dgListener(&onTraverseFilter);
-    
-    display.addFilter(DWT.MouseDown, mouseDownFilter);
-    display.addFilter(DWT.FocusIn, focusInFilter);
-    display.addFilter(DWT.Traverse, traverseFilter);
-    
-    addListener(DWT.Dispose, dgListener(&onDispose));
-  }
-  
-  
-  private void onResize(Event event)
-  {
-        Rectangle ca = getClientArea();
-        foreach(c; getChildren())
-        {
-          if(cast(InternalShell)c !is null)
-            (cast(InternalShell)c).desktopResized(ca);
-        }
-  }
-
-
-  private void onMouseDownFilter(Event event)
-  {
-        if(!(cast(Control)event.widget !is null)) return;
-        Control c = cast(Control)event.widget;
-        if(c.getShell() !is shell) return;
-        bool[] desktopHit = new bool[1];
-        InternalShell ishell = getInternalShell(c, desktopHit);
-        if(desktopHit[0] && allowDeactivate) activate(null);
-        if(ishell is null) return;
-        activate(ishell);
-  }
-
-
-  private void onFocusInFilter(Event event)
-  {
-        if(!(cast(Control)event.widget !is null)) return;
-        Control c = cast(Control)event.widget;
-        if(c.getShell() !is shell) return;
-        bool[] desktopHit = new bool[1];
-        ishell = getInternalShell(c, desktopHit);
-        if(desktopHit[0] && allowDeactivate) activate(null);
-        if(ishell is null) return;
-        ishell.focusControl = c;
-  }
-
-
-  private void onTraverseFilter(Event event)
-  {
-        if(!enableCtrlTab) return;
-        if(!event.doit) return; // don't steal traverse event if a control wants to handle it directly
-        if((event.stateMask & DWT.CTRL) is 0) return;
-        if(event.detail !is DWT.TRAVERSE_TAB_NEXT && event.detail !is DWT.TRAVERSE_TAB_PREVIOUS) return;
-        if(!(cast(Control)event.widget !is null)) return;
-        Control c = cast(Control)event.widget;
-        if(c.getShell() !is shell) return;
-        bool[] desktopHit = new bool[1];
-        InternalShell ishell = getInternalShell(c, desktopHit);
-        if(ishell !is null || desktopHit[0])
-        {
-          if(event.detail is DWT.TRAVERSE_TAB_NEXT) activateNextShell();
-          else activatePreviousShell();
-          event.doit = false;
-        }
-  }
-
-
-  private void onDispose(Event event)
-  {
-        display.removeFilter(DWT.MouseDown, mouseDownFilter);
-        display.removeFilter(DWT.FocusIn, focusInFilter);
-        display.removeFilter(DWT.Traverse, traverseFilter);
-  }
-
-
-  void manage(InternalShell ishell)
-  {
-    Rectangle bounds = getBounds();
-    if(nextShellLocation > bounds.height-100 || nextShellLocation > bounds.width-100)
-      nextShellLocation = FIRST_SHELL_LOCATION;
-    ishell.setLocation(bounds.x+nextShellLocation, bounds.y+nextShellLocation);
-    nextShellLocation += SHELL_LOCATION_OFFSET;
-
-    ishell.addListener(DWT.Dispose, dgListener(&onIshellDispose));
-    allShells ~= ishell;
-    if(ishell.isVisible()) visibleShells ~= ishell;
-    notifyDesktopListenersCreate(ishell);
-  }
-  
-  
-  private void onIshellDispose(Event event)
-  {
-        allShells.remove(ishell);
-        visibleShells.remove(ishell);
-        if(ishell is activeShell)
-        {
-          activateTopmostVisibleShellExcept(ishell);
-          if(autoMaximize && !hasVisibleMaximizedShell())
-            setAllVisibleMaximized(false);
-        }
-        notifyDesktopListenersDispose(ishell);
-  }
-
-
-  private InternalShell activateTopmostVisibleShellExcept(InternalShell except)
-  {
-    Control[] children = getChildren();
-    for(int i=0; i<children.length; i++)
-    {
-      Control c = children[i];
-      if(c is except) continue;
-      if(cast(InternalShell)c !is null && c.isVisible())
-      {
-        InternalShell ishell = cast(InternalShell)c;
-        activate(ishell);
-        return ishell;
-      }
-    }
-    activeShell = null;
-    notifyDesktopListenersActivate(null);
-    return null;
-  }
-  
-  
-  void activate(InternalShell ishell)
-  {
-    if(ishell is activeShell) return;
-    checkWidget();
-    if(ishell !is null)
-    {
-      if(!ishell.isVisible()) ishell.setVisible(true);
-      if((ishell.getStyle() & DWT.ON_TOP) !is 0)
-        ishell.moveAbove(null);
-      else
-      {
-        InternalShell firstRegular = getTopmostRegularShell();
-        if(firstRegular !is null && firstRegular !is ishell) ishell.moveAbove(firstRegular);
-        else
-        {
-          Control[] children = getChildren();
-          if(children.length > 0) ishell.moveAbove(children[0]);
-        }
-      }
-    }
-    InternalShell oldActiveShell = activeShell;
-    activeShell = ishell;
-    if(oldActiveShell !is null) oldActiveShell.redrawDecorationsAfterActivityChange();
-    if(ishell !is null)
-    {
-      if(activeShell.isVisible()) activeShell.redrawDecorationsAfterActivityChange();
-      setTabList(/**new Control[] { activeShell }*/[ activeShell ]);
-      activeShell.setFocus();
-    }
-    else
-    {
-      setTabList(/**new Control[] {}*/[]);
-      forceFocus();
-    }
-    notifyDesktopListenersActivate(ishell);
-  }
-  
-  
-  private InternalShell getTopmostRegularShell()
-  {
-    foreach(c; getChildren())
-    {
-      if(!(cast(InternalShell)c !is null)) continue;
-      if((c.getStyle() & DWT.ON_TOP) is 0) return cast(InternalShell)c;
-    }
-    return null;
-  }
-  
-  
-  private InternalShell getBottommostOnTopShell()
-  {
-    Control[] ch = getChildren();
-    for(int i=ch.length-1; i>=0; i--)
-    {
-      Control c = ch[i];
-      if(!(cast(InternalShell)c !is null)) continue;
-      if((c.getStyle() & DWT.ON_TOP) !is 0) return cast(InternalShell)c;
-    }
-    return null;
-  }
-  
-  
-  void shellVisibilityChanged(InternalShell ishell, bool visible)
-  {
-    if(visible)
-    {
-      if(!contains(visibleShells, ishell))
-      {
-        visibleShells ~= ishell;
-        if(autoMaximize && !ishell.getMaximized() && (ishell.getStyle() & DWT.MAX) !is 0 && hasVisibleMaximizedShell())
-          ishell.setMaximizedWithoutNotification(true);
-      }
-      if(ishell.getMaximized())
-        ishell.desktopResized(getClientArea());
-    }
-    else
-    {
-      visibleShells.remove(ishell);
-      if(ishell is activeShell)
-      {
-        activateTopmostVisibleShellExcept(ishell);
-        if(autoMaximize && !hasVisibleMaximizedShell())
-          setAllVisibleMaximized(false);
-      }
-    }
-  }
-  
-  
-  private InternalShell getInternalShell(Control c, bool[] desktopHit)
-  {
-    while(c !is null && c !is /**DesktopForm.*/this)
-    {
-      if(cast(InternalShell)c !is null && (cast(InternalShell)c).getParent() is this)
-        return cast(InternalShell)c;
-      c = c.getParent();
-    }
-    if(desktopHit !is null && c is /**DesktopForm.*/this) desktopHit[0] = true;
-    return null;
-  }
-  
-  
-  public InternalShell getActiveShell()
-  {
-    return activeShell;
-  }
-  
-  
-  public InternalShell[] getVisibleShells()
-  {
-    checkWidget();
-    return visibleShells;
-  }
-  
-  
-  public InternalShell[] getShells()
-  {
-    checkWidget();
-    return allShells;
-  }
-  
-  
-  public void setShowMaximizedTitle(bool b)
-  {
-    checkWidget();
-    showMaximizedTitle = b;
-    Rectangle ca = getClientArea();
-    foreach(c; getChildren())
-    {
-      if(cast(InternalShell)c !is null)
-        (cast(InternalShell)c).desktopResized(ca);
-    }
-  }
-
-
-  public bool getShowMaximizedTitle()
-  {
-    checkWidget();
-    return showMaximizedTitle;
-  }
-
-  
-  public void setAutoMaximize(bool b)
-  {
-    checkWidget();
-    autoMaximize = b;
-    bool hasMax = false;
-    foreach(ins; visibleShells)
-    {
-      if(ins.getMaximized())
-      {
-        hasMax = true;
-        break;
-      }
-    }
-    if(hasMax)
-    {
-      // Maximize all shells
-      foreach(ins; visibleShells)
-      {
-        if((ins.getStyle() & DWT.MAX) !is 0) ins.setMaximized(true);
-      }
-    }
-  }
-
-
-  public bool getAutoMaximize()
-  {
-    checkWidget();
-    return autoMaximize;
-  }
-  
-  
-  public void setEnableCtrlTab(bool b)
-  {
-    checkWidget();
-    this.enableCtrlTab = b;
-  }
-  
-  
-  public bool getEnableCtrlTab()
-  {
-    return enableCtrlTab;
-  }
-
-  
-  public void setAllowDeactivate(bool b)
-  {
-    checkWidget();
-    this.allowDeactivate = b;
-    if(!allowDeactivate && activeShell is null)
-      activateTopmostVisibleShellExcept(null);
-  }
-  
-  
-  public bool getAllowDeactivate()
-  {
-    return allowDeactivate;
-  }
-
-  
-  void shellMaximizedOrRestored(InternalShell ishell, bool maximized)
-  {
-    setAllVisibleMaximized(maximized);
-  }
-
-
-  private void setAllVisibleMaximized(bool maximized)
-  {
-    if(autoMaximize) // maximize or restore all shells
-    {
-      foreach(c; getChildren())
-      {
-        if(cast(InternalShell)c !is null)
-        {
-          InternalShell ishell = cast(InternalShell)c;
-          if((ishell.getStyle() & DWT.MAX) !is 0 && ishell.isVisible())
-            (cast(InternalShell)c).setMaximizedWithoutNotification(maximized);
-        }
-      }
-    }
-  }
-
-
-  private void activateNextShell()
-  {
-    if(activeShell is null)
-    {
-      activateTopmostVisibleShellExcept(null);
-      return;
-    }
-    if(visibleShells.length < 2) return;
-    InternalShell topReg = getTopmostRegularShell();
-    InternalShell botTop = getBottommostOnTopShell();
-    if((activeShell.getStyle() & DWT.ON_TOP) !is 0)
-    {
-      activeShell.moveBelow(botTop);
-      if(topReg !is null) activate(topReg);
-      else activateTopmostVisibleShellExcept(null);
-    }
-    else
-    {
-      activeShell.moveBelow(null);
-      activateTopmostVisibleShellExcept(null);
-    }
-  }
-
-
-  private void activatePreviousShell()
-  {
-    if(activeShell is null)
-    {
-      activateTopmostVisibleShellExcept(null);
-      return;
-    }
-    if(visibleShells.length < 2) return;
-    InternalShell topReg = getTopmostRegularShell();
-    InternalShell botTop = getBottommostOnTopShell();
-    if(activeShell is topReg && botTop !is null) activate(botTop);
-    else
-    {
-      Control[] ch = getChildren();
-      for(int i=ch.length-1; i>=0; i--)
-      {
-        if(cast(InternalShell)ch[i] !is null && ch[i].isVisible())
-        {
-          activate(cast(InternalShell)ch[i]);
-          break;
-        }
-      }
-    }
-  }
-
-
-  public void addDesktopListener(DesktopListener l)
-  {
-    desktopListeners ~= l;
-  }
-
-
-  public void removeDesktopListener(DesktopListener l)
-  {
-    desktopListeners.remove(l);
-  }
-
-
-  private void notifyDesktopListenersCreate(InternalShell ishell)
-  {
-    Event event = new Event();
-    event.widget = ishell;
-    foreach(l; desktopListeners) l.shellCreated(event);
-  }
-  
-  
-  private void notifyDesktopListenersDispose(InternalShell ishell)
-  {
-    Event event = new Event();
-    event.widget = ishell;
-    foreach(l; desktopListeners) l.shellDisposed(event);
-  }
-  
-  
-  private void notifyDesktopListenersActivate(InternalShell ishell)
-  {
-    Event event = new Event();
-    event.widget = ishell;
-    foreach(l; desktopListeners) l.shellActivated(event);
-  }
-  
-  
-  private bool hasVisibleMaximizedShell()
-  {
-    foreach(ins; visibleShells)
-      if(ins.getMaximized()) return true;
-    return false;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
+ *******************************************************************************/
+
+module dwtx.novocode.ishell.DesktopForm;
+
+import dwt.DWT;
+import dwt.graphics.Color;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.widgets.Shell;
+
+import dwtx.novocode.ishell.internal.DesktopListener;
+import dwtx.novocode.ishell.InternalShell;
+
+import tango.core.Array;
+
+
+/**
+ * A desktop which manages internal shells.
+ *
+ * @author Stefan Zeiger (szeiger@novocode.com)
+ * @since Jan 21, 2005
+ * @version $Id: DesktopForm.java 344 2005-07-09 22:37:51 +0000 (Sat, 09 Jul 2005) szeiger $
+ */
+
+class DesktopForm : Composite
+{
+    private static const InternalShell[] EMPTY_INTERNALSHELL_ARRAY/** = new InternalShell[0]*/;
+    private static const int FIRST_SHELL_LOCATION = 32;
+    private static const int SHELL_LOCATION_OFFSET = 16;
+
+    private InternalShell activeShell;
+    private DesktopListener[] desktopListeners;
+    private InternalShell[] allShells;
+    private InternalShell[] visibleShells;
+    private int nextShellLocation = FIRST_SHELL_LOCATION;
+    private bool showMaximizedTitle;
+    private bool autoMaximize = true;
+    private bool enableCtrlTab = true;
+    private bool allowDeactivate;
+    private Shell shell;
+    private InternalShell ishell;
+    private Listener mouseDownFilter, focusInFilter, traverseFilter;
+
+
+    this(Composite parent, int style)
+    {
+        super(parent, style);
+        Display display = getDisplay();
+        shell = getShell();
+
+        Color bg = display.getSystemColor(DWT.COLOR_TITLE_INACTIVE_BACKGROUND);
+        setBackground(bg);
+        int brightness = bg.getRed() + bg.getGreen() + bg.getBlue();
+        setForeground(display.getSystemColor(brightness > 400 ? DWT.COLOR_BLACK : DWT.COLOR_WHITE));
+
+        addListener(DWT.Resize, dgListener(&onResize));
+
+        mouseDownFilter = dgListener(&onMouseDownFilter);
+        focusInFilter = dgListener(&onFocusInFilter);
+        traverseFilter = dgListener(&onTraverseFilter);
+
+        display.addFilter(DWT.MouseDown, mouseDownFilter);
+        display.addFilter(DWT.FocusIn, focusInFilter);
+        display.addFilter(DWT.Traverse, traverseFilter);
+
+        addListener(DWT.Dispose, dgListener(&onDispose));
+    }
+
+
+    private void onResize(Event event)
+    {
+        Rectangle ca = getClientArea();
+        foreach(c; getChildren())
+        {
+            if(cast(InternalShell)c !is null)
+                (cast(InternalShell)c).desktopResized(ca);
+        }
+    }
+
+
+    private void onMouseDownFilter(Event event)
+    {
+        if(!(cast(Control)event.widget !is null)) return;
+        Control c = cast(Control)event.widget;
+        if(c.getShell() !is shell) return;
+        bool[] desktopHit = new bool[1];
+        InternalShell ishell = getInternalShell(c, desktopHit);
+        if(desktopHit[0] && allowDeactivate) activate(null);
+        if(ishell is null) return;
+        activate(ishell);
+    }
+
+
+    private void onFocusInFilter(Event event)
+    {
+        if(!(cast(Control)event.widget !is null)) return;
+        Control c = cast(Control)event.widget;
+        if(c.getShell() !is shell) return;
+        bool[] desktopHit = new bool[1];
+        ishell = getInternalShell(c, desktopHit);
+        if(desktopHit[0] && allowDeactivate) activate(null);
+        if(ishell is null) return;
+        ishell.focusControl = c;
+    }
+
+
+    private void onTraverseFilter(Event event)
+    {
+        if(!enableCtrlTab) return;
+        if(!event.doit) return; // don't steal traverse event if a control wants to handle it directly
+        if((event.stateMask & DWT.CTRL) is 0) return;
+        if(event.detail !is DWT.TRAVERSE_TAB_NEXT && event.detail !is DWT.TRAVERSE_TAB_PREVIOUS) return;
+        if(!(cast(Control)event.widget !is null)) return;
+        Control c = cast(Control)event.widget;
+        if(c.getShell() !is shell) return;
+        bool[] desktopHit = new bool[1];
+        InternalShell ishell = getInternalShell(c, desktopHit);
+        if(ishell !is null || desktopHit[0])
+        {
+            if(event.detail is DWT.TRAVERSE_TAB_NEXT) activateNextShell();
+            else activatePreviousShell();
+            event.doit = false;
+        }
+    }
+
+
+    private void onDispose(Event event)
+    {
+        display.removeFilter(DWT.MouseDown, mouseDownFilter);
+        display.removeFilter(DWT.FocusIn, focusInFilter);
+        display.removeFilter(DWT.Traverse, traverseFilter);
+    }
+
+
+    void manage(InternalShell ishell)
+    {
+        Rectangle bounds = getBounds();
+        if(nextShellLocation > bounds.height-100 || nextShellLocation > bounds.width-100)
+            nextShellLocation = FIRST_SHELL_LOCATION;
+        ishell.setLocation(bounds.x+nextShellLocation, bounds.y+nextShellLocation);
+        nextShellLocation += SHELL_LOCATION_OFFSET;
+
+        ishell.addListener(DWT.Dispose, dgListener(&onIshellDispose));
+        allShells ~= ishell;
+        if(ishell.isVisible()) visibleShells ~= ishell;
+        notifyDesktopListenersCreate(ishell);
+    }
+
+
+    private void onIshellDispose(Event event)
+    {
+        allShells.remove(ishell);
+        visibleShells.remove(ishell);
+        if(ishell is activeShell)
+        {
+            activateTopmostVisibleShellExcept(ishell);
+            if(autoMaximize && !hasVisibleMaximizedShell())
+                setAllVisibleMaximized(false);
+        }
+        notifyDesktopListenersDispose(ishell);
+    }
+
+
+    private InternalShell activateTopmostVisibleShellExcept(InternalShell except)
+    {
+        Control[] children = getChildren();
+        for(int i=0; i<children.length; i++)
+        {
+            Control c = children[i];
+            if(c is except) continue;
+            if(cast(InternalShell)c !is null && c.isVisible())
+            {
+                InternalShell ishell = cast(InternalShell)c;
+                activate(ishell);
+                return ishell;
+            }
+        }
+        activeShell = null;
+        notifyDesktopListenersActivate(null);
+        return null;
+    }
+
+
+    void activate(InternalShell ishell)
+    {
+        if(ishell is activeShell) return;
+        checkWidget();
+        if(ishell !is null)
+        {
+            if(!ishell.isVisible()) ishell.setVisible(true);
+            if((ishell.getStyle() & DWT.ON_TOP) !is 0)
+                ishell.moveAbove(null);
+            else
+            {
+                InternalShell firstRegular = getTopmostRegularShell();
+                if(firstRegular !is null && firstRegular !is ishell) ishell.moveAbove(firstRegular);
+                else
+                {
+                    Control[] children = getChildren();
+                    if(children.length > 0) ishell.moveAbove(children[0]);
+                }
+            }
+        }
+        InternalShell oldActiveShell = activeShell;
+        activeShell = ishell;
+        if(oldActiveShell !is null) oldActiveShell.redrawDecorationsAfterActivityChange();
+        if(ishell !is null)
+        {
+            if(activeShell.isVisible()) activeShell.redrawDecorationsAfterActivityChange();
+            setTabList(/**new Control[] { activeShell }*/[ activeShell ]);
+            activeShell.setFocus();
+        }
+        else
+        {
+            setTabList(/**new Control[] {}*/[]);
+            forceFocus();
+        }
+        notifyDesktopListenersActivate(ishell);
+    }
+
+
+    private InternalShell getTopmostRegularShell()
+    {
+        foreach(c; getChildren())
+        {
+            if(!(cast(InternalShell)c !is null)) continue;
+            if((c.getStyle() & DWT.ON_TOP) is 0) return cast(InternalShell)c;
+        }
+        return null;
+    }
+
+
+    private InternalShell getBottommostOnTopShell()
+    {
+        Control[] ch = getChildren();
+        for(int i=ch.length-1; i>=0; i--)
+        {
+            Control c = ch[i];
+            if(!(cast(InternalShell)c !is null)) continue;
+            if((c.getStyle() & DWT.ON_TOP) !is 0) return cast(InternalShell)c;
+        }
+        return null;
+    }
+
+
+    void shellVisibilityChanged(InternalShell ishell, bool visible)
+    {
+        if(visible)
+        {
+            if(!contains(visibleShells, ishell))
+            {
+                visibleShells ~= ishell;
+                if(autoMaximize && !ishell.getMaximized() && (ishell.getStyle() & DWT.MAX) !is 0 && hasVisibleMaximizedShell())
+                    ishell.setMaximizedWithoutNotification(true);
+            }
+            if(ishell.getMaximized())
+                ishell.desktopResized(getClientArea());
+        }
+        else
+        {
+            visibleShells.remove(ishell);
+            if(ishell is activeShell)
+            {
+                activateTopmostVisibleShellExcept(ishell);
+                if(autoMaximize && !hasVisibleMaximizedShell())
+                    setAllVisibleMaximized(false);
+            }
+        }
+    }
+
+
+    private InternalShell getInternalShell(Control c, bool[] desktopHit)
+    {
+        while(c !is null && c !is /**DesktopForm.*/this)
+        {
+            if(cast(InternalShell)c !is null && (cast(InternalShell)c).getParent() is this)
+                return cast(InternalShell)c;
+            c = c.getParent();
+        }
+        if(desktopHit !is null && c is /**DesktopForm.*/this) desktopHit[0] = true;
+        return null;
+    }
+
+
+    public InternalShell getActiveShell()
+    {
+        return activeShell;
+    }
+
+
+    public InternalShell[] getVisibleShells()
+    {
+        checkWidget();
+        return visibleShells;
+    }
+
+
+    public InternalShell[] getShells()
+    {
+        checkWidget();
+        return allShells;
+    }
+
+
+    public void setShowMaximizedTitle(bool b)
+    {
+        checkWidget();
+        showMaximizedTitle = b;
+        Rectangle ca = getClientArea();
+        foreach(c; getChildren())
+        {
+            if(cast(InternalShell)c !is null)
+                (cast(InternalShell)c).desktopResized(ca);
+        }
+    }
+
+
+    public bool getShowMaximizedTitle()
+    {
+        checkWidget();
+        return showMaximizedTitle;
+    }
+
+
+    public void setAutoMaximize(bool b)
+    {
+        checkWidget();
+        autoMaximize = b;
+        bool hasMax = false;
+        foreach(ins; visibleShells)
+        {
+            if(ins.getMaximized())
+            {
+                hasMax = true;
+                break;
+            }
+        }
+        if(hasMax)
+        {
+            // Maximize all shells
+            foreach(ins; visibleShells)
+            {
+                if((ins.getStyle() & DWT.MAX) !is 0) ins.setMaximized(true);
+            }
+        }
+    }
+
+
+    public bool getAutoMaximize()
+    {
+        checkWidget();
+        return autoMaximize;
+    }
+
+
+    public void setEnableCtrlTab(bool b)
+    {
+        checkWidget();
+        this.enableCtrlTab = b;
+    }
+
+
+    public bool getEnableCtrlTab()
+    {
+        return enableCtrlTab;
+    }
+
+
+    public void setAllowDeactivate(bool b)
+    {
+        checkWidget();
+        this.allowDeactivate = b;
+        if(!allowDeactivate && activeShell is null)
+            activateTopmostVisibleShellExcept(null);
+    }
+
+
+    public bool getAllowDeactivate()
+    {
+        return allowDeactivate;
+    }
+
+
+    void shellMaximizedOrRestored(InternalShell ishell, bool maximized)
+    {
+        setAllVisibleMaximized(maximized);
+    }
+
+
+    private void setAllVisibleMaximized(bool maximized)
+    {
+        if(autoMaximize) // maximize or restore all shells
+        {
+            foreach(c; getChildren())
+            {
+                if(cast(InternalShell)c !is null)
+                {
+                    InternalShell ishell = cast(InternalShell)c;
+                    if((ishell.getStyle() & DWT.MAX) !is 0 && ishell.isVisible())
+                        (cast(InternalShell)c).setMaximizedWithoutNotification(maximized);
+                }
+            }
+        }
+    }
+
+
+    private void activateNextShell()
+    {
+        if(activeShell is null)
+        {
+            activateTopmostVisibleShellExcept(null);
+            return;
+        }
+        if(visibleShells.length < 2) return;
+        InternalShell topReg = getTopmostRegularShell();
+        InternalShell botTop = getBottommostOnTopShell();
+        if((activeShell.getStyle() & DWT.ON_TOP) !is 0)
+        {
+            activeShell.moveBelow(botTop);
+            if(topReg !is null) activate(topReg);
+            else activateTopmostVisibleShellExcept(null);
+        }
+        else
+        {
+            activeShell.moveBelow(null);
+            activateTopmostVisibleShellExcept(null);
+        }
+    }
+
+
+    private void activatePreviousShell()
+    {
+        if(activeShell is null)
+        {
+            activateTopmostVisibleShellExcept(null);
+            return;
+        }
+        if(visibleShells.length < 2) return;
+        InternalShell topReg = getTopmostRegularShell();
+        InternalShell botTop = getBottommostOnTopShell();
+        if(activeShell is topReg && botTop !is null) activate(botTop);
+        else
+        {
+            Control[] ch = getChildren();
+            for(int i=ch.length-1; i>=0; i--)
+            {
+                if(cast(InternalShell)ch[i] !is null && ch[i].isVisible())
+                {
+                    activate(cast(InternalShell)ch[i]);
+                    break;
+                }
+            }
+        }
+    }
+
+
+    public void addDesktopListener(DesktopListener l)
+    {
+        desktopListeners ~= l;
+    }
+
+
+    public void removeDesktopListener(DesktopListener l)
+    {
+        desktopListeners.remove(l);
+    }
+
+
+    private void notifyDesktopListenersCreate(InternalShell ishell)
+    {
+        Event event = new Event();
+        event.widget = ishell;
+        foreach(l; desktopListeners) l.shellCreated(event);
+    }
+
+
+    private void notifyDesktopListenersDispose(InternalShell ishell)
+    {
+        Event event = new Event();
+        event.widget = ishell;
+        foreach(l; desktopListeners) l.shellDisposed(event);
+    }
+
+
+    private void notifyDesktopListenersActivate(InternalShell ishell)
+    {
+        Event event = new Event();
+        event.widget = ishell;
+        foreach(l; desktopListeners) l.shellActivated(event);
+    }
+
+
+    private bool hasVisibleMaximizedShell()
+    {
+        foreach(ins; visibleShells)
+            if(ins.getMaximized()) return true;
+        return false;
+    }
+}
--- a/dwtx/novocode/ishell/InternalShell.d	Sun Oct 26 14:57:25 2008 +0100
+++ b/dwtx/novocode/ishell/InternalShell.d	Sun Oct 26 15:04:41 2008 +0100
@@ -1,398 +1,398 @@
-/*******************************************************************************
- * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
- *
- * Contributors:
- *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
- *******************************************************************************/
-
-module dwtx.novocode.ishell.InternalShell;
-
-import dwt.dwthelper.utils;
-import dwt.DWT;
-import dwt.DWTException;
-import dwt.graphics.Image;
-import dwt.graphics.Point;
-import dwt.graphics.Rectangle;
-import dwt.layout.FormAttachment;
-import dwt.layout.FormData;
-import dwt.layout.FormLayout;
-import dwt.widgets.Composite;
-import dwt.widgets.Control;
-import dwt.widgets.Event;
-import dwt.widgets.Listener;
-import dwt.widgets.Menu;
-
-import dwtx.novocode.SizeBorder;
-import dwtx.novocode.SizeGrip;
-import dwtx.novocode.ishell.DesktopForm;
-import dwtx.novocode.ishell.internal.TitleBar;
-import dwtx.novocode.ishell.internal.TitleBarButton;
-
-
-/**
- * An internal shell which can be placed on a DesktopForm.
- * <p>
- * <dl>
- * <dt><b>Styles:</b></dt>
- * <dd>RESIZE, CLOSE, MAX, ON_TOP, TOOL, NO_RADIO_GROUP</dd>
- * <dt><b>Events:</b></dt>
- * <dd>(none)</dd>
- * </dl>
- * </p>
- *
- * @author Stefan Zeiger (szeiger@novocode.com)
- * @since Jan 21, 2005
- * @version $Id: InternalShell.java 344 2005-07-09 22:37:51 +0000 (Sat, 09 Jul 2005) szeiger $
- */
-
-// [TODO] Support styles NO_TRIM, BORDER, TITLE
-// [TODO] Separate "minimized" from "not visible"
-
-class InternalShell : Composite
-{
-  private static const int BORDER_SIZE = 4;
-
-  private Composite contentPane;
-  private TitleBar titleBar;
-  private SizeGrip sizeGrip;
-  private SizeBorder sizeBorder;
-  private int minWidth = 112;
-  private int minHeight;
-  private DesktopForm desktop;
-  private bool maximized;
-  private Rectangle pluralizedBounds;
-  private int titleHeight;
-  private int style;
-  private TitleBarButton closeButton, maxButton, minButton;
-
-  Control focusControl;
-
-
-  this(DesktopForm parent, int style)
-  {
-    super(parent, checkStyle(style));
-    this.desktop = parent;
-    this.style = style;
-    setBackground(getDisplay().getSystemColor(DWT.COLOR_WIDGET_BACKGROUND));
-    FormLayout layout = new FormLayout();
-    setLayout(layout);
-    FormData fd;
-
-    titleBar = new TitleBar(this, style & (DWT.CLOSE | DWT.RESIZE | DWT.MAX | DWT.TOOL | DWT.MIN));
-    titleHeight = titleBar.computeSize(DWT.DEFAULT, DWT.DEFAULT, true).y;
-
-    Control leftButton = null;
-
-    if((style & (DWT.CLOSE | DWT.MAX | DWT.MIN)) !is 0)
-    {
-      closeButton = new TitleBarButton(this, DWT.CLOSE);
-      if((style & DWT.CLOSE) is 0) closeButton.setEnabled(false);
-      closeButton.addListener(DWT.Selection, dgListener(&closeListener));
-      fd = new FormData(titleHeight, titleHeight);
-      if(leftButton !is null) fd.right = new FormAttachment(leftButton);
-      else fd.right = new FormAttachment(100, -BORDER_SIZE);
-      fd.top = new FormAttachment(0, BORDER_SIZE);
-      closeButton.setLayoutData(fd);
-      leftButton = closeButton;
-
-      if((style & (DWT.MAX|DWT.MIN)) !is 0)
-      {
-        maxButton = new TitleBarButton(this, DWT.MAX);
-        if((style & DWT.MAX) is 0) maxButton.setEnabled(false);
-        maxButton.addListener(DWT.Selection, dgListener(&maximizeListener));
-        fd = new FormData(titleHeight, titleHeight);
-        if(leftButton !is null) fd.right = new FormAttachment(leftButton);
-        else fd.right = new FormAttachment(100, -BORDER_SIZE);
-        fd.top = new FormAttachment(0, BORDER_SIZE);
-        maxButton.setLayoutData(fd);
-        leftButton = maxButton;
-
-        minButton = new TitleBarButton(this, DWT.MIN);
-        if((style & DWT.MIN) is 0) minButton.setEnabled(false);
-        minButton.addListener(DWT.Selection, dgListener(&minimizeListener));
-        fd = new FormData(titleHeight, titleHeight);
-        if(leftButton !is null) fd.right = new FormAttachment(leftButton);
-        else fd.right = new FormAttachment(100, -BORDER_SIZE);
-        fd.top = new FormAttachment(0, BORDER_SIZE);
-        minButton.setLayoutData(fd);
-        leftButton = minButton;
-      }
-    }
-
-    fd = new FormData();
-    fd.left = new FormAttachment(0, BORDER_SIZE);
-    if(leftButton !is null) fd.right = new FormAttachment(leftButton);
-    else fd.right = new FormAttachment(100, -BORDER_SIZE);
-    fd.top = new FormAttachment(0, BORDER_SIZE);
-    titleBar.setLayoutData(fd);
-
-    contentPane = new Composite(this, DWT.NONE);
-    fd = new FormData();
-    fd.left = new FormAttachment(0, BORDER_SIZE);
-    fd.right = new FormAttachment(100, -BORDER_SIZE);
-    fd.top = new FormAttachment(titleBar, 1);
-    fd.bottom = new FormAttachment(100, -BORDER_SIZE);
-    contentPane.setLayoutData(fd);
-
-    sizeBorder = new SizeBorder(this, this, DWT.BORDER);
-    sizeBorder.setBorderWidth(BORDER_SIZE);
-    fd = new FormData();
-    fd.left = new FormAttachment(0);
-    fd.right = new FormAttachment(100);
-    fd.top = new FormAttachment(0);
-    fd.bottom = new FormAttachment(100);
-    sizeBorder.setLayoutData(fd);
-
-    minHeight = titleHeight + 2*BORDER_SIZE;
-    sizeBorder.setMinimumShellSize(minWidth, minHeight);
-    sizeBorder.setCornerSize(titleHeight + BORDER_SIZE);
-    if((style & DWT.RESIZE) is 0) sizeBorder.setEnabled(false);
-
-    setSize(320, 240);
-    setVisible(false);
-
-    desktop.manage(this);
-  }
-
-
-  private void closeListener(Event event)
-  {
-      close();
-  }
-
-
-  private void maximizeListener(Event event)
-  {
-      setMaximized(!maximized);
-  }
-
-
-  private void minimizeListener(Event event)
-  {
-      setMinimized(true);
-  }
-
-
-  private static int checkStyle(int style)
-  {
-    int mask = DWT.NO_RADIO_GROUP;
-    style &= mask;
-    return style;
-  }
-
-
-  public int getStyle()
-  {
-    return style;
-  }
-
-
-  public Composite getContentPane() { return contentPane; }
-
-
-  public void setText(String s) { titleBar.setText(s); }
-
-  public String getText() { return titleBar.getText(); }
-
-
-  public void setCustomMenu(Menu menu) { titleBar.setMenu(menu); }
-
-  public Menu getCustomMenu() { return titleBar.getMenu(); }
-
-
-  public void setImage(Image image) { titleBar.setImage(image); }
-
-  public Image getImage() { return titleBar.getImage(); }
-
-
-  public void createSizeGrip(int style)
-  {
-    checkWidget();
-    if(sizeGrip !is null)
-      throw new DWTException("SizeGrip was already created");
-    if((this.style & DWT.RESIZE) is 0)
-      throw new DWTException("Cannot create SizeGrip for InternalShell without style RESIZE");
-    sizeGrip = new SizeGrip(this, this, style);
-    sizeGrip.setBackground(contentPane.getBackground());
-    sizeGrip.moveAbove(contentPane);
-    FormData fd = new FormData();
-    fd.right = new FormAttachment(100, -BORDER_SIZE);
-    fd.bottom = new FormAttachment(100, -BORDER_SIZE);
-    sizeGrip.setLayoutData(fd);
-    sizeGrip.setMinimumShellSize(minWidth, minHeight);
-    if(isVisible()) layout(true);
-  }
-
-
-  public Point computeSize(int wHint, int hHint, bool changed)
-  {
-    Point p = super.computeSize(wHint, hHint, changed);
-    if(p.x < minWidth) p.x = minWidth;
-    if(p.y < minHeight) p.y = minHeight;
-    return p;
-  }
-
-
-  public void setSize(int width, int height)
-  {
-    if(width < minWidth) width = minWidth;
-    if(height < minHeight) height = minHeight;
-    super.setSize(width, height);
-  }
-
-
-  public void setBounds(int x, int y, int width, int height)
-  {
-    if(width < minWidth) width = minWidth;
-    if(height < minHeight) height = minHeight;
-    super.setBounds(x, y, width, height);
-  }
-
-
-  public void setMinimumSize(int width, int height)
-  {
-    checkWidget();
-    minWidth = width;
-    minHeight = height;
-    sizeGrip.setMinimumShellSize(minWidth, minHeight);
-    sizeBorder.setMinimumShellSize(minWidth, minHeight);
-    Point size = getSize();
-    if(size.x < minWidth || size.y < minHeight)
-      setSize(Math.max(minWidth, size.x), Math.max(minHeight, size.y));
-  }
-
-
-  public void close()
-  {
-    Event event = new Event();
-    notifyListeners(DWT.Close, event);
-    if(event.doit && !isDisposed()) dispose();
-  }
-
-
-  public void open()
-  {
-    desktop.activate(this);
-    setVisible(true);
-    setFocus();
-  }
-
-
-  public void setVisible(bool visible)
-  {
-    if(!visible) desktop.shellVisibilityChanged(this, false);
-    super.setVisible(visible);
-    if(visible) desktop.shellVisibilityChanged(this, true);
-  }
-
-
-  public void setActive()
-  {
-    desktop.activate(this);
-  }
-
-
-  public void setMaximized(bool maximized)
-  {
-    checkWidget();
-    if(this.maximized is maximized) return;
-    setMaximizedWithoutNotification(maximized);
-    desktop.shellMaximizedOrRestored(this, maximized);
-  }
-
-
-  public void setMinimized(bool minimized)
-  {
-    checkWidget();
-    bool wasMaximized = maximized;
-    setVisible(!minimized);
-    maximized = wasMaximized;
-  }
-
-
-  public bool getMinimized()
-  {
-    return getVisible();
-  }
-
-
-  void setMaximizedWithoutNotification(bool maximized)
-  {
-    if(this.maximized is maximized) return;
-    this.maximized = maximized;
-    if(maximized)
-    {
-      pluralizedBounds = getBounds();
-      desktopResized(desktop.getClientArea());
-    }
-    else
-    {
-      setBounds(pluralizedBounds.x,pluralizedBounds.y,pluralizedBounds.width,pluralizedBounds.height);
-    }
-    // Note: This method may be called in a Dispose event for this object
-    if(sizeGrip !is null && !sizeGrip.isDisposed()) sizeGrip.setVisible(!maximized);
-    if(!sizeBorder.isDisposed()) sizeBorder.setEnabled(!maximized && (style & DWT.RESIZE) !is 0);
-    if(maxButton !is null && !maxButton.isDisposed()) maxButton.redraw();
-  }
-
-
-  public bool getMaximized()
-  {
-    checkWidget();
-    return maximized;
-  }
-
-
-  void redrawDecorationsAfterActivityChange()
-  {
-    // Note: This method may be called in a Dispose event for this object
-    if(!titleBar.isDisposed()) titleBar.redraw();
-    if(closeButton !is null && !closeButton.isDisposed()) closeButton.redraw();
-    if(maxButton !is null && !maxButton.isDisposed()) maxButton.redraw();
-    if(minButton !is null && !minButton.isDisposed()) minButton.redraw();
-  }
-
-
-  void desktopResized(Rectangle deskCA)
-  {
-    if(maximized)
-    {
-      int hideTitle = desktop.getShowMaximizedTitle() ? 0 : (titleHeight+1);
-      setBounds(deskCA.x - BORDER_SIZE,
-        deskCA.y - BORDER_SIZE - hideTitle,
-        deskCA.width + 2*BORDER_SIZE,
-        deskCA.height + 2*BORDER_SIZE + hideTitle);
-    }
-    else forceVisibleLocation(deskCA);
-  }
-
-
-  public bool setFocus()
-  {
-    if(focusControl !is null && focusControl !is this && !focusControl.isDisposed())
-      return focusControl.setFocus();
-    return super.setFocus();
-  }
-
-
-  public bool isActiveShell()
-  {
-    return desktop.getActiveShell() is this;
-  }
-
-
-  private void forceVisibleLocation(Rectangle deskCA)
-  {
-    Point p = getLocation();
-    Point minGrabSize = titleBar.getMinGrabSize();
-    int x = p.x, y = p.y;
-    int minX = minGrabSize.x + BORDER_SIZE, minY = minGrabSize.y + BORDER_SIZE;
-    x = Math.min(Math.max(x, deskCA.x+minY), deskCA.x+deskCA.width-minX);
-    y = Math.min(Math.max(y, deskCA.y+minY), deskCA.y+deskCA.height-minY);
-    if(x != p.x || y != p.y) setLocation(x, y);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
+ *******************************************************************************/
+
+module dwtx.novocode.ishell.InternalShell;
+
+import dwt.dwthelper.utils;
+import dwt.DWT;
+import dwt.DWTException;
+import dwt.graphics.Image;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.layout.FormAttachment;
+import dwt.layout.FormData;
+import dwt.layout.FormLayout;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.widgets.Menu;
+
+import dwtx.novocode.SizeBorder;
+import dwtx.novocode.SizeGrip;
+import dwtx.novocode.ishell.DesktopForm;
+import dwtx.novocode.ishell.internal.TitleBar;
+import dwtx.novocode.ishell.internal.TitleBarButton;
+
+
+/**
+ * An internal shell which can be placed on a DesktopForm.
+ * <p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>RESIZE, CLOSE, MAX, ON_TOP, TOOL, NO_RADIO_GROUP</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * </p>
+ *
+ * @author Stefan Zeiger (szeiger@novocode.com)
+ * @since Jan 21, 2005
+ * @version $Id: InternalShell.java 344 2005-07-09 22:37:51 +0000 (Sat, 09 Jul 2005) szeiger $
+ */
+
+// [TODO] Support styles NO_TRIM, BORDER, TITLE
+// [TODO] Separate "minimized" from "not visible"
+
+class InternalShell : Composite
+{
+    private static const int BORDER_SIZE = 4;
+
+    private Composite contentPane;
+    private TitleBar titleBar;
+    private SizeGrip sizeGrip;
+    private SizeBorder sizeBorder;
+    private int minWidth = 112;
+    private int minHeight;
+    private DesktopForm desktop;
+    private bool maximized;
+    private Rectangle pluralizedBounds;
+    private int titleHeight;
+    private int style;
+    private TitleBarButton closeButton, maxButton, minButton;
+
+    Control focusControl;
+
+
+    this(DesktopForm parent, int style)
+    {
+        super(parent, checkStyle(style));
+        this.desktop = parent;
+        this.style = style;
+        setBackground(getDisplay().getSystemColor(DWT.COLOR_WIDGET_BACKGROUND));
+        FormLayout layout = new FormLayout();
+        setLayout(layout);
+        FormData fd;
+
+        titleBar = new TitleBar(this, style & (DWT.CLOSE | DWT.RESIZE | DWT.MAX | DWT.TOOL | DWT.MIN));
+        titleHeight = titleBar.computeSize(DWT.DEFAULT, DWT.DEFAULT, true).y;
+
+        Control leftButton = null;
+
+        if((style & (DWT.CLOSE | DWT.MAX | DWT.MIN)) !is 0)
+        {
+            closeButton = new TitleBarButton(this, DWT.CLOSE);
+            if((style & DWT.CLOSE) is 0) closeButton.setEnabled(false);
+            closeButton.addListener(DWT.Selection, dgListener(&closeListener));
+            fd = new FormData(titleHeight, titleHeight);
+            if(leftButton !is null) fd.right = new FormAttachment(leftButton);
+            else fd.right = new FormAttachment(100, -BORDER_SIZE);
+            fd.top = new FormAttachment(0, BORDER_SIZE);
+            closeButton.setLayoutData(fd);
+            leftButton = closeButton;
+
+            if((style & (DWT.MAX|DWT.MIN)) !is 0)
+            {
+                maxButton = new TitleBarButton(this, DWT.MAX);
+                if((style & DWT.MAX) is 0) maxButton.setEnabled(false);
+                maxButton.addListener(DWT.Selection, dgListener(&maximizeListener));
+                fd = new FormData(titleHeight, titleHeight);
+                if(leftButton !is null) fd.right = new FormAttachment(leftButton);
+                else fd.right = new FormAttachment(100, -BORDER_SIZE);
+                fd.top = new FormAttachment(0, BORDER_SIZE);
+                maxButton.setLayoutData(fd);
+                leftButton = maxButton;
+
+                minButton = new TitleBarButton(this, DWT.MIN);
+                if((style & DWT.MIN) is 0) minButton.setEnabled(false);
+                minButton.addListener(DWT.Selection, dgListener(&minimizeListener));
+                fd = new FormData(titleHeight, titleHeight);
+                if(leftButton !is null) fd.right = new FormAttachment(leftButton);
+                else fd.right = new FormAttachment(100, -BORDER_SIZE);
+                fd.top = new FormAttachment(0, BORDER_SIZE);
+                minButton.setLayoutData(fd);
+                leftButton = minButton;
+            }
+        }
+
+        fd = new FormData();
+        fd.left = new FormAttachment(0, BORDER_SIZE);
+        if(leftButton !is null) fd.right = new FormAttachment(leftButton);
+        else fd.right = new FormAttachment(100, -BORDER_SIZE);
+        fd.top = new FormAttachment(0, BORDER_SIZE);
+        titleBar.setLayoutData(fd);
+
+        contentPane = new Composite(this, DWT.NONE);
+        fd = new FormData();
+        fd.left = new FormAttachment(0, BORDER_SIZE);
+        fd.right = new FormAttachment(100, -BORDER_SIZE);
+        fd.top = new FormAttachment(titleBar, 1);
+        fd.bottom = new FormAttachment(100, -BORDER_SIZE);
+        contentPane.setLayoutData(fd);
+
+        sizeBorder = new SizeBorder(this, this, DWT.BORDER);
+        sizeBorder.setBorderWidth(BORDER_SIZE);
+        fd = new FormData();
+        fd.left = new FormAttachment(0);
+        fd.right = new FormAttachment(100);
+        fd.top = new FormAttachment(0);
+        fd.bottom = new FormAttachment(100);
+        sizeBorder.setLayoutData(fd);
+
+        minHeight = titleHeight + 2*BORDER_SIZE;
+        sizeBorder.setMinimumShellSize(minWidth, minHeight);
+        sizeBorder.setCornerSize(titleHeight + BORDER_SIZE);
+        if((style & DWT.RESIZE) is 0) sizeBorder.setEnabled(false);
+
+        setSize(320, 240);
+        setVisible(false);
+
+        desktop.manage(this);
+    }
+
+
+    private void closeListener(Event event)
+    {
+        close();
+    }
+
+
+    private void maximizeListener(Event event)
+    {
+        setMaximized(!maximized);
+    }
+
+
+    private void minimizeListener(Event event)
+    {
+        setMinimized(true);
+    }
+
+
+    private static int checkStyle(int style)
+    {
+        int mask = DWT.NO_RADIO_GROUP;
+        style &= mask;
+        return style;
+    }
+
+
+    public int getStyle()
+    {
+        return style;
+    }
+
+
+    public Composite getContentPane() { return contentPane; }
+
+
+    public void setText(String s) { titleBar.setText(s); }
+
+    public String getText() { return titleBar.getText(); }
+
+
+    public void setCustomMenu(Menu menu) { titleBar.setMenu(menu); }
+
+    public Menu getCustomMenu() { return titleBar.getMenu(); }
+
+
+    public void setImage(Image image) { titleBar.setImage(image); }
+
+    public Image getImage() { return titleBar.getImage(); }
+
+
+    public void createSizeGrip(int style)
+    {
+        checkWidget();
+        if(sizeGrip !is null)
+            throw new DWTException("SizeGrip was already created");
+        if((this.style & DWT.RESIZE) is 0)
+            throw new DWTException("Cannot create SizeGrip for InternalShell without style RESIZE");
+        sizeGrip = new SizeGrip(this, this, style);
+        sizeGrip.setBackground(contentPane.getBackground());
+        sizeGrip.moveAbove(contentPane);
+        FormData fd = new FormData();
+        fd.right = new FormAttachment(100, -BORDER_SIZE);
+        fd.bottom = new FormAttachment(100, -BORDER_SIZE);
+        sizeGrip.setLayoutData(fd);
+        sizeGrip.setMinimumShellSize(minWidth, minHeight);
+        if(isVisible()) layout(true);
+    }
+
+
+    public Point computeSize(int wHint, int hHint, bool changed)
+    {
+        Point p = super.computeSize(wHint, hHint, changed);
+        if(p.x < minWidth) p.x = minWidth;
+        if(p.y < minHeight) p.y = minHeight;
+        return p;
+    }
+
+
+    public void setSize(int width, int height)
+    {
+        if(width < minWidth) width = minWidth;
+        if(height < minHeight) height = minHeight;
+        super.setSize(width, height);
+    }
+
+
+    public void setBounds(int x, int y, int width, int height)
+    {
+        if(width < minWidth) width = minWidth;
+        if(height < minHeight) height = minHeight;
+        super.setBounds(x, y, width, height);
+    }
+
+
+    public void setMinimumSize(int width, int height)
+    {
+        checkWidget();
+        minWidth = width;
+        minHeight = height;
+        sizeGrip.setMinimumShellSize(minWidth, minHeight);
+        sizeBorder.setMinimumShellSize(minWidth, minHeight);
+        Point size = getSize();
+        if(size.x < minWidth || size.y < minHeight)
+            setSize(Math.max(minWidth, size.x), Math.max(minHeight, size.y));
+    }
+
+
+    public void close()
+    {
+        Event event = new Event();
+        notifyListeners(DWT.Close, event);
+        if(event.doit && !isDisposed()) dispose();
+    }
+
+
+    public void open()
+    {
+        desktop.activate(this);
+        setVisible(true);
+        setFocus();
+    }
+
+
+    public void setVisible(bool visible)
+    {
+        if(!visible) desktop.shellVisibilityChanged(this, false);
+        super.setVisible(visible);
+        if(visible) desktop.shellVisibilityChanged(this, true);
+    }
+
+
+    public void setActive()
+    {
+        desktop.activate(this);
+    }
+
+
+    public void setMaximized(bool maximized)
+    {
+        checkWidget();
+        if(this.maximized is maximized) return;
+        setMaximizedWithoutNotification(maximized);
+        desktop.shellMaximizedOrRestored(this, maximized);
+    }
+
+
+    public void setMinimized(bool minimized)
+    {
+        checkWidget();
+        bool wasMaximized = maximized;
+        setVisible(!minimized);
+        maximized = wasMaximized;
+    }
+
+
+    public bool getMinimized()
+    {
+        return getVisible();
+    }
+
+
+    void setMaximizedWithoutNotification(bool maximized)
+    {
+        if(this.maximized is maximized) return;
+        this.maximized = maximized;
+        if(maximized)
+        {
+            pluralizedBounds = getBounds();
+            desktopResized(desktop.getClientArea());
+        }
+        else
+        {
+            setBounds(pluralizedBounds.x,pluralizedBounds.y,pluralizedBounds.width,pluralizedBounds.height);
+        }
+        // Note: This method may be called in a Dispose event for this object
+        if(sizeGrip !is null && !sizeGrip.isDisposed()) sizeGrip.setVisible(!maximized);
+        if(!sizeBorder.isDisposed()) sizeBorder.setEnabled(!maximized && (style & DWT.RESIZE) !is 0);
+        if(maxButton !is null && !maxButton.isDisposed()) maxButton.redraw();
+    }
+
+
+    public bool getMaximized()
+    {
+        checkWidget();
+        return maximized;
+    }
+
+
+    void redrawDecorationsAfterActivityChange()
+    {
+        // Note: This method may be called in a Dispose event for this object
+        if(!titleBar.isDisposed()) titleBar.redraw();
+        if(closeButton !is null && !closeButton.isDisposed()) closeButton.redraw();
+        if(maxButton !is null && !maxButton.isDisposed()) maxButton.redraw();
+        if(minButton !is null && !minButton.isDisposed()) minButton.redraw();
+    }
+
+
+    void desktopResized(Rectangle deskCA)
+    {
+        if(maximized)
+        {
+            int hideTitle = desktop.getShowMaximizedTitle() ? 0 : (titleHeight+1);
+            setBounds(deskCA.x - BORDER_SIZE,
+                    deskCA.y - BORDER_SIZE - hideTitle,
+                    deskCA.width + 2*BORDER_SIZE,
+                    deskCA.height + 2*BORDER_SIZE + hideTitle);
+        }
+        else forceVisibleLocation(deskCA);
+    }
+
+
+    public bool setFocus()
+    {
+        if(focusControl !is null && focusControl !is this && !focusControl.isDisposed())
+            return focusControl.setFocus();
+        return super.setFocus();
+    }
+
+
+    public bool isActiveShell()
+    {
+        return desktop.getActiveShell() is this;
+    }
+
+
+    private void forceVisibleLocation(Rectangle deskCA)
+    {
+        Point p = getLocation();
+        Point minGrabSize = titleBar.getMinGrabSize();
+        int x = p.x, y = p.y;
+        int minX = minGrabSize.x + BORDER_SIZE, minY = minGrabSize.y + BORDER_SIZE;
+        x = Math.min(Math.max(x, deskCA.x+minY), deskCA.x+deskCA.width-minX);
+        y = Math.min(Math.max(y, deskCA.y+minY), deskCA.y+deskCA.height-minY);
+        if(x != p.x || y != p.y) setLocation(x, y);
+    }
+}
--- a/dwtx/novocode/ishell/internal/CustomDrawnButton.d	Sun Oct 26 14:57:25 2008 +0100
+++ b/dwtx/novocode/ishell/internal/CustomDrawnButton.d	Sun Oct 26 15:04:41 2008 +0100
@@ -1,134 +1,134 @@
-/*******************************************************************************
- * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
- * 
- * Contributors:
- *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
- *******************************************************************************/
-
-module dwtx.novocode.ishell.internal.CustomDrawnButton;
-
-import dwt.DWT;
-import dwt.graphics.Point;
-import dwt.widgets.Canvas;
-import dwt.widgets.Composite;
-import dwt.widgets.Display;
-import dwt.widgets.Event;
-import dwt.widgets.Listener;
-
-
-/**
- * A simple button control which needs to be subclassed to draw a specific
- * kind of button. This base class provides the event handling.
- * 
- * @author Stefan Zeiger (szeiger@novocode.com)
- * @since Jan 30, 2005
- * @version $Id: CustomDrawnButton.java 320 2005-02-26 13:37:02 +0000 (Sat, 26 Feb 2005) szeiger $
- */
-
-class CustomDrawnButton : Canvas
-{
-  private bool pressed;
-  private Display display;
-  private bool drawnMouseIn = false;
-
-
-  this(Composite parent, int style)
-  {
-    super(parent, style);
-    this.display = getDisplay();
-
-    addListener(DWT.Paint, dgListener(&paintListener));
-
-    addListener(DWT.MouseDown, dgListener(&onMouseDown));
-
-    addListener(DWT.MouseUp, dgListener(&onMouseUp));
-    
-    addListener(DWT.MouseMove, dgListener(&onMouseMove));
-  }
-  
-  
-  private void paintListener(Event event)
-  {
-        bool mouseIn = mouseIn();
-        onPaint(event, pressed && mouseIn);
-        drawnMouseIn = mouseIn;
-  }
-
-
-  private void onMouseDown(Event event)
-  {
-        if(event.button is 1)
-        {
-          pressed = true;
-          redraw();
-        }
-        else if(event.button is 3 && (event.stateMask & DWT.BUTTON1) !is 0) // chord click
-        {
-          pressed = false;
-          redraw();
-        }
-  }
-
-
-  private void onMouseUp(Event event)
-  {
-        if(pressed && (event.stateMask & DWT.BUTTON1) !is 0)
-        {
-          pressed = false;
-          if(mouseIn())
-          {
-            Event selectionEvent = new Event();
-            notifyListeners(DWT.Selection, selectionEvent);
-          }
-          if(!isDisposed()) redraw();
-        }
-  }
-
-
-  private void onMouseMove(Event event)
-  {
-        if(!pressed) return;
-        bool mouseIn = mouseIn();
-        if(mouseIn is drawnMouseIn) return;
-        redraw();
-  }
-
-
-  private bool mouseIn()
-  {
-    Point p = toControl(display.getCursorLocation());
-    if(p.x < -1 || p.y < -1) return false;
-    Point size = getSize();
-    return p.x <= size.x+1 && p.y <= size.y+1;
-  }
-
-
-  public Point computeSize(int wHint, int hHint, bool changed)
-  {
-    checkWidget();
-    if(wHint is DWT.DEFAULT) wHint = 0;
-    if(hHint is DWT.DEFAULT) hHint = 0;
-    return new Point(wHint, hHint);
-  }
-
-
-  public bool setFocus()
-  {
-    checkWidget();
-    return false;
-  }
-
-
-  public bool isReparentable ()
-  {
-    checkWidget();
-    return false;
-  }
-  
-  
-  protected abstract void onPaint(Event event, bool pressed);
-}
+/*******************************************************************************
+ * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
+ *******************************************************************************/
+
+module dwtx.novocode.ishell.internal.CustomDrawnButton;
+
+import dwt.DWT;
+import dwt.graphics.Point;
+import dwt.widgets.Canvas;
+import dwt.widgets.Composite;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+
+
+/**
+ * A simple button control which needs to be subclassed to draw a specific
+ * kind of button. This base class provides the event handling.
+ * 
+ * @author Stefan Zeiger (szeiger@novocode.com)
+ * @since Jan 30, 2005
+ * @version $Id: CustomDrawnButton.java 320 2005-02-26 13:37:02 +0000 (Sat, 26 Feb 2005) szeiger $
+ */
+
+class CustomDrawnButton : Canvas
+{
+    private bool pressed;
+    private Display display;
+    private bool drawnMouseIn = false;
+
+
+    this(Composite parent, int style)
+    {
+        super(parent, style);
+        this.display = getDisplay();
+
+        addListener(DWT.Paint, dgListener(&paintListener));
+
+        addListener(DWT.MouseDown, dgListener(&onMouseDown));
+
+        addListener(DWT.MouseUp, dgListener(&onMouseUp));
+
+        addListener(DWT.MouseMove, dgListener(&onMouseMove));
+    }
+
+
+    private void paintListener(Event event)
+    {
+        bool mouseIn = mouseIn();
+        onPaint(event, pressed && mouseIn);
+        drawnMouseIn = mouseIn;
+    }
+
+
+    private void onMouseDown(Event event)
+    {
+        if(event.button is 1)
+        {
+            pressed = true;
+            redraw();
+        }
+        else if(event.button is 3 && (event.stateMask & DWT.BUTTON1) !is 0) // chord click
+        {
+            pressed = false;
+            redraw();
+        }
+    }
+
+
+    private void onMouseUp(Event event)
+    {
+        if(pressed && (event.stateMask & DWT.BUTTON1) !is 0)
+        {
+            pressed = false;
+            if(mouseIn())
+            {
+                Event selectionEvent = new Event();
+                notifyListeners(DWT.Selection, selectionEvent);
+            }
+            if(!isDisposed()) redraw();
+        }
+    }
+
+
+    private void onMouseMove(Event event)
+    {
+        if(!pressed) return;
+        bool mouseIn = mouseIn();
+        if(mouseIn is drawnMouseIn) return;
+        redraw();
+    }
+
+
+    private bool mouseIn()
+    {
+        Point p = toControl(display.getCursorLocation());
+        if(p.x < -1 || p.y < -1) return false;
+        Point size = getSize();
+        return p.x <= size.x+1 && p.y <= size.y+1;
+    }
+
+
+    public Point computeSize(int wHint, int hHint, bool changed)
+    {
+        checkWidget();
+        if(wHint is DWT.DEFAULT) wHint = 0;
+        if(hHint is DWT.DEFAULT) hHint = 0;
+        return new Point(wHint, hHint);
+    }
+
+
+    public bool setFocus()
+    {
+        checkWidget();
+        return false;
+    }
+
+
+    public bool isReparentable ()
+    {
+        checkWidget();
+        return false;
+    }
+
+
+    protected abstract void onPaint(Event event, bool pressed);
+}
--- a/dwtx/novocode/ishell/internal/DesktopListener.d	Sun Oct 26 14:57:25 2008 +0100
+++ b/dwtx/novocode/ishell/internal/DesktopListener.d	Sun Oct 26 15:04:41 2008 +0100
@@ -1,33 +1,33 @@
-/*******************************************************************************
- * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
- * 
- * Contributors:
- *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
- *******************************************************************************/
-
-module dwtx.novocode.ishell.internal.DesktopListener;
-
-import dwt.internal.DWTEventListener;
-import dwt.widgets.Event;
-
-
-/**
- * A listener which receives events when a change occurs on a DesktopForm.
- *
- * @author Stefan Zeiger (szeiger@novocode.com)
- * @since Jan 23, 2005
- * @version $Id: DesktopListener.java 320 2005-02-26 13:37:02 +0000 (Sat, 26 Feb 2005) szeiger $
- */
-
-interface DesktopListener : DWTEventListener
-{
-  public void shellCreated(Event event);
-  
-  public void shellDisposed(Event event);
-  
-  public void shellActivated(Event event);
-}
+/*******************************************************************************
+ * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
+ *******************************************************************************/
+
+module dwtx.novocode.ishell.internal.DesktopListener;
+
+import dwt.internal.DWTEventListener;
+import dwt.widgets.Event;
+
+
+/**
+ * A listener which receives events when a change occurs on a DesktopForm.
+ *
+ * @author Stefan Zeiger (szeiger@novocode.com)
+ * @since Jan 23, 2005
+ * @version $Id: DesktopListener.java 320 2005-02-26 13:37:02 +0000 (Sat, 26 Feb 2005) szeiger $
+ */
+
+interface DesktopListener : DWTEventListener
+{
+    public void shellCreated(Event event);
+
+    public void shellDisposed(Event event);
+
+    public void shellActivated(Event event);
+}
--- a/dwtx/novocode/ishell/internal/TitleBar.d	Sun Oct 26 14:57:25 2008 +0100
+++ b/dwtx/novocode/ishell/internal/TitleBar.d	Sun Oct 26 15:04:41 2008 +0100
@@ -1,567 +1,567 @@
-/*******************************************************************************
- * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
- *
- * Contributors:
- *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
- *******************************************************************************/
-
-module dwtx.novocode.ishell.internal.TitleBar;
-
-import dwt.dwthelper.utils;
-import dwt.dwthelper.Runnable;
-import dwtx.dwtxhelper.Timer;
-import dwtx.dwtxhelper.TimerTask;
-
-import dwt.DWT;
-import dwt.graphics.Color;
-import dwt.graphics.Font;
-import dwt.graphics.FontData;
-import dwt.graphics.GC;
-import dwt.graphics.Image;
-import dwt.graphics.ImageData;
-import dwt.graphics.PaletteData;
-import dwt.graphics.Point;
-import dwt.graphics.Rectangle;
-import dwt.graphics.RGB;
-import dwt.widgets.Canvas;
-import dwt.widgets.Display;
-import dwt.widgets.Event;
-import dwt.widgets.Listener;
-import dwt.widgets.Menu;
-import dwt.widgets.MenuItem;
-import dwt.widgets.Shell;
-
-import dwtx.novocode.ishell.DesktopForm;
-import dwtx.novocode.ishell.InternalShell;
-
-import dwt.dwthelper.utils;
-
-
-/**
- * A title bar for an InternalShell.
- *
- * @author Stefan Zeiger (szeiger@novocode.com)
- * @since Jan 21, 2005
- * @version $Id: TitleBar.java 342 2005-07-09 20:37:13 +0000 (Sat, 09 Jul 2005) szeiger $
- */
-
-class TitleBar : Canvas
-{
-  private static const long UPDATE_DELAY = 25;
-  private static const int MINIMUM_GRAB_AREA = 2;
-  private static const String ELLIPSIS = "...";
-  private static const int LEFT_PADDING = 2;
-  private static const int RIGHT_PADDING = 2;
-  private static const int IMAGE_SIZE = 16;
-  private static const int TOOL_SIZE = 14;
-  private static const int TOP_PADDING = 1;
-  private static const int BOTTOM_PADDING = 1;
-
-  private int mouseDownOffsetX, mouseDownOffsetY, snapBackX, snapBackY;
-  private bool cancelled;
-  private /**volatile*/ long lastUpdate;
-  private Timer timer;
-  private TimerTask timerTask;
-  private InternalShell ishell;
-  private DesktopForm desktop;
-  private String text;
-  private Image image;
-  private bool styleClose, styleMax, styleTool, styleMin;
-  private Image closeImage, restoreImage, maximizeImage, minimizeImage;
-  private MenuItem restoreItem, closeItem, maximizeItem;
-  private Menu defaultPopup;
-  private Point minGrabSize;
-  private Shell shell;
-  private Color gradStartColor, gradEndColor, textColor, inactiveGradStartColor, inactiveGradEndColor, inactiveTextColor;
-  private Listener activateListener, deactivateListener;
-
-
-  this(InternalShell parent, int style)
-  {
-    super(parent, checkStyle(style));
-    this.timer = new Timer(true);
-    this.minGrabSize = new Point(MINIMUM_GRAB_AREA, MINIMUM_GRAB_AREA);
-    this.ishell = parent;
-    this.desktop = cast(DesktopForm)ishell.getParent();
-    this.styleClose = (style & DWT.CLOSE) !is 0;
-    this.styleMax = (style & DWT.MAX) !is 0;
-    this.styleMin = (style & DWT.MIN) !is 0;
-    this.styleTool = (style & DWT.TOOL) !is 0;
-
-    Display display = getDisplay();
-    shell = getShell();
-
-    gradStartColor = display.getSystemColor(DWT.COLOR_TITLE_BACKGROUND);
-    gradEndColor = display.getSystemColor(DWT.COLOR_TITLE_BACKGROUND_GRADIENT);
-    textColor = display.getSystemColor(DWT.COLOR_TITLE_FOREGROUND);
-    inactiveGradStartColor = display.getSystemColor(DWT.COLOR_TITLE_INACTIVE_BACKGROUND);
-    inactiveGradEndColor = display.getSystemColor(DWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT);
-    inactiveTextColor = display.getSystemColor(DWT.COLOR_TITLE_INACTIVE_FOREGROUND);
-
-    GC gc = new GC(this);
-    int imgHeight = gc.getFontMetrics().getHeight()-1;
-    if(imgHeight%2 is 0) imgHeight--;
-    gc.dispose();
-
-    closeImage = createMenuImage(IMAGE_TYPE_CLOSE, imgHeight);
-    restoreImage = createMenuImage(IMAGE_TYPE_RESTORE, imgHeight);
-    maximizeImage = createMenuImage(IMAGE_TYPE_MAXIMIZE, imgHeight);
-    minimizeImage = createMenuImage(IMAGE_TYPE_MINIMIZE, imgHeight);
-
-    setFont(createTitleFont(getFont(), styleTool));
-
-    defaultPopup = new Menu(this);
-
-    restoreItem = new MenuItem(defaultPopup, DWT.PUSH);
-    restoreItem.setText("&Restore");
-    restoreItem.setImage(restoreImage);
-    restoreItem.addListener(DWT.Selection, dgListener(&restoreListener));
-
-    MenuItem minimizeItem = new MenuItem(defaultPopup, DWT.PUSH);
-    minimizeItem.setText("Mi&nimize");
-    minimizeItem.setEnabled(styleMin);
-    minimizeItem.setImage(minimizeImage);
-    minimizeItem.addListener(DWT.Selection, dgListener(&minimizeListener));
-
-    maximizeItem = new MenuItem(defaultPopup, DWT.PUSH);
-    maximizeItem.setText("Ma&ximize");
-    maximizeItem.setImage(maximizeImage);
-    maximizeItem.addListener(DWT.Selection, dgListener(&maximizeListener));
-
-    new MenuItem(defaultPopup, DWT.SEPARATOR);
-
-    closeItem = new MenuItem(defaultPopup, DWT.PUSH);
-    closeItem.setText("&Close");
-    closeItem.setEnabled(styleClose);
-    closeItem.setImage(closeImage);
-    closeItem.addListener(DWT.Selection, dgListener(&closeListener));
-
-    addListener(DWT.Paint, dgListener(&onPaint));
-    addListener(DWT.MouseDown, dgListener(&onMouseDown));
-    addListener(DWT.MenuDetect, dgListener(&onMenuDetect));
-    addListener(DWT.MouseDoubleClick, dgListener(&onMouseDoubleClick));
-    addListener(DWT.MouseMove, dgListener(&onMouseMove));
-    addListener(DWT.MouseUp, dgListener(&onMouseUp));
-
-    activateListener = dgListener(&onActivateListener);
-    deactivateListener = dgListener(&onDeactivateListener);
-    shell.addListener(DWT.Activate, activateListener);
-    shell.addListener(DWT.Deactivate, deactivateListener);
-
-    addListener(DWT.Dispose, dgListener(&onDispose));
-  }
-
-
-  private void restoreListener(Event event)
-  {
-    ishell.setMaximized(false);
-  }
-
-
-  private void minimizeListener(Event event)
-  {
-    ishell.setMinimized(true);
-  }
-
-
-  private void maximizeListener(Event event)
-  {
-    ishell.setMaximized(true);
-  }
-
-
-  private void closeListener(Event event)
-  {
-    ishell.close();
-  }
-
-
-  private void onPaint(Event event)
-  {
-        Rectangle r = getClientArea();
-        if(r.width is 0 || r.height is 0) return;
-
-        bool active = (shell is display.getActiveShell() && ishell.isActiveShell());
-
-        GC gc = event.gc;
-        gc.setForeground(active ? gradStartColor : inactiveGradStartColor);
-        gc.setBackground(active ? gradEndColor : inactiveGradEndColor);
-        gc.fillGradientRectangle(r.x, r.y, r.width, r.height, false);
-
-        int textLeftPadding = LEFT_PADDING;
-        if(image !is null)
-        {
-          Rectangle imageBounds = image.getBounds();
-          if(imageBounds.width > IMAGE_SIZE || imageBounds.height > IMAGE_SIZE)
-            gc.drawImage(image, 0, 0, imageBounds.width, imageBounds.height, LEFT_PADDING, TOP_PADDING, IMAGE_SIZE, IMAGE_SIZE);
-          else
-            gc.drawImage(image, LEFT_PADDING + (IMAGE_SIZE-imageBounds.width)/2, (r.height-imageBounds.height)/2);
-          textLeftPadding += IMAGE_SIZE + LEFT_PADDING;
-        }
-
-        if(text !is null && text.length() > 0)
-        {
-          gc.setForeground(active ? textColor : inactiveTextColor);
-          String s = text;
-          int availableWidth = r.width - textLeftPadding - RIGHT_PADDING;
-          if(gc.textExtent(s, DWT.DRAW_TRANSPARENT).x > availableWidth)
-          {
-            int ellipsisWidth = gc.textExtent(ELLIPSIS, DWT.DRAW_TRANSPARENT).x;
-            while(s.length() > 0)
-            {
-              s = s.substring(0, s.length()-1);
-              if(gc.textExtent(s, DWT.DRAW_TRANSPARENT).x + ellipsisWidth <= availableWidth)
-              {
-                s ~= ELLIPSIS;
-                break;
-              }
-            }
-            setToolTipText(text);
-          }
-          else setToolTipText(null);
-          if(s.length() > 0) gc.drawString(s, textLeftPadding, (r.height-gc.getFontMetrics().getHeight())/2, true);
-        }
-        else setToolTipText(null);
-  }
-
-
-  private void onMouseDown(Event event)
-  {
-        if(event.button is 1)
-        {
-          if(image !is null && event.x < LEFT_PADDING + IMAGE_SIZE)
-          {
-            cancelled = true;
-            // left-clicking on the image always shows the default popup menu
-            instrumentDefaultPopup(true);
-            defaultPopup.setLocation(toDisplay(0, getSize().y));
-            defaultPopup.setVisible(true);
-          }
-          else
-          {
-            mouseDownOffsetX = event.x;
-            mouseDownOffsetY = event.y;
-            Point p = ishell.getLocation();
-            snapBackX = p.x;
-            snapBackY = p.y;
-            cancelled = false;
-          }
-        }
-        else if(event.button is 3)
-        {
-          if((event.stateMask & DWT.BUTTON1) !is 0 && snapBackX !is Integer.MIN_VALUE && snapBackY !is Integer.MIN_VALUE)
-          {
-            ishell.setLocation(snapBackX, snapBackY);
-            snapBackX = Integer.MIN_VALUE;
-            snapBackY = Integer.MIN_VALUE;
-            cancelled = true;
-          }
-          else
-          {
-          }
-        }
-  }
-
-
-  private void onMenuDetect(Event event)
-  {
-        event.doit = false;
-        Menu m = getMenu();
-        if(m is null || m.isDisposed())
-        {
-          m = defaultPopup;
-          instrumentDefaultPopup(false);
-        }
-        m.setLocation(event.x, event.y);
-        m.setVisible(true);
-  }
-
-
-  private void onMouseDoubleClick(Event event)
-  {
-        if(event.button is 1)
-        {
-          if(image !is null && event.x < LEFT_PADDING + IMAGE_SIZE)
-          {
-            if(styleClose) ishell.close();
-          }
-          else
-          {
-            if(styleMax) ishell.setMaximized(!ishell.getMaximized());
-          }
-          cancelled = true;
-        }
-  }
-
-
-  private void onMouseMove(Event event)
-  {
-        if(!cancelled && (event.stateMask & DWT.BUTTON1) !is 0 && !ishell.getMaximized())
-        {
-          if(timerTask !is null)
-          {
-            timerTask.cancel();
-            timerTask = null;
-          }
-          long now = System.currentTimeMillis();
-          if(lastUpdate + UPDATE_DELAY < now)
-          {
-            performMove(event);
-            lastUpdate = now;
-          }
-          else
-          {
-            timerTask = new class() TimerTask
-            {
-              public void run()
-              {
-                TimerTask executingTask = this;
-                event.display.asyncExec(new class() Runnable
-                {
-                  public void run()
-                  {
-                    if(executingTask !is timerTask) return;
-                    performMove(event);
-                  }
-                });
-              }
-            };
-            timer.schedule(timerTask, UPDATE_DELAY);
-          }
-        }
-  }
-
-
-  private void onMouseUp(Event event)
-  {
-        if(ishell.getMaximized()) return;
-        if(image is null || event.x >= LEFT_PADDING + IMAGE_SIZE)
-        {
-          if(timerTask !is null)
-          {
-            timerTask.cancel();
-            timerTask = null;
-          }
-          if(!cancelled && (event.stateMask & DWT.BUTTON1) !is 0)
-          {
-            performMove(event);
-          }
-        }
-  }
-
-
-  private void onActivateListener(Event event)
-  {
-    redraw();
-  }
-
-
-  private void onDeactivateListener(Event event)
-  {
-    redraw();
-  }
-
-
-  private void onDispose(Event event)
-  {
-        timer.cancel();
-        shell.removeListener(DWT.Activate, activateListener);
-        shell.removeListener(DWT.Deactivate, deactivateListener);
-        closeImage.dispose();
-        maximizeImage.dispose();
-        restoreImage.dispose();
-        minimizeImage.dispose();
-        defaultPopup.dispose();
-  }
-
-
-  private void performMove(Event event)
-  {
-    Point p = ishell.getLocation();
-    int newX = p.x + event.x - mouseDownOffsetX;
-    int newY = p.y + event.y - mouseDownOffsetY;
-
-    // Make sure that the minimum grab area stays visible
-    Rectangle deskCA = desktop.getClientArea();
-    Rectangle bounds = getBounds();
-    newX = Math.min(Math.max(newX, deskCA.x-bounds.x-bounds.width+MINIMUM_GRAB_AREA), deskCA.x-bounds.x+deskCA.width-minGrabSize.x);
-    newY = Math.min(Math.max(newY, deskCA.y-bounds.y-bounds.height+MINIMUM_GRAB_AREA), deskCA.y-bounds.y+deskCA.height-MINIMUM_GRAB_AREA);
-
-    if(newX !is p.x || newY !is p.y) ishell.setLocation(newX, newY);
-  }
-
-
-  public Point getMinGrabSize()
-  {
-    return minGrabSize;
-  }
-
-
-  public Point computeSize(int wHint, int hHint, bool changed)
-  {
-    checkWidget();
-    if(wHint is DWT.DEFAULT) wHint = 50;
-    if(hHint is DWT.DEFAULT)
-    {
-      GC gc = new GC(this);
-      hHint = gc.getFontMetrics().getHeight();
-      hHint = Math.max(hHint, styleTool ?  TOOL_SIZE : IMAGE_SIZE);
-      hHint += TOP_PADDING + BOTTOM_PADDING;
-      gc.dispose();
-    }
-    return new Point(wHint, hHint);
-  }
-
-
-  private static int checkStyle(int style)
-  {
-    //int mask = DWT.SHADOW_IN | DWT.FLAT;
-    //style &= mask;
-    style = DWT.NO_FOCUS;
-    return style;
-  }
-
-
-  public bool setFocus()
-  {
-    checkWidget();
-    return false;
-  }
-
-
-  public bool isReparentable ()
-  {
-    checkWidget();
-    return false;
-  }
-
-
-  public void setText(String text)
-  {
-    checkWidget();
-    this.text = text;
-    redraw();
-  }
-
-
-  public String getText() { return text; }
-
-
-  public void setImage(Image image)
-  {
-    checkWidget();
-    if(styleTool) return;
-    this.image = image;
-    minGrabSize.x = MINIMUM_GRAB_AREA;
-    if(image !is null) minGrabSize.x += LEFT_PADDING + IMAGE_SIZE;
-    redraw();
-  }
-
-
-  public Image getImage() { return image; }
-
-
-  private Font createTitleFont(Font f, bool tool)
-  {
-    FontData[] fds = f.getFontData();
-    foreach(fd; fds)
-    {
-      fd.setStyle(fd.getStyle() | DWT.BOLD);
-      if(tool) fd.setHeight(cast(int)(fd.getHeight()*0.9));
-    }
-    return new Font(getDisplay(), fds);
-  }
-
-
-  private void instrumentDefaultPopup(bool onImage)
-  {
-    restoreItem.setEnabled(styleMax && ishell.getMaximized());
-    maximizeItem.setEnabled(styleMax && !ishell.getMaximized());
-    MenuItem def = null;
-    if(onImage)
-    {
-      if(styleClose) def = closeItem;
-    }
-    else if(styleMax)
-    {
-      def = ishell.getMaximized() ? restoreItem : maximizeItem;
-    }
-    defaultPopup.setDefaultItem(def);
-  }
-
-
-  private static const int IMAGE_TYPE_CLOSE    = 1;
-  private static const int IMAGE_TYPE_MAXIMIZE = 2;
-  private static const int IMAGE_TYPE_RESTORE  = 3;
-  private static const int IMAGE_TYPE_MINIMIZE = 4;
-
-
-  private Image createMenuImage(int type, int height)
-  {
-    final Point size = new Point(height, height);
-    final int imgWidth = height + height/2;
-    final Color fg = getForeground();
-    final Color white = getDisplay().getSystemColor(DWT.COLOR_WHITE);
-    final RGB blackRGB = new RGB(0,0,0);
-
-    ImageData id = new ImageData(imgWidth, size.y, 1, new PaletteData([ blackRGB, fg.getRGB() ]));
-    ImageData maskid = new ImageData(imgWidth, size.y, 1, new PaletteData([ blackRGB, white.getRGB() ]));
-
-    Image img = new Image(getDisplay(), id);
-    GC gc = new GC(img);
-    gc.setForeground(fg);
-    drawMenuImage(gc, size, type);
-    gc.dispose();
-
-    Image maskimg = new Image(getDisplay(), maskid);
-    gc = new GC(maskimg);
-    gc.setForeground(white);
-    drawMenuImage(gc, size, type);
-    gc.dispose();
-
-    Image transp = new Image(getDisplay(), img.getImageData(), maskimg.getImageData());
-    img.dispose();
-    maskimg.dispose();
-    return transp;
-  }
-
-
-  private void drawMenuImage(GC gc, Point size, int type)
-  {
-    switch(type)
-    {
-      case IMAGE_TYPE_CLOSE:
-        gc.drawLine(1, 1, size.x-2, size.y-2);
-        gc.drawLine(2, 1, size.x-2, size.y-3);
-        gc.drawLine(1, 2, size.x-3, size.y-2);
-        gc.drawLine(1, size.y-2, size.x-2, 1);
-        gc.drawLine(1, size.y-3, size.x-3, 1);
-        gc.drawLine(2, size.y-2, size.x-2, 2);
-        break;
-
-      case IMAGE_TYPE_RESTORE:
-        gc.drawRectangle(0, 4, size.x-4, size.y-6);
-        gc.drawLine(1, 5, size.x-5, 5);
-        gc.drawLine(2, 1, size.x-2, 1);
-        gc.drawLine(2, 2, size.x-2, 2);
-        gc.drawPoint(2, 3);
-        gc.drawLine(size.x-2, 3, size.x-2, size.y-5);
-        gc.drawPoint(size.x-3, size.y-5);
-        break;
-
-      case IMAGE_TYPE_MAXIMIZE:
-        gc.drawRectangle(0, 0, size.x-2, size.y-2);
-        gc.drawLine(1, 1, size.x-3, 1);
-        break;
-
-      case IMAGE_TYPE_MINIMIZE:
-        gc.drawLine(1, size.y-2, size.x-4, size.y-2);
-        gc.drawLine(1, size.y-3, size.x-4, size.y-3);
-        break;
-    }
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
+ *******************************************************************************/
+
+module dwtx.novocode.ishell.internal.TitleBar;
+
+import dwt.dwthelper.utils;
+import dwt.dwthelper.Runnable;
+import dwtx.dwtxhelper.Timer;
+import dwtx.dwtxhelper.TimerTask;
+
+import dwt.DWT;
+import dwt.graphics.Color;
+import dwt.graphics.Font;
+import dwt.graphics.FontData;
+import dwt.graphics.GC;
+import dwt.graphics.Image;
+import dwt.graphics.ImageData;
+import dwt.graphics.PaletteData;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.graphics.RGB;
+import dwt.widgets.Canvas;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.widgets.Menu;
+import dwt.widgets.MenuItem;
+import dwt.widgets.Shell;
+
+import dwtx.novocode.ishell.DesktopForm;
+import dwtx.novocode.ishell.InternalShell;
+
+import dwt.dwthelper.utils;
+
+
+/**
+ * A title bar for an InternalShell.
+ *
+ * @author Stefan Zeiger (szeiger@novocode.com)
+ * @since Jan 21, 2005
+ * @version $Id: TitleBar.java 342 2005-07-09 20:37:13 +0000 (Sat, 09 Jul 2005) szeiger $
+ */
+
+class TitleBar : Canvas
+{
+    private static const long UPDATE_DELAY = 25;
+    private static const int MINIMUM_GRAB_AREA = 2;
+    private static const String ELLIPSIS = "...";
+    private static const int LEFT_PADDING = 2;
+    private static const int RIGHT_PADDING = 2;
+    private static const int IMAGE_SIZE = 16;
+    private static const int TOOL_SIZE = 14;
+    private static const int TOP_PADDING = 1;
+    private static const int BOTTOM_PADDING = 1;
+
+    private int mouseDownOffsetX, mouseDownOffsetY, snapBackX, snapBackY;
+    private bool cancelled;
+    private /**volatile*/ long lastUpdate;
+    private Timer timer;
+    private TimerTask timerTask;
+    private InternalShell ishell;
+    private DesktopForm desktop;
+    private String text;
+    private Image image;
+    private bool styleClose, styleMax, styleTool, styleMin;
+    private Image closeImage, restoreImage, maximizeImage, minimizeImage;
+    private MenuItem restoreItem, closeItem, maximizeItem;
+    private Menu defaultPopup;
+    private Point minGrabSize;
+    private Shell shell;
+    private Color gradStartColor, gradEndColor, textColor, inactiveGradStartColor, inactiveGradEndColor, inactiveTextColor;
+    private Listener activateListener, deactivateListener;
+
+
+    this(InternalShell parent, int style)
+    {
+        super(parent, checkStyle(style));
+        this.timer = new Timer(true);
+        this.minGrabSize = new Point(MINIMUM_GRAB_AREA, MINIMUM_GRAB_AREA);
+        this.ishell = parent;
+        this.desktop = cast(DesktopForm)ishell.getParent();
+        this.styleClose = (style & DWT.CLOSE) !is 0;
+        this.styleMax = (style & DWT.MAX) !is 0;
+        this.styleMin = (style & DWT.MIN) !is 0;
+        this.styleTool = (style & DWT.TOOL) !is 0;
+
+        Display display = getDisplay();
+        shell = getShell();
+
+        gradStartColor = display.getSystemColor(DWT.COLOR_TITLE_BACKGROUND);
+        gradEndColor = display.getSystemColor(DWT.COLOR_TITLE_BACKGROUND_GRADIENT);
+        textColor = display.getSystemColor(DWT.COLOR_TITLE_FOREGROUND);
+        inactiveGradStartColor = display.getSystemColor(DWT.COLOR_TITLE_INACTIVE_BACKGROUND);
+        inactiveGradEndColor = display.getSystemColor(DWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT);
+        inactiveTextColor = display.getSystemColor(DWT.COLOR_TITLE_INACTIVE_FOREGROUND);
+
+        GC gc = new GC(this);
+        int imgHeight = gc.getFontMetrics().getHeight()-1;
+        if(imgHeight%2 is 0) imgHeight--;
+        gc.dispose();
+
+        closeImage = createMenuImage(IMAGE_TYPE_CLOSE, imgHeight);
+        restoreImage = createMenuImage(IMAGE_TYPE_RESTORE, imgHeight);
+        maximizeImage = createMenuImage(IMAGE_TYPE_MAXIMIZE, imgHeight);
+        minimizeImage = createMenuImage(IMAGE_TYPE_MINIMIZE, imgHeight);
+
+        setFont(createTitleFont(getFont(), styleTool));
+
+        defaultPopup = new Menu(this);
+
+        restoreItem = new MenuItem(defaultPopup, DWT.PUSH);
+        restoreItem.setText("&Restore");
+        restoreItem.setImage(restoreImage);
+        restoreItem.addListener(DWT.Selection, dgListener(&restoreListener));
+
+        MenuItem minimizeItem = new MenuItem(defaultPopup, DWT.PUSH);
+        minimizeItem.setText("Mi&nimize");
+        minimizeItem.setEnabled(styleMin);
+        minimizeItem.setImage(minimizeImage);
+        minimizeItem.addListener(DWT.Selection, dgListener(&minimizeListener));
+
+        maximizeItem = new MenuItem(defaultPopup, DWT.PUSH);
+        maximizeItem.setText("Ma&ximize");
+        maximizeItem.setImage(maximizeImage);
+        maximizeItem.addListener(DWT.Selection, dgListener(&maximizeListener));
+
+        new MenuItem(defaultPopup, DWT.SEPARATOR);
+
+        closeItem = new MenuItem(defaultPopup, DWT.PUSH);
+        closeItem.setText("&Close");
+        closeItem.setEnabled(styleClose);
+        closeItem.setImage(closeImage);
+        closeItem.addListener(DWT.Selection, dgListener(&closeListener));
+
+        addListener(DWT.Paint, dgListener(&onPaint));
+        addListener(DWT.MouseDown, dgListener(&onMouseDown));
+        addListener(DWT.MenuDetect, dgListener(&onMenuDetect));
+        addListener(DWT.MouseDoubleClick, dgListener(&onMouseDoubleClick));
+        addListener(DWT.MouseMove, dgListener(&onMouseMove));
+        addListener(DWT.MouseUp, dgListener(&onMouseUp));
+
+        activateListener = dgListener(&onActivateListener);
+        deactivateListener = dgListener(&onDeactivateListener);
+        shell.addListener(DWT.Activate, activateListener);
+        shell.addListener(DWT.Deactivate, deactivateListener);
+
+        addListener(DWT.Dispose, dgListener(&onDispose));
+    }
+
+
+    private void restoreListener(Event event)
+    {
+        ishell.setMaximized(false);
+    }
+
+
+    private void minimizeListener(Event event)
+    {
+        ishell.setMinimized(true);
+    }
+
+
+    private void maximizeListener(Event event)
+    {
+        ishell.setMaximized(true);
+    }
+
+
+    private void closeListener(Event event)
+    {
+        ishell.close();
+    }
+
+
+    private void onPaint(Event event)
+    {
+        Rectangle r = getClientArea();
+        if(r.width is 0 || r.height is 0) return;
+
+        bool active = (shell is display.getActiveShell() && ishell.isActiveShell());
+
+        GC gc = event.gc;
+        gc.setForeground(active ? gradStartColor : inactiveGradStartColor);
+        gc.setBackground(active ? gradEndColor : inactiveGradEndColor);
+        gc.fillGradientRectangle(r.x, r.y, r.width, r.height, false);
+
+        int textLeftPadding = LEFT_PADDING;
+        if(image !is null)
+        {
+            Rectangle imageBounds = image.getBounds();
+            if(imageBounds.width > IMAGE_SIZE || imageBounds.height > IMAGE_SIZE)
+                gc.drawImage(image, 0, 0, imageBounds.width, imageBounds.height, LEFT_PADDING, TOP_PADDING, IMAGE_SIZE, IMAGE_SIZE);
+            else
+                gc.drawImage(image, LEFT_PADDING + (IMAGE_SIZE-imageBounds.width)/2, (r.height-imageBounds.height)/2);
+            textLeftPadding += IMAGE_SIZE + LEFT_PADDING;
+        }
+
+        if(text !is null && text.length() > 0)
+        {
+            gc.setForeground(active ? textColor : inactiveTextColor);
+            String s = text;
+            int availableWidth = r.width - textLeftPadding - RIGHT_PADDING;
+            if(gc.textExtent(s, DWT.DRAW_TRANSPARENT).x > availableWidth)
+            {
+                int ellipsisWidth = gc.textExtent(ELLIPSIS, DWT.DRAW_TRANSPARENT).x;
+                while(s.length() > 0)
+                {
+                    s = s.substring(0, s.length()-1);
+                    if(gc.textExtent(s, DWT.DRAW_TRANSPARENT).x + ellipsisWidth <= availableWidth)
+                    {
+                        s ~= ELLIPSIS;
+                        break;
+                    }
+                }
+                setToolTipText(text);
+            }
+            else setToolTipText(null);
+            if(s.length() > 0) gc.drawString(s, textLeftPadding, (r.height-gc.getFontMetrics().getHeight())/2, true);
+        }
+        else setToolTipText(null);
+    }
+
+
+    private void onMouseDown(Event event)
+    {
+        if(event.button is 1)
+        {
+            if(image !is null && event.x < LEFT_PADDING + IMAGE_SIZE)
+            {
+                cancelled = true;
+                // left-clicking on the image always shows the default popup menu
+                instrumentDefaultPopup(true);
+                defaultPopup.setLocation(toDisplay(0, getSize().y));
+                defaultPopup.setVisible(true);
+            }
+            else
+            {
+                mouseDownOffsetX = event.x;
+                mouseDownOffsetY = event.y;
+                Point p = ishell.getLocation();
+                snapBackX = p.x;
+                snapBackY = p.y;
+                cancelled = false;
+            }
+        }
+        else if(event.button is 3)
+        {
+            if((event.stateMask & DWT.BUTTON1) !is 0 && snapBackX !is Integer.MIN_VALUE && snapBackY !is Integer.MIN_VALUE)
+            {
+                ishell.setLocation(snapBackX, snapBackY);
+                snapBackX = Integer.MIN_VALUE;
+                snapBackY = Integer.MIN_VALUE;
+                cancelled = true;
+            }
+            else
+            {
+            }
+        }
+    }
+
+
+    private void onMenuDetect(Event event)
+    {
+        event.doit = false;
+        Menu m = getMenu();
+        if(m is null || m.isDisposed())
+        {
+            m = defaultPopup;
+            instrumentDefaultPopup(false);
+        }
+        m.setLocation(event.x, event.y);
+        m.setVisible(true);
+    }
+
+
+    private void onMouseDoubleClick(Event event)
+    {
+        if(event.button is 1)
+        {
+            if(image !is null && event.x < LEFT_PADDING + IMAGE_SIZE)
+            {
+                if(styleClose) ishell.close();
+            }
+            else
+            {
+                if(styleMax) ishell.setMaximized(!ishell.getMaximized());
+            }
+            cancelled = true;
+        }
+    }
+
+
+    private void onMouseMove(Event event)
+    {
+        if(!cancelled && (event.stateMask & DWT.BUTTON1) !is 0 && !ishell.getMaximized())
+        {
+            if(timerTask !is null)
+            {
+                timerTask.cancel();
+                timerTask = null;
+            }
+            long now = System.currentTimeMillis();
+            if(lastUpdate + UPDATE_DELAY < now)
+            {
+                performMove(event);
+                lastUpdate = now;
+            }
+            else
+            {
+                timerTask = new class() TimerTask
+                {
+                    public void run()
+                    {
+                        TimerTask executingTask = this;
+                        event.display.asyncExec(new class() Runnable
+                            {
+                                public void run()
+                                {
+                                    if(executingTask !is timerTask) return;
+                                    performMove(event);
+                                }
+                            });
+                    }
+                };
+                timer.schedule(timerTask, UPDATE_DELAY);
+            }
+        }
+    }
+
+
+    private void onMouseUp(Event event)
+    {
+        if(ishell.getMaximized()) return;
+        if(image is null || event.x >= LEFT_PADDING + IMAGE_SIZE)
+        {
+            if(timerTask !is null)
+            {
+                timerTask.cancel();
+                timerTask = null;
+            }
+            if(!cancelled && (event.stateMask & DWT.BUTTON1) !is 0)
+            {
+                performMove(event);
+            }
+        }
+    }
+
+
+    private void onActivateListener(Event event)
+    {
+        redraw();
+    }
+
+
+    private void onDeactivateListener(Event event)
+    {
+        redraw();
+    }
+
+
+    private void onDispose(Event event)
+    {
+        timer.cancel();
+        shell.removeListener(DWT.Activate, activateListener);
+        shell.removeListener(DWT.Deactivate, deactivateListener);
+        closeImage.dispose();
+        maximizeImage.dispose();
+        restoreImage.dispose();
+        minimizeImage.dispose();
+        defaultPopup.dispose();
+    }
+
+
+    private void performMove(Event event)
+    {
+        Point p = ishell.getLocation();
+        int newX = p.x + event.x - mouseDownOffsetX;
+        int newY = p.y + event.y - mouseDownOffsetY;
+
+        // Make sure that the minimum grab area stays visible
+        Rectangle deskCA = desktop.getClientArea();
+        Rectangle bounds = getBounds();
+        newX = Math.min(Math.max(newX, deskCA.x-bounds.x-bounds.width+MINIMUM_GRAB_AREA), deskCA.x-bounds.x+deskCA.width-minGrabSize.x);
+        newY = Math.min(Math.max(newY, deskCA.y-bounds.y-bounds.height+MINIMUM_GRAB_AREA), deskCA.y-bounds.y+deskCA.height-MINIMUM_GRAB_AREA);
+
+        if(newX !is p.x || newY !is p.y) ishell.setLocation(newX, newY);
+    }
+
+
+    public Point getMinGrabSize()
+    {
+        return minGrabSize;
+    }
+
+
+    public Point computeSize(int wHint, int hHint, bool changed)
+    {
+        checkWidget();
+        if(wHint is DWT.DEFAULT) wHint = 50;
+        if(hHint is DWT.DEFAULT)
+        {
+            GC gc = new GC(this);
+            hHint = gc.getFontMetrics().getHeight();
+            hHint = Math.max(hHint, styleTool ?  TOOL_SIZE : IMAGE_SIZE);
+            hHint += TOP_PADDING + BOTTOM_PADDING;
+            gc.dispose();
+        }
+        return new Point(wHint, hHint);
+    }
+
+
+    private static int checkStyle(int style)
+    {
+        //int mask = DWT.SHADOW_IN | DWT.FLAT;
+        //style &= mask;
+        style = DWT.NO_FOCUS;
+        return style;
+    }
+
+
+    public bool setFocus()
+    {
+        checkWidget();
+        return false;
+    }
+
+
+    public bool isReparentable ()
+    {
+        checkWidget();
+        return false;
+    }
+
+
+    public void setText(String text)
+    {
+        checkWidget();
+        this.text = text;
+        redraw();
+    }
+
+
+    public String getText() { return text; }
+
+
+    public void setImage(Image image)
+    {
+        checkWidget();
+        if(styleTool) return;
+        this.image = image;
+        minGrabSize.x = MINIMUM_GRAB_AREA;
+        if(image !is null) minGrabSize.x += LEFT_PADDING + IMAGE_SIZE;
+        redraw();
+    }
+
+
+    public Image getImage() { return image; }
+
+
+    private Font createTitleFont(Font f, bool tool)
+    {
+        FontData[] fds = f.getFontData();
+        foreach(fd; fds)
+        {
+            fd.setStyle(fd.getStyle() | DWT.BOLD);
+            if(tool) fd.setHeight(cast(int)(fd.getHeight()*0.9));
+        }
+        return new Font(getDisplay(), fds);
+    }
+
+
+    private void instrumentDefaultPopup(bool onImage)
+    {
+        restoreItem.setEnabled(styleMax && ishell.getMaximized());
+        maximizeItem.setEnabled(styleMax && !ishell.getMaximized());
+        MenuItem def = null;
+        if(onImage)
+        {
+            if(styleClose) def = closeItem;
+        }
+        else if(styleMax)
+        {
+            def = ishell.getMaximized() ? restoreItem : maximizeItem;
+        }
+        defaultPopup.setDefaultItem(def);
+    }
+
+
+    private static const int IMAGE_TYPE_CLOSE    = 1;
+    private static const int IMAGE_TYPE_MAXIMIZE = 2;
+    private static const int IMAGE_TYPE_RESTORE  = 3;
+    private static const int IMAGE_TYPE_MINIMIZE = 4;
+
+
+    private Image createMenuImage(int type, int height)
+    {
+        final Point size = new Point(height, height);
+        final int imgWidth = height + height/2;
+        final Color fg = getForeground();
+        final Color white = getDisplay().getSystemColor(DWT.COLOR_WHITE);
+        final RGB blackRGB = new RGB(0,0,0);
+
+        ImageData id = new ImageData(imgWidth, size.y, 1, new PaletteData([ blackRGB, fg.getRGB() ]));
+        ImageData maskid = new ImageData(imgWidth, size.y, 1, new PaletteData([ blackRGB, white.getRGB() ]));
+
+        Image img = new Image(getDisplay(), id);
+        GC gc = new GC(img);
+        gc.setForeground(fg);
+        drawMenuImage(gc, size, type);
+        gc.dispose();
+
+        Image maskimg = new Image(getDisplay(), maskid);
+        gc = new GC(maskimg);
+        gc.setForeground(white);
+        drawMenuImage(gc, size, type);
+        gc.dispose();
+
+        Image transp = new Image(getDisplay(), img.getImageData(), maskimg.getImageData());
+        img.dispose();
+        maskimg.dispose();
+        return transp;
+    }
+
+
+    private void drawMenuImage(GC gc, Point size, int type)
+    {
+        switch(type)
+        {
+            case IMAGE_TYPE_CLOSE:
+                gc.drawLine(1, 1, size.x-2, size.y-2);
+                gc.drawLine(2, 1, size.x-2, size.y-3);
+                gc.drawLine(1, 2, size.x-3, size.y-2);
+                gc.drawLine(1, size.y-2, size.x-2, 1);
+                gc.drawLine(1, size.y-3, size.x-3, 1);
+                gc.drawLine(2, size.y-2, size.x-2, 2);
+                break;
+
+            case IMAGE_TYPE_RESTORE:
+                gc.drawRectangle(0, 4, size.x-4, size.y-6);
+                gc.drawLine(1, 5, size.x-5, 5);
+                gc.drawLine(2, 1, size.x-2, 1);
+                gc.drawLine(2, 2, size.x-2, 2);
+                gc.drawPoint(2, 3);
+                gc.drawLine(size.x-2, 3, size.x-2, size.y-5);
+                gc.drawPoint(size.x-3, size.y-5);
+                break;
+
+            case IMAGE_TYPE_MAXIMIZE:
+                gc.drawRectangle(0, 0, size.x-2, size.y-2);
+                gc.drawLine(1, 1, size.x-3, 1);
+                break;
+
+            case IMAGE_TYPE_MINIMIZE:
+                gc.drawLine(1, size.y-2, size.x-4, size.y-2);
+                gc.drawLine(1, size.y-3, size.x-4, size.y-3);
+                break;
+        }
+    }
+}
--- a/dwtx/novocode/ishell/internal/TitleBarButton.d	Sun Oct 26 14:57:25 2008 +0100
+++ b/dwtx/novocode/ishell/internal/TitleBarButton.d	Sun Oct 26 15:04:41 2008 +0100
@@ -1,205 +1,205 @@
-/*******************************************************************************
- * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
- *
- * Contributors:
- *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
- *******************************************************************************/
-
-module dwtx.novocode.ishell.internal.TitleBarButton;
-
-import dwt.DWT;
-import dwt.graphics.Color;
-import dwt.graphics.GC;
-import dwt.graphics.Point;
-import dwt.widgets.Display;
-import dwt.widgets.Event;
-import dwt.widgets.Listener;
-import dwt.widgets.Shell;
-
-import dwtx.novocode.ishell.InternalShell;
-import dwtx.novocode.ishell.internal.CustomDrawnButton;
-
-
-/**
- * A title bar button for an InternalShell.
- *
- * @author Stefan Zeiger (szeiger@novocode.com)
- * @since Jan 30, 2005
- * @version $Id: TitleBarButton.java 322 2005-02-26 20:31:26 +0000 (Sat, 26 Feb 2005) szeiger $
- */
-
-class TitleBarButton : CustomDrawnButton
-{
-  private Color highlightShadowColor, lightShadowColor, normalShadowColor, darkShadowColor;
-  private Color gradEndColor, inactiveGradEndColor, widgetBackgroundColor, widgetForegroundColor;
-  private int style;
-  private Shell shell;
-  private Display display;
-  private InternalShell ishell;
-  private int leftOff, rightOff;
-  private Listener activateListener, deactivateListener;
-
-  this(InternalShell parent, int style)
-  {
-    super(parent, DWT.NO_FOCUS | DWT.NO_BACKGROUND);
-    this.style = style;
-    this.shell = getShell();
-    this.display = getDisplay();
-    this.ishell = parent;
-
-    highlightShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
-    lightShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_LIGHT_SHADOW);
-    normalShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
-    darkShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_DARK_SHADOW);
-    gradEndColor = display.getSystemColor(DWT.COLOR_TITLE_BACKGROUND_GRADIENT);
-    inactiveGradEndColor = display.getSystemColor(DWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT);
-    widgetBackgroundColor = display.getSystemColor(DWT.COLOR_WIDGET_BACKGROUND);
-    widgetForegroundColor = display.getSystemColor(DWT.COLOR_WIDGET_FOREGROUND);
-
-    if((style & (DWT.CLOSE | DWT.MAX)) !is 0) rightOff = 2;
-    else leftOff = 2;
-
-    activateListener = dgListener(&onActivateListener);
-    deactivateListener = dgListener(&onDeactivateListener);
-    shell.addListener(DWT.Activate, activateListener);
-    shell.addListener(DWT.Deactivate, deactivateListener);
-
-    addListener(DWT.Dispose, dgListener(&onDispose));
-  }
-
-
-  private void onActivateListener(Event event)
-  {
-      redraw();
-  }
-
-
-  private void onDeactivateListener(Event event)
-  {
-      redraw();
-  }
-
-
-  private void onDispose(Event event)
-  {
-        shell.removeListener(DWT.Activate, activateListener);
-        shell.removeListener(DWT.Deactivate, deactivateListener);
-  }
-
-
-  public int getStyle()
-  {
-    return style;
-  }
-
-
-  protected void onPaint(Event event, bool pressed)
-  {
-    Point size = getSize();
-    bool active = (shell is display.getActiveShell() && ishell.isActiveShell());
-    GC gc = event.gc;
-
-    gc.setBackground(active ? gradEndColor : inactiveGradEndColor);
-    gc.fillRectangle(0, 0, size.x, size.y);
-    gc.setBackground(widgetBackgroundColor);
-    gc.fillRectangle(2, 4, size.x-4, size.y-6);
-
-    Color tloColor, tliColor, broColor, briColor;
-    int pOff;
-    if(pressed)
-    {
-      tloColor = darkShadowColor;
-      tliColor = normalShadowColor;
-      broColor = highlightShadowColor;
-      briColor = lightShadowColor;
-      pOff = 1;
-    }
-    else
-    {
-      tloColor = highlightShadowColor;
-      tliColor = lightShadowColor;
-      broColor = darkShadowColor;
-      briColor = normalShadowColor;
-      pOff = 0;
-    }
-
-    drawBevelRect(gc, leftOff, 2, size.x-1-leftOff-rightOff, size.y-5, tloColor, broColor);
-    drawBevelRect(gc, 1+leftOff, 3, size.x-3-leftOff-rightOff, size.y-7, tliColor, briColor);
-
-    if(isEnabled())
-    {
-      gc.setForeground(widgetForegroundColor);
-      drawImage(gc, size, pOff);
-    }
-    else
-    {
-      gc.setForeground(highlightShadowColor);
-      drawImage(gc, size, 1);
-      gc.setForeground(normalShadowColor);
-      drawImage(gc, size, 0);
-    }
-  }
-
-
-  private void drawImage(GC gc, Point size, int pOff)
-  {
-    if((style & DWT.CLOSE) !is 0) drawCloseImage(gc, size, pOff);
-    else if((style & DWT.MAX) !is 0)
-    {
-      if(ishell.getMaximized()) drawRestoreImage(gc, size, pOff);
-      else drawMaximizeImage(gc, size, pOff);
-    }
-    else if((style & DWT.MIN) !is 0) drawMinimizeImage(gc, size, pOff);
-  }
-
-
-  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);
-  }
-
-
-  private void drawCloseImage(GC gc, Point size, int pOff)
-  {
-    gc.drawLine(pOff+leftOff+4, pOff+5, pOff+size.x-leftOff-rightOff-6, pOff+size.y-7);
-    gc.drawLine(pOff+leftOff+5, pOff+5, pOff+size.x-leftOff-rightOff-5, pOff+size.y-7);
-    gc.drawLine(pOff+leftOff+4, pOff+size.y-7, pOff+size.x-leftOff-rightOff-6, pOff+5);
-    gc.drawLine(pOff+leftOff+5, pOff+size.y-7, pOff+size.x-leftOff-rightOff-5, pOff+5);
-  }
-
-
-  private void drawRestoreImage(GC gc, Point size, int pOff)
-  {
-    gc.drawRectangle(pOff+leftOff+3, pOff+7, size.x-leftOff-rightOff-11, size.y-13);
-    gc.drawLine(pOff+leftOff+4, pOff+8, pOff+size.x-leftOff-rightOff-9, pOff+8);
-    gc.drawLine(pOff+leftOff+6, pOff+5, pOff+size.x-leftOff-rightOff-7, pOff+5);
-    gc.drawLine(pOff+leftOff+5, pOff+4, pOff+size.x-leftOff-rightOff-6, pOff+4);
-    gc.drawLine(pOff+size.x-leftOff-rightOff-7, pOff+size.y-9, pOff+size.x-leftOff-rightOff-6, pOff+size.y-9);
-    gc.drawLine(pOff+size.x-leftOff-rightOff-6, pOff+size.y-10, pOff+size.x-leftOff-rightOff-6, pOff+5);
-    gc.drawLine(pOff+leftOff+5, pOff+5, pOff+leftOff+5, pOff+6);
-  }
-
-
-  private void drawMaximizeImage(GC gc, Point size, int pOff)
-  {
-    gc.drawRectangle(pOff+leftOff+3, pOff+4, size.x-leftOff-rightOff-8, size.y-10);
-    gc.drawLine(pOff+leftOff+4, pOff+5, pOff+size.x-leftOff-rightOff-6, pOff+5);
-  }
-
-
-  private void drawMinimizeImage(GC gc, Point size, int pOff)
-  {
-    gc.drawLine(pOff+leftOff+4, pOff+size.y-6, pOff+size.x-leftOff-rightOff-5, pOff+size.y-6);
-    gc.drawLine(pOff+leftOff+4, pOff+size.y-7, pOff+size.x-leftOff-rightOff-5, pOff+size.y-7);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2005 Stefan Zeiger 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.novocode.com/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
+ *******************************************************************************/
+
+module dwtx.novocode.ishell.internal.TitleBarButton;
+
+import dwt.DWT;
+import dwt.graphics.Color;
+import dwt.graphics.GC;
+import dwt.graphics.Point;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.widgets.Shell;
+
+import dwtx.novocode.ishell.InternalShell;
+import dwtx.novocode.ishell.internal.CustomDrawnButton;
+
+
+/**
+ * A title bar button for an InternalShell.
+ *
+ * @author Stefan Zeiger (szeiger@novocode.com)
+ * @since Jan 30, 2005
+ * @version $Id: TitleBarButton.java 322 2005-02-26 20:31:26 +0000 (Sat, 26 Feb 2005) szeiger $
+ */
+
+class TitleBarButton : CustomDrawnButton
+{
+    private Color highlightShadowColor, lightShadowColor, normalShadowColor, darkShadowColor;
+    private Color gradEndColor, inactiveGradEndColor, widgetBackgroundColor, widgetForegroundColor;
+    private int style;
+    private Shell shell;
+    private Display display;
+    private InternalShell ishell;
+    private int leftOff, rightOff;
+    private Listener activateListener, deactivateListener;
+
+    this(InternalShell parent, int style)
+    {
+        super(parent, DWT.NO_FOCUS | DWT.NO_BACKGROUND);
+        this.style = style;
+        this.shell = getShell();
+        this.display = getDisplay();
+        this.ishell = parent;
+
+        highlightShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
+        lightShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_LIGHT_SHADOW);
+        normalShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
+        darkShadowColor = display.getSystemColor(DWT.COLOR_WIDGET_DARK_SHADOW);
+        gradEndColor = display.getSystemColor(DWT.COLOR_TITLE_BACKGROUND_GRADIENT);
+        inactiveGradEndColor = display.getSystemColor(DWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT);
+        widgetBackgroundColor = display.getSystemColor(DWT.COLOR_WIDGET_BACKGROUND);
+        widgetForegroundColor = display.getSystemColor(DWT.COLOR_WIDGET_FOREGROUND);
+
+        if((style & (DWT.CLOSE | DWT.MAX)) !is 0) rightOff = 2;
+        else leftOff = 2;
+
+        activateListener = dgListener(&onActivateListener);
+        deactivateListener = dgListener(&onDeactivateListener);
+        shell.addListener(DWT.Activate, activateListener);
+        shell.addListener(DWT.Deactivate, deactivateListener);
+
+        addListener(DWT.Dispose, dgListener(&onDispose));
+    }
+
+
+    private void onActivateListener(Event event)
+    {
+        redraw();
+    }
+
+
+    private void onDeactivateListener(Event event)
+    {
+        redraw();
+    }
+
+
+    private void onDispose(Event event)
+    {
+        shell.removeListener(DWT.Activate, activateListener);
+        shell.removeListener(DWT.Deactivate, deactivateListener);
+    }
+
+
+    public int getStyle()
+    {
+        return style;
+    }
+
+
+    protected void onPaint(Event event, bool pressed)
+    {
+        Point size = getSize();
+        bool active = (shell is display.getActiveShell() && ishell.isActiveShell());
+        GC gc = event.gc;
+
+        gc.setBackground(active ? gradEndColor : inactiveGradEndColor);
+        gc.fillRectangle(0, 0, size.x, size.y);
+        gc.setBackground(widgetBackgroundColor);
+        gc.fillRectangle(2, 4, size.x-4, size.y-6);
+
+        Color tloColor, tliColor, broColor, briColor;
+        int pOff;
+        if(pressed)
+        {
+            tloColor = darkShadowColor;
+            tliColor = normalShadowColor;
+            broColor = highlightShadowColor;
+            briColor = lightShadowColor;
+            pOff = 1;
+        }
+        else
+        {
+            tloColor = highlightShadowColor;
+            tliColor = lightShadowColor;
+            broColor = darkShadowColor;
+            briColor = normalShadowColor;
+            pOff = 0;
+        }
+
+        drawBevelRect(gc, leftOff, 2, size.x-1-leftOff-rightOff, size.y-5, tloColor, broColor);
+        drawBevelRect(gc, 1+leftOff, 3, size.x-3-leftOff-rightOff, size.y-7, tliColor, briColor);
+
+        if(isEnabled())
+        {
+            gc.setForeground(widgetForegroundColor);
+            drawImage(gc, size, pOff);
+        }
+        else
+        {
+            gc.setForeground(highlightShadowColor);
+            drawImage(gc, size, 1);
+            gc.setForeground(normalShadowColor);
+            drawImage(gc, size, 0);
+        }
+    }
+
+
+    private void drawImage(GC gc, Point size, int pOff)
+    {
+        if((style & DWT.CLOSE) !is 0) drawCloseImage(gc, size, pOff);
+        else if((style & DWT.MAX) !is 0)
+        {
+            if(ishell.getMaximized()) drawRestoreImage(gc, size, pOff);
+            else drawMaximizeImage(gc, size, pOff);
+        }
+        else if((style & DWT.MIN) !is 0) drawMinimizeImage(gc, size, pOff);
+    }
+
+
+    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);
+    }
+
+
+    private void drawCloseImage(GC gc, Point size, int pOff)
+    {
+        gc.drawLine(pOff+leftOff+4, pOff+5, pOff+size.x-leftOff-rightOff-6, pOff+size.y-7);
+        gc.drawLine(pOff+leftOff+5, pOff+5, pOff+size.x-leftOff-rightOff-5, pOff+size.y-7);
+        gc.drawLine(pOff+leftOff+4, pOff+size.y-7, pOff+size.x-leftOff-rightOff-6, pOff+5);
+        gc.drawLine(pOff+leftOff+5, pOff+size.y-7, pOff+size.x-leftOff-rightOff-5, pOff+5);
+    }
+
+
+    private void drawRestoreImage(GC gc, Point size, int pOff)
+    {
+        gc.drawRectangle(pOff+leftOff+3, pOff+7, size.x-leftOff-rightOff-11, size.y-13);
+        gc.drawLine(pOff+leftOff+4, pOff+8, pOff+size.x-leftOff-rightOff-9, pOff+8);
+        gc.drawLine(pOff+leftOff+6, pOff+5, pOff+size.x-leftOff-rightOff-7, pOff+5);
+        gc.drawLine(pOff+leftOff+5, pOff+4, pOff+size.x-leftOff-rightOff-6, pOff+4);
+        gc.drawLine(pOff+size.x-leftOff-rightOff-7, pOff+size.y-9, pOff+size.x-leftOff-rightOff-6, pOff+size.y-9);
+        gc.drawLine(pOff+size.x-leftOff-rightOff-6, pOff+size.y-10, pOff+size.x-leftOff-rightOff-6, pOff+5);
+        gc.drawLine(pOff+leftOff+5, pOff+5, pOff+leftOff+5, pOff+6);
+    }
+
+
+    private void drawMaximizeImage(GC gc, Point size, int pOff)
+    {
+        gc.drawRectangle(pOff+leftOff+3, pOff+4, size.x-leftOff-rightOff-8, size.y-10);
+        gc.drawLine(pOff+leftOff+4, pOff+5, pOff+size.x-leftOff-rightOff-6, pOff+5);
+    }
+
+
+    private void drawMinimizeImage(GC gc, Point size, int pOff)
+    {
+        gc.drawLine(pOff+leftOff+4, pOff+size.y-6, pOff+size.x-leftOff-rightOff-5, pOff+size.y-6);
+        gc.drawLine(pOff+leftOff+4, pOff+size.y-7, pOff+size.x-leftOff-rightOff-5, pOff+size.y-7);
+    }
+}