changeset 41:6337764516f1

Sync dwt/custom with dwt-linux (took copy of complete folder)
author Frank Benoit <benoit@tionex.de>
date Tue, 07 Oct 2008 16:29:55 +0200
parents fbe68c33eeee
children e51524512e8a
files dwt/custom/AnimatedProgress.d dwt/custom/BidiSegmentEvent.d dwt/custom/BidiSegmentListener.d dwt/custom/Bullet.d dwt/custom/BusyIndicator.d dwt/custom/CBanner.d dwt/custom/CBannerLayout.d dwt/custom/CCombo.d dwt/custom/CLabel.d dwt/custom/CLayoutData.d dwt/custom/CTabFolder.d dwt/custom/CTabFolder2Adapter.d dwt/custom/CTabFolder2Listener.d dwt/custom/CTabFolderAdapter.d dwt/custom/CTabFolderEvent.d dwt/custom/CTabFolderLayout.d dwt/custom/CTabFolderListener.d dwt/custom/CTabItem.d dwt/custom/ControlEditor.d dwt/custom/DefaultContent.d dwt/custom/ExtendedModifyEvent.d dwt/custom/ExtendedModifyListener.d dwt/custom/LineBackgroundEvent.d dwt/custom/LineBackgroundListener.d dwt/custom/LineStyleEvent.d dwt/custom/LineStyleListener.d dwt/custom/MovementEvent.d dwt/custom/MovementListener.d dwt/custom/PaintObjectEvent.d dwt/custom/PaintObjectListener.d dwt/custom/PopupList.d dwt/custom/ST.d dwt/custom/SashForm.d dwt/custom/SashFormData.d dwt/custom/SashFormLayout.d dwt/custom/ScrolledComposite.d dwt/custom/ScrolledCompositeLayout.d dwt/custom/StackLayout.d dwt/custom/StyleRange.d dwt/custom/StyledText.d dwt/custom/StyledTextContent.d dwt/custom/StyledTextDropTargetEffect.d dwt/custom/StyledTextEvent.d dwt/custom/StyledTextListener.d dwt/custom/StyledTextPrintOptions.d dwt/custom/StyledTextRenderer.d dwt/custom/TableCursor.d dwt/custom/TableEditor.d dwt/custom/TableTree.d dwt/custom/TableTreeEditor.d dwt/custom/TableTreeItem.d dwt/custom/TextChangeListener.d dwt/custom/TextChangedEvent.d dwt/custom/TextChangingEvent.d dwt/custom/TreeEditor.d dwt/custom/VerifyKeyListener.d dwt/custom/ViewForm.d dwt/custom/ViewFormLayout.d
diffstat 58 files changed, 11767 insertions(+), 12615 deletions(-) [+]
line wrap: on
line diff
--- a/dwt/custom/AnimatedProgress.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/AnimatedProgress.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,13 +7,14 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.AnimatedProgress;
 
+
 import dwt.DWT;
+import dwt.DWTException;
 import dwt.events.ControlAdapter;
 import dwt.events.ControlEvent;
 import dwt.events.DisposeEvent;
@@ -23,20 +24,26 @@
 import dwt.graphics.Color;
 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.dwthelper.Runnable;
 
 /**
  * A control for showing progress feedback for a long running operation.
  *
  * @deprecated As of Eclipse 2.1, use ProgressBar with the style DWT.INDETERMINATE
- * 
+ *
  * <dl>
  * <dt><b>Styles:</b><dd>VERTICAL, HORIZONTAL, BORDER
  * </dl>
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
-public class AnimatedProgress : Canvas
-{
+public class AnimatedProgress : Canvas {
+
+    alias Canvas.computeSize computeSize;
 
     static const int SLEEP = 70;
     static const int DEFAULT_WIDTH = 160;
@@ -47,236 +54,192 @@
     int orientation = DWT.HORIZONTAL;
     bool showBorder = false;
 
-    /**
-     * Constructs a new instance of this class given its parent
-     * and a style value describing its behavior and appearance.
-     * <p>
-     * The style value is either one of the style constants defined in
-     * class <code>DWT</code> which is applicable to instances of this
-     * class, or must be built by <em>bitwise OR</em>'ing together 
-     * (that is, using the <code>int</code> "|" operator) two or more
-     * of those <code>DWT</code> style constants. The class description
-     * lists the style constants that are applicable to the class.
-     * Style bits are also inherited from superclasses.
-     * </p>
-     *
-     * @param parent a widget which will be the parent of the new instance (cannot be null)
-     * @param style the style of widget to construct
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
-     * </ul>
-     *
-     * @see DWT#VERTICAL
-     * @see DWT#HORIZONTAL
-     * @see DWT#BORDER
-     * @see #getStyle()
-     */
-    public this (Composite parent, int style)
-    {
-        super(parent, checkStyle(style));
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>DWT</code> which is applicable to instances of this
+ * class, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DWT</code> style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a widget which will be the parent of the new instance (cannot be null)
+ * @param style the style of widget to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * </ul>
+ *
+ * @see DWT#VERTICAL
+ * @see DWT#HORIZONTAL
+ * @see DWT#BORDER
+ * @see #getStyle()
+ */
+public this(Composite parent, int style) {
+    super(parent, checkStyle(style));
 
-        if ((style & DWT.VERTICAL) !is 0)
-        {
-            orientation = DWT.VERTICAL;
-        }
-        showBorder = (style & DWT.BORDER) !is 0;
+    if ((style & DWT.VERTICAL) !is 0) {
+        orientation = DWT.VERTICAL;
+    }
+    showBorder = (style & DWT.BORDER) !is 0;
 
-        addControlListener(new class ControlAdapter
-        {
-            public void controlResized (ControlEvent e)
-            {
-                redraw();
-            }
-        });
-        addPaintListener(new class PaintListener
-        {
-            public void paintControl (PaintEvent e)
-            {
-                paint(e);
-            }
-        });
-        addDisposeListener(new class DisposeListener
-        {
-            public void widgetDisposed (DisposeEvent e)
-            {
-                stop();
-            }
-        });
+    addControlListener(new class() ControlAdapter {
+        public void controlResized(ControlEvent e) {
+            redraw();
+        }
+    });
+    addPaintListener(new class() PaintListener {
+        public void paintControl(PaintEvent e) {
+            paint(e);
+        }
+    });
+    addDisposeListener(new class() DisposeListener {
+        public void widgetDisposed(DisposeEvent e){
+            stop();
+        }
+    });
+}
+private static int checkStyle (int style) {
+    int mask = DWT.NONE;
+    return style & mask;
+}
+/**
+ * Stop the animation if it is not already stopped and
+ * reset the presentation to a blank appearance.
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public synchronized void clear(){
+    checkWidget();
+    if (active) stop();
+    showStripes = false;
+    redraw();
+}
+public override Point computeSize(int wHint, int hHint, bool changed) {
+    checkWidget();
+    Point size = null;
+    if (orientation is DWT.HORIZONTAL) {
+        size = new Point(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+    } else {
+        size = new Point(DEFAULT_HEIGHT, DEFAULT_WIDTH);
     }
+    if (wHint !is DWT.DEFAULT) size.x = wHint;
+    if (hHint !is DWT.DEFAULT) size.y = hHint;
 
-    private static int checkStyle (int style)
-    {
-        int mask = DWT.NONE;
-        return style & mask;
-    }
+    return size;
+}
+private void drawBevelRect(GC gc, int x, int y, int w, int h, Color topleft, Color bottomright) {
+    gc.setForeground(topleft);
+    gc.drawLine(x, y, x+w-1, y);
+    gc.drawLine(x, y, x, y+h-1);
 
-    /**
-     * Stop the animation if it is not already stopped and 
-     * reset the presentation to a blank appearance.
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public synchronized void clear ()
-    {
-        checkWidget();
-        if (active)
-            stop();
-        showStripes = false;
-        redraw();
+    gc.setForeground(bottomright);
+    gc.drawLine(x+w, y, x+w, y+h);
+    gc.drawLine(x, y+h, x+w, y+h);
+}
+void paint(PaintEvent event) {
+    GC gc = event.gc;
+    Display disp= getDisplay();
+
+    Rectangle rect= getClientArea();
+    gc.fillRectangle(rect);
+    if (showBorder) {
+        drawBevelRect(gc, rect.x, rect.y, rect.width-1, rect.height-1,
+            disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW),
+            disp.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW));
     }
 
-    public Point computeSize (int wHint, int hHint, bool changed)
-    {
-        checkWidget();
-        Point size = null;
-        if (orientation is DWT.HORIZONTAL)
-        {
-            size = new Point(DEFAULT_WIDTH, DEFAULT_HEIGHT);
-        }
-        else
-        {
-            size = new Point(DEFAULT_HEIGHT, DEFAULT_WIDTH);
-        }
-        if (wHint !is DWT.DEFAULT)
-            size.x = wHint;
-        if (hHint !is DWT.DEFAULT)
-            size.y = hHint;
-
-        return size;
-    }
+    paintStripes(gc);
+}
+void paintStripes(GC gc) {
 
-    private void drawBevelRect (GC gc, int x, int y, int w, int h,
-            Color topleft, Color bottomright)
-    {
-        gc.setForeground(topleft);
-        gc.drawLine(x, y, x + w - 1, y);
-        gc.drawLine(x, y, x, y + h - 1);
-
-        gc.setForeground(bottomright);
-        gc.drawLine(x + w, y, x + w, y + h);
-        gc.drawLine(x, y + h, x + w, y + h);
-    }
+    if (!showStripes) return;
 
-    void paint (PaintEvent event)
-    {
-        GC gc = event.gc;
-        Display disp = getDisplay();
-
-        Rectangle rect = getClientArea();
-        gc.fillRectangle(rect);
-        if (showBorder)
-        {
-            drawBevelRect(gc, rect.x, rect.y, rect.width - 1, rect.height - 1,
-                    disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW),
-                    disp.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW));
-        }
+    Rectangle rect= getClientArea();
+    // Subtracted border painted by paint.
+    rect = new Rectangle(rect.x+2, rect.y+2, rect.width-4, rect.height-4);
 
-        paintStripes(gc);
-    }
-
-    void paintStripes (GC gc)
-    {
-
-        if (!showStripes)
-            return;
-
-        Rectangle rect = getClientArea();
-        // Subtracted border painted by paint.
-        rect = new Rectangle(rect.x + 2, rect.y + 2, rect.width - 4,
-                rect.height - 4);
+    gc.setLineWidth(2);
+    gc.setClipping(rect);
+    Color color = getDisplay().getSystemColor(DWT.COLOR_LIST_SELECTION);
+    gc.setBackground(color);
+    gc.fillRectangle(rect);
+    gc.setForeground(this.getBackground());
+    int step = 12;
+    int foregroundValue = value is 0 ? step - 2 : value - 2;
+    if (orientation is DWT.HORIZONTAL) {
+        int y = rect.y - 1;
+        int w = rect.width;
+        int h = rect.height + 2;
+        for (int i= 0; i < w; i+= step) {
+            int x = i + foregroundValue;
+            gc.drawLine(x, y, x, h);
+        }
+    } else {
+        int x = rect.x - 1;
+        int w = rect.width + 2;
+        int h = rect.height;
 
-        gc.setLineWidth(2);
-        gc.setClipping(rect);
-        Color color = getDisplay().getSystemColor(DWT.COLOR_LIST_SELECTION);
-        gc.setBackground(color);
-        gc.fillRectangle(rect);
-        gc.setForeground(this.getBackground());
-        int step = 12;
-        int foregroundValue = value is 0 ? step - 2 : value - 2;
-        if (orientation is DWT.HORIZONTAL)
-        {
-            int y = rect.y - 1;
-            int w = rect.width;
-            int h = rect.height + 2;
-            for (int i = 0; i < w; i += step)
-            {
-                int x = i + foregroundValue;
-                gc.drawLine(x, y, x, h);
-            }
-        }
-        else
-        {
-            int x = rect.x - 1;
-            int w = rect.width + 2;
-            int h = rect.height;
-
-            for (int i = 0; i < h; i += step)
-            {
-                int y = i + foregroundValue;
-                gc.drawLine(x, y, w, y);
-            }
-        }
-
-        if (active)
-        {
-            value = (value + 2) % step;
+        for (int i= 0; i < h; i+= step) {
+            int y = i + foregroundValue;
+            gc.drawLine(x, y, w, y);
         }
     }
 
-    /**
-     * Start the animation.
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public synchronized void start ()
-    {
-        checkWidget();
-        if (active)
-            return;
-
-        active = true;
-        showStripes = true;
-
-        const Display display = getDisplay();
-        const Runnable[] timer = new Runnable[1];
-        timer[0] = new class (display) Runnable
-        {
-            Display display;
-
-            this (Display display)
-            {
-                this.display = display;
-            }
-
-            public void run ()
-            {
-                if (!active)
-                    return;
-                GC gc = new GC(this);
-                paintStripes(gc);
-                gc.dispose();
-                display.timerExec(SLEEP, timer[0]);
-            }
-        };
-        display.timerExec(SLEEP, timer[0]);
-    }
-
-    /**
-     * Stop the animation.   Freeze the presentation at its current appearance.
-     */
-    public synchronized void stop ()
-    {
-        //checkWidget();
-        active = false;
+    if (active) {
+        value = (value + 2) % step;
     }
 }
+/**
+* Start the animation.
+*
+* @exception DWTException <ul>
+*    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+*    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+* </ul>
+*/
+public synchronized void start() {
+    checkWidget();
+    if (active) return;
+
+    active = true;
+    showStripes = true;
+
+    Display display = getDisplay();
+    Runnable [] timer = new Runnable [1];
+
+    timer [0] = new class( display, timer ) Runnable {
+        Display disp;
+        Runnable [] runs;
+        this( Display disp, Runnable[] runs ){
+            this.disp = disp;
+            this.runs = runs;
+        }
+        public void run () {
+            if (!active) return;
+            GC gc = new GC(this.outer);
+            paintStripes(gc);
+            gc.dispose();
+            disp.timerExec (SLEEP, runs [0]);
+        }
+    };
+    display.timerExec (SLEEP, timer [0]);
+}
+/**
+* Stop the animation.   Freeze the presentation at its current appearance.
+*/
+public synchronized void stop() {
+    //checkWidget();
+    active = false;
+}
+}
--- a/dwt/custom/BidiSegmentEvent.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/BidiSegmentEvent.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,25 +7,25 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.BidiSegmentEvent;
 
-import dwt.custom.StyledTextEvent;
+import dwt.dwthelper.utils;
+
+
 import dwt.events.TypedEvent;
-
-import dwt.dwthelper.string;
+import dwt.custom.StyledTextEvent;
 
 /**
  * This event is sent to BidiSegmentListeners when a line is to
- * be measured or rendered in a bidi locale.  The segments field is 
- * used to specify text ranges in the line that should be treated as 
- * separate segments for bidi reordering.  Each segment will be reordered 
+ * be measured or rendered in a bidi locale.  The segments field is
+ * used to specify text ranges in the line that should be treated as
+ * separate segments for bidi reordering.  Each segment will be reordered
  * and rendered separately.
  * <p>
- * The elements in the segments field specify the start offset of 
+ * The elements in the segments field specify the start offset of
  * a segment relative to the start of the line. They must follow
  * the following rules:
  * <ul>
@@ -33,57 +33,57 @@
  * <li>elements must be in ascending order and must not have duplicates
  * <li>elements must not exceed the line length
  * </ul>
- * In addition, the last element may be set to the end of the line 
+ * In addition, the last element may be set to the end of the line
  * but this is not required.
  *
- * The segments field may be left null if the entire line should 
+ * The segments field may be left null if the entire line should
  * be reordered as is.
  * </p>
- * A BidiSegmentListener may be used when adjacent segments of 
- * right-to-left text should not be reordered relative to each other. 
- * For example, within a Java editor, you may wish multiple 
- * right-to-left String literals to be reordered differently than the
- * bidi algorithm specifies.  
+ * A BidiSegmentListener may be used when adjacent segments of
+ * right-to-left text should not be reordered relative to each other.
+ * For example, within a Java editor, you may wish multiple
+ * right-to-left string literals to be reordered differently than the
+ * bidi algorithm specifies.
  *
  * Example:
  * <pre>
  *  stored line = "R1R2R3" + "R4R5R6"
  *      R1 to R6 are right-to-left characters. The quotation marks
  *      are part of the line text. The line is 13 characters long.
- * 
- *  segments = null: 
- *      entire line will be reordered and thus the two R2L segments 
- *      swapped (as per the bidi algorithm). 
+ *
+ *  segments = null:
+ *      entire line will be reordered and thus the two R2L segments
+ *      swapped (as per the bidi algorithm).
  *      visual line (rendered on screen) = "R6R5R4" + "R3R2R1"
- * 
- *  segments = [0, 5, 8]    
- *      "R1R2R3" will be reordered, followed by [blank]+[blank] and 
- *      "R4R5R6". 
+ *
+ *  segments = [0, 5, 8]
+ *      "R1R2R3" will be reordered, followed by [blank]+[blank] and
+ *      "R4R5R6".
  *      visual line = "R3R2R1" + "R6R5R4"
  * </pre>
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 public class BidiSegmentEvent : TypedEvent {
 
-    /** 
-     * line start offset 
+    /**
+     * line start offset
      */
     public int lineOffset;
 
-    /** 
-     * line text 
+    /**
+     * line text
      */
     public String lineText;
 
-    /** 
-     * bidi segments, see above 
+    /**
+     * bidi segments, see above
      */
     public int[] segments;
 
-    static final long serialVersionUID = 3257846571587547957L;
-
-    this (StyledTextEvent e) {
-        super(e);
-        lineOffset = e.detail;
-        lineText = e.text;
-    }
+this(StyledTextEvent e) {
+    super(cast(Object)e);
+    lineOffset = e.detail;
+    lineText = e.text;
 }
+}
--- a/dwt/custom/BidiSegmentListener.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/BidiSegmentListener.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
  * Copyright (c) 2000, 2005 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -7,14 +7,13 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.BidiSegmentListener;
 
+import dwt.internal.DWTEventListener;
 import dwt.custom.BidiSegmentEvent;
-import dwt.internal.DWTEventListener;
 
 /**
  * This listener interface may be implemented in order to receive
@@ -23,21 +22,22 @@
  */
 public interface BidiSegmentListener : DWTEventListener {
 
-    /**
-     * This method is called when a line needs to be reordered for 
-     * measuring or rendering in a bidi locale. 
-     * <p>
-     * The following event fields are used:<ul>
-     * <li>event.lineOffset line start offset (input)</li>
-     * <li>event.lineText line text (input)</li>
-     * <li>event.segments text segments that should be reordered 
-     *  separately. (output)</li> 
-     * </ul>
-     *
-     * @param event the given event
-     *  separately. (output)
-     * @see BidiSegmentEvent
-     */
-    public void lineGetSegments (BidiSegmentEvent event);
+/**
+ * This method is called when a line needs to be reordered for
+ * measuring or rendering in a bidi locale.
+ * <p>
+ * The following event fields are used:<ul>
+ * <li>event.lineOffset line start offset (input)</li>
+ * <li>event.lineText line text (input)</li>
+ * <li>event.segments text segments that should be reordered
+ *  separately. (output)</li>
+ * </ul>
+ *
+ * @param event the given event
+ *  separately. (output)
+ * @see BidiSegmentEvent
+ */
+public void lineGetSegments(BidiSegmentEvent event);
 
 }
+
--- a/dwt/custom/Bullet.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/Bullet.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,154 +7,157 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.Bullet;
 
+import dwt.dwthelper.utils;
+
 import dwt.DWT;
 import dwt.custom.StyleRange;
-
-import dwt.dwthelper.string;
+import dwt.custom.ST;
 import dwt.dwthelper.System;
 
 /**
  * Instances of this class represent bullets in the <code>StyledText</code>.
  * <p>
- * The toHash() method in this class uses the values of the public
+ * The hashCode() method in this class uses the values of the public
  * fields to compute the hash value. When storing instances of the
  * class in hashed collections, do not modify these fields after the
- * object has been inserted.  
+ * object has been inserted.
  * </p>
  * <p>
  * Application code does <em>not</em> need to explicitly release the
  * resources managed by each instance when those instances are no longer
  * required, and thus no <code>dispose()</code> method is provided.
  * </p>
- * 
+ *
  * @see StyledText#setLineBullet(int, int, Bullet)
- * 
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
  * @since 3.2
  */
 public class Bullet {
+    /**
+    * The bullet type.  Possible values are:
+    * <ul>
+    * <li><code>ST.BULLET_DOT</code></li>
+    * <li><code>ST.BULLET_NUMBER</code></li>
+    * <li><code>ST.BULLET_LETTER_LOWER</code></li>
+    * <li><code>ST.BULLET_LETTER_UPPER</code></li>
+    * <li><code>ST.BULLET_TEXT</code></li>
+    * <li><code>ST.BULLET_CUSTOM</code></li>
+    * </ul>
+    */
     public int type;
+
+    /**
+    * The bullet style.
+    */
     public StyleRange style;
+
+    /**
+    * The bullet text.
+    */
     public String text;
+
     int[] linesIndices;
     int count;
 
-    /** 
-     * Create a new bullet the specified style, the type is set to ST.BULLET_DOT. 
-     * The style must have a glyph metrics set.
-     *
-     * @param style the style 
-     * 
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT when the style or the glyph metrics are null</li>
-     * </ul> 
-     */
-    public this (StyleRange style) {
-        this(DWT.BULLET_DOT, style);
-    }
-
-    /** 
-     * Create a new bullet the specified style and type. 
-     * The style must have a glyph metrics set.
-     *
-     * @param style the style 
-     * 
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT when the style or the glyph metrics are null</li>
-     * </ul> 
-     */
-    public this (int type, StyleRange style) {
-        if (style is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        if (style.metrics is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        this.type = type;
-        this.style = style;
+/**
+ * Create a new bullet with the specified style, and type <code>ST.BULLET_DOT</code>. 
+ * The style must have a glyph metrics set.
+ *
+ * @param style the style
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT when the style or the glyph metrics are null</li>
+ * </ul>
+ */
+public this(StyleRange style) {
+    this(ST.BULLET_DOT, style);
+}
+/**
+ * Create a new bullet the specified style and type.
+ * The style must have a glyph metrics set.
+ *
+ * @param type the bullet type
+ * @param style the style
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT when the style or the glyph metrics are null</li>
+ * </ul>
+ */
+public this(int type, StyleRange style) {
+    if (style is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    if (style.metrics is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    this.type = type;
+    this.style = style;
+}
+void addIndices (int startLine, int lineCount) {
+    if (linesIndices is null) {
+        linesIndices = new int[lineCount];
+        count = lineCount;
+        for (int i = 0; i < lineCount; i++) linesIndices[i] = startLine + i;
+    } else {
+        int modifyStart = 0;
+        while (modifyStart < count) {
+            if (startLine <= linesIndices[modifyStart]) break;
+            modifyStart++;
+        }
+        int modifyEnd = modifyStart;
+        while (modifyEnd < count) {
+            if (startLine + lineCount <= linesIndices[modifyEnd]) break;
+            modifyEnd++;
+        }
+        int newSize = modifyStart + lineCount + count - modifyEnd;
+        if (newSize > linesIndices.length) {
+            int[] newLinesIndices = new int[newSize];
+            System.arraycopy(linesIndices, 0, newLinesIndices, 0, count);
+            linesIndices = newLinesIndices;
+        }
+        System.arraycopy(linesIndices, modifyEnd, linesIndices, modifyStart + lineCount, count - modifyEnd);
+        for (int i = 0; i < lineCount; i++) linesIndices[modifyStart + i] = startLine + i;
+        count = newSize;
     }
-
-    void addIndices (int startLine, int lineCount) {
-        if (linesIndices is null) {
-            linesIndices = new int[lineCount];
-            count = lineCount;
-            for (int i = 0; i < lineCount; i++)
-                linesIndices[i] = startLine + i;
-        }
-        else {
-            int modifyStart = 0;
-            while (modifyStart < count) {
-                if (startLine <= linesIndices[modifyStart])
-                    break;
-                modifyStart++;
+}
+int indexOf (int lineIndex) {
+    for (int i = 0; i < count; i++) {
+        if (linesIndices[i] is lineIndex) return i;
+    }
+    return -1;
+}
+public override hash_t toHash() {
+    return style.toHash() ^ type;
+}
+int[] removeIndices (int startLine, int replaceLineCount, int newLineCount, bool update) {
+    if (count is 0) return null;
+    if (startLine > linesIndices[count - 1]) return null;
+    int endLine = startLine + replaceLineCount;
+    int delta = newLineCount - replaceLineCount;
+    for (int i = 0; i < count; i++) {
+        int index = linesIndices[i];
+        if (startLine <= index) {
+            int j = i;
+            while (j < count) {
+                if (linesIndices[j] >= endLine) break;
+                j++;
             }
-            int modifyEnd = modifyStart;
-            while (modifyEnd < count) {
-                if (startLine + lineCount <= linesIndices[modifyEnd])
-                    break;
-                modifyEnd++;
+            if (update) {
+                for (int k = j; k < count; k++) linesIndices[k] += delta;
             }
-            int newSize = modifyStart + lineCount + count - modifyEnd;
-            if (newSize > linesIndices.length) {
-                int[] newLinesIndices = new int[newSize];
-                System.arraycopy(linesIndices, 0, newLinesIndices, 0, count);
-                linesIndices = newLinesIndices;
-            }
-            System.arraycopy(linesIndices, modifyEnd, linesIndices, modifyStart + lineCount, count - modifyEnd);
-            for (int i = 0; i < lineCount; i++)
-                linesIndices[modifyStart + i] = startLine + i;
-            count = newSize;
+            int[] redrawLines = new int[count - j];
+            System.arraycopy(linesIndices, j, redrawLines, 0, count - j);
+            System.arraycopy(linesIndices, j, linesIndices, i, count - j);
+            count -= (j - i);
+            return redrawLines;
         }
     }
-
-    int indexOf (int lineIndex) {
-        for (int i = 0; i < count; i++) {
-            if (linesIndices[i] is lineIndex)
-                return i;
-        }
-        return -1;
-    }
-
-    public hash_t toHash () {
-        return style.toHash() ^ type;
-    }
-
-    int[] removeIndices (int startLine, int replaceLineCount, int newLineCount, bool update) {
-        if (count is 0)
-            return null;
-        if (startLine > linesIndices[count - 1])
-            return null;
-        int endLine = startLine + replaceLineCount;
-        int delta = newLineCount - replaceLineCount;
-        for (int i = 0; i < count; i++) {
-            int index = linesIndices[i];
-            if (startLine <= index) {
-                int j = i;
-                while (j < count) {
-                    if (linesIndices[j] >= endLine)
-                        break;
-                    j++;
-                }
-                if (update) {
-                    for (int k = j; k < count; k++)
-                        linesIndices[k] += delta;
-                }
-                int[] redrawLines = new int[count - j];
-                System.arraycopy(linesIndices, j, redrawLines, 0, count - j);
-                System.arraycopy(linesIndices, j, linesIndices, i, count - j);
-                count -= (j - i);
-                return redrawLines;
-            }
-        }
-        for (int i = 0; i < count; i++)
-            linesIndices[i] += delta;
-        return null;
-    }
-
-    int size () {
-        return count;
-    }
+    for (int i = 0; i < count; i++) linesIndices[i] += delta;
+    return null;
 }
+int size() {
+    return count;
+}
+}
--- a/dwt/custom/BusyIndicator.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/BusyIndicator.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,81 +7,82 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.BusyIndicator;
 
+
+
 import dwt.DWT;
 import dwt.graphics.Cursor;
 import dwt.widgets.Display;
 import dwt.widgets.Shell;
-
 import dwt.dwthelper.Runnable;
-import dwt.dwthelper.string;
-import dwt.dwthelper.utils : Integer;
+import dwt.dwthelper.utils;
 
 /**
  * Support for showing a Busy Cursor during a long running process.
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#busyindicator">BusyIndicator snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 public class BusyIndicator {
 
     static int nextBusyId = 1;
-    static final String BUSYID_NAME = "DWT BusyIndicator"; //$NON-NLS-1$
-    static final String BUSY_CURSOR = "DWT BusyIndicator Cursor"; //$NON-NLS-1$
+    static const String BUSYID_NAME = "DWT BusyIndicator"; //$NON-NLS-1$
+    static const String BUSY_CURSOR = "DWT BusyIndicator Cursor"; //$NON-NLS-1$
 
-    /**
-     * Runs the given <code>Runnable</code> while providing
-     * busy feedback using this busy indicator.
-     * 
-     * @param display the display on which the busy feedback should be
-     *        displayed.  If the display is null, the Display for the current
-     *        thread will be used.  If there is no Display for the current thread,
-     *        the runnable code will be executed and no busy feedback will be displayed.
-     * @param runnable the runnable for which busy feedback is to be shown.
-     *        Must not be null.
-     * 
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the runnable is null</li>
-     * </ul>
-     */
+/**
+ * Runs the given <code>Runnable</code> while providing
+ * busy feedback using this busy indicator.
+ *
+ * @param display the display on which the busy feedback should be
+ *        displayed.  If the display is null, the Display for the current
+ *        thread will be used.  If there is no Display for the current thread,
+ *        the runnable code will be executed and no busy feedback will be displayed.
+ * @param runnable the runnable for which busy feedback is to be shown.
+ *        Must not be null.
+ *
+* @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the runnable is null</li>
+ * </ul>
+ */
 
-    public static void showWhile (Display display, Runnable runnable) {
-        if (runnable is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
+public static void showWhile(Display display, Runnable runnable) {
+    if (runnable is null)
+        DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    if (display is null) {
+        display = Display.getCurrent();
         if (display is null) {
-            display = Display.getCurrent();
-            if (display is null) {
-                runnable.run();
-                return;
-            }
+            runnable.run();
+            return;
         }
+    }
 
-        Integer busyId = new Integer(nextBusyId);
-        nextBusyId++;
-        Cursor cursor = display.getSystemCursor(DWT.CURSOR_WAIT);
-        Shell[] shells = display.getShells();
+    Integer busyId = new Integer(nextBusyId);
+    nextBusyId++;
+    Cursor cursor = display.getSystemCursor(DWT.CURSOR_WAIT);
+    Shell[] shells = display.getShells();
+    for (int i = 0; i < shells.length; i++) {
+        Integer id = cast(Integer)shells[i].getData(BUSYID_NAME);
+        if (id is null) {
+            shells[i].setCursor(cursor);
+            shells[i].setData(BUSYID_NAME, busyId);
+        }
+    }
+
+    try {
+        runnable.run();
+    } finally {
+        shells = display.getShells();
         for (int i = 0; i < shells.length; i++) {
-            Integer id = cast(Integer) shells[i].getData(BUSYID_NAME);
-            if (id is null) {
-                shells[i].setCursor(cursor);
-                shells[i].setData(BUSYID_NAME, busyId);
-            }
-        }
-
-        try {
-            runnable.run();
-        }
-        finally {
-            shells = display.getShells();
-            for (int i = 0; i < shells.length; i++) {
-                Integer id = cast(Integer) shells[i].getData(BUSYID_NAME);
-                if (id is busyId) {
-                    shells[i].setCursor(null);
-                    shells[i].setData(BUSYID_NAME, null);
-                }
+            Integer id = cast(Integer)shells[i].getData(BUSYID_NAME);
+            if ( id !is null && id == busyId) {
+                shells[i].setCursor(null);
+                shells[i].setData(BUSYID_NAME, null);
             }
         }
     }
 }
+}
--- a/dwt/custom/CBanner.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/CBanner.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,12 +7,13 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.CBanner;
 
+
+
 import dwt.DWT;
 import dwt.DWTException;
 import dwt.graphics.Color;
@@ -26,6 +27,10 @@
 import dwt.widgets.Event;
 import dwt.widgets.Layout;
 import dwt.widgets.Listener;
+import dwt.custom.CBannerLayout;
+
+import Math = tango.math.Math;
+
 
 /**
  * Instances of this class implement a Composite that lays out its
@@ -42,12 +47,14 @@
  * <dt><b>Styles:</b></dt>
  * <dd>NONE</dd>
  * <dt><b>Events:</b></dt>
- * <dd>cast(None)</dd>
+ * <dd>(None)</dd>
  * </dl>
  * <p>
  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
  * </p>
- * 
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
  * @since 3.0
  */
 
@@ -59,9 +66,9 @@
 
     bool simple = true;
 
-    int[] curve = new int[0];
+    int[] curve;
     int curveStart = 0;
-    Rectangle curveRect = new Rectangle(0, 0, 0, 0);
+    Rectangle curveRect;
     int curve_width = 5;
     int curve_indent = -2;
 
@@ -82,506 +89,472 @@
     static const int MIN_LEFT = 10;
     static int BORDER1 = DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW;
 
-    /**
-     * Constructs a new instance of this class given its parent
-     * and a style value describing its behavior and appearance.
-     * <p>
-     * The style value is either one of the style constants defined in
-     * class <code>DWT</code> which is applicable to instances of this
-     * class, or must be built by <em>bitwise OR</em>'ing together 
-     * (that is, using the <code>int</code> "|" operator) two or more
-     * of those <code>DWT</code> style constants. The class description
-     * lists the style constants that are applicable to the class.
-     * Style bits are also inherited from superclasses.
-     * </p>
-     *
-     * @param parent a widget which will be the parent of the new instance (cannot be null)
-     * @param style the style of widget to construct
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
-     * </ul>
-     *
-     */
-    public this (Composite parent, int style) {
-        super(parent, checkStyle(style));
-        super.setLayout(new CBannerLayout());
-        resizeCursor = new Cursor(getDisplay(), DWT.CURSOR_SIZEWE);
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>DWT</code> which is applicable to instances of this
+ * class, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DWT</code> style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a widget which will be the parent of the new instance (cannot be null)
+ * @param style the style of widget to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * </ul>
+ *
+ */
+public this(Composite parent, int style) {
+    curveRect = new Rectangle(0, 0, 0, 0);
+    super(parent, checkStyle(style));
+    super.setLayout(new CBannerLayout());
+    resizeCursor = new Cursor(getDisplay(), DWT.CURSOR_SIZEWE);
 
-        Listener listener = new class Listener {
-            public void handleEvent (Event e) {
-                switch (e.type) {
-                    case DWT.Dispose:
-                        onDispose();
-                    break;
-                    case DWT.MouseDown:
-                        onMouseDown(e.x, e.y);
-                    break;
-                    case DWT.MouseExit:
-                        onMouseExit();
-                    break;
-                    case DWT.MouseMove:
-                        onMouseMove(e.x, e.y);
-                    break;
-                    case DWT.MouseUp:
-                        onMouseUp();
-                    break;
-                    case DWT.Paint:
-                        onPaint(e.gc);
-                    break;
-                    case DWT.Resize:
-                        onResize();
-                    break;
-                }
+    Listener listener = new class() Listener {
+        public void handleEvent(Event e) {
+            switch (e.type) {
+                case DWT.Dispose:
+                    onDispose(); break;
+                case DWT.MouseDown:
+                    onMouseDown (e.x, e.y); break;
+                case DWT.MouseExit:
+                    onMouseExit(); break;
+                case DWT.MouseMove:
+                    onMouseMove(e.x, e.y); break;
+                case DWT.MouseUp:
+                    onMouseUp(); break;
+                case DWT.Paint:
+                    onPaint(e.gc); break;
+                case DWT.Resize:
+                    onResize(); break;
+                default:
             }
-        };
-        int[] events = new int[][DWT.Dispose , DWT.MouseDown , DWT.MouseExit , DWT.MouseMove , DWT.MouseUp , DWT.Paint , DWT.Resize];
-        for (int i = 0; i < events.length; i++) {
-            addListener(events[i], listener);
         }
+    };
+    int[] events = [DWT.Dispose, DWT.MouseDown, DWT.MouseExit, DWT.MouseMove, DWT.MouseUp, DWT.Paint, DWT.Resize];
+    for (int i = 0; i < events.length; i++) {
+        addListener(events[i], listener);
     }
+}
+static int[] bezier(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3, int count) {
+    // The parametric equations for a Bezier curve for x[t] and y[t] where  0 <= t <=1 are:
+    // x[t] = x0+3(x1-x0)t+3(x0+x2-2x1)t^2+(x3-x0+3x1-3x2)t^3
+    // y[t] = y0+3(y1-y0)t+3(y0+y2-2y1)t^2+(y3-y0+3y1-3y2)t^3
+    double a0 = x0;
+    double a1 = 3*(x1 - x0);
+    double a2 = 3*(x0 + x2 - 2*x1);
+    double a3 = x3 - x0 + 3*x1 - 3*x2;
+    double b0 = y0;
+    double b1 = 3*(y1 - y0);
+    double b2 = 3*(y0 + y2 - 2*y1);
+    double b3 = y3 - y0 + 3*y1 - 3*y2;
 
-    static int[] bezier (int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3, int count) {
-        // The parametric equations for a Bezier curve for x[t] and y[t] where  0 <= t <=1 are:
-        // x[t] = x0+3(x1-x0)t+3(x0+x2-2x1)t^2+(x3-x0+3x1-3x2)t^3
-        // y[t] = y0+3(y1-y0)t+3(y0+y2-2y1)t^2+(y3-y0+3y1-3y2)t^3
-        double a0 = x0;
-        double a1 = 3 * (x1 - x0);
-        double a2 = 3 * (x0 + x2 - 2 * x1);
-        double a3 = x3 - x0 + 3 * x1 - 3 * x2;
-        double b0 = y0;
-        double b1 = 3 * (y1 - y0);
-        double b2 = 3 * (y0 + y2 - 2 * y1);
-        double b3 = y3 - y0 + 3 * y1 - 3 * y2;
-
-        int[] polygon = new int[2 * count + 2];
-        for (int i = 0; i <= count; i++) {
-            double t = cast(double) i / cast(double) count;
-            polygon[2 * i] = cast(int) (a0 + a1 * t + a2 * t * t + a3 * t * t * t);
-            polygon[2 * i + 1] = cast(int) (b0 + b1 * t + b2 * t * t + b3 * t * t * t);
-        }
-        return polygon;
+    int[] polygon = new int[2*count + 2];
+    for (int i = 0; i <= count; i++) {
+        double t = cast(double)i / cast(double)count;
+        polygon[2*i] = cast(int)(a0 + a1*t + a2*t*t + a3*t*t*t);
+        polygon[2*i + 1] = cast(int)(b0 + b1*t + b2*t*t + b3*t*t*t);
     }
+    return polygon;
+}
+static int checkStyle (int style) {
+    return DWT.NONE;
+}
+/**
+* Returns the Control that appears on the bottom side of the banner.
+*
+* @return the control that appears on the bottom side of the banner or null
+*
+* @exception DWTException <ul>
+*    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+*    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+* </ul>
+*
+* @since 3.0
+*/
+public Control getBottom() {
+    checkWidget();
+    return bottom;
+}
+public override Rectangle getClientArea() {
+    return new Rectangle(0, 0, 0, 0);
+}
 
-    static int checkStyle (int style) {
-        return DWT.NONE;
-    }
-
-    /**
-     * Returns the Control that appears on the bottom side of the banner.
-     * 
-     * @return the control that appears on the bottom side of the banner or null
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public Control getBottom () {
-        checkWidget();
-        return bottom;
-    }
-
-    public Rectangle getClientArea () {
-        return new Rectangle(0, 0, 0, 0);
-    }
+/**
+* Returns the Control that appears on the left side of the banner.
+*
+* @return the control that appears on the left side of the banner or null
+*
+* @exception DWTException <ul>
+*    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+*    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+* </ul>
+*
+* @since 3.0
+*/
+public Control getLeft() {
+    checkWidget();
+    return left;
+}
 
-    /**
-     * Returns the Control that appears on the left side of the banner.
-     * 
-     * @return the control that appears on the left side of the banner or null
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public Control getLeft () {
-        checkWidget();
-        return left;
+/**
+* Returns the Control that appears on the right side of the banner.
+*
+* @return the control that appears on the right side of the banner or null
+*
+* @exception DWTException <ul>
+*    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+*    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+* </ul>
+*
+* @since 3.0
+*/
+public Control getRight() {
+    checkWidget();
+    return right;
+}
+/**
+ * Returns the minimum size of the control that appears on the right of the banner.
+ *
+ * @return the minimum size of the control that appears on the right of the banner
+ *
+ * @since 3.1
+ */
+public Point getRightMinimumSize() {
+    checkWidget();
+    return new Point(rightMinWidth, rightMinHeight);
+}
+/**
+ * Returns the width of the control that appears on the right of the banner.
+ *
+ * @return the width of the control that appears on the right of the banner
+ *
+ * @since 3.0
+ */
+public int getRightWidth() {
+    checkWidget();
+    if (right is null) return 0;
+    if (rightWidth is DWT.DEFAULT) {
+        Point size = right.computeSize(DWT.DEFAULT, DWT.DEFAULT, false);
+        return size.x;
     }
-
-    /**
-     * Returns the Control that appears on the right side of the banner.
-     * 
-     * @return the control that appears on the right side of the banner or null
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public Control getRight () {
-        checkWidget();
-        return right;
+    return rightWidth;
+}
+/**
+ * Returns <code>true</code> if the CBanner is rendered
+ * with a simple, traditional shape.
+ *
+ * @return <code>true</code> if the CBanner is rendered with a simple shape
+ *
+ * @since 3.0
+ */
+public bool getSimple() {
+    checkWidget();
+    return simple;
+}
+void onDispose() {
+    if (resizeCursor !is null) resizeCursor.dispose();
+    resizeCursor = null;
+    left = null;
+    right = null;
+    bottom = null;
+}
+void onMouseDown (int x, int y) {
+    if (curveRect.contains(x, y)) {
+        dragging = true;
+        rightDragDisplacement = curveStart - x + curve_width - curve_indent;
     }
-
-    /**
-     * Returns the minimum size of the control that appears on the right of the banner.
-     * 
-     * @return the minimum size of the control that appears on the right of the banner
-     * 
-     * @since 3.1
-     */
-    public Point getRightMinimumSize () {
-        checkWidget();
-        return new Point(rightMinWidth, rightMinHeight);
-    }
-
-    /**
-     * Returns the width of the control that appears on the right of the banner.
-     * 
-     * @return the width of the control that appears on the right of the banner
-     * 
-     * @since 3.0
-     */
-    public int getRightWidth () {
-        checkWidget();
-        if (right is null)
-            return 0;
-        if (rightWidth is DWT.DEFAULT) {
-            Point size = right.computeSize(DWT.DEFAULT, DWT.DEFAULT, false);
-            return size.x;
+}
+void onMouseExit() {
+    if (!dragging) setCursor(null);
+}
+void onMouseMove(int x, int y) {
+    if (dragging) {
+        Point size = getSize();
+        if (!(0 < x && x < size.x)) return;
+        rightWidth = Math.max(0, size.x - x - rightDragDisplacement);
+        if (rightMinWidth is DWT.DEFAULT) {
+            Point minSize = right.computeSize(rightMinWidth, rightMinHeight);
+            rightWidth = Math.max(minSize.x, rightWidth);
+        } else {
+            rightWidth = Math.max(rightMinWidth, rightWidth);
         }
-        return rightWidth;
+        layout(false);
+        return;
     }
-
-    /**
-     * Returns <code>true</code> if the CBanner is rendered
-     * with a simple, traditional shape.
-     * 
-     * @return <code>true</code> if the CBanner is rendered with a simple shape
-     * 
-     * @since 3.0
-     */
-    public bool getSimple () {
-        checkWidget();
-        return simple;
+    if (curveRect.contains(x, y)) {
+        setCursor(resizeCursor);
+    } else {
+        setCursor(null);
     }
-
-    void onDispose () {
-        if (resizeCursor !is null)
-            resizeCursor.dispose();
-        resizeCursor = null;
-        left = null;
-        right = null;
-        bottom = null;
+}
+void onMouseUp () {
+    dragging = false;
+}
+void onPaint(GC gc) {
+//   Useful for debugging paint problems
+//  {
+//  Point size = getSize();
+//  gc.setBackground(getDisplay().getSystemColor(DWT.COLOR_GREEN));
+//  gc.fillRectangle(-10, -10, size.x+20, size.y+20);
+//  }
+    if (left is null && right is null) return;
+    Point size = getSize();
+    Color border1 = getDisplay().getSystemColor(BORDER1);
+    if (bottom !is null) {
+        int y = bottom.getBounds().y - BORDER_STRIPE - 1;
+        gc.setForeground(border1);
+        gc.drawLine(0, y, size.x, y);
     }
-
-    void onMouseDown (int x, int y) {
-        if (curveRect.contains(x, y)) {
-            dragging = true;
-            rightDragDisplacement = curveStart - x + curve_width - curve_indent;
-        }
+    if (left is null || right is null) return;
+    int[] line1 = new int[curve.length+6];
+    int index = 0;
+    int x = curveStart;
+    line1[index++] = x + 1;
+    line1[index++] = size.y - BORDER_STRIPE;
+    for (int i = 0; i < curve.length/2; i++) {
+        line1[index++]=x+curve[2*i];
+        line1[index++]=curve[2*i+1];
     }
+    line1[index++] = x + curve_width;
+    line1[index++] = 0;
+    line1[index++] = size.x;
+    line1[index++] = 0;
 
-    void onMouseExit () {
-        if (!dragging)
-            setCursor(null);
-    }
+    Color background = getBackground();
 
-    void onMouseMove (int x, int y) {
-        if (dragging) {
-            Point size = getSize();
-            if (!(0 < x && x < size.x))
-                return;
-            rightWidth = Math.max(0, size.x - x - rightDragDisplacement);
-            if (rightMinWidth is DWT.DEFAULT) {
-                Point minSize = right.computeSize(rightMinWidth, rightMinHeight);
-                rightWidth = Math.max(minSize.x, rightWidth);
-            }
-            else {
-                rightWidth = Math.max(rightMinWidth, rightWidth);
-            }
-            layout(false);
-            return;
+    if (getDisplay().getDepth() >= 15) {
+        // Anti- aliasing
+        int[] line2 = new int[line1.length];
+        index = 0;
+        for (int i = 0; i < line1.length/2; i++) {
+            line2[index] = line1[index++]  - 1;
+            line2[index] = line1[index++];
+        }
+        int[] line3 = new int[line1.length];
+        index = 0;
+        for (int i = 0; i < line1.length/2; i++) {
+            line3[index] = line1[index++] + 1;
+            line3[index] = line1[index++];
         }
-        if (curveRect.contains(x, y)) {
-            setCursor(resizeCursor);
-        }
-        else {
-            setCursor(null);
-        }
-    }
+        RGB from = border1.getRGB();
+        RGB to = background.getRGB();
+        int red = from.red + 3*(to.red - from.red)/4;
+        int green = from.green + 3*(to.green - from.green)/4;
+        int blue = from.blue + 3*(to.blue - from.blue)/4;
+        Color color = new Color(getDisplay(), red, green, blue);
+        gc.setForeground(color);
+        gc.drawPolyline(line2);
+        gc.drawPolyline(line3);
+        color.dispose();
 
-    void onMouseUp () {
-        dragging = false;
+        // draw tail fading to background
+        int x1 = Math.max(0, curveStart - CURVE_TAIL);
+        gc.setForeground(background);
+        gc.setBackground(border1);
+        gc.fillGradientRectangle(x1, size.y - BORDER_STRIPE, curveStart-x1+1, 1, false);
+    } else {
+        // draw solid tail
+        int x1 = Math.max(0, curveStart - CURVE_TAIL);
+        gc.setForeground(border1);
+        gc.drawLine(x1, size.y - BORDER_STRIPE, curveStart+1, size.y - BORDER_STRIPE);
     }
 
-    void onPaint (GC gc) {
-        //   Useful for debugging paint problems
-        //  {
-        //  Point size = getSize(); 
-        //  gc.setBackground(getDisplay().getSystemColor(DWT.COLOR_GREEN));
-        //  gc.fillRectangle(-10, -10, size.x+20, size.y+20);
-        //  }
-        if (left is null && right is null)
-            return;
-        Point size = getSize();
-        Color border1 = getDisplay().getSystemColor(BORDER1);
-        if (bottom !is null) {
-            int y = bottom.getBounds().y - BORDER_STRIPE - 1;
-            gc.setForeground(border1);
-            gc.drawLine(0, y, size.x, y);
-        }
-        if (left is null || right is null)
-            return;
-        int[] line1 = new int[curve.length + 6];
-        int index = 0;
-        int x = curveStart;
-        line1[index++] = x + 1;
-        line1[index++] = size.y - BORDER_STRIPE;
-        for (int i = 0; i < curve.length / 2; i++) {
-            line1[index++] = x + curve[2 * i];
-            line1[index++] = curve[2 * i + 1];
-        }
-        line1[index++] = x + curve_width;
-        line1[index++] = 0;
-        line1[index++] = size.x;
-        line1[index++] = 0;
-
-        Color background = getBackground();
-
-        if (getDisplay().getDepth() >= 15) {
-            // Anti- aliasing
-            int[] line2 = new int[line1.length];
-            index = 0;
-            for (int i = 0; i < line1.length / 2; i++) {
-                line2[index] = line1[index++] - 1;
-                line2[index] = line1[index++];
-            }
-            int[] line3 = new int[line1.length];
-            index = 0;
-            for (int i = 0; i < line1.length / 2; i++) {
-                line3[index] = line1[index++] + 1;
-                line3[index] = line1[index++];
-            }
-            RGB from = border1.getRGB();
-            RGB to = background.getRGB();
-            int red = from.red + 3 * (to.red - from.red) / 4;
-            int green = from.green + 3 * (to.green - from.green) / 4;
-            int blue = from.blue + 3 * (to.blue - from.blue) / 4;
-            Color color = new Color(getDisplay(), red, green, blue);
-            gc.setForeground(color);
-            gc.drawPolyline(line2);
-            gc.drawPolyline(line3);
-            color.dispose();
+    // draw border
+    gc.setForeground(border1);
+    gc.drawPolyline(line1);
+}
 
-            // draw tail fading to background
-            int x1 = Math.max(0, curveStart - CURVE_TAIL);
-            gc.setForeground(background);
-            gc.setBackground(border1);
-            gc.fillGradientRectangle(x1, size.y - BORDER_STRIPE, curveStart - x1 + 1, 1, false);
-        }
-        else {
-            // draw solid tail
-            int x1 = Math.max(0, curveStart - CURVE_TAIL);
-            gc.setForeground(border1);
-            gc.drawLine(x1, size.y - BORDER_STRIPE, curveStart + 1, size.y - BORDER_STRIPE);
-        }
-
-        // draw border
-        gc.setForeground(border1);
-        gc.drawPolyline(line1);
-    }
-
-    void onResize () {
-        updateCurve(getSize().y);
+void onResize() {
+    updateCurve(getSize().y);
+}
+/**
+* Set the control that appears on the bottom side of the banner.
+* The bottom control is optional.  Setting the bottom control to null will remove it from
+* the banner - however, the creator of the control must dispose of the control.
+*
+* @param control the control to be displayed on the bottom or null
+*
+* @exception DWTException <ul>
+*    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+*    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+*    <li>ERROR_INVALID_ARGUMENT - if the bottom control was not created as a child of the receiver</li>
+* </ul>
+*
+* @since 3.0
+*/
+public void setBottom(Control control) {
+    checkWidget();
+    if (control !is null && control.getParent() !is this) {
+        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     }
-
-    /**
-     * Set the control that appears on the bottom side of the banner.
-     * The bottom control is optional.  Setting the bottom control to null will remove it from 
-     * the banner - however, the creator of the control must dispose of the control.
-     * 
-     * @param control the control to be displayed on the bottom or null
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if the bottom control was not created as a child of the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setBottom (Control control) {
-        checkWidget();
-        if (control !is null && control.getParent() !is this) {
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }
-        if (bottom !is null && !bottom.isDisposed()) {
-            Point size = bottom.getSize();
-            bottom.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
-        }
-        bottom = control;
-        layout(false);
+    if (bottom !is null && !bottom.isDisposed()) {
+        Point size = bottom.getSize();
+        bottom.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
     }
-
-    /**
-     * Sets the layout which is associated with the receiver to be
-     * the argument which may be null.
-     * <p>
-     * Note: No Layout can be set on this Control because it already
-     * manages the size and position of its children.
-     * </p>
-     *
-     * @param layout the receiver's new layout or null
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setLayout (Layout layout) {
-        checkWidget();
-        return;
-    }
+    bottom = control;
+    layout(false);
+}
+/**
+ * Sets the layout which is associated with the receiver to be
+ * the argument which may be null.
+ * <p>
+ * Note: No Layout can be set on this Control because it already
+ * manages the size and position of its children.
+ * </p>
+ *
+ * @param layout the receiver's new layout or null
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public override void setLayout (Layout layout) {
+    checkWidget();
+    return;
+}
 
-    /**
-     * Set the control that appears on the left side of the banner.
-     * The left control is optional.  Setting the left control to null will remove it from 
-     * the banner - however, the creator of the control must dispose of the control.
-     * 
-     * @param control the control to be displayed on the left or null
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if the left control was not created as a child of the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setLeft (Control control) {
-        checkWidget();
-        if (control !is null && control.getParent() !is this) {
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }
-        if (left !is null && !left.isDisposed()) {
-            Point size = left.getSize();
-            left.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
-        }
-        left = control;
-        layout(false);
+/**
+* Set the control that appears on the left side of the banner.
+* The left control is optional.  Setting the left control to null will remove it from
+* the banner - however, the creator of the control must dispose of the control.
+*
+* @param control the control to be displayed on the left or null
+*
+* @exception DWTException <ul>
+*    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+*    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+*    <li>ERROR_INVALID_ARGUMENT - if the left control was not created as a child of the receiver</li>
+* </ul>
+*
+* @since 3.0
+*/
+public void setLeft(Control control) {
+    checkWidget();
+    if (control !is null && control.getParent() !is this) {
+        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    if (left !is null && !left.isDisposed()) {
+        Point size = left.getSize();
+        left.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
     }
-
-    /**
-     * Set the control that appears on the right side of the banner.
-     * The right control is optional.  Setting the right control to null will remove it from 
-     * the banner - however, the creator of the control must dispose of the control.
-     * 
-     * @param control the control to be displayed on the right or null
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if the right control was not created as a child of the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setRight (Control control) {
-        checkWidget();
-        if (control !is null && control.getParent() !is this) {
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }
-        if (right !is null && !right.isDisposed()) {
-            Point size = right.getSize();
-            right.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
-        }
-        right = control;
-        layout(false);
+    left = control;
+    layout(false);
+}
+/**
+* Set the control that appears on the right side of the banner.
+* The right control is optional.  Setting the right control to null will remove it from
+* the banner - however, the creator of the control must dispose of the control.
+*
+* @param control the control to be displayed on the right or null
+*
+* @exception DWTException <ul>
+*    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+*    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+*    <li>ERROR_INVALID_ARGUMENT - if the right control was not created as a child of the receiver</li>
+* </ul>
+*
+* @since 3.0
+*/
+public void setRight(Control control) {
+    checkWidget();
+    if (control !is null && control.getParent() !is this) {
+        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    if (right !is null && !right.isDisposed()) {
+        Point size = right.getSize();
+        right.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
     }
-
-    /**
-     * Set the minimum height of the control that appears on the right side of the banner.
-     * 
-     * @param size the minimum size of the control on the right
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if the size is null or the values of size are less than DWT.DEFAULT</li>
-     * </ul>
-     * 
-     * @since 3.1
-     */
-    public void setRightMinimumSize (Point size) {
-        checkWidget();
-        if (size is null || size.x < DWT.DEFAULT || size.y < DWT.DEFAULT)
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        rightMinWidth = size.x;
-        rightMinHeight = size.y;
+    right = control;
+    layout(false);
+}
+/**
+ * Set the minimum height of the control that appears on the right side of the banner.
+ *
+ * @param size the minimum size of the control on the right
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the size is null or the values of size are less than DWT.DEFAULT</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setRightMinimumSize(Point size) {
+    checkWidget();
+    if (size is null || size.x < DWT.DEFAULT || size.y < DWT.DEFAULT) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    rightMinWidth = size.x;
+    rightMinHeight = size.y;
+    layout(false);
+}
+/**
+ * Set the width of the control that appears on the right side of the banner.
+ *
+ * @param width the width of the control on the right
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if width is less than DWT.DEFAULT</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setRightWidth(int width) {
+    checkWidget();
+    if (width < DWT.DEFAULT) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    rightWidth = width;
+    layout(false);
+}
+/**
+ * Sets the shape that the CBanner will use to render itself.
+ *
+ * @param simple <code>true</code> if the CBanner should render itself in a simple, traditional style
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setSimple(bool simple) {
+    checkWidget();
+    if (this.simple !is simple) {
+        this.simple = simple;
+        if (simple) {
+            curve_width = 5;
+            curve_indent = -2;
+        } else {
+            curve_width = 50;
+            curve_indent = 5;
+        }
+        updateCurve(getSize().y);
         layout(false);
-    }
-
-    /**
-     * Set the width of the control that appears on the right side of the banner.
-     * 
-     * @param width the width of the control on the right
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if width is less than DWT.DEFAULT</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setRightWidth (int width) {
-        checkWidget();
-        if (width < DWT.DEFAULT)
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        rightWidth = width;
-        layout(false);
-    }
-
-    /**
-     * Sets the shape that the CBanner will use to render itself.  
-     * 
-     * @param simple <code>true</code> if the CBanner should render itself in a simple, traditional style
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @since 3.0
-     */
-    public void setSimple (bool simple) {
-        checkWidget();
-        if (this.simple !is simple) {
-            this.simple = simple;
-            if (simple) {
-                curve_width = 5;
-                curve_indent = -2;
-            }
-            else {
-                curve_width = 50;
-                curve_indent = 5;
-            }
-            updateCurve(getSize().y);
-            layout(false);
-            redraw();
-        }
-    }
-
-    void updateCurve (int height) {
-        int h = height - BORDER_STRIPE;
-        if (simple) {
-            curve = new int[][0 , h , 1 , h , 2 , h - 1 , 3 , h - 2 , 3 , 2 , 4 , 1 , 5 , 0];
-        }
-        else {
-            curve = bezier(0, h + 1, BEZIER_LEFT, h + 1, curve_width - BEZIER_RIGHT, 0, curve_width, 0, curve_width);
-        }
+        redraw();
     }
 }
+void updateCurve(int height) {
+    int h = height - BORDER_STRIPE;
+    if (simple) {
+        curve = [0,h, 1,h, 2,h-1, 3,h-2,
+                                   3,2, 4,1, 5,0];
+    } else {
+        curve = bezier(0, h+1, BEZIER_LEFT, h+1,
+                             curve_width-BEZIER_RIGHT, 0, curve_width, 0,
+                             curve_width);
+    }
+}
+}
--- a/dwt/custom/CBannerLayout.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/CBannerLayout.d	Tue Oct 07 16:29:55 2008 +0200
@@ -7,207 +7,193 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.CBannerLayout;
 
-import Math = tango.math.Math;
 
 import dwt.DWT;
-import dwt.custom.CBanner;
 import dwt.graphics.Point;
 import dwt.graphics.Rectangle;
 import dwt.widgets.Composite;
 import dwt.widgets.Control;
 import dwt.widgets.Layout;
 import dwt.widgets.Scrollable;
+import dwt.custom.CBanner;
+import dwt.custom.CLayoutData;
+
+import Math = tango.math.Math;
 
 /**
  * This class provides the layout for CBanner
- * 
+ *
  * @see CBanner
  */
 class CBannerLayout : Layout {
 
-    protected Point computeSize (Composite composite, int wHint, int hHint, bool flushCache) {
-        CBanner banner = cast(CBanner) composite;
-        Control left = banner.left;
-        Control right = banner.right;
-        Control bottom = banner.bottom;
-        bool showCurve = left !is null && right !is null;
-        int height = hHint;
-        int width = wHint;
+protected override Point computeSize(Composite composite, int wHint, int hHint, bool flushCache) {
+    CBanner banner = cast(CBanner)composite;
+    Control left = banner.left;
+    Control right = banner.right;
+    Control bottom = banner.bottom;
+    bool showCurve = left !is null && right !is null;
+    int height = hHint;
+    int width = wHint;
 
-        // Calculate component sizes
-        Point bottomSize = new Point(0, 0);
-        if (bottom !is null) {
-            int trim = computeTrim(bottom);
-            int w = wHint is DWT.DEFAULT ? DWT.DEFAULT : Math.max(0, width - trim);
-            bottomSize = computeChildSize(bottom, w, DWT.DEFAULT, flushCache);
-        }
-        Point rightSize = new Point(0, 0);
-        if (right !is null) {
-            int trim = computeTrim(right);
-            int w = DWT.DEFAULT;
-            if (banner.rightWidth !is DWT.DEFAULT) {
-                w = banner.rightWidth - trim;
-                if (left !is null) {
-                    w = Math.min(w, width - banner.curve_width + 2 * banner.curve_indent - CBanner.MIN_LEFT - trim);
-                }
-                w = Math.max(0, w);
+    // Calculate component sizes
+    Point bottomSize = new Point(0, 0);
+    if (bottom !is null) {
+        int trim = computeTrim(bottom);
+        int w = wHint is DWT.DEFAULT ? DWT.DEFAULT : Math.max(0, width - trim);
+        bottomSize = computeChildSize(bottom, w, DWT.DEFAULT, flushCache);
+    }
+    Point rightSize = new Point(0, 0);
+    if (right !is null) {
+        int trim = computeTrim(right);
+        int w = DWT.DEFAULT;
+        if (banner.rightWidth !is DWT.DEFAULT) {
+            w = banner.rightWidth - trim;
+            if (left !is null) {
+                w = Math.min(w, width - banner.curve_width + 2* banner.curve_indent - CBanner.MIN_LEFT - trim);
             }
-            rightSize = computeChildSize(right, w, DWT.DEFAULT, flushCache);
-            if (wHint !is DWT.DEFAULT) {
-                width -= rightSize.x + banner.curve_width - 2 * banner.curve_indent;
-            }
+            w = Math.max(0, w);
         }
-        Point leftSize = new Point(0, 0);
-        if (left !is null) {
-            int trim = computeTrim(left);
-            int w = wHint is DWT.DEFAULT ? DWT.DEFAULT : Math.max(0, width - trim);
-            leftSize = computeChildSize(left, w, DWT.DEFAULT, flushCache);
-        }
-
-        // Add up sizes
-        width = leftSize.x + rightSize.x;
-        height = bottomSize.y;
-        if (bottom !is null && (left !is null || right !is null)) {
-            height += CBanner.BORDER_STRIPE + 2;
+        rightSize = computeChildSize(right, w, DWT.DEFAULT, flushCache);
+        if (wHint !is DWT.DEFAULT) {
+            width -= rightSize.x + banner.curve_width - 2* banner.curve_indent;
         }
-        if (left !is null) {
-            if (right is null) {
-                height += leftSize.y;
-            }
-            else {
-                height += Math.max(leftSize.y, banner.rightMinHeight is DWT.DEFAULT ? rightSize.y : banner.rightMinHeight);
-            }
-        }
-        else {
-            height += rightSize.y;
-        }
-        if (showCurve) {
-            width += banner.curve_width - 2 * banner.curve_indent;
-            height += CBanner.BORDER_TOP + CBanner.BORDER_BOTTOM + 2 * CBanner.BORDER_STRIPE;
-        }
-
-        if (wHint !is DWT.DEFAULT)
-            width = wHint;
-        if (hHint !is DWT.DEFAULT)
-            height = hHint;
-
-        return new Point(width, height);
+    }
+    Point leftSize = new Point(0, 0);
+    if (left !is null) {
+        int trim = computeTrim(left);
+        int w = wHint is DWT.DEFAULT ? DWT.DEFAULT : Math.max(0, width - trim);
+        leftSize = computeChildSize(left, w, DWT.DEFAULT, flushCache);
     }
 
-    Point computeChildSize (Control control, int wHint, int hHint, bool flushCache) {
-        Object data = control.getLayoutData();
-        if (data is null || !(cast(CLayoutData) data)) {
-            data = new CLayoutData();
-            control.setLayoutData(data);
-        }
-        return (cast(CLayoutData) data).computeSize(control, wHint, hHint, flushCache);
+    // Add up sizes
+    width = leftSize.x + rightSize.x;
+    height = bottomSize.y;
+    if (bottom !is null && (left !is null || right !is null)) {
+        height += CBanner.BORDER_STRIPE + 2;
     }
-
-    int computeTrim (Control c) {
-        if (cast(Scrollable) c) {
-            Rectangle rect = (cast(Scrollable) c).computeTrim(0, 0, 0, 0);
-            return rect.width;
+    if (left !is null) {
+        if (right is null) {
+            height += leftSize.y;
+        } else {
+            height += Math.max(leftSize.y, banner.rightMinHeight is DWT.DEFAULT ? rightSize.y : banner.rightMinHeight);
         }
-        return c.getBorderWidth() * 2;
+    } else {
+        height += rightSize.y;
+    }
+    if (showCurve) {
+        width += banner.curve_width - 2*banner.curve_indent;
+        height +=  CBanner.BORDER_TOP + CBanner.BORDER_BOTTOM + 2*CBanner.BORDER_STRIPE;
     }
 
-    protected bool flushCache (Control control) {
-        Object data = control.getLayoutData();
-        if (data !is null && cast(CLayoutData) data)
-            (cast(CLayoutData) data).flushCache();
-        return true;
+    if (wHint !is DWT.DEFAULT) width = wHint;
+    if (hHint !is DWT.DEFAULT) height = hHint;
+
+    return new Point(width, height);
+}
+Point computeChildSize(Control control, int wHint, int hHint, bool flushCache) {
+    Object data = control.getLayoutData();
+    if (data is null || !( null !is cast(CLayoutData)data)) {
+        data = new CLayoutData();
+        control.setLayoutData(data);
+    }
+    return (cast(CLayoutData)data).computeSize(control, wHint, hHint, flushCache);
+}
+int computeTrim(Control c) {
+    if ( auto s = cast(Scrollable)c) {
+        Rectangle rect = s.computeTrim (0, 0, 0, 0);
+        return rect.width;
+    }
+    return c.getBorderWidth () * 2;
+}
+protected override bool flushCache(Control control) {
+    Object data = control.getLayoutData();
+    if ( auto ld = cast(CLayoutData)data ) ld.flushCache();
+    return true;
+}
+protected override void layout(Composite composite, bool flushCache) {
+    CBanner banner = cast(CBanner)composite;
+    Control left = banner.left;
+    Control right = banner.right;
+    Control bottom = banner.bottom;
+
+    Point size = banner.getSize();
+    bool showCurve = left !is null && right !is null;
+    int width = size.x - 2*banner.getBorderWidth();
+    int height = size.y - 2*banner.getBorderWidth();
+
+    Point bottomSize = new Point(0, 0);
+    if (bottom !is null) {
+        int trim = computeTrim(bottom);
+        int w = Math.max(0, width - trim);
+        bottomSize = computeChildSize(bottom, w, DWT.DEFAULT, flushCache);
+        height -= bottomSize.y + CBanner.BORDER_STRIPE + 2;
+    }
+    if (showCurve) height -=  CBanner.BORDER_TOP + CBanner.BORDER_BOTTOM + 2*CBanner.BORDER_STRIPE;
+    height = Math.max(0, height);
+    Point rightSize = new Point(0,0);
+    if (right !is null) {
+        int trim = computeTrim(right);
+        int w = DWT.DEFAULT;
+        if (banner.rightWidth !is DWT.DEFAULT) {
+            w = banner.rightWidth - trim;
+            if (left !is null) {
+                w = Math.min(w, width - banner.curve_width + 2* banner.curve_indent - CBanner.MIN_LEFT - trim);
+            }
+            w = Math.max(0, w);
+        }
+        rightSize = computeChildSize(right, w, DWT.DEFAULT, flushCache);
+        width = width - (rightSize.x - banner.curve_indent + banner.curve_width - banner.curve_indent);
+    }
+    Point leftSize = new Point(0, 0);
+    if (left !is null) {
+        int trim = computeTrim(left);
+        int w = Math.max(0, width - trim);
+        leftSize = computeChildSize(left, w, DWT.DEFAULT, flushCache);
     }
 
-    protected void layout (Composite composite, bool flushCache) {
-        CBanner banner = cast(CBanner) composite;
-        Control left = banner.left;
-        Control right = banner.right;
-        Control bottom = banner.bottom;
-
-        Point size = banner.getSize();
-        bool showCurve = left !is null && right !is null;
-        int width = size.x - 2 * banner.getBorderWidth();
-        int height = size.y - 2 * banner.getBorderWidth();
-
-        Point bottomSize = new Point(0, 0);
-        if (bottom !is null) {
-            int trim = computeTrim(bottom);
-            int w = Math.max(0, width - trim);
-            bottomSize = computeChildSize(bottom, w, DWT.DEFAULT, flushCache);
-            height -= bottomSize.y + CBanner.BORDER_STRIPE + 2;
-        }
-        if (showCurve)
-            height -= CBanner.BORDER_TOP + CBanner.BORDER_BOTTOM + 2 * CBanner.BORDER_STRIPE;
-        height = Math.max(0, height);
-        Point rightSize = new Point(0, 0);
-        if (right !is null) {
-            int trim = computeTrim(right);
-            int w = DWT.DEFAULT;
-            if (banner.rightWidth !is DWT.DEFAULT) {
-                w = banner.rightWidth - trim;
-                if (left !is null) {
-                    w = Math.min(w, width - banner.curve_width + 2 * banner.curve_indent - CBanner.MIN_LEFT - trim);
-                }
-                w = Math.max(0, w);
-            }
-            rightSize = computeChildSize(right, w, DWT.DEFAULT, flushCache);
-            width = width - (rightSize.x - banner.curve_indent + banner.curve_width - banner.curve_indent);
-        }
-        Point leftSize = new Point(0, 0);
+    int x = 0;
+    int y = 0;
+    int oldStart = banner.curveStart;
+    Rectangle leftRect = null;
+    Rectangle rightRect = null;
+    Rectangle bottomRect = null;
+    if (bottom !is null) {
+        bottomRect = new Rectangle(x, y+size.y-bottomSize.y, bottomSize.x, bottomSize.y);
+    }
+    if (showCurve) y += CBanner.BORDER_TOP + CBanner.BORDER_STRIPE;
+    if(left !is null) {
+        leftRect = new Rectangle(x, y, leftSize.x, leftSize.y);
+        banner.curveStart = x + leftSize.x - banner.curve_indent;
+        x += leftSize.x - banner.curve_indent + banner.curve_width - banner.curve_indent;
+    }
+    if (right !is null) {
         if (left !is null) {
-            int trim = computeTrim(left);
-            int w = Math.max(0, width - trim);
-            leftSize = computeChildSize(left, w, DWT.DEFAULT, flushCache);
+            rightSize.y = Math.max(leftSize.y, banner.rightMinHeight is DWT.DEFAULT ? rightSize.y : banner.rightMinHeight);
         }
-
-        int x = 0;
-        int y = 0;
-        int oldStart = banner.curveStart;
-        Rectangle leftRect = null;
-        Rectangle rightRect = null;
-        Rectangle bottomRect = null;
-        if (bottom !is null) {
-            bottomRect = new Rectangle(x, y + size.y - bottomSize.y, bottomSize.x, bottomSize.y);
-        }
-        if (showCurve)
-            y += CBanner.BORDER_TOP + CBanner.BORDER_STRIPE;
-        if (left !is null) {
-            leftRect = new Rectangle(x, y, leftSize.x, leftSize.y);
-            banner.curveStart = x + leftSize.x - banner.curve_indent;
-            x += leftSize.x - banner.curve_indent + banner.curve_width - banner.curve_indent;
-        }
-        if (right !is null) {
-            if (left !is null) {
-                rightSize.y = Math.max(leftSize.y, banner.rightMinHeight is DWT.DEFAULT ? rightSize.y : banner.rightMinHeight);
-            }
-            rightRect = new Rectangle(x, y, rightSize.x, rightSize.y);
-        }
-        if (banner.curveStart < oldStart) {
-            banner.redraw(banner.curveStart - CBanner.CURVE_TAIL, 0, oldStart + banner.curve_width - banner.curveStart + CBanner.CURVE_TAIL + 5,
-                    size.y, false);
-        }
-        if (banner.curveStart > oldStart) {
-            banner.redraw(oldStart - CBanner.CURVE_TAIL, 0, banner.curveStart + banner.curve_width - oldStart + CBanner.CURVE_TAIL + 5, size.y, false);
-        }
-        /*
-         * The paint events must be flushed in order to make the curve draw smoothly
-         * while the user drags the divider.
-         * On Windows, it is necessary to flush the paints before the children are 
-         * resized because otherwise the children (particularly toolbars) will flash.
-         */
-        banner.update();
-        banner.curveRect = new Rectangle(banner.curveStart, 0, banner.curve_width, size.y);
-        if (bottomRect !is null)
-            bottom.setBounds(bottomRect);
-        if (rightRect !is null)
-            right.setBounds(rightRect);
-        if (leftRect !is null)
-            left.setBounds(leftRect);
+        rightRect = new Rectangle(x, y, rightSize.x, rightSize.y);
+    }
+    if (banner.curveStart < oldStart) {
+        banner.redraw(banner.curveStart - CBanner.CURVE_TAIL, 0, oldStart + banner.curve_width - banner.curveStart + CBanner.CURVE_TAIL + 5, size.y, false);
+    }
+    if (banner.curveStart > oldStart) {
+        banner.redraw(oldStart - CBanner.CURVE_TAIL, 0, banner.curveStart + banner.curve_width - oldStart + CBanner.CURVE_TAIL + 5, size.y, false);
     }
+    /*
+     * The paint events must be flushed in order to make the curve draw smoothly
+     * while the user drags the divider.
+     * On Windows, it is necessary to flush the paints before the children are
+     * resized because otherwise the children (particularly toolbars) will flash.
+     */
+    banner.update();
+    banner.curveRect = new Rectangle(banner.curveStart, 0, banner.curve_width, size.y);
+    if (bottomRect !is null) bottom.setBounds(bottomRect);
+    if (rightRect !is null) right.setBounds(rightRect);
+    if (leftRect !is null) left.setBounds(leftRect);
 }
+}
--- a/dwt/custom/CCombo.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/CCombo.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,12 +7,13 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.CCombo;
 
+
+
 import dwt.DWT;
 import dwt.DWTException;
 import dwt.accessibility.ACC;
@@ -46,7 +47,11 @@
 import dwt.widgets.TypedListener;
 import dwt.widgets.Widget;
 
+static import tango.text.convert.Utf;
+static import tango.text.Unicode;
+static import tango.text.convert.Format;
 import dwt.dwthelper.utils;
+import dwt.dwthelper.Runnable;
 
 /**
  * The CCombo class represents a selectable user interface object
@@ -57,7 +62,7 @@
  * combo box. Specifically, on win32, the height of a CCombo can be set;
  * attempts to set the height of a Combo are ignored. CCombo can be used
  * anywhere that having the increased flexibility is more important than
- * getting native L&F, but the decision should not be taken lightly. 
+ * getting native L&F, but the decision should not be taken lightly.
  * There is no is no strict requirement that CCombo look or behave
  * the same as the native combo box.
  * </p>
@@ -71,9 +76,14 @@
  * <dt><b>Events:</b>
  * <dd>DefaultSelection, Modify, Selection, Verify</dd>
  * </dl>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#ccombo">CCombo snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: CustomControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
-public final class CCombo : Composite
-{
+public final class CCombo : Composite {
+
+    alias Composite.computeSize computeSize;
 
     Text text;
     List list;
@@ -85,2090 +95,1712 @@
     Color foreground, background;
     Font font;
 
-    /**
-     * Constructs a new instance of this class given its parent
-     * and a style value describing its behavior and appearance.
-     * <p>
-     * The style value is either one of the style constants defined in
-     * class <code>DWT</code> which is applicable to instances of this
-     * class, or must be built by <em>bitwise OR</em>'ing together 
-     * (that is, using the <code>int</code> "|" operator) two or more
-     * of those <code>DWT</code> style constants. The class description
-     * lists the style constants that are applicable to the class.
-     * Style bits are also inherited from superclasses.
-     * </p>
-     *
-     * @param parent a widget which will be the parent of the new instance (cannot be null)
-     * @param style the style of widget to construct
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
-     * </ul>
-     *
-     * @see DWT#BORDER
-     * @see DWT#READ_ONLY
-     * @see DWT#FLAT
-     * @see Widget#getStyle()
-     */
-    public this (Composite parent, int style)
-    {
-        super(parent, style = checkStyle(style));
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>DWT</code> which is applicable to instances of this
+ * class, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DWT</code> style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a widget which will be the parent of the new instance (cannot be null)
+ * @param style the style of widget to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * </ul>
+ *
+ * @see DWT#BORDER
+ * @see DWT#READ_ONLY
+ * @see DWT#FLAT
+ * @see Widget#getStyle()
+ */
+public this (Composite parent, int style) {
+    super (parent, style = checkStyle (style));
 
-        int textStyle = DWT.SINGLE;
-        if ((style & DWT.READ_ONLY) !is 0)
-            textStyle |= DWT.READ_ONLY;
-        if ((style & DWT.FLAT) !is 0)
-            textStyle |= DWT.FLAT;
-        text = new Text(this, textStyle);
-        int arrowStyle = DWT.ARROW | DWT.DOWN;
-        if ((style & DWT.FLAT) !is 0)
-            arrowStyle |= DWT.FLAT;
-        arrow = new Button(this, arrowStyle);
+    int textStyle = DWT.SINGLE;
+    if ((style & DWT.READ_ONLY) !is 0) textStyle |= DWT.READ_ONLY;
+    if ((style & DWT.FLAT) !is 0) textStyle |= DWT.FLAT;
+    text = new Text (this, textStyle);
+    int arrowStyle = DWT.ARROW | DWT.DOWN;
+    if ((style & DWT.FLAT) !is 0) arrowStyle |= DWT.FLAT;
+    arrow = new Button (this, arrowStyle);
 
-        listener = new class Listener
-        {
-            public void handleEvent (Event event)
-            {
-                if (popup is event.widget)
-                {
-                    popupEvent(event);
-                    return;
-                }
-                if (text is event.widget)
-                {
-                    textEvent(event);
-                    return;
-                }
-                if (list is event.widget)
-                {
-                    listEvent(event);
-                    return;
-                }
-                if (arrow is event.widget)
-                {
-                    arrowEvent(event);
-                    return;
-                }
-                if (this is event.widget)
-                {
-                    comboEvent(event);
-                    return;
-                }
-                if (getShell() is event.widget)
-                {
-                    getDisplay().asyncExec(new class Runnable
-                    {
-                        public void run ()
-                        {
-                            if (isDisposed())
-                                return;
-                            handleFocus(DWT.FocusOut);
-                        }
-                    });
-                }
+    listener = new class() Listener {
+        public void handleEvent (Event event) {
+            if (popup is event.widget) {
+                popupEvent (event);
+                return;
+            }
+            if (text is event.widget) {
+                textEvent (event);
+                return;
+            }
+            if (list is event.widget) {
+                listEvent (event);
+                return;
+            }
+            if (arrow is event.widget) {
+                arrowEvent (event);
+                return;
+            }
+            if (this.outer is event.widget) {
+                comboEvent (event);
+                return;
             }
-        };
-        filter = new class Listener
-        {
-            public void handleEvent (Event event)
-            {
-                Shell shell = (cast(Control) event.widget).getShell();
-                if (shell is this.getShell())
-                {
-                    handleFocus(DWT.FocusOut);
-                }
+            if (getShell () is event.widget) {
+                getDisplay().asyncExec(new class() Runnable {
+                    public void run() {
+                        if (isDisposed()) return;
+                        handleFocus (DWT.FocusOut);
+                    }
+                });
             }
-        };
-
-        int[] comboEvents = [DWT.Dispose, DWT.FocusIn, DWT.Move, DWT.Resize];
-        for (int i = 0; i < comboEvents.length; i++)
-            this.addListener(comboEvents[i], listener);
-
-        int[] textEvents = [DWT.DefaultSelection, DWT.KeyDown, DWT.KeyUp,
-                DWT.MenuDetect, DWT.Modify, DWT.MouseDown, DWT.MouseUp,
-                DWT.MouseDoubleClick, DWT.MouseWheel, DWT.Traverse,
-                DWT.FocusIn, DWT.Verify];
-        for (int i = 0; i < textEvents.length; i++)
-            text.addListener(textEvents[i], listener);
-
-        int[] arrowEvents = [DWT.MouseDown, DWT.MouseUp, DWT.Selection,
-                DWT.FocusIn];
-        for (int i = 0; i < arrowEvents.length; i++)
-            arrow.addListener(arrowEvents[i], listener);
+        }
+    };
+    filter = new class() Listener {
+        public void handleEvent(Event event) {
+            Shell shell = (cast(Control)event.widget).getShell ();
+            if (shell is this.outer.getShell ()) {
+                handleFocus (DWT.FocusOut);
+            }
+        }
+    };
 
-        createPopup(null, -1);
-        initAccessible();
-    }
-
-    static int checkStyle (int style)
-    {
-        int
-                mask = DWT.BORDER | DWT.READ_ONLY | DWT.FLAT | DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT;
-        return DWT.NO_FOCUS | (style & mask);
-    }
+    int [] comboEvents = [DWT.Dispose, DWT.FocusIn, DWT.Move, DWT.Resize];
+    for (int i=0; i<comboEvents.length; i++) this.addListener (comboEvents [i], listener);
 
-    /**
-     * Adds the argument to the end of the receiver's list.
-     *
-     * @param String the new item
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the String is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see #add(String,int)
-     */
-    public void add (String str)
-    {
-        checkWidget();
-        if (str is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        list.add(str);
-    }
+    int [] textEvents = [DWT.DefaultSelection, DWT.KeyDown, DWT.KeyUp, DWT.MenuDetect, DWT.Modify, DWT.MouseDown, DWT.MouseUp, DWT.MouseDoubleClick, DWT.MouseWheel, DWT.Traverse, DWT.FocusIn, DWT.Verify];
+    for (int i=0; i<textEvents.length; i++) text.addListener (textEvents [i], listener);
+
+    int [] arrowEvents = [DWT.MouseDown, DWT.MouseUp, DWT.Selection, DWT.FocusIn];
+    for (int i=0; i<arrowEvents.length; i++) arrow.addListener (arrowEvents [i], listener);
 
-    /**
-     * Adds the argument to the receiver's list at the given
-     * zero-relative index.
-     * <p>
-     * Note: To add an item at the end of the list, use the
-     * result of calling <code>getItemCount()</code> as the
-     * index or use <code>add(String)</code>.
-     * </p>
-     *
-     * @param String the new item
-     * @param index the index for the item
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the String is null</li>
-     *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see #add(String)
-     */
-    public void add (String str, int index)
-    {
-        checkWidget();
-        if (str is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        list.add(str, index);
-    }
-
-    /**
-     * Adds the listener to the collection of listeners who will
-     * be notified when the receiver's text is modified, by sending
-     * it one of the messages defined in the <code>ModifyListener</code>
-     * interface.
-     *
-     * @param listener the listener which should be notified
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see ModifyListener
-     * @see #removeModifyListener
-     */
-    public void addModifyListener (ModifyListener listener)
-    {
-        checkWidget();
-        if (listener is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        TypedListener typedListener = new TypedListener(listener);
-        addListener(DWT.Modify, typedListener);
-    }
-
-    /**
-     * Adds the listener to the collection of listeners who will
-     * be notified when the user changes the receiver's selection, by sending
-     * it one of the messages defined in the <code>SelectionListener</code>
-     * interface.
-     * <p>
-     * <code>widgetSelected</code> is called when the combo's list selection changes.
-     * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed the combo's text area.
-     * </p>
-     *
-     * @param listener the listener which should be notified when the user changes the receiver's selection
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see SelectionListener
-     * @see #removeSelectionListener
-     * @see SelectionEvent
-     */
-    public void addSelectionListener (SelectionListener listener)
-    {
-        checkWidget();
-        if (listener is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        TypedListener typedListener = new TypedListener(listener);
-        addListener(DWT.Selection, typedListener);
-        addListener(DWT.DefaultSelection, typedListener);
-    }
-
-    /**
-     * Adds the listener to the collection of listeners who will
-     * be notified when the receiver's text is verified, by sending
-     * it one of the messages defined in the <code>VerifyListener</code>
-     * interface.
-     *
-     * @param listener the listener which should be notified
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see VerifyListener
-     * @see #removeVerifyListener
-     * 
-     * @since 3.3
-     */
-    public void addVerifyListener (VerifyListener listener)
-    {
-        checkWidget();
-        if (listener is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        TypedListener typedListener = new TypedListener(listener);
-        addListener(DWT.Verify, typedListener);
-    }
-
-    void arrowEvent (Event event)
-    {
-        switch (event.type)
-        {
-            case DWT.FocusIn:
-            {
-                handleFocus(DWT.FocusIn);
-                break;
-            }
-            case DWT.MouseDown:
-            {
-                Event mouseEvent = new Event();
-                mouseEvent.button = event.button;
-                mouseEvent.count = event.count;
-                mouseEvent.stateMask = event.stateMask;
-                mouseEvent.time = event.time;
-                mouseEvent.x = event.x;
-                mouseEvent.y = event.y;
-                notifyListeners(DWT.MouseDown, mouseEvent);
-                event.doit = mouseEvent.doit;
-                break;
-            }
-            case DWT.MouseUp:
-            {
-                Event mouseEvent = new Event();
-                mouseEvent.button = event.button;
-                mouseEvent.count = event.count;
-                mouseEvent.stateMask = event.stateMask;
-                mouseEvent.time = event.time;
-                mouseEvent.x = event.x;
-                mouseEvent.y = event.y;
-                notifyListeners(DWT.MouseUp, mouseEvent);
-                event.doit = mouseEvent.doit;
-                break;
-            }
-            case DWT.Selection:
-            {
-                text.setFocus();
-                dropDown(!isDropped());
-                break;
-            }
-
-            default:
+    createPopup(null, -1);
+    initAccessible();
+}
+static int checkStyle (int style) {
+    int mask = DWT.BORDER | DWT.READ_ONLY | DWT.FLAT | DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT;
+    return DWT.NO_FOCUS | (style & mask);
+}
+/**
+ * Adds the argument to the end of the receiver's list.
+ *
+ * @param string the new item
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see #add(String,int)
+ */
+public void add (String string) {
+    checkWidget();
+    // DWT extension: allow null for zero length string
+    //if (string is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    list.add (string);
+}
+/**
+ * Adds the argument to the receiver's list at the given
+ * zero-relative index.
+ * <p>
+ * Note: To add an item at the end of the list, use the
+ * result of calling <code>getItemCount()</code> as the
+ * index or use <code>add(String)</code>.
+ * </p>
+ *
+ * @param string the new item
+ * @param index the index for the item
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see #add(String)
+ */
+public void add (String string, int index) {
+    checkWidget();
+    // DWT extension: allow null for zero length string
+    //if (string is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    list.add (string, index);
+}
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver's text is modified, by sending
+ * it one of the messages defined in the <code>ModifyListener</code>
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see ModifyListener
+ * @see #removeModifyListener
+ */
+public void addModifyListener (ModifyListener listener) {
+    checkWidget();
+    if (listener is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    TypedListener typedListener = new TypedListener (listener);
+    addListener (DWT.Modify, typedListener);
+}
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's selection, by sending
+ * it one of the messages defined in the <code>SelectionListener</code>
+ * interface.
+ * <p>
+ * <code>widgetSelected</code> is called when the combo's list selection changes.
+ * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed the combo's text area.
+ * </p>
+ *
+ * @param listener the listener which should be notified when the user changes the receiver's selection
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener(SelectionListener listener) {
+    checkWidget();
+    if (listener is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    TypedListener typedListener = new TypedListener (listener);
+    addListener (DWT.Selection,typedListener);
+    addListener (DWT.DefaultSelection,typedListener);
+}
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the receiver's text is verified, by sending
+ * it one of the messages defined in the <code>VerifyListener</code>
+ * interface.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see VerifyListener
+ * @see #removeVerifyListener
+ *
+ * @since 3.3
+ */
+public void addVerifyListener (VerifyListener listener) {
+    checkWidget();
+    if (listener is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    TypedListener typedListener = new TypedListener (listener);
+    addListener (DWT.Verify,typedListener);
+}
+void arrowEvent (Event event) {
+    switch (event.type) {
+        case DWT.FocusIn: {
+            handleFocus (DWT.FocusIn);
             break;
         }
-    }
-
-    /**
-     * Sets the selection in the receiver's text field to an empty
-     * selection starting just before the first character. If the
-     * text field is editable, this has the effect of placing the
-     * i-beam at the start of the text.
-     * <p>
-     * Note: To clear the selected items in the receiver's list, 
-     * use <code>deselectAll()</code>.
-     * </p>
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see #deselectAll
-     */
-    public void clearSelection ()
-    {
-        checkWidget();
-        text.clearSelection();
-        list.deselectAll();
-    }
-
-    void comboEvent (Event event)
-    {
-        switch (event.type)
-        {
-            case DWT.Dispose:
-                if (popup !is null && !popup.isDisposed())
-                {
-                    list.removeListener(DWT.Dispose, listener);
-                    popup.dispose();
-                }
-                Shell shell = getShell();
-                shell.removeListener(DWT.Deactivate, listener);
-                Display display = getDisplay();
-                display.removeFilter(DWT.FocusIn, filter);
-                popup = null;
-                text = null;
-                list = null;
-                arrow = null;
+        case DWT.MouseDown: {
+            Event mouseEvent = new Event ();
+            mouseEvent.button = event.button;
+            mouseEvent.count = event.count;
+            mouseEvent.stateMask = event.stateMask;
+            mouseEvent.time = event.time;
+            mouseEvent.x = event.x; mouseEvent.y = event.y;
+            notifyListeners (DWT.MouseDown, mouseEvent);
+            event.doit = mouseEvent.doit;
             break;
-            case DWT.FocusIn:
-                Control focusControl = getDisplay().getFocusControl();
-                if (focusControl is arrow || focusControl is list)
-                    return;
-                if (isDropped())
-                {
-                    list.setFocus();
-                }
-                else
-                {
-                    text.setFocus();
-                }
+        }
+        case DWT.MouseUp: {
+            Event mouseEvent = new Event ();
+            mouseEvent.button = event.button;
+            mouseEvent.count = event.count;
+            mouseEvent.stateMask = event.stateMask;
+            mouseEvent.time = event.time;
+            mouseEvent.x = event.x; mouseEvent.y = event.y;
+            notifyListeners (DWT.MouseUp, mouseEvent);
+            event.doit = mouseEvent.doit;
             break;
-            case DWT.Move:
-                dropDown(false);
-            break;
-            case DWT.Resize:
-                internalLayout(false);
-            break;
-
-            default:
+        }
+        case DWT.Selection: {
+            text.setFocus();
+            dropDown (!isDropped ());
             break;
         }
+        default:
     }
-
-    public Point computeSize (int wHint, int hHint, bool changed)
-    {
-        checkWidget();
-        int width = 0, height = 0;
-        String[] items = list.getItems();
-        GC gc = new GC(text);
-        int spacer = gc.StringExtent(" ").x; //$NON-NLS-1$
-        int textWidth = gc.StringExtent(text.getText()).x;
-        for (int i = 0; i < items.length; i++)
-        {
-            textWidth = Math.max(gc.StringExtent(items[i]).x, textWidth);
-        }
-        gc.dispose();
-        Point textSize = text.computeSize(DWT.DEFAULT, DWT.DEFAULT, changed);
-        Point arrowSize = arrow.computeSize(DWT.DEFAULT, DWT.DEFAULT, changed);
-        Point listSize = list.computeSize(DWT.DEFAULT, DWT.DEFAULT, changed);
-        int borderWidth = getBorderWidth();
+}
+/**
+ * Sets the selection in the receiver's text field to an empty
+ * selection starting just before the first character. If the
+ * text field is editable, this has the effect of placing the
+ * i-beam at the start of the text.
+ * <p>
+ * Note: To clear the selected items in the receiver's list,
+ * use <code>deselectAll()</code>.
+ * </p>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see #deselectAll
+ */
+public void clearSelection () {
+    checkWidget ();
+    text.clearSelection ();
+    list.deselectAll ();
+}
+void comboEvent (Event event) {
+    switch (event.type) {
+        case DWT.Dispose:
+            if (popup !is null && !popup.isDisposed ()) {
+                list.removeListener (DWT.Dispose, listener);
+                popup.dispose ();
+            }
+            Shell shell = getShell ();
+            shell.removeListener (DWT.Deactivate, listener);
+            Display display = getDisplay ();
+            display.removeFilter (DWT.FocusIn, filter);
+            popup = null;
+            text = null;
+            list = null;
+            arrow = null;
+            break;
+        case DWT.FocusIn:
+            Control focusControl = getDisplay ().getFocusControl ();
+            if (focusControl is arrow || focusControl is list) return;
+            if (isDropped()) {
+                list.setFocus();
+            } else {
+                text.setFocus();
+            }
+            break;
+        case DWT.Move:
+            dropDown (false);
+            break;
+        case DWT.Resize:
+            internalLayout (false);
+            break;
+        default:
+    }
+}
 
-        height = Math.max(textSize.y, arrowSize.y);
-        width = Math.max(
-                textWidth + 2 * spacer + arrowSize.x + 2 * borderWidth,
-                listSize.x);
-        if (wHint !is DWT.DEFAULT)
-            width = wHint;
-        if (hHint !is DWT.DEFAULT)
-            height = hHint;
-        return new Point(width + 2 * borderWidth, height + 2 * borderWidth);
+public override Point computeSize (int wHint, int hHint, bool changed) {
+    checkWidget ();
+    int width = 0, height = 0;
+    String[] items = list.getItems ();
+    GC gc = new GC (text);
+    int spacer = gc.stringExtent (" ").x; //$NON-NLS-1$
+    int textWidth = gc.stringExtent (text.getText ()).x;
+    for (int i = 0; i < items.length; i++) {
+        textWidth = Math.max (gc.stringExtent (items[i]).x, textWidth);
     }
-
-    /**
-     * Copies the selected text.
-     * <p>
-     * The current selection is copied to the clipboard.
-     * </p>
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.3
-     */
-    public void copy ()
-    {
-        checkWidget();
-        text.copy();
-    }
+    gc.dispose ();
+    Point textSize = text.computeSize (DWT.DEFAULT, DWT.DEFAULT, changed);
+    Point arrowSize = arrow.computeSize (DWT.DEFAULT, DWT.DEFAULT, changed);
+    Point listSize = list.computeSize (DWT.DEFAULT, DWT.DEFAULT, changed);
+    int borderWidth = getBorderWidth ();
 
-    void createPopup (String[] items, int selectionIndex)
-    {
-        // create shell and list
-        popup = new Shell(getShell(), DWT.NO_TRIM | DWT.ON_TOP);
-        int style = getStyle();
-        int listStyle = DWT.SINGLE | DWT.V_SCROLL;
-        if ((style & DWT.FLAT) !is 0)
-            listStyle |= DWT.FLAT;
-        if ((style & DWT.RIGHT_TO_LEFT) !is 0)
-            listStyle |= DWT.RIGHT_TO_LEFT;
-        if ((style & DWT.LEFT_TO_RIGHT) !is 0)
-            listStyle |= DWT.LEFT_TO_RIGHT;
-        list = new List(popup, listStyle);
-        if (font !is null)
-            list.setFont(font);
-        if (foreground !is null)
-            list.setForeground(foreground);
-        if (background !is null)
-            list.setBackground(background);
+    height = Math.max (textSize.y, arrowSize.y);
+    width = Math.max (textWidth + 2*spacer + arrowSize.x + 2*borderWidth, listSize.x);
+    if (wHint !is DWT.DEFAULT) width = wHint;
+    if (hHint !is DWT.DEFAULT) height = hHint;
+    return new Point (width + 2*borderWidth, height + 2*borderWidth);
+}
+/**
+ * Copies the selected text.
+ * <p>
+ * The current selection is copied to the clipboard.
+ * </p>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.3
+ */
+public void copy () {
+    checkWidget ();
+    text.copy ();
+}
+void createPopup(String[] items, int selectionIndex) {
+    // create shell and list
+    popup = new Shell (getShell (), DWT.NO_TRIM | DWT.ON_TOP);
+    int style = getStyle ();
+    int listStyle = DWT.SINGLE | DWT.V_SCROLL;
+    if ((style & DWT.FLAT) !is 0) listStyle |= DWT.FLAT;
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) listStyle |= DWT.RIGHT_TO_LEFT;
+    if ((style & DWT.LEFT_TO_RIGHT) !is 0) listStyle |= DWT.LEFT_TO_RIGHT;
+    list = new List (popup, listStyle);
+    if (font !is null) list.setFont (font);
+    if (foreground !is null) list.setForeground (foreground);
+    if (background !is null) list.setBackground (background);
+
+    int [] popupEvents = [DWT.Close, DWT.Paint, DWT.Deactivate];
+    for (int i=0; i<popupEvents.length; i++) popup.addListener (popupEvents [i], listener);
+    int [] listEvents = [DWT.MouseUp, DWT.Selection, DWT.Traverse, DWT.KeyDown, DWT.KeyUp, DWT.FocusIn, DWT.Dispose];
+    for (int i=0; i<listEvents.length; i++) list.addListener (listEvents [i], listener);
 
-        int[] popupEvents = [DWT.Close, DWT.Paint, DWT.Deactivate];
-        for (int i = 0; i < popupEvents.length; i++)
-            popup.addListener(popupEvents[i], listener);
-        int[] listEvents = [DWT.MouseUp, DWT.Selection, DWT.Traverse,
-                DWT.KeyDown, DWT.KeyUp, DWT.FocusIn, DWT.Dispose];
-        for (int i = 0; i < listEvents.length; i++)
-            list.addListener(listEvents[i], listener);
-
-        if (items !is null)
-            list.setItems(items);
-        if (selectionIndex !is -1)
-            list.setSelection(selectionIndex);
+    if (items !is null) list.setItems (items);
+    if (selectionIndex !is -1) list.setSelection (selectionIndex);
+}
+/**
+ * Cuts the selected text.
+ * <p>
+ * The current selection is first copied to the
+ * clipboard and then deleted from the widget.
+ * </p>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.3
+ */
+public void cut () {
+    checkWidget ();
+    text.cut ();
+}
+/**
+ * Deselects the item at the given zero-relative index in the receiver's
+ * list.  If the item at the index was already deselected, it remains
+ * deselected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to deselect
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void deselect (int index) {
+    checkWidget ();
+    if (0 <= index && index < list.getItemCount () &&
+            index is list.getSelectionIndex() &&
+            text.getText().equals(list.getItem(index))) {
+        text.setText("");  //$NON-NLS-1$
+        list.deselect (index);
     }
-
-    /**
-     * Cuts the selected text.
-     * <p>
-     * The current selection is first copied to the
-     * clipboard and then deleted from the widget.
-     * </p>
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.3
-     */
-    public void cut ()
-    {
-        checkWidget();
-        text.cut();
+}
+/**
+ * Deselects all selected items in the receiver's list.
+ * <p>
+ * Note: To clear the selection in the receiver's text field,
+ * use <code>clearSelection()</code>.
+ * </p>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see #clearSelection
+ */
+public void deselectAll () {
+    checkWidget ();
+    text.setText("");  //$NON-NLS-1$
+    list.deselectAll ();
+}
+void dropDown (bool drop) {
+    if (drop is isDropped () || !isVisible()) return;
+    if (!drop) {
+        popup.setVisible (false);
+        if (!isDisposed () && isFocusControl()) {
+            text.setFocus();
+        }
+        return;
     }
 
-    /**
-     * Deselects the item at the given zero-relative index in the receiver's 
-     * list.  If the item at the index was already deselected, it remains
-     * deselected. Indices that are out of range are ignored.
-     *
-     * @param index the index of the item to deselect
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void deselect (int index)
-    {
-        checkWidget();
-        if (0 <= index && index < list.getItemCount() && index is list.getSelectionIndex() && text.getText().opEquals(
-                list.getItem(index)))
-        {
-            text.setText(""); //$NON-NLS-1$
-            list.deselect(index);
-        }
-    }
-
-    /**
-     * Deselects all selected items in the receiver's list.
-     * <p>
-     * Note: To clear the selection in the receiver's text field,
-     * use <code>clearSelection()</code>.
-     * </p>
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see #clearSelection
-     */
-    public void deselectAll ()
-    {
-        checkWidget();
-        text.setText(""); //$NON-NLS-1$
-        list.deselectAll();
-    }
-
-    void dropDown (bool drop)
-    {
-        if (drop is isDropped())
-            return;
-        if (!drop)
-        {
-            popup.setVisible(false);
-            if (!isDisposed() && isFocusControl())
-            {
-                text.setFocus();
-            }
-            return;
-        }
-
-        if (getShell() !is popup.getParent())
-        {
-            String[] items = list.getItems();
-            int selectionIndex = list.getSelectionIndex();
-            list.removeListener(DWT.Dispose, listener);
-            popup.dispose();
-            popup = null;
-            list = null;
-            createPopup(items, selectionIndex);
-        }
-
-        Point size = getSize();
-        int itemCount = list.getItemCount();
-        itemCount = (itemCount is 0) ? visibleItemCount : Math.min(
-                visibleItemCount, itemCount);
-        int itemHeight = list.getItemHeight() * itemCount;
-        Point listSize = list.computeSize(DWT.DEFAULT, itemHeight, false);
-        list.setBounds(1, 1, Math.max(size.x - 2, listSize.x), listSize.y);
-
-        int index = list.getSelectionIndex();
-        if (index !is -1)
-            list.setTopIndex(index);
-        Display display = getDisplay();
-        Rectangle listRect = list.getBounds();
-        Rectangle parentRect = display.map(getParent(), null, getBounds());
-        Point comboSize = getSize();
-        Rectangle displayRect = getMonitor().getClientArea();
-        int width = Math.max(comboSize.x, listRect.width + 2);
-        int height = listRect.height + 2;
-        int x = parentRect.x;
-        int y = parentRect.y + comboSize.y;
-        if (y + height > displayRect.y + displayRect.height)
-            y = parentRect.y - height;
-        if (x + width > displayRect.x + displayRect.width)
-            x = displayRect.x + displayRect.width - listRect.width;
-        popup.setBounds(x, y, width, height);
-        popup.setVisible(true);
-        if (isFocusControl())
-            list.setFocus();
-    }
-
-    /*
-     * Return the lowercase of the first non-'&' character following
-     * an '&' character in the given String. If there are no '&'
-     * characters in the given String, return '\0'.
-     */
-    char _findMnemonic (String str)
-    {
-        if (str is null)
-            return '\0';
-        int index = 0;
-        int length = str.length();
-        do
-        {
-            while (index < length && str.charAt(index) !is '&')
-                index++;
-            if (++index >= length)
-                return '\0';
-            if (str.charAt(index) !is '&')
-                return CharacterToLower(string.charAt(index));
-            index++;
-        } while (index < length);
-        return '\0';
-    }
-
-    /* 
-     * Return the Label immediately preceding the receiver in the z-order, 
-     * or null if none. 
-     */
-    Label getAssociatedLabel ()
-    {
-        Control[] siblings = getParent().getChildren();
-        for (int i = 0; i < siblings.length; i++)
-        {
-            if (siblings[i] is this)
-            {
-                if (i > 0 && cast(Label) (siblings[i - 1]))
-                {
-                    return cast(Label) (siblings[i - 1]);
-                }
-            }
-        }
-        return null;
-    }
-
-    public Control[] getChildren ()
-    {
-        checkWidget();
-        return new Control[0];
-    }
-
-    /**
-     * Gets the editable state.
-     *
-     * @return whether or not the receiver is editable
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public bool getEditable ()
-    {
-        checkWidget();
-        return text.getEditable();
-    }
-
-    /**
-     * Returns the item at the given, zero-relative index in the
-     * receiver's list. Throws an exception if the index is out
-     * of range.
-     *
-     * @param index the index of the item to return
-     * @return the item at the given index
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public String getItem (int index)
-    {
-        checkWidget();
-        return list.getItem(index);
-    }
-
-    /**
-     * Returns the number of items contained in the receiver's list.
-     *
-     * @return the number of items
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public int getItemCount ()
-    {
-        checkWidget();
-        return list.getItemCount();
-    }
-
-    /**
-     * Returns the height of the area which would be used to
-     * display <em>one</em> of the items in the receiver's list.
-     *
-     * @return the height of one item
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public int getItemHeight ()
-    {
-        checkWidget();
-        return list.getItemHeight();
-    }
-
-    /**
-     * Returns an array of <code>String</code>s which are the items
-     * in the receiver's list. 
-     * <p>
-     * Note: This is not the actual structure used by the receiver
-     * to maintain its list of items, so modifying the array will
-     * not affect the receiver. 
-     * </p>
-     *
-     * @return the items in the receiver's list
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public String[] getItems ()
-    {
-        checkWidget();
-        return list.getItems();
+    if (getShell() !is popup.getParent ()) {
+        String[] items = list.getItems ();
+        int selectionIndex = list.getSelectionIndex ();
+        list.removeListener (DWT.Dispose, listener);
+        popup.dispose();
+        popup = null;
+        list = null;
+        createPopup (items, selectionIndex);
     }
 
-    /**
-     * Returns <code>true</code> if the receiver's list is visible,
-     * and <code>false</code> otherwise.
-     * <p>
-     * If one of the receiver's ancestors is not visible or some
-     * other condition makes the receiver not visible, this method
-     * may still indicate that it is considered visible even though
-     * it may not actually be showing.
-     * </p>
-     *
-     * @return the receiver's list's visibility state
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.4
-     */
-    public bool getListVisible ()
-    {
-        checkWidget();
-        return isDropped();
-    }
-
-    public Menu getMenu ()
-    {
-        return text.getMenu();
-    }
-
-    /**
-     * Returns a <code>Point</code> whose x coordinate is the start
-     * of the selection in the receiver's text field, and whose y
-     * coordinate is the end of the selection. The returned values
-     * are zero-relative. An "empty" selection as indicated by
-     * the the x and y coordinates having the same value.
-     *
-     * @return a point representing the selection start and end
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public Point getSelection ()
-    {
-        checkWidget();
-        return text.getSelection();
-    }
-
-    /**
-     * Returns the zero-relative index of the item which is currently
-     * selected in the receiver's list, or -1 if no item is selected.
-     *
-     * @return the index of the selected item
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public int getSelectionIndex ()
-    {
-        checkWidget();
-        return list.getSelectionIndex();
-    }
-
-    public int getStyle ()
-    {
-        int style = super.getStyle();
-        style &= ~DWT.READ_ONLY;
-        if (!text.getEditable())
-            style |= DWT.READ_ONLY;
-        return style;
-    }
-
-    /**
-     * Returns a String containing a copy of the contents of the
-     * receiver's text field.
-     *
-     * @return the receiver's text
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public String getText ()
-    {
-        checkWidget();
-        return text.getText();
-    }
-
-    /**
-     * Returns the height of the receivers's text field.
-     *
-     * @return the text height
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public int getTextHeight ()
-    {
-        checkWidget();
-        return text.getLineHeight();
-    }
-
-    /**
-     * Returns the maximum number of characters that the receiver's
-     * text field is capable of holding. If this has not been changed
-     * by <code>setTextLimit()</code>, it will be the constant
-     * <code>Combo.LIMIT</code>.
-     * 
-     * @return the text limit
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public int getTextLimit ()
-    {
-        checkWidget();
-        return text.getTextLimit();
-    }
+    Point size = getSize ();
+    int itemCount = list.getItemCount ();
+    itemCount = (itemCount is 0) ? visibleItemCount : Math.min(visibleItemCount, itemCount);
+    int itemHeight = list.getItemHeight () * itemCount;
+    Point listSize = list.computeSize (DWT.DEFAULT, itemHeight, false);
+    list.setBounds (1, 1, Math.max (size.x - 2, listSize.x), listSize.y);
 
-    /**
-     * Gets the number of items that are visible in the drop
-     * down portion of the receiver's list.
-     *
-     * @return the number of items that are visible
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public int getVisibleItemCount ()
-    {
-        checkWidget();
-        return visibleItemCount;
-    }
-
-    void handleFocus (int type)
-    {
-        if (isDisposed())
-            return;
-        switch (type)
-        {
-            case DWT.FocusIn:
-            {
-                if (hasFocus)
-                    return;
-                if (getEditable())
-                    text.selectAll();
-                hasFocus = true;
-                Shell shell = getShell();
-                shell.removeListener(DWT.Deactivate, listener);
-                shell.addListener(DWT.Deactivate, listener);
-                Display display = getDisplay();
-                display.removeFilter(DWT.FocusIn, filter);
-                display.addFilter(DWT.FocusIn, filter);
-                Event e = new Event();
-                notifyListeners(DWT.FocusIn, e);
-                break;
-            }
-            case DWT.FocusOut:
-            {
-                if (!hasFocus)
-                    return;
-                Control focusControl = getDisplay().getFocusControl();
-                if (focusControl is arrow || focusControl is list || focusControl is text)
-                    return;
-                hasFocus = false;
-                Shell shell = getShell();
-                shell.removeListener(DWT.Deactivate, listener);
-                Display display = getDisplay();
-                display.removeFilter(DWT.FocusIn, filter);
-                Event e = new Event();
-                notifyListeners(DWT.FocusOut, e);
-                break;
-            }
-
-            default:
-            break;
+    int index = list.getSelectionIndex ();
+    if (index !is -1) list.setTopIndex (index);
+    Display display = getDisplay ();
+    Rectangle listRect = list.getBounds ();
+    Rectangle parentRect = display.map (getParent (), null, getBounds ());
+    Point comboSize = getSize ();
+    Rectangle displayRect = getMonitor ().getClientArea ();
+    int width = Math.max (comboSize.x, listRect.width + 2);
+    int height = listRect.height + 2;
+    int x = parentRect.x;
+    int y = parentRect.y + comboSize.y;
+    if (y + height > displayRect.y + displayRect.height) y = parentRect.y - height;
+    if (x + width > displayRect.x + displayRect.width) x = displayRect.x + displayRect.width - listRect.width;
+    popup.setBounds (x, y, width, height);
+    popup.setVisible (true);
+    if (isFocusControl()) list.setFocus ();
+}
+/*
+ * Return the lowercase of the first non-'&' character following
+ * an '&' character in the given string. If there are no '&'
+ * characters in the given string, return '\0'.
+ */
+dchar _findMnemonic (String string) {
+    if (string is null) return '\0';
+    int index = 0;
+    int length = string.length;
+    do {
+        while (index < length && string[index] !is '&') index++;
+        if (++index >= length) return '\0';
+        if (string[index] !is '&') {
+            dchar[1] d; uint ate;
+            auto d2 = tango.text.convert.Utf.toString32( string[ index .. Math.min( index +4, string.length )], d, &ate );
+            auto d3 = tango.text.Unicode.toLower( d2, d2 );
+            return d3[0];
         }
-    }
-
-    /**
-     * Searches the receiver's list starting at the first item
-     * (index 0) until an item is found that is equal to the 
-     * argument, and returns the index of that item. If no item
-     * is found, returns -1.
-     *
-     * @param String the search item
-     * @return the index of the item
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the String is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public int indexOf (String String)
-    {
-        checkWidget();
-        if (String is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        return list.indexOf(String);
-    }
-
-    /**
-     * Searches the receiver's list starting at the given, 
-     * zero-relative index until an item is found that is equal
-     * to the argument, and returns the index of that item. If
-     * no item is found or the starting index is out of range,
-     * returns -1.
-     *
-     * @param String the search item
-     * @param start the zero-relative index at which to begin the search
-     * @return the index of the item
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the String is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public int indexOf (String String, int start)
-    {
-        checkWidget();
-        if (String is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        return list.indexOf(String, start);
-    }
-
-    void initAccessible ()
-    {
-        AccessibleAdapter accessibleAdapter = new class AccessibleAdapter
-        {
-            public void getName (AccessibleEvent e)
-            {
-                String name = null;
-                Label label = getAssociatedLabel();
-                if (label !is null)
-                {
-                    name = stripMnemonic(label.getText());
-                }
-                e.result = name;
-            }
-
-            public void getKeyboardShortcut (AccessibleEvent e)
-            {
-                String shortcut = null;
-                Label label = getAssociatedLabel();
-                if (label !is null)
-                {
-                    String text = label.getText();
-                    if (text !is null)
-                    {
-                        char mnemonic = _findMnemonic(text);
-                        if (mnemonic !is '\0')
-                        {
-                            shortcut = "Alt+" + mnemonic; //$NON-NLS-1$
+        index++;
+    } while (index < length);
+    return '\0';
+}
+/*
+ * Return the Label immediately preceding the receiver in the z-order,
+ * or null if none.
+ */
+Label getAssociatedLabel () {
+    Control[] siblings = getParent ().getChildren ();
+    for (int i = 0; i < siblings.length; i++) {
+        if (siblings [i] is this) {
+            if (i > 0 && ( null !is cast(Label)siblings [i-1] )) {
+                return cast(Label) siblings [i-1];
             }
         }
     }
-    e.result = shortcut;
+    return null;
+}
+public override Control [] getChildren () {
+    checkWidget();
+    return new Control [0];
+}
+/**
+ * Gets the editable state.
+ *
+ * @return whether or not the receiver is editable
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public bool getEditable () {
+    checkWidget ();
+    return text.getEditable();
+}
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver's list. Throws an exception if the index is out
+ * of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public String getItem (int index) {
+    checkWidget();
+    return list.getItem (index);
+}
+/**
+ * Returns the number of items contained in the receiver's list.
+ *
+ * @return the number of items
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public int getItemCount () {
+    checkWidget ();
+    return list.getItemCount ();
+}
+/**
+ * Returns the height of the area which would be used to
+ * display <em>one</em> of the items in the receiver's list.
+ *
+ * @return the height of one item
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public int getItemHeight () {
+    checkWidget ();
+    return list.getItemHeight ();
+}
+/**
+ * Returns an array of <code>String</code>s which are the items
+ * in the receiver's list.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the items in the receiver's list
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public String [] getItems () {
+    checkWidget ();
+    return list.getItems ();
+}
+/**
+ * Returns <code>true</code> if the receiver's list is visible,
+ * and <code>false</code> otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, this method
+ * may still indicate that it is considered visible even though
+ * it may not actually be showing.
+ * </p>
+ *
+ * @return the receiver's list's visibility state
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.4
+ */
+public bool getListVisible () {
+    checkWidget ();
+    return isDropped();
+}
+public override Menu getMenu() {
+    return text.getMenu();
+}
+/**
+ * Returns a <code>Point</code> whose x coordinate is the start
+ * of the selection in the receiver's text field, and whose y
+ * coordinate is the end of the selection. The returned values
+ * are zero-relative. An "empty" selection as indicated by
+ * the the x and y coordinates having the same value.
+ *
+ * @return a point representing the selection start and end
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public Point getSelection () {
+    checkWidget ();
+    return text.getSelection ();
+}
+/**
+ * Returns the zero-relative index of the item which is currently
+ * selected in the receiver's list, or -1 if no item is selected.
+ *
+ * @return the index of the selected item
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public int getSelectionIndex () {
+    checkWidget ();
+    return list.getSelectionIndex ();
+}
+public override int getStyle () {
+    int style = super.getStyle ();
+    style &= ~DWT.READ_ONLY;
+    if (!text.getEditable()) style |= DWT.READ_ONLY;
+    return style;
+}
+/**
+ * Returns a string containing a copy of the contents of the
+ * receiver's text field.
+ *
+ * @return the receiver's text
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public String getText () {
+    checkWidget ();
+    return text.getText ();
+}
+/**
+ * Returns the height of the receivers's text field.
+ *
+ * @return the text height
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public int getTextHeight () {
+    checkWidget ();
+    return text.getLineHeight ();
+}
+/**
+ * Returns the maximum number of characters that the receiver's
+ * text field is capable of holding. If this has not been changed
+ * by <code>setTextLimit()</code>, it will be the constant
+ * <code>Combo.LIMIT</code>.
+ *
+ * @return the text limit
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public int getTextLimit () {
+    checkWidget ();
+    return text.getTextLimit ();
+}
+/**
+ * Gets the number of items that are visible in the drop
+ * down portion of the receiver's list.
+ *
+ * @return the number of items that are visible
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public int getVisibleItemCount () {
+    checkWidget ();
+    return visibleItemCount;
+}
+void handleFocus (int type) {
+    if (isDisposed ()) return;
+    switch (type) {
+        case DWT.FocusIn: {
+            if (hasFocus) return;
+            if (getEditable ()) text.selectAll ();
+            hasFocus = true;
+            Shell shell = getShell ();
+            shell.removeListener (DWT.Deactivate, listener);
+            shell.addListener (DWT.Deactivate, listener);
+            Display display = getDisplay ();
+            display.removeFilter (DWT.FocusIn, filter);
+            display.addFilter (DWT.FocusIn, filter);
+            Event e = new Event ();
+            notifyListeners (DWT.FocusIn, e);
+            break;
+        }
+        case DWT.FocusOut: {
+            if (!hasFocus) return;
+            Control focusControl = getDisplay ().getFocusControl ();
+            if (focusControl is arrow || focusControl is list || focusControl is text) return;
+            hasFocus = false;
+            Shell shell = getShell ();
+            shell.removeListener(DWT.Deactivate, listener);
+            Display display = getDisplay ();
+            display.removeFilter (DWT.FocusIn, filter);
+            Event e = new Event ();
+            notifyListeners (DWT.FocusOut, e);
+            break;
+        }
+        default:
+    }
+}
+/**
+ * Searches the receiver's list starting at the first item
+ * (index 0) until an item is found that is equal to the
+ * argument, and returns the index of that item. If no item
+ * is found, returns -1.
+ *
+ * @param string the search item
+ * @return the index of the item
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public int indexOf (String string) {
+    checkWidget ();
+    // DWT extension: allow null for zero length string
+    //if (string is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    return list.indexOf (string);
+}
+/**
+ * Searches the receiver's list starting at the given,
+ * zero-relative index until an item is found that is equal
+ * to the argument, and returns the index of that item. If
+ * no item is found or the starting index is out of range,
+ * returns -1.
+ *
+ * @param string the search item
+ * @param start the zero-relative index at which to begin the search
+ * @return the index of the item
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public int indexOf (String string, int start) {
+    checkWidget ();
+    // DWT extension: allow null for zero length string
+    //if (string is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    return list.indexOf (string, start);
 }
 
-public void getHelp (AccessibleEvent e)
-{
-    e.result = getToolTipText();
-}
-}       ;
-        getAccessible().addAccessibleListener(accessibleAdapter);
-        text.getAccessible().addAccessibleListener(accessibleAdapter);
-        list.getAccessible().addAccessibleListener(accessibleAdapter);
-
-        arrow.getAccessible().addAccessibleListener(
-                new class AccessibleAdapter
-                {
-                    public void getName (AccessibleEvent e)
-                    {
-                        e.result = isDropped() ? DWT.getMessage("DWT_Close") : DWT.getMessage(
-                                "DWT_Open"); //$NON-NLS-1$ //$NON-NLS-2$
-                    }
-
-                    public void getKeyboardShortcut (AccessibleEvent e)
-                    {
-                        e.result = "Alt+Down Arrow"; //$NON-NLS-1$
-                    }
-
-                    public void getHelp (AccessibleEvent e)
-                    {
-                        e.result = getToolTipText();
+void initAccessible() {
+    AccessibleAdapter accessibleAdapter = new class() AccessibleAdapter {
+        public void getName (AccessibleEvent e) {
+            String name = null;
+            Label label = getAssociatedLabel ();
+            if (label !is null) {
+                name = stripMnemonic (label.getText());
+            }
+            e.result = name;
+        }
+        public void getKeyboardShortcut(AccessibleEvent e) {
+            String shortcut = null;
+            Label label = getAssociatedLabel ();
+            if (label !is null) {
+                String text = label.getText ();
+                if (text !is null) {
+                    dchar mnemonic = _findMnemonic (text);
+                    if (mnemonic !is '\0') {
+                        shortcut = tango.text.convert.Format.Format( "Alt+{}", mnemonic ); //$NON-NLS-1$
                     }
-                });
-
-        getAccessible().addAccessibleTextListener(new class
-                AccessibleTextAdapter
-        {
-            public void getCaretOffset (AccessibleTextEvent e)
-            {
-                e.offset = text.getCaretPosition();
-            }
-
-            public void getSelectionRange (AccessibleTextEvent e)
-            {
-                Point sel = text.getSelection();
-                e.offset = sel.x;
-                e.length = sel.y - sel.x;
-            }
-        });
-
-        getAccessible().addAccessibleControlListener(new class
-                AccessibleControlAdapter
-        {
-            public void getChildAtPoint (AccessibleControlEvent e)
-            {
-                Point testPoint = toControl(e.x, e.y);
-                if (getBounds().contains(testPoint))
-                {
-                    e.childID = ACC.CHILDID_SELF;
                 }
             }
-
-            public void getLocation (AccessibleControlEvent e)
-            {
-                Rectangle location = getBounds();
-                Point pt = getParent().toDisplay(location.x, location.y);
-                e.x = pt.x;
-                e.y = pt.y;
-                e.width = location.width;
-                e.height = location.height;
-            }
+            e.result = shortcut;
+        }
+        public void getHelp (AccessibleEvent e) {
+            e.result = getToolTipText ();
+        }
+    };
+    getAccessible ().addAccessibleListener (accessibleAdapter);
+    text.getAccessible ().addAccessibleListener (accessibleAdapter);
+    list.getAccessible ().addAccessibleListener (accessibleAdapter);
 
-            public void getChildCount (AccessibleControlEvent e)
-            {
-                e.detail = 0;
-            }
+    arrow.getAccessible ().addAccessibleListener (new class() AccessibleAdapter {
+        public void getName (AccessibleEvent e) {
+            e.result = isDropped () ? DWT.getMessage ("SWT_Close") : DWT.getMessage ("SWT_Open"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        public void getKeyboardShortcut (AccessibleEvent e) {
+            e.result = "Alt+Down Arrow"; //$NON-NLS-1$
+        }
+        public void getHelp (AccessibleEvent e) {
+            e.result = getToolTipText ();
+        }
+    });
 
-            public void getRole (AccessibleControlEvent e)
-            {
-                e.detail = ACC.ROLE_COMBOBOX;
-            }
-
-            public void getState (AccessibleControlEvent e)
-            {
-                e.detail = ACC.STATE_NORMAL;
-            }
+    getAccessible().addAccessibleTextListener (new class() AccessibleTextAdapter {
+        public void getCaretOffset (AccessibleTextEvent e) {
+            e.offset = text.getCaretPosition ();
+        }
+        public void getSelectionRange(AccessibleTextEvent e) {
+            Point sel = text.getSelection();
+            e.offset = sel.x;
+            e.length = sel.y - sel.x;
+        }
+    });
 
-            public void getValue (AccessibleControlEvent e)
-            {
-                e.result = getText();
+    getAccessible().addAccessibleControlListener (new class() AccessibleControlAdapter {
+        public void getChildAtPoint (AccessibleControlEvent e) {
+            Point testPoint = toControl (e.x, e.y);
+            if (getBounds ().contains (testPoint)) {
+                e.childID = ACC.CHILDID_SELF;
             }
-        });
+        }
 
-        text.getAccessible().addAccessibleControlListener(new class
-                AccessibleControlAdapter
-        {
-            public void getRole (AccessibleControlEvent e)
-            {
-                e.detail = text.getEditable() ? ACC.ROLE_TEXT : ACC.ROLE_LABEL;
-            }
-        });
+        public void getLocation (AccessibleControlEvent e) {
+            Rectangle location = getBounds ();
+            Point pt = getParent().toDisplay (location.x, location.y);
+            e.x = pt.x;
+            e.y = pt.y;
+            e.width = location.width;
+            e.height = location.height;
+        }
 
-        arrow.getAccessible().addAccessibleControlListener(
-                new class AccessibleControlAdapter
-                {
-                    public void getDefaultAction (AccessibleControlEvent e)
-                    {
-                        e.result = isDropped() ? DWT.getMessage("DWT_Close") : DWT.getMessage(
-                                "DWT_Open"); //$NON-NLS-1$ //$NON-NLS-2$
-                    }
-                });
-    }
+        public void getChildCount (AccessibleControlEvent e) {
+            e.detail = 0;
+        }
+
+        public void getRole (AccessibleControlEvent e) {
+            e.detail = ACC.ROLE_COMBOBOX;
+        }
 
-    bool isDropped ()
-    {
-        return popup.getVisible();
-    }
+        public void getState (AccessibleControlEvent e) {
+            e.detail = ACC.STATE_NORMAL;
+        }
+
+        public void getValue (AccessibleControlEvent e) {
+            e.result = getText ();
+        }
+    });
+
+    text.getAccessible ().addAccessibleControlListener (new class() AccessibleControlAdapter {
+        public void getRole (AccessibleControlEvent e) {
+            e.detail = text.getEditable () ? ACC.ROLE_TEXT : ACC.ROLE_LABEL;
+        }
+    });
 
-    public bool isFocusControl ()
-    {
-        checkWidget();
-        if (text.isFocusControl() || arrow.isFocusControl() || list.isFocusControl() || popup.isFocusControl())
-        {
-            return true;
+    arrow.getAccessible ().addAccessibleControlListener (new class() AccessibleControlAdapter {
+        public void getDefaultAction (AccessibleControlEvent e) {
+            e.result = isDropped () ? DWT.getMessage ("SWT_Close") : DWT.getMessage ("SWT_Open"); //$NON-NLS-1$ //$NON-NLS-2$
         }
-        return super.isFocusControl();
-    }
-
-    void internalLayout (bool changed)
-    {
-        if (isDropped())
-            dropDown(false);
-        Rectangle rect = getClientArea();
-        int width = rect.width;
-        int height = rect.height;
-        Point arrowSize = arrow.computeSize(DWT.DEFAULT, height, changed);
-        text.setBounds(0, 0, width - arrowSize.x, height);
-        arrow.setBounds(width - arrowSize.x, 0, arrowSize.x, arrowSize.y);
+    });
+}
+bool isDropped () {
+    return popup.getVisible ();
+}
+public override bool isFocusControl () {
+    checkWidget();
+    if (text.isFocusControl () || arrow.isFocusControl () || list.isFocusControl () || popup.isFocusControl ()) {
+        return true;
     }
-
-    void listEvent (Event event)
-    {
-        switch (event.type)
-        {
-            case DWT.Dispose:
-                if (getShell() !is popup.getParent())
-                {
-                    String[] items = list.getItems();
-                    int selectionIndex = list.getSelectionIndex();
-                    popup = null;
-                    list = null;
-                    createPopup(items, selectionIndex);
-                }
+    return super.isFocusControl ();
+}
+void internalLayout (bool changed) {
+    if (isDropped ()) dropDown (false);
+    Rectangle rect = getClientArea ();
+    int width = rect.width;
+    int height = rect.height;
+    Point arrowSize = arrow.computeSize (DWT.DEFAULT, height, changed);
+    text.setBounds (0, 0, width - arrowSize.x, height);
+    arrow.setBounds (width - arrowSize.x, 0, arrowSize.x, arrowSize.y);
+}
+void listEvent (Event event) {
+    switch (event.type) {
+        case DWT.Dispose:
+            if (getShell () !is popup.getParent ()) {
+                String[] items = list.getItems ();
+                int selectionIndex = list.getSelectionIndex ();
+                popup = null;
+                list = null;
+                createPopup (items, selectionIndex);
+            }
+            break;
+        case DWT.FocusIn: {
+            handleFocus (DWT.FocusIn);
+            break;
+        }
+        case DWT.MouseUp: {
+            if (event.button !is 1) return;
+            dropDown (false);
+            break;
+        }
+        case DWT.Selection: {
+            int index = list.getSelectionIndex ();
+            if (index is -1) return;
+            text.setText (list.getItem (index));
+            text.selectAll ();
+            list.setSelection (index);
+            Event e = new Event ();
+            e.time = event.time;
+            e.stateMask = event.stateMask;
+            e.doit = event.doit;
+            notifyListeners (DWT.Selection, e);
+            event.doit = e.doit;
             break;
-            case DWT.FocusIn:
-            {
-                handleFocus(DWT.FocusIn);
-                break;
-            }
-            case DWT.MouseUp:
-            {
-                if (event.button !is 1)
+        }
+        case DWT.Traverse: {
+            switch (event.detail) {
+                case DWT.TRAVERSE_RETURN:
+                case DWT.TRAVERSE_ESCAPE:
+                case DWT.TRAVERSE_ARROW_PREVIOUS:
+                case DWT.TRAVERSE_ARROW_NEXT:
+                    event.doit = false;
+                    break;
+                case DWT.TRAVERSE_TAB_NEXT:
+                case DWT.TRAVERSE_TAB_PREVIOUS:
+                    event.doit = text.traverse(event.detail);
+                    event.detail = DWT.TRAVERSE_NONE;
+                    if (event.doit) dropDown(false);
                     return;
-                dropDown(false);
-                break;
+                default:
             }
-            case DWT.Selection:
-            {
-                int index = list.getSelectionIndex();
-                if (index is -1)
-                    return;
-                text.setText(list.getItem(index));
-                text.selectAll();
-                list.setSelection(index);
-                Event e = new Event();
+            Event e = new Event ();
+            e.time = event.time;
+            e.detail = event.detail;
+            e.doit = event.doit;
+            e.character = event.character;
+            e.keyCode = event.keyCode;
+            notifyListeners (DWT.Traverse, e);
+            event.doit = e.doit;
+            event.detail = e.detail;
+            break;
+        }
+        case DWT.KeyUp: {
+            Event e = new Event ();
+            e.time = event.time;
+            e.character = event.character;
+            e.keyCode = event.keyCode;
+            e.stateMask = event.stateMask;
+            notifyListeners (DWT.KeyUp, e);
+            break;
+        }
+        case DWT.KeyDown: {
+            if (event.character is DWT.ESC) {
+                // Escape key cancels popup list
+                dropDown (false);
+            }
+            if ((event.stateMask & DWT.ALT) !is 0 && (event.keyCode is DWT.ARROW_UP || event.keyCode is DWT.ARROW_DOWN)) {
+                dropDown (false);
+            }
+            if (event.character is DWT.CR) {
+                // Enter causes default selection
+                dropDown (false);
+                Event e = new Event ();
                 e.time = event.time;
                 e.stateMask = event.stateMask;
-                e.doit = event.doit;
-                notifyListeners(DWT.Selection, e);
-                event.doit = e.doit;
-                break;
+                notifyListeners (DWT.DefaultSelection, e);
+            }
+            // At this point the widget may have been disposed.
+            // If so, do not continue.
+            if (isDisposed ()) break;
+            Event e = new Event();
+            e.time = event.time;
+            e.character = event.character;
+            e.keyCode = event.keyCode;
+            e.stateMask = event.stateMask;
+            notifyListeners(DWT.KeyDown, e);
+            break;
+
+        }
+        default:
+    }
+}
+/**
+ * Pastes text from clipboard.
+ * <p>
+ * The selected text is deleted from the widget
+ * and new text inserted from the clipboard.
+ * </p>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.3
+ */
+public void paste () {
+    checkWidget ();
+    text.paste ();
+}
+void popupEvent(Event event) {
+    switch (event.type) {
+        case DWT.Paint:
+            // draw black rectangle around list
+            Rectangle listRect = list.getBounds();
+            Color black = getDisplay().getSystemColor(DWT.COLOR_BLACK);
+            event.gc.setForeground(black);
+            event.gc.drawRectangle(0, 0, listRect.width + 1, listRect.height + 1);
+            break;
+        case DWT.Close:
+            event.doit = false;
+            dropDown (false);
+            break;
+        case DWT.Deactivate:
+            /*
+             * Bug in GTK. When the arrow button is pressed the popup control receives a
+             * deactivate event and then the arrow button receives a selection event. If
+             * we hide the popup in the deactivate event, the selection event will show
+             * it again. To prevent the popup from showing again, we will let the selection
+             * event of the arrow button hide the popup.
+             * In Windows, hiding the popup during the deactivate causes the deactivate
+             * to be called twice and the selection event to be disappear.
+             */
+            if (!"carbon".equals(DWT.getPlatform())) {
+                Point point = arrow.toControl(getDisplay().getCursorLocation());
+                Point size = arrow.getSize();
+                Rectangle rect = new Rectangle(0, 0, size.x, size.y);
+                if (!rect.contains(point)) dropDown (false);
+            } else {
+                dropDown(false);
             }
-            case DWT.Traverse:
-            {
-                switch (event.detail)
-                {
-                    case DWT.TRAVERSE_RETURN:
-                    case DWT.TRAVERSE_ESCAPE:
-                    case DWT.TRAVERSE_ARROW_PREVIOUS:
-                    case DWT.TRAVERSE_ARROW_NEXT:
-                        event.doit = false;
+            break;
+        default:
+    }
+}
+public override void redraw () {
+    super.redraw();
+    text.redraw();
+    arrow.redraw();
+    if (popup.isVisible()) list.redraw();
+}
+public override void redraw (int x, int y, int width, int height, bool all) {
+    super.redraw(x, y, width, height, true);
+}
+
+/**
+ * Removes the item from the receiver's list at the given
+ * zero-relative index.
+ *
+ * @param index the index for the item
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void remove (int index) {
+    checkWidget();
+    list.remove (index);
+}
+/**
+ * Removes the items from the receiver's list which are
+ * between the given zero-relative start and end
+ * indices (inclusive).
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_RANGE - if either the start or end are not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void remove (int start, int end) {
+    checkWidget();
+    list.remove (start, end);
+}
+/**
+ * Searches the receiver's list starting at the first item
+ * until an item is found that is equal to the argument,
+ * and removes that item from the list.
+ *
+ * @param string the item to remove
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void remove (String string) {
+    checkWidget();
+    // DWT extension: allow null for zero length string
+    //if (string is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    list.remove (string);
+}
+/**
+ * Removes all of the items from the receiver's list and clear the
+ * contents of receiver's text field.
+ * <p>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void removeAll () {
+    checkWidget();
+    text.setText (""); //$NON-NLS-1$
+    list.removeAll ();
+}
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the receiver's text is modified.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see ModifyListener
+ * @see #addModifyListener
+ */
+public void removeModifyListener (ModifyListener listener) {
+    checkWidget();
+    if (listener is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    removeListener(DWT.Modify, listener);
+}
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's selection.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener (SelectionListener listener) {
+    checkWidget();
+    if (listener is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    removeListener(DWT.Selection, listener);
+    removeListener(DWT.DefaultSelection,listener);
+}
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the control is verified.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see VerifyListener
+ * @see #addVerifyListener
+ *
+ * @since 3.3
+ */
+public void removeVerifyListener (VerifyListener listener) {
+    checkWidget();
+    if (listener is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    removeListener(DWT.Verify, listener);
+}
+/**
+ * Selects the item at the given zero-relative index in the receiver's
+ * list.  If the item at the index was already selected, it remains
+ * selected. Indices that are out of range are ignored.
+ *
+ * @param index the index of the item to select
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void select (int index) {
+    checkWidget();
+    if (index is -1) {
+        list.deselectAll ();
+        text.setText (""); //$NON-NLS-1$
+        return;
+    }
+    if (0 <= index && index < list.getItemCount()) {
+        if (index !is getSelectionIndex()) {
+            text.setText (list.getItem (index));
+            text.selectAll ();
+            list.select (index);
+            list.showSelection ();
+        }
+    }
+}
+public override void setBackground (Color color) {
+    super.setBackground(color);
+    background = color;
+    if (text !is null) text.setBackground(color);
+    if (list !is null) list.setBackground(color);
+    if (arrow !is null) arrow.setBackground(color);
+}
+/**
+ * Sets the editable state.
+ *
+ * @param editable the new editable state
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setEditable (bool editable) {
+    checkWidget ();
+    text.setEditable(editable);
+}
+public override void setEnabled (bool enabled) {
+    super.setEnabled(enabled);
+    if (popup !is null) popup.setVisible (false);
+    if (text !is null) text.setEnabled(enabled);
+    if (arrow !is null) arrow.setEnabled(enabled);
+}
+public override bool setFocus () {
+    checkWidget();
+    if (!isEnabled () || !isVisible ()) return false;
+    if (isFocusControl ()) return true;
+    return text.setFocus ();
+}
+public override void setFont (Font font) {
+    super.setFont (font);
+    this.font = font;
+    text.setFont (font);
+    list.setFont (font);
+    internalLayout (true);
+}
+public override void setForeground (Color color) {
+    super.setForeground(color);
+    foreground = color;
+    if (text !is null) text.setForeground(color);
+    if (list !is null) list.setForeground(color);
+    if (arrow !is null) arrow.setForeground(color);
+}
+/**
+ * Sets the text of the item in the receiver's list at the given
+ * zero-relative index to the string argument. This is equivalent
+ * to <code>remove</code>'ing the old item at the index, and then
+ * <code>add</code>'ing the new item at that index.
+ *
+ * @param index the index for the item
+ * @param string the new text for the item
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setItem (int index, String string) {
+    checkWidget();
+    list.setItem (index, string);
+}
+/**
+ * Sets the receiver's list to be the given array of items.
+ *
+ * @param items the array of items
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setItems (String [] items) {
+    checkWidget ();
+    list.setItems (items);
+    if (!text.getEditable ()) text.setText (""); //$NON-NLS-1$
+}
+/**
+ * Sets the layout which is associated with the receiver to be
+ * the argument which may be null.
+ * <p>
+ * Note: No Layout can be set on this Control because it already
+ * manages the size and position of its children.
+ * </p>
+ *
+ * @param layout the receiver's new layout or null
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public override void setLayout (Layout layout) {
+    checkWidget ();
+    return;
+}
+/**
+ * Marks the receiver's list as visible if the argument is <code>true</code>,
+ * and marks it invisible otherwise.
+ * <p>
+ * If one of the receiver's ancestors is not visible or some
+ * other condition makes the receiver not visible, marking
+ * it visible may not actually cause it to be displayed.
+ * </p>
+ *
+ * @param visible the new visibility state
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.4
+ */
+public void setListVisible (bool visible) {
+    checkWidget ();
+    dropDown(visible);
+}
+public override void setMenu(Menu menu) {
+    text.setMenu(menu);
+}
+/**
+ * Sets the selection in the receiver's text field to the
+ * range specified by the argument whose x coordinate is the
+ * start of the selection and whose y coordinate is the end
+ * of the selection.
+ *
+ * @param selection a point representing the new selection start and end
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setSelection (Point selection) {
+    checkWidget();
+    if (selection is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    text.setSelection (selection.x, selection.y);
+}
+
+/**
+ * Sets the contents of the receiver's text field to the
+ * given string.
+ * <p>
+ * Note: The text field in a <code>Combo</code> is typically
+ * only capable of displaying a single line of text. Thus,
+ * setting the text to a string containing line breaks or
+ * other special characters will probably cause it to
+ * display incorrectly.
+ * </p>
+ *
+ * @param string the new text
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setText (String string) {
+    checkWidget();
+    // DWT extension: allow null for zero length string
+    //if (string is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    int index = list.indexOf (string);
+    if (index is -1) {
+        list.deselectAll ();
+        text.setText (string);
+        return;
+    }
+    text.setText (string);
+    text.selectAll ();
+    list.setSelection (index);
+    list.showSelection ();
+}
+/**
+ * Sets the maximum number of characters that the receiver's
+ * text field is capable of holding to be the argument.
+ *
+ * @param limit new text limit
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setTextLimit (int limit) {
+    checkWidget();
+    text.setTextLimit (limit);
+}
+
+public override void setToolTipText (String string) {
+    checkWidget();
+    super.setToolTipText(string);
+    arrow.setToolTipText (string);
+    text.setToolTipText (string);
+}
+
+public override void setVisible (bool visible) {
+    super.setVisible(visible);
+    /*
+     * At this point the widget may have been disposed in a FocusOut event.
+     * If so then do not continue.
+     */
+    if (isDisposed ()) return;
+    // TEMPORARY CODE
+    if (popup is null || popup.isDisposed ()) return;
+    if (!visible) popup.setVisible (false);
+}
+/**
+ * Sets the number of items that are visible in the drop
+ * down portion of the receiver's list.
+ *
+ * @param count the new number of items to be visible
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setVisibleItemCount (int count) {
+    checkWidget ();
+    if (count < 0) return;
+    visibleItemCount = count;
+}
+String stripMnemonic (String string) {
+    int index = 0;
+    int length_ = string.length;
+    do {
+        while ((index < length_) && (string[index] !is '&')) index++;
+        if (++index >= length_) return string;
+        if (string[index] !is '&') {
+            return string[0 .. index-1] ~ string[index .. length_];
+        }
+        index++;
+    } while (index < length_);
+    return string;
+}
+void textEvent (Event event) {
+    switch (event.type) {
+        case DWT.FocusIn: {
+            handleFocus (DWT.FocusIn);
+            break;
+        }
+        case DWT.DefaultSelection: {
+            dropDown (false);
+            Event e = new Event ();
+            e.time = event.time;
+            e.stateMask = event.stateMask;
+            notifyListeners (DWT.DefaultSelection, e);
+            break;
+        }
+        case DWT.KeyDown: {
+            Event keyEvent = new Event ();
+            keyEvent.time = event.time;
+            keyEvent.character = event.character;
+            keyEvent.keyCode = event.keyCode;
+            keyEvent.stateMask = event.stateMask;
+            notifyListeners (DWT.KeyDown, keyEvent);
+            if (isDisposed ()) break;
+            event.doit = keyEvent.doit;
+            if (!event.doit) break;
+            if (event.keyCode is DWT.ARROW_UP || event.keyCode is DWT.ARROW_DOWN) {
+                event.doit = false;
+                if ((event.stateMask & DWT.ALT) !is 0) {
+                    bool dropped = isDropped ();
+                    text.selectAll ();
+                    if (!dropped) setFocus ();
+                    dropDown (!dropped);
                     break;
-                    case DWT.TRAVERSE_TAB_NEXT:
-                    case DWT.TRAVERSE_TAB_PREVIOUS:
-                        event.doit = text.traverse(event.detail);
-                        event.detail = DWT.TRAVERSE_NONE;
-                        if (event.doit)
-                            dropDown(false);
-                        return;
                 }
-                Event e = new Event();
-                e.time = event.time;
-                e.detail = event.detail;
-                e.doit = event.doit;
-                e.character = event.character;
-                e.keyCode = event.keyCode;
-                notifyListeners(DWT.Traverse, e);
-                event.doit = e.doit;
-                event.detail = e.detail;
-                break;
-            }
-            case DWT.KeyUp:
-            {
-                Event e = new Event();
-                e.time = event.time;
-                e.character = event.character;
-                e.keyCode = event.keyCode;
-                e.stateMask = event.stateMask;
-                notifyListeners(DWT.KeyUp, e);
-                break;
-            }
-            case DWT.KeyDown:
-            {
-                if (event.character is DWT.ESC)
-                {
-                    // Escape key cancels popup list
-                    dropDown(false);
+
+                int oldIndex = getSelectionIndex ();
+                if (event.keyCode is DWT.ARROW_UP) {
+                    select (Math.max (oldIndex - 1, 0));
+                } else {
+                    select (Math.min (oldIndex + 1, getItemCount () - 1));
                 }
-                if ((event.stateMask & DWT.ALT) !is 0 && (event.keyCode is DWT.ARROW_UP || event.keyCode is DWT.ARROW_DOWN))
-                {
-                    dropDown(false);
-                }
-                if (event.character is DWT.CR)
-                {
-                    // Enter causes default selection
-                    dropDown(false);
+                if (oldIndex !is getSelectionIndex ()) {
                     Event e = new Event();
                     e.time = event.time;
                     e.stateMask = event.stateMask;
-                    notifyListeners(DWT.DefaultSelection, e);
+                    notifyListeners (DWT.Selection, e);
                 }
-                // At this point the widget may have been disposed.
-                // If so, do not continue.
-                if (isDisposed())
-                    break;
-                Event e = new Event();
-                e.time = event.time;
-                e.character = event.character;
-                e.keyCode = event.keyCode;
-                e.stateMask = event.stateMask;
-                notifyListeners(DWT.KeyDown, e);
-                break;
-
+                if (isDisposed ()) break;
             }
 
-            default:
+            // Further work : Need to add support for incremental search in
+            // pop up list as characters typed in text widget
+            break;
+        }
+        case DWT.KeyUp: {
+            Event e = new Event ();
+            e.time = event.time;
+            e.character = event.character;
+            e.keyCode = event.keyCode;
+            e.stateMask = event.stateMask;
+            notifyListeners (DWT.KeyUp, e);
+            event.doit = e.doit;
+            break;
+        }
+        case DWT.MenuDetect: {
+            Event e = new Event ();
+            e.time = event.time;
+            notifyListeners (DWT.MenuDetect, e);
+            break;
+        }
+        case DWT.Modify: {
+            list.deselectAll ();
+            Event e = new Event ();
+            e.time = event.time;
+            notifyListeners (DWT.Modify, e);
             break;
         }
-    }
-
-    /**
-     * Pastes text from clipboard.
-     * <p>
-     * The selected text is deleted from the widget
-     * and new text inserted from the clipboard.
-     * </p>
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.3
-     */
-    public void paste ()
-    {
-        checkWidget();
-        text.paste();
-    }
-
-    void popupEvent (Event event)
-    {
-        switch (event.type)
-        {
-            case DWT.Paint:
-                // draw black rectangle around list
-                Rectangle listRect = list.getBounds();
-                Color black = getDisplay().getSystemColor(DWT.COLOR_BLACK);
-                event.gc.setForeground(black);
-                event.gc.drawRectangle(0, 0, listRect.width + 1,
-                        listRect.height + 1);
+        case DWT.MouseDown: {
+            Event mouseEvent = new Event ();
+            mouseEvent.button = event.button;
+            mouseEvent.count = event.count;
+            mouseEvent.stateMask = event.stateMask;
+            mouseEvent.time = event.time;
+            mouseEvent.x = event.x; mouseEvent.y = event.y;
+            notifyListeners (DWT.MouseDown, mouseEvent);
+            if (isDisposed ()) break;
+            event.doit = mouseEvent.doit;
+            if (!event.doit) break;
+            if (event.button !is 1) return;
+            if (text.getEditable ()) return;
+            bool dropped = isDropped ();
+            text.selectAll ();
+            if (!dropped) setFocus ();
+            dropDown (!dropped);
             break;
-            case DWT.Close:
-                event.doit = false;
-                dropDown(false);
-            break;
-            case DWT.Deactivate:
-                /*
-                 * Bug in GTK. When the arrow button is pressed the popup control receives a
-                 * deactivate event and then the arrow button receives a selection event. If 
-                 * we hide the popup in the deactivate event, the selection event will show 
-                 * it again. To prevent the popup from showing again, we will let the selection 
-                 * event of the arrow button hide the popup.
-                 * In Windows, hiding the popup during the deactivate causes the deactivate 
-                 * to be called twice and the selection event to be disappear.
-                 */
-                if (!"carbon".opEquals(DWT.getPlatform()))
-                {
-                    Point point = arrow.toControl(
-                            getDisplay().getCursorLocation());
-                    Point size = arrow.getSize();
-                    Rectangle rect = new Rectangle(0, 0, size.x, size.y);
-                    if (!rect.contains(point))
-                        dropDown(false);
-                }
-                else
-                {
-                    dropDown(false);
-                }
-            break;
-
-            default:
+        }
+        case DWT.MouseUp: {
+            Event mouseEvent = new Event ();
+            mouseEvent.button = event.button;
+            mouseEvent.count = event.count;
+            mouseEvent.stateMask = event.stateMask;
+            mouseEvent.time = event.time;
+            mouseEvent.x = event.x; mouseEvent.y = event.y;
+            notifyListeners (DWT.MouseUp, mouseEvent);
+            if (isDisposed ()) break;
+            event.doit = mouseEvent.doit;
+            if (!event.doit) break;
+            if (event.button !is 1) return;
+            if (text.getEditable ()) return;
+            text.selectAll ();
             break;
         }
-    }
-
-    public void redraw ()
-    {
-        super.redraw();
-        text.redraw();
-        arrow.redraw();
-        if (popup.isVisible())
-            list.redraw();
-    }
-
-    public void redraw (int x, int y, int width, int height, bool all)
-    {
-        super.redraw(x, y, width, height, true);
-    }
-
-    /**
-     * Removes the item from the receiver's list at the given
-     * zero-relative index.
-     *
-     * @param index the index for the item
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void remove (int index)
-    {
-        checkWidget();
-        list.remove(index);
-    }
-
-    /**
-     * Removes the items from the receiver's list which are
-     * between the given zero-relative start and end 
-     * indices (inclusive).
-     *
-     * @param start the start of the range
-     * @param end the end of the range
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_INVALID_RANGE - if either the start or end are not between 0 and the number of elements in the list minus 1 (inclusive)</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void remove (int start, int end)
-    {
-        checkWidget();
-        list.remove(start, end);
-    }
-
-    /**
-     * Searches the receiver's list starting at the first item
-     * until an item is found that is equal to the argument, 
-     * and removes that item from the list.
-     *
-     * @param String the item to remove
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the String is null</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if the String is not found in the list</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void remove (String String)
-    {
-        checkWidget();
-        if (String is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        list.remove(String);
-    }
-
-    /**
-     * Removes all of the items from the receiver's list and clear the
-     * contents of receiver's text field.
-     * <p>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void removeAll ()
-    {
-        checkWidget();
-        text.setText(""); //$NON-NLS-1$
-        list.removeAll();
-    }
-
-    /**
-     * Removes the listener from the collection of listeners who will
-     * be notified when the receiver's text is modified.
-     *
-     * @param listener the listener which should no longer be notified
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see ModifyListener
-     * @see #addModifyListener
-     */
-    public void removeModifyListener (ModifyListener listener)
-    {
-        checkWidget();
-        if (listener is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        removeListener(DWT.Modify, listener);
-    }
-
-    /**
-     * Removes the listener from the collection of listeners who will
-     * be notified when the user changes the receiver's selection.
-     *
-     * @param listener the listener which should no longer be notified
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see SelectionListener
-     * @see #addSelectionListener
-     */
-    public void removeSelectionListener (SelectionListener listener)
-    {
-        checkWidget();
-        if (listener is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        removeListener(DWT.Selection, listener);
-        removeListener(DWT.DefaultSelection, listener);
-    }
-
-    /**
-     * Removes the listener from the collection of listeners who will
-     * be notified when the control is verified.
-     *
-     * @param listener the listener which should no longer be notified
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see VerifyListener
-     * @see #addVerifyListener
-     * 
-     * @since 3.3
-     */
-    public void removeVerifyListener (VerifyListener listener)
-    {
-        checkWidget();
-        if (listener is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        removeListener(DWT.Verify, listener);
-    }
-
-    /**
-     * Selects the item at the given zero-relative index in the receiver's 
-     * list.  If the item at the index was already selected, it remains
-     * selected. Indices that are out of range are ignored.
-     *
-     * @param index the index of the item to select
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void select (int index)
-    {
-        checkWidget();
-        if (index is -1)
-        {
-            list.deselectAll();
-            text.setText(""); //$NON-NLS-1$
-            return;
-        }
-        if (0 <= index && index < list.getItemCount())
-        {
-            if (index !is getSelectionIndex())
-            {
-                text.setText(list.getItem(index));
-                text.selectAll();
-                list.select(index);
-                list.showSelection();
-            }
+        case DWT.MouseDoubleClick: {
+            Event mouseEvent = new Event ();
+            mouseEvent.button = event.button;
+            mouseEvent.count = event.count;
+            mouseEvent.stateMask = event.stateMask;
+            mouseEvent.time = event.time;
+            mouseEvent.x = event.x; mouseEvent.y = event.y;
+            notifyListeners (DWT.MouseDoubleClick, mouseEvent);
+            break;
         }
-    }
-
-    public void setBackground (Color color)
-    {
-        super.setBackground(color);
-        background = color;
-        if (text !is null)
-            text.setBackground(color);
-        if (list !is null)
-            list.setBackground(color);
-        if (arrow !is null)
-            arrow.setBackground(color);
-    }
-
-    /**
-     * Sets the editable state.
-     *
-     * @param editable the new editable state
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setEditable (bool editable)
-    {
-        checkWidget();
-        text.setEditable(editable);
-    }
-
-    public void setEnabled (bool enabled)
-    {
-        super.setEnabled(enabled);
-        if (popup !is null)
-            popup.setVisible(false);
-        if (text !is null)
-            text.setEnabled(enabled);
-        if (arrow !is null)
-            arrow.setEnabled(enabled);
-    }
-
-    public bool setFocus ()
-    {
-        checkWidget();
-        if (!isEnabled() || !isVisible())
-            return false;
-        if (isFocusControl())
-            return true;
-        return text.setFocus();
-    }
-
-    public void setFont (Font font)
-    {
-        super.setFont(font);
-        this.font = font;
-        text.setFont(font);
-        list.setFont(font);
-        internalLayout(true);
-    }
-
-    public void setForeground (Color color)
-    {
-        super.setForeground(color);
-        foreground = color;
-        if (text !is null)
-            text.setForeground(color);
-        if (list !is null)
-            list.setForeground(color);
-        if (arrow !is null)
-            arrow.setForeground(color);
-    }
-
-    /**
-     * Sets the text of the item in the receiver's list at the given
-     * zero-relative index to the String argument. This is equivalent
-     * to <code>remove</code>'ing the old item at the index, and then
-     * <code>add</code>'ing the new item at that index.
-     *
-     * @param index the index for the item
-     * @param String the new text for the item
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
-     *    <li>ERROR_NULL_ARGUMENT - if the String is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setItem (int index, String String)
-    {
-        checkWidget();
-        list.setItem(index, String);
-    }
-
-    /**
-     * Sets the receiver's list to be the given array of items.
-     *
-     * @param items the array of items
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setItems (String[] items)
-    {
-        checkWidget();
-        list.setItems(items);
-        if (!text.getEditable())
-            text.setText(""); //$NON-NLS-1$
-    }
-
-    /**
-     * Sets the layout which is associated with the receiver to be
-     * the argument which may be null.
-     * <p>
-     * Note: No Layout can be set on this Control because it already
-     * manages the size and position of its children.
-     * </p>
-     *
-     * @param layout the receiver's new layout or null
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setLayout (Layout layout)
-    {
-        checkWidget();
-        return;
-    }
-
-    /**
-     * Marks the receiver's list as visible if the argument is <code>true</code>,
-     * and marks it invisible otherwise.
-     * <p>
-     * If one of the receiver's ancestors is not visible or some
-     * other condition makes the receiver not visible, marking
-     * it visible may not actually cause it to be displayed.
-     * </p>
-     *
-     * @param visible the new visibility state
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.4
-     */
-    public void setListVisible (bool visible)
-    {
-        checkWidget();
-        dropDown(visible);
-    }
-
-    public void setMenu (Menu menu)
-    {
-        text.setMenu(menu);
-    }
-
-    /**
-     * Sets the selection in the receiver's text field to the
-     * range specified by the argument whose x coordinate is the
-     * start of the selection and whose y coordinate is the end
-     * of the selection. 
-     *
-     * @param selection a point representing the new selection start and end
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setSelection (Point selection)
-    {
-        checkWidget();
-        if (selection is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        text.setSelection(selection.x, selection.y);
-    }
-
-    /**
-     * Sets the contents of the receiver's text field to the
-     * given String.
-     * <p>
-     * Note: The text field in a <code>Combo</code> is typically
-     * only capable of displaying a single line of text. Thus,
-     * setting the text to a String containing line breaks or
-     * other special characters will probably cause it to 
-     * display incorrectly.
-     * </p>
-     *
-     * @param String the new text
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the String is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setText (String String)
-    {
-        checkWidget();
-        if (String is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        int index = list.indexOf(String);
-        if (index is -1)
-        {
-            list.deselectAll();
-            text.setText(String);
-            return;
-        }
-        text.setText(String);
-        text.selectAll();
-        list.setSelection(index);
-        list.showSelection();
-    }
-
-    /**
-     * Sets the maximum number of characters that the receiver's
-     * text field is capable of holding to be the argument.
-     *
-     * @param limit new text limit
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setTextLimit (int limit)
-    {
-        checkWidget();
-        text.setTextLimit(limit);
-    }
-
-    public void setToolTipText (String String)
-    {
-        checkWidget();
-        super.setToolTipText(String);
-        arrow.setToolTipText(String);
-        text.setToolTipText(String);
-    }
-
-    public void setVisible (bool visible)
-    {
-        super.setVisible(visible);
-        /* 
-         * At this point the widget may have been disposed in a FocusOut event.
-         * If so then do not continue.
-         */
-        if (isDisposed())
-            return;
-        if (!visible)
-            popup.setVisible(false);
-    }
-
-    /**
-     * Sets the number of items that are visible in the drop
-     * down portion of the receiver's list.
-     *
-     * @param count the new number of items to be visible
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setVisibleItemCount (int count)
-    {
-        checkWidget();
-        if (count < 0)
-            return;
-        visibleItemCount = count;
-    }
-
-    String stripMnemonic (String String)
-    {
-        int index = 0;
-        int length = String.length();
-        do
-        {
-            while ((index < length) && (String.charAt(index) !is '&'))
-                index++;
-            if (++index >= length)
-                return String;
-            if (String.charAt(index) !is '&')
-            {
-                return String.substring(0, index - 1) + String.substring(index,
-                        length);
+        case DWT.MouseWheel: {
+            Event keyEvent = new Event ();
+            keyEvent.time = event.time;
+            keyEvent.keyCode = event.count > 0 ? DWT.ARROW_UP : DWT.ARROW_DOWN;
+            keyEvent.stateMask = event.stateMask;
+            notifyListeners (DWT.KeyDown, keyEvent);
+            if (isDisposed ()) break;
+            event.doit = keyEvent.doit;
+            if (!event.doit) break;
+            if (event.count !is 0) {
+                event.doit = false;
+                int oldIndex = getSelectionIndex ();
+                if (event.count > 0) {
+                    select (Math.max (oldIndex - 1, 0));
+                } else {
+                    select (Math.min (oldIndex + 1, getItemCount () - 1));
+                }
+                if (oldIndex !is getSelectionIndex ()) {
+                    Event e = new Event();
+                    e.time = event.time;
+                    e.stateMask = event.stateMask;
+                    notifyListeners (DWT.Selection, e);
+                }
+                if (isDisposed ()) break;
             }
-            index++;
-        } while (index < length);
-        return String;
-    }
-
-    void textEvent (Event event)
-    {
-        switch (event.type)
-        {
-            case DWT.FocusIn:
-            {
-                handleFocus(DWT.FocusIn);
-                break;
-            }
-            case DWT.DefaultSelection:
-            {
-                dropDown(false);
-                Event e = new Event();
-                e.time = event.time;
-                e.stateMask = event.stateMask;
-                notifyListeners(DWT.DefaultSelection, e);
-                break;
-            }
-            case DWT.KeyDown:
-            {
-                Event keyEvent = new Event();
-                keyEvent.time = event.time;
-                keyEvent.character = event.character;
-                keyEvent.keyCode = event.keyCode;
-                keyEvent.stateMask = event.stateMask;
-                notifyListeners(DWT.KeyDown, keyEvent);
-                if (isDisposed())
-                    break;
-                event.doit = keyEvent.doit;
-                if (!event.doit)
-                    break;
-                if (event.keyCode is DWT.ARROW_UP || event.keyCode is DWT.ARROW_DOWN)
-                {
-                    event.doit = false;
-                    if ((event.stateMask & DWT.ALT) !is 0)
-                    {
-                        bool dropped = isDropped();
-                        text.selectAll();
-                        if (!dropped)
-                            setFocus();
-                        dropDown(!dropped);
-                        break;
-                    }
-
-                    int oldIndex = getSelectionIndex();
-                    if (event.keyCode is DWT.ARROW_UP)
-                    {
-                        select(Math.max(oldIndex - 1, 0));
-                    }
-                    else
-                    {
-                        select(Math.min(oldIndex + 1, getItemCount() - 1));
-                    }
-                    if (oldIndex !is getSelectionIndex())
-                    {
-                        Event e = new Event();
-                        e.time = event.time;
-                        e.stateMask = event.stateMask;
-                        notifyListeners(DWT.Selection, e);
-                    }
-                    if (isDisposed())
-                        break;
-                }
-
-                // Further work : Need to add support for incremental search in 
-                // pop up list as characters typed in text widget
-                break;
-            }
-            case DWT.KeyUp:
-            {
-                Event e = new Event();
-                e.time = event.time;
-                e.character = event.character;
-                e.keyCode = event.keyCode;
-                e.stateMask = event.stateMask;
-                notifyListeners(DWT.KeyUp, e);
-                event.doit = e.doit;
-                break;
-            }
-            case DWT.MenuDetect:
-            {
-                Event e = new Event();
-                e.time = event.time;
-                notifyListeners(DWT.MenuDetect, e);
-                break;
-            }
-            case DWT.Modify:
-            {
-                list.deselectAll();
-                Event e = new Event();
-                e.time = event.time;
-                notifyListeners(DWT.Modify, e);
-                break;
-            }
-            case DWT.MouseDown:
-            {
-                Event mouseEvent = new Event();
-                mouseEvent.button = event.button;
-                mouseEvent.count = event.count;
-                mouseEvent.stateMask = event.stateMask;
-                mouseEvent.time = event.time;
-                mouseEvent.x = event.x;
-                mouseEvent.y = event.y;
-                notifyListeners(DWT.MouseDown, mouseEvent);
-                if (isDisposed())
-                    break;
-                event.doit = mouseEvent.doit;
-                if (!event.doit)
-                    break;
-                if (event.button !is 1)
-                    return;
-                if (text.getEditable())
-                    return;
-                bool dropped = isDropped();
-                text.selectAll();
-                if (!dropped)
-                    setFocus();
-                dropDown(!dropped);
-                break;
-            }
-            case DWT.MouseUp:
-            {
-                Event mouseEvent = new Event();
-                mouseEvent.button = event.button;
-                mouseEvent.count = event.count;
-                mouseEvent.stateMask = event.stateMask;
-                mouseEvent.time = event.time;
-                mouseEvent.x = event.x;
-                mouseEvent.y = event.y;
-                notifyListeners(DWT.MouseUp, mouseEvent);
-                if (isDisposed())
-                    break;
-                event.doit = mouseEvent.doit;
-                if (!event.doit)
-                    break;
-                if (event.button !is 1)
-                    return;
-                if (text.getEditable())
-                    return;
-                text.selectAll();
-                break;
-            }
-            case DWT.MouseDoubleClick:
-            {
-                Event mouseEvent = new Event();
-                mouseEvent.button = event.button;
-                mouseEvent.count = event.count;
-                mouseEvent.stateMask = event.stateMask;
-                mouseEvent.time = event.time;
-                mouseEvent.x = event.x;
-                mouseEvent.y = event.y;
-                notifyListeners(DWT.MouseDoubleClick, mouseEvent);
-                break;
-            }
-            case DWT.MouseWheel:
-            {
-                Event keyEvent = new Event();
-                keyEvent.time = event.time;
-                keyEvent.keyCode = event.count > 0 ? DWT.ARROW_UP : DWT.ARROW_DOWN;
-                keyEvent.stateMask = event.stateMask;
-                notifyListeners(DWT.KeyDown, keyEvent);
-                if (isDisposed())
-                    break;
-                event.doit = keyEvent.doit;
-                if (!event.doit)
-                    break;
-                if (event.count !is 0)
-                {
-                    event.doit = false;
-                    int oldIndex = getSelectionIndex();
-                    if (event.count > 0)
-                    {
-                        select(Math.max(oldIndex - 1, 0));
-                    }
-                    else
-                    {
-                        select(Math.min(oldIndex + 1, getItemCount() - 1));
-                    }
-                    if (oldIndex !is getSelectionIndex())
-                    {
-                        Event e = new Event();
-                        e.time = event.time;
-                        e.stateMask = event.stateMask;
-                        notifyListeners(DWT.Selection, e);
-                    }
-                    if (isDisposed())
-                        break;
-                }
-                break;
-            }
-            case DWT.Traverse:
-            {
-                switch (event.detail)
-                {
-                    case DWT.TRAVERSE_ARROW_PREVIOUS:
-                    case DWT.TRAVERSE_ARROW_NEXT:
-                        // The enter causes default selection and
-                        // the arrow keys are used to manipulate the list contents so
-                        // do not use them for traversal.
-                        event.doit = false;
-                    break;
-                    case DWT.TRAVERSE_TAB_PREVIOUS:
-                        event.doit = traverse(DWT.TRAVERSE_TAB_PREVIOUS);
-                        event.detail = DWT.TRAVERSE_NONE;
-                        return;
-                }
-                Event e = new Event();
-                e.time = event.time;
-                e.detail = event.detail;
-                e.doit = event.doit;
-                e.character = event.character;
-                e.keyCode = event.keyCode;
-                notifyListeners(DWT.Traverse, e);
-                event.doit = e.doit;
-                event.detail = e.detail;
-                break;
-            }
-            case DWT.Verify:
-            {
-                Event e = new Event();
-                e.text = event.text;
-                e.start = event.start;
-                e.end = event.end;
-                e.character = event.character;
-                e.keyCode = event.keyCode;
-                e.stateMask = event.stateMask;
-                notifyListeners(DWT.Verify, e);
-                event.doit = e.doit;
-                break;
-            }
-
-            default:
             break;
         }
+        case DWT.Traverse: {
+            switch (event.detail) {
+                case DWT.TRAVERSE_ARROW_PREVIOUS:
+                case DWT.TRAVERSE_ARROW_NEXT:
+                    // The enter causes default selection and
+                    // the arrow keys are used to manipulate the list contents so
+                    // do not use them for traversal.
+                    event.doit = false;
+                    break;
+                case DWT.TRAVERSE_TAB_PREVIOUS:
+                    event.doit = traverse(DWT.TRAVERSE_TAB_PREVIOUS);
+                    event.detail = DWT.TRAVERSE_NONE;
+                    return;
+                default:
+            }
+            Event e = new Event ();
+            e.time = event.time;
+            e.detail = event.detail;
+            e.doit = event.doit;
+            e.character = event.character;
+            e.keyCode = event.keyCode;
+            notifyListeners (DWT.Traverse, e);
+            event.doit = e.doit;
+            event.detail = e.detail;
+            break;
+        }
+        case DWT.Verify: {
+            Event e = new Event ();
+            e.text = event.text;
+            e.start = event.start;
+            e.end = event.end;
+            e.character = event.character;
+            e.keyCode = event.keyCode;
+            e.stateMask = event.stateMask;
+            notifyListeners (DWT.Verify, e);
+            event.doit = e.doit;
+            break;
+        }
+        default:
     }
 }
+}
--- a/dwt/custom/CLabel.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/CLabel.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,12 +7,12 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.CLabel;
 
+
 import dwt.DWT;
 import dwt.DWTException;
 import dwt.accessibility.ACC;
@@ -38,13 +38,15 @@
 import dwt.widgets.Composite;
 import dwt.widgets.Control;
 import dwt.widgets.Display;
+import dwt.dwthelper.utils;
 
-import dwt.dwthelper.utils;
+static import tango.text.Unicode;
+static import tango.text.convert.Utf;
 
 /**
  * A Label which supports aligned text and/or an image and different border styles.
  * <p>
- * If there is not enough space a CLabel uses the following strategy to fit the 
+ * If there is not enough space a CLabel uses the following strategy to fit the
  * information into the available space:
  * <pre>
  *      ignores the indent in left align mode
@@ -59,22 +61,26 @@
  * <dt><b>Events:</b>
  * <dd></dd>
  * </dl>
- * 
+ *
  * </p><p>
  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
  * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: CustomControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
-public class CLabel : Canvas
-{
+public class CLabel : Canvas {
+
+    alias Canvas.computeSize computeSize;
 
     /** Gap between icon and text */
     private static const int GAP = 5;
     /** Left and right margins */
     private static const int INDENT = 3;
-    /** a String inserted in the middle of text that has been shortened */
+    /** a string inserted in the middle of text that has been shortened */
     private static const String ELLIPSIS = "..."; //$NON-NLS-1$ // could use the ellipsis glyph on some platforms "\u2026"
-    /** the alignnment. Either CENTER, RIGHT, LEFT. Default is LEFT*/
-    private int alignn = DWT.LEFT;
+    /** the alignment. Either CENTER, RIGHT, LEFT. Default is LEFT*/
+    private int align_ = DWT.LEFT;
     private int hIndent = INDENT;
     private int vIndent = INDENT;
     /** the current text */
@@ -84,7 +90,7 @@
     // The tooltip is used for two purposes - the application can set
     // a tooltip or the tooltip can be used to display the full text when the
     // the text has been truncated due to the label being too short.
-    // The appToolTip stores the tooltip set by the application.  Control.tooltiptext 
+    // The appToolTip stores the tooltip set by the application.  Control.tooltiptext
     // contains whatever tooltip is currently being displayed.
     private String appToolTipText;
 
@@ -94,947 +100,750 @@
     private bool gradientVertical;
     private Color background;
 
-    private static int
-            DRAW_FLAGS = DWT.DRAW_MNEMONIC | DWT.DRAW_TAB | DWT.DRAW_TRANSPARENT | DWT.DRAW_DELIMITER;
+    private static int DRAW_FLAGS = DWT.DRAW_MNEMONIC | DWT.DRAW_TAB | DWT.DRAW_TRANSPARENT | DWT.DRAW_DELIMITER;
 
-    /**
-     * Constructs a new instance of this class given its parent
-     * and a style value describing its behavior and appearance.
-     * <p>
-     * The style value is either one of the style constants defined in
-     * class <code>DWT</code> which is applicable to instances of this
-     * class, or must be built by <em>bitwise OR</em>'ing together 
-     * (that is, using the <code>int</code> "|" operator) two or more
-     * of those <code>DWT</code> style constants. The class description
-     * lists the style constants that are applicable to the class.
-     * Style bits are also inherited from superclasses.
-     * </p>
-     *
-     * @param parent a widget which will be the parent of the new instance (cannot be null)
-     * @param style the style of widget to construct
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
-     * </ul>
-     *
-     * @see DWT#LEFT
-     * @see DWT#RIGHT
-     * @see DWT#CENTER
-     * @see DWT#SHADOW_IN
-     * @see DWT#SHADOW_OUT
-     * @see DWT#SHADOW_NONE
-     * @see #getStyle()
-     */
-    public this (Composite parent, int style)
-    {
-        super(parent, checkStyle(style));
-        if ((style & (DWT.CENTER | DWT.RIGHT)) is 0)
-            style |= DWT.LEFT;
-        if ((style & DWT.CENTER) !is 0)
-            alignn = DWT.CENTER;
-        if ((style & DWT.RIGHT) !is 0)
-            alignn = DWT.RIGHT;
-        if ((style & DWT.LEFT) !is 0)
-            alignn = DWT.LEFT;
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>DWT</code> which is applicable to instances of this
+ * class, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DWT</code> style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a widget which will be the parent of the new instance (cannot be null)
+ * @param style the style of widget to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * </ul>
+ *
+ * @see DWT#LEFT
+ * @see DWT#RIGHT
+ * @see DWT#CENTER
+ * @see DWT#SHADOW_IN
+ * @see DWT#SHADOW_OUT
+ * @see DWT#SHADOW_NONE
+ * @see #getStyle()
+ */
+public this(Composite parent, int style) {
+    super(parent, checkStyle(style));
+    if ((style & (DWT.CENTER | DWT.RIGHT)) is 0) style |= DWT.LEFT;
+    if ((style & DWT.CENTER) !is 0) align_ = DWT.CENTER;
+    if ((style & DWT.RIGHT) !is 0)  align_ = DWT.RIGHT;
+    if ((style & DWT.LEFT) !is 0)   align_ = DWT.LEFT;
 
-        addPaintListener(new class PaintListener
-        {
-            public void paintControl (PaintEvent event)
-            {
-                onPaint(event);
-            }
-        });
+    addPaintListener(new class() PaintListener{
+        public void paintControl(PaintEvent event) {
+            onPaint(event);
+        }
+    });
 
-        addDisposeListener(new class DisposeListener
-        {
-            public void widgetDisposed (DisposeEvent event)
-            {
-                onDispose(event);
+    addDisposeListener(new class() DisposeListener{
+        public void widgetDisposed(DisposeEvent event) {
+            onDispose(event);
+        }
+    });
+
+    addTraverseListener(new class() TraverseListener {
+        public void keyTraversed(TraverseEvent event) {
+            if (event.detail is DWT.TRAVERSE_MNEMONIC) {
+                onMnemonic(event);
             }
-        });
+        }
+    });
+
+    initAccessible();
 
-        addTraverseListener(new class TraverseListener
-        {
-            public void keyTraversed (TraverseEvent event)
-            {
-                if (event.detail is DWT.TRAVERSE_MNEMONIC)
-                {
-                    onMnemonic(event);
-                }
-            }
-        });
-
-        initAccessible();
-
-    }
+}
+/**
+ * Check the style bits to ensure that no invalid styles are applied.
+ */
+private static int checkStyle (int style) {
+    if ((style & DWT.BORDER) !is 0) style |= DWT.SHADOW_IN;
+    int mask = DWT.SHADOW_IN | DWT.SHADOW_OUT | DWT.SHADOW_NONE | DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT;
+    style = style & mask;
+    return style |= DWT.NO_FOCUS | DWT.DOUBLE_BUFFERED;
+}
 
-    /**
-     * Check the style bits to ensure that no invalid styles are applied.
-     */
-    private static int checkStyle (int style)
-    {
-        if ((style & DWT.BORDER) !is 0)
-            style |= DWT.SHADOW_IN;
-        int
-                mask = DWT.SHADOW_IN | DWT.SHADOW_OUT | DWT.SHADOW_NONE | DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT;
-        style = style & mask;
-        return style |= DWT.NO_FOCUS | DWT.DOUBLE_BUFFERED;
-    }
-
-    //protected void checkSubclass () {
-    //  String name = getClass().getName ();
-    //  String validName = CLabel.class.getName();
-    //  if (!validName.opEquals(name)) {
-    //      DWT.error (DWT.ERROR_INVALID_SUBCLASS);
-    //  }
-    //}
+//protected void checkSubclass () {
+//  String name = getClass().getName ();
+//  String validName = CLabel.class.getName();
+//  if (!validName.equals(name)) {
+//      DWT.error (DWT.ERROR_INVALID_SUBCLASS);
+//  }
+//}
 
-    public Point computeSize (int wHint, int hHint, bool changed)
-    {
-        checkWidget();
-        Point e = getTotalSize(image, text);
-        if (wHint is DWT.DEFAULT)
-        {
-            e.x += 2 * hIndent;
-        }
-        else
-        {
-            e.x = wHint;
-        }
-        if (hHint is DWT.DEFAULT)
-        {
-            e.y += 2 * vIndent;
-        }
-        else
-        {
-            e.y = hHint;
-        }
-        return e;
+public override Point computeSize(int wHint, int hHint, bool changed) {
+    checkWidget();
+    Point e = getTotalSize(image, text);
+    if (wHint is DWT.DEFAULT){
+        e.x += 2*hIndent;
+    } else {
+        e.x = wHint;
     }
+    if (hHint is DWT.DEFAULT) {
+        e.y += 2*vIndent;
+    } else {
+        e.y = hHint;
+    }
+    return e;
+}
+/**
+ * Draw a rectangle in the given colors.
+ */
+private 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);
 
-    /**
-     * Draw a rectangle in the given colors.
-     */
-    private 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);
-    }
+    gc.setForeground(topleft);
+    gc.drawLine(x, y, x+w-1, y);
+    gc.drawLine(x, y, x,     y+h-1);
+}
+/*
+ * Return the lowercase of the first non-'&' character following
+ * an '&' character in the given string. If there are no '&'
+ * characters in the given string, return '\0'.
+ */
+dchar _findMnemonic (String string) {
+    if (string is null) return '\0';
+    int index = 0;
+    int length = string.length;
+    do {
+        while (index < length && string[index] !is '&') index++;
+        if (++index >= length) return '\0';
+        if (string[index] !is '&') {
+            dchar[1] tmp; uint ate;
+            dchar[] tmp2 = tango.text.convert.Utf.toString32( string[index .. Math.min( index + 4, string.length ) ], tmp, &ate );
+            assert( tmp2.length == 1 );
+            return tango.text.Unicode.toLower( tmp2 )[0];
+        }
+        index++;
+    } while (index < length);
+    return '\0';
+}
+/**
+ * Returns the alignment.
+ * The alignment style (LEFT, CENTER or RIGHT) is returned.
+ *
+ * @return DWT.LEFT, DWT.RIGHT or DWT.CENTER
+ */
+public int getAlignment() {
+    //checkWidget();
+    return align_;
+}
+/**
+ * Return the CLabel's image or <code>null</code>.
+ *
+ * @return the image of the label or null
+ */
+public Image getImage() {
+    //checkWidget();
+    return image;
+}
+/**
+ * Compute the minimum size.
+ */
+private Point getTotalSize(Image image, String text) {
+    Point size = new Point(0, 0);
 
-    /*
-     * Return the lowercase of the first non-'&' character following
-     * an '&' character in the given String. If there are no '&'
-     * characters in the given String, return '\0'.
-     */
-    char _findMnemonic (String str)
-    {
-        if (str is null)
-            return '\0';
-        int index = 0;
-        int length = str.length();
-        do
-        {
-            while (index < length && str.charAt(index) !is '&')
-                index++;
-            if (++index >= length)
-                return '\0';
-            if (str.charAt(index) !is '&')
-                return CharacterToLower(str.charAt(index));
-            index++;
-        } while (index < length);
-        return '\0';
-    }
-
-    /**
-     * Returns the alignnment.
-     * The alignnment style (LEFT, CENTER or RIGHT) is returned.
-     * 
-     * @return DWT.LEFT, DWT.RIGHT or DWT.CENTER
-     */
-    public int getAlignment ()
-    {
-        //checkWidget();
-        return alignn;
+    if (image !is null) {
+        Rectangle r = image.getBounds();
+        size.x += r.width;
+        size.y += r.height;
     }
 
-    /**
-     * Return the CLabel's image or <code>null</code>.
-     * 
-     * @return the image of the label or null
-     */
-    public Image getImage ()
-    {
-        //checkWidget();
-        return image;
+    GC gc = new GC(this);
+    if (text !is null && text.length > 0) {
+        Point e = gc.textExtent(text, DRAW_FLAGS);
+        size.x += e.x;
+        size.y = Math.max(size.y, e.y);
+        if (image !is null) size.x += GAP;
+    } else {
+        size.y = Math.max(size.y, gc.getFontMetrics().getHeight());
     }
+    gc.dispose();
+
+    return size;
+}
+public override int getStyle () {
+    int style = super.getStyle();
+    switch (align_) {
+        case DWT.RIGHT: style |= DWT.RIGHT; break;
+        case DWT.CENTER: style |= DWT.CENTER; break;
+        case DWT.LEFT: style |= DWT.LEFT; break;
+        default:
+    }
+    return style;
+}
 
-    /**
-     * Compute the minimum size.
-     */
-    private Point getTotalSize (Image image, String text)
-    {
-        Point size = new Point(0, 0);
+/**
+ * Return the Label's text.
+ *
+ * @return the text of the label or null
+ */
+public String getText() {
+    //checkWidget();
+    return text;
+}
+public override String getToolTipText () {
+    checkWidget();
+    return appToolTipText;
+}
+private void initAccessible() {
+    Accessible accessible = getAccessible();
+    accessible.addAccessibleListener(new class() AccessibleAdapter {
+        public void getName(AccessibleEvent e) {
+            e.result = getText();
+        }
 
-        if (image !is null)
-        {
-            Rectangle r = image.getBounds();
-            size.x += r.width;
-            size.y += r.height;
+        public void getHelp(AccessibleEvent e) {
+            e.result = getToolTipText();
+        }
+
+        public void getKeyboardShortcut(AccessibleEvent e) {
+            dchar mnemonic = _findMnemonic(this.outer.text);
+            if (mnemonic !is '\0') {
+                dchar[1] d;
+                d[0] = mnemonic;
+                e.result = "Alt+" ~ tango.text.convert.Utf.toString(d); //$NON-NLS-1$
+            }
+        }
+    });
+
+    accessible.addAccessibleControlListener(new class() AccessibleControlAdapter {
+        public void getChildAtPoint(AccessibleControlEvent e) {
+            e.childID = ACC.CHILDID_SELF;
         }
 
-        GC gc = new GC(this);
-        if (text !is null && text.length() > 0)
-        {
-            Point e = gc.textExtent(text, DRAW_FLAGS);
-            size.x += e.x;
-            size.y = Math.max(size.y, e.y);
-            if (image !is null)
-                size.x += GAP;
+        public void getLocation(AccessibleControlEvent e) {
+            Rectangle rect = getDisplay().map(getParent(), null, getBounds());
+            e.x = rect.x;
+            e.y = rect.y;
+            e.width = rect.width;
+            e.height = rect.height;
         }
-        else
-        {
-            size.y = Math.max(size.y, gc.getFontMetrics().getHeight());
-        }
-        gc.dispose();
-
-        return size;
-    }
 
-    public int getStyle ()
-    {
-        int style = super.getStyle();
-        switch (alignn)
-        {
-            case DWT.RIGHT:
-                style |= DWT.RIGHT;
-            break;
-            case DWT.CENTER:
-                style |= DWT.CENTER;
-            break;
-            case DWT.LEFT:
-                style |= DWT.LEFT;
-            break;
+        public void getChildCount(AccessibleControlEvent e) {
+            e.detail = 0;
         }
-        return style;
-    }
+
+        public void getRole(AccessibleControlEvent e) {
+            e.detail = ACC.ROLE_LABEL;
+        }
 
-    /**
-     * Return the Label's text.
-     * 
-     * @return the text of the label or null
-     */
-    public String getText ()
-    {
-        //checkWidget();
-        return text;
-    }
-
-    public String getToolTipText ()
-    {
-        checkWidget();
-        return appToolTipText;
-    }
-
-    private void initAccessible ()
-    {
-        Accessible accessible = getAccessible();
-        accessible.addAccessibleListener(new class AccessibleAdapter
-        {
-            public void getName (AccessibleEvent e)
-            {
-                e.result = getText();
-            }
-
-            public void getHelp (AccessibleEvent e)
-            {
-                e.result = getToolTipText();
-            }
-
-            public void getKeyboardShortcut (AccessibleEvent e)
-            {
-                char mnemonic = _findMnemonic(this.text);
-                if (mnemonic !is '\0')
-                {
-                    e.result = "Alt+" + mnemonic; //$NON-NLS-1$
+        public void getState(AccessibleControlEvent e) {
+            e.detail = ACC.STATE_READONLY;
+        }
+    });
+}
+void onDispose(DisposeEvent event) {
+    gradientColors = null;
+    gradientPercents = null;
+    backgroundImage = null;
+    text = null;
+    image = null;
+    appToolTipText = null;
+}
+void onMnemonic(TraverseEvent event) {
+    dchar mnemonic = _findMnemonic(text);
+    if (mnemonic is '\0') return;
+    dchar[1] d; uint ate;
+    auto r = tango.text.convert.Utf.toString32( [event.character][], d, &ate );
+    if (tango.text.Unicode.toLower(r)[0] !is mnemonic) return;
+    Composite control = this.getParent();
+    while (control !is null) {
+        Control [] children = control.getChildren();
+        int index = 0;
+        while (index < children.length) {
+            if (children [index] is this) break;
+            index++;
+        }
+        index++;
+        if (index < children.length) {
+            if (children [index].setFocus ()) {
+                event.doit = true;
+                event.detail = DWT.TRAVERSE_NONE;
             }
         }
-    }   );
-
-        accessible.addAccessibleControlListener(new class
-                AccessibleControlAdapter
-        {
-            public void getChildAtPoint (AccessibleControlEvent e)
-            {
-                e.childID = ACC.CHILDID_SELF;
-            }
+        control = control.getParent();
+    }
+}
 
-            public void getLocation (AccessibleControlEvent e)
-            {
-                Rectangle rect = getDisplay().map(getParent(), null,
-                        getBounds());
-                e.x = rect.x;
-                e.y = rect.y;
-                e.width = rect.width;
-                e.height = rect.height;
-            }
-
-            public void getChildCount (AccessibleControlEvent e)
-            {
-                e.detail = 0;
-            }
-
-            public void getRole (AccessibleControlEvent e)
-            {
-                e.detail = ACC.ROLE_LABEL;
-            }
-
-            public void getState (AccessibleControlEvent e)
-            {
-                e.detail = ACC.STATE_READONLY;
-            }
-        });
-    }
+void onPaint(PaintEvent event) {
+    Rectangle rect = getClientArea();
+    if (rect.width is 0 || rect.height is 0) return;
 
-    void onDispose (DisposeEvent event)
-    {
-        gradientColors = null;
-        gradientPercents = null;
-        backgroundImage = null;
-        text = null;
-        image = null;
-        appToolTipText = null;
-    }
-
-    void onMnemonic (TraverseEvent event)
-    {
-        char mnemonic = _findMnemonic(text);
-        if (mnemonic is '\0')
-            return;
-        if (CharacterToLower(event.character) !is mnemonic)
-            return;
-        Composite control = this.getParent();
-        while (control !is null)
-        {
-            Control[] children = control.getChildren();
-            int index = 0;
-            while (index < children.length)
-            {
-                if (children[index] is this)
-                    break;
-                index++;
-            }
-            index++;
-            if (index < children.length)
-            {
-                if (children[index].setFocus())
-                {
-                    event.doit = true;
-                    event.detail = DWT.TRAVERSE_NONE;
-                }
-            }
-            control = control.getParent();
+    bool shortenText_ = false;
+    String t = text;
+    Image img = image;
+    int availableWidth = Math.max(0, rect.width - 2*hIndent);
+    Point extent = getTotalSize(img, t);
+    if (extent.x > availableWidth) {
+        img = null;
+        extent = getTotalSize(img, t);
+        if (extent.x > availableWidth) {
+            shortenText_ = true;
         }
     }
 
-    void onPaint (PaintEvent event)
-    {
-        Rectangle rect = getClientArea();
-        if (rect.width is 0 || rect.height is 0)
-            return;
-
-        bool shortenText = false;
-        String t = text;
-        Image img = image;
-        int availableWidth = Math.max(0, rect.width - 2 * hIndent);
-        Point extent = getTotalSize(img, t);
-        if (extent.x > availableWidth)
-        {
-            img = null;
-            extent = getTotalSize(img, t);
-            if (extent.x > availableWidth)
-            {
-                shortenText = true;
-            }
-        }
+    GC gc = event.gc;
+    String[] lines = text is null ? null : splitString(text);
 
-        GC gc = event.gc;
-        String[] lines = text is null ? null : splitString(text);
-
-        // shorten the text
-        if (shortenText)
-        {
-            extent.x = 0;
-            for (int i = 0; i < lines.length; i++)
-            {
-                Point e = gc.textExtent(lines[i], DRAW_FLAGS);
-                if (e.x > availableWidth)
-                {
-                    lines[i] = shortenText(gc, lines[i], availableWidth);
-                    extent.x = Math.max(extent.x,
-                            getTotalSize(null, lines[i]).x);
-                }
-                else
-                {
-                    extent.x = Math.max(extent.x, e.x);
-                }
-            }
-            if (appToolTipText is null)
-            {
-                super.setToolTipText(text);
+    // shorten the text
+    if (shortenText_) {
+        extent.x = 0;
+        for(int i = 0; i < lines.length; i++) {
+            Point e = gc.textExtent(lines[i], DRAW_FLAGS);
+            if (e.x > availableWidth) {
+                lines[i] = shortenText(gc, lines[i], availableWidth);
+                extent.x = Math.max(extent.x, getTotalSize(null, lines[i]).x);
+            } else {
+                extent.x = Math.max(extent.x, e.x);
             }
         }
-        else
-        {
-            super.setToolTipText(appToolTipText);
+        if (appToolTipText is null) {
+            super.setToolTipText(text);
         }
-
-        // determine horizontal position
-        int x = rect.x + hIndent;
-        if (alignn is DWT.CENTER)
-        {
-            x = (rect.width - extent.x) / 2;
-        }
-        if (alignn is DWT.RIGHT)
-        {
-            x = rect.width - hIndent - extent.x;
-        }
+    } else {
+        super.setToolTipText(appToolTipText);
+    }
 
-        // draw a background image behind the text
-        try
-        {
-            if (backgroundImage !is null)
-            {
-                // draw a background image behind the text
-                Rectangle imageRect = backgroundImage.getBounds();
-                // tile image to fill space
-                gc.setBackground(getBackground());
-                gc.fillRectangle(rect);
-                int xPos = 0;
-                while (xPos < rect.width)
-                {
-                    int yPos = 0;
-                    while (yPos < rect.height)
-                    {
-                        gc.drawImage(backgroundImage, xPos, yPos);
-                        yPos += imageRect.height;
-                    }
-                    xPos += imageRect.width;
-                }
-            }
-            else if (gradientColors !is null)
-            {
-                // draw a gradient behind the text
-                const 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);
+    // determine horizontal position
+    int x = rect.x + hIndent;
+    if (align_ is DWT.CENTER) {
+        x = (rect.width - extent.x)/2;
+    }
+    if (align_ is DWT.RIGHT) {
+        x = rect.width - hIndent - extent.x;
+    }
+
+    // draw a background image behind the text
+    try {
+        if (backgroundImage !is null) {
+            // draw a background image behind the text
+            Rectangle imageRect = backgroundImage.getBounds();
+            // tile image to fill space
+            gc.setBackground(getBackground());
+            gc.fillRectangle(rect);
+            int xPos = 0;
+            while (xPos < rect.width) {
+                int yPos = 0;
+                while (yPos < rect.height) {
+                    gc.drawImage(backgroundImage, xPos, yPos);
+                    yPos += imageRect.height;
                 }
-                else
-                {
-                    const 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)
-                        {
-                            const int
-                                    gradientHeight = (gradientPercents[i] * rect.height / 100) - pos;
-                            gc.fillGradientRectangle(0, pos, rect.width,
-                                    gradientHeight, true);
-                            pos += gradientHeight;
-                        }
-                        else
-                        {
-                            const int
-                                    gradientWidth = (gradientPercents[i] * rect.width / 100) - pos;
-                            gc.fillGradientRectangle(pos, 0, gradientWidth,
-                                    rect.height, false);
-                            pos += gradientWidth;
-                        }
+                xPos += imageRect.width;
+            }
+        } else if (gradientColors !is null) {
+            // draw a gradient behind the text
+            final 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 {
+                final 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) {
+                        final int gradientHeight = (gradientPercents[i] * rect.height / 100) - pos;
+                        gc.fillGradientRectangle(0, pos, rect.width, gradientHeight, true);
+                        pos += gradientHeight;
+                    } else {
+                        final 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);
+                }
+                if (gradientVertical && pos < rect.height) {
+                    gc.setBackground(getBackground());
+                    gc.fillRectangle(0, pos, rect.width, rect.height - pos);
                 }
-                gc.setBackground(oldBackground);
+                if (!gradientVertical && pos < rect.width) {
+                    gc.setBackground(getBackground());
+                    gc.fillRectangle(pos, 0, rect.width - pos, rect.height);
+                }
+                gc.setForeground(oldForeground);
             }
-            else
-            {
-                if (background !is null || (getStyle() & DWT.DOUBLE_BUFFERED) is 0)
-                {
-                    gc.setBackground(getBackground());
-                    gc.fillRectangle(rect);
-                }
-            }
-        }
-        catch (DWTException e)
-        {
-            if ((getStyle() & DWT.DOUBLE_BUFFERED) is 0)
-            {
+            gc.setBackground(oldBackground);
+        } else {
+            if (background !is null || (getStyle() & DWT.DOUBLE_BUFFERED) is 0) {
                 gc.setBackground(getBackground());
                 gc.fillRectangle(rect);
             }
         }
+    } catch (DWTException e) {
+        if ((getStyle() & DWT.DOUBLE_BUFFERED) is 0) {
+            gc.setBackground(getBackground());
+            gc.fillRectangle(rect);
+        }
+    }
 
-        // draw border
-        int style = getStyle();
-        if ((style & DWT.SHADOW_IN) !is 0 || (style & DWT.SHADOW_OUT) !is 0)
-        {
-            paintBorder(gc, rect);
-        }
+    // draw border
+    int style = getStyle();
+    if ((style & DWT.SHADOW_IN) !is 0 || (style & DWT.SHADOW_OUT) !is 0) {
+        paintBorder(gc, rect);
+    }
 
-        // draw the image
-        if (img !is null)
-        {
-            Rectangle imageRect = img.getBounds();
-            gc.drawImage(img, 0, 0, imageRect.width, imageRect.height, x,
-                    (rect.height - imageRect.height) / 2, imageRect.width,
-                    imageRect.height);
-            x += imageRect.width + GAP;
-            extent.x -= imageRect.width + GAP;
+    // draw the image
+    if (img !is null) {
+        Rectangle imageRect = img.getBounds();
+        gc.drawImage(img, 0, 0, imageRect.width, imageRect.height,
+                        x, (rect.height-imageRect.height)/2, imageRect.width, imageRect.height);
+        x +=  imageRect.width + GAP;
+        extent.x -= imageRect.width + GAP;
+    }
+    // draw the text
+    if (lines !is null) {
+        int lineHeight = gc.getFontMetrics().getHeight();
+        int textHeight = lines.length * lineHeight;
+        int lineY = Math.max(vIndent, rect.y + (rect.height - textHeight) / 2);
+        gc.setForeground(getForeground());
+        for (int i = 0; i < lines.length; i++) {
+            int lineX = x;
+            if (lines.length > 1) {
+                if (align_ is DWT.CENTER) {
+                    int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x;
+                    lineX = x + Math.max(0, (extent.x - lineWidth) / 2);
+                }
+                if (align_ is DWT.RIGHT) {
+                    int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x;
+                    lineX = Math.max(x, rect.x + rect.width - hIndent - lineWidth);
+                }
+            }
+            gc.drawText(lines[i], lineX, lineY, DRAW_FLAGS);
+            lineY += lineHeight;
         }
-        // draw the text
-        if (lines !is null)
-        {
-            int lineHeight = gc.getFontMetrics().getHeight();
-            int textHeight = lines.length * lineHeight;
-            int lineY = Math.max(vIndent,
-                    rect.y + (rect.height - textHeight) / 2);
-            gc.setForeground(getForeground());
-            for (int i = 0; i < lines.length; i++)
-            {
-                int lineX = x;
-                if (lines.length > 1)
-                {
-                    if (alignn is DWT.CENTER)
-                    {
-                        int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x;
-                        lineX = x + Math.max(0, (extent.x - lineWidth) / 2);
-                    }
-                    if (alignn is DWT.RIGHT)
-                    {
-                        int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x;
-                        lineX = Math.max(x,
-                                rect.x + rect.width - hIndent - lineWidth);
-                    }
-                }
-                gc.drawText(lines[i], lineX, lineY, DRAW_FLAGS);
-                lineY += lineHeight;
+    }
+}
+/**
+ * Paint the Label's border.
+ */
+private void paintBorder(GC gc, Rectangle r) {
+    Display disp= getDisplay();
+
+    Color c1 = null;
+    Color c2 = null;
+
+    int style = getStyle();
+    if ((style & DWT.SHADOW_IN) !is 0) {
+        c1 = disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
+        c2 = disp.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
+    }
+    if ((style & DWT.SHADOW_OUT) !is 0) {
+        c1 = disp.getSystemColor(DWT.COLOR_WIDGET_LIGHT_SHADOW);
+        c2 = disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
+    }
+
+    if (c1 !is null && c2 !is null) {
+        gc.setLineWidth(1);
+        drawBevelRect(gc, r.x, r.y, r.width-1, r.height-1, c1, c2);
+    }
+}
+/**
+ * Set the alignment of the CLabel.
+ * Use the values LEFT, CENTER and RIGHT to align image and text within the available space.
+ *
+ * @param align the alignment style of LEFT, RIGHT or CENTER
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the value of align is not one of DWT.LEFT, DWT.RIGHT or DWT.CENTER</li>
+ * </ul>
+ */
+public void setAlignment(int align_) {
+    checkWidget();
+    if (align_ !is DWT.LEFT && align_ !is DWT.RIGHT && align_ !is DWT.CENTER) {
+        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    if (this.align_ !is align_) {
+        this.align_ = align_;
+        redraw();
+    }
+}
+
+public override void setBackground (Color color) {
+    super.setBackground (color);
+    // Are these settings the same as before?
+    if (backgroundImage is null &&
+        gradientColors is null &&
+        gradientPercents is null) {
+        if (color is null) {
+            if (background is null) return;
+        } else {
+            if (color ==/*eq*/ background) return;
+        }
+    }
+    background = color;
+    backgroundImage = null;
+    gradientColors = null;
+    gradientPercents = null;
+    redraw ();
+}
+
+/**
+ * Specify a gradient of colours to be drawn in the background of the CLabel.
+ * <p>For example, to draw a gradient that varies from dark blue to blue and then to
+ * white and stays white for the right half of the label, use the following call
+ * to setBackground:</p>
+ * <pre>
+ *  clabel.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE),
+ *                                 display.getSystemColor(DWT.COLOR_BLUE),
+ *                                 display.getSystemColor(DWT.COLOR_WHITE),
+ *                                 display.getSystemColor(DWT.COLOR_WHITE)},
+ *                     new int[] {25, 50, 100});
+ * </pre>
+ *
+ * @param colors an array of Color that specifies the colors to appear in the gradient
+ *               in order of appearance from left to right;  The value <code>null</code>
+ *               clears the background gradient; the value <code>null</code> can be used
+ *               inside the array of Color to specify the background color.
+ * @param percents an array of integers between 0 and 100 specifying the percent of the width
+ *                 of the widget at which the color should change; the size of the percents
+ *                 array must be one less than the size of the colors array.
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the values of colors and percents are not consistent</li>
+ * </ul>
+ */
+public void setBackground(Color[] colors, int[] percents) {
+    setBackground(colors, percents, false);
+}
+/**
+ * Specify a gradient of colours to be drawn in the background of the CLabel.
+ * <p>For example, to draw a gradient that varies from dark blue to white in the vertical,
+ * direction use the following call
+ * to setBackground:</p>
+ * <pre>
+ *  clabel.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE),
+ *                                 display.getSystemColor(DWT.COLOR_WHITE)},
+ *                       new int[] {100}, true);
+ * </pre>
+ *
+ * @param colors an array of Color that specifies the colors to appear in the gradient
+ *               in order of appearance from left/top to right/bottom;  The value <code>null</code>
+ *               clears the background gradient; the value <code>null</code> can be used
+ *               inside the array of Color to specify the background color.
+ * @param percents an array of integers between 0 and 100 specifying the percent of the width/height
+ *                 of the widget at which the color should change; the size of the percents
+ *                 array must be one less than the size of the colors array.
+ * @param vertical indicate the direction of the gradient.  True is vertical and false is horizontal.
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the values of colors and percents are not consistent</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+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 = null;
+        }
+        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);
             }
         }
     }
 
-    /**
-     * Paint the Label's border.
-     */
-    private void paintBorder (GC gc, Rectangle r)
-    {
-        Display disp = getDisplay();
-
-        Color c1 = null;
-        Color c2 = null;
-
-        int style = getStyle();
-        if ((style & DWT.SHADOW_IN) !is 0)
-        {
-            c1 = disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
-            c2 = disp.getSystemColor(DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
-        }
-        if ((style & DWT.SHADOW_OUT) !is 0)
-        {
-            c1 = disp.getSystemColor(DWT.COLOR_WIDGET_LIGHT_SHADOW);
-            c2 = disp.getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
-        }
-
-        if (c1 !is null && c2 !is null)
-        {
-            gc.setLineWidth(1);
-            drawBevelRect(gc, r.x, r.y, r.width - 1, r.height - 1, c1, c2);
-        }
-    }
-
-    /**
-     * Set the alignnment of the CLabel.
-     * Use the values LEFT, CENTER and RIGHT to alignn image and text within the available space.
-     * 
-     * @param alignn the alignnment style of LEFT, RIGHT or CENTER
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if the value of alignn is not one of DWT.LEFT, DWT.RIGHT or DWT.CENTER</li>
-     * </ul>
-     */
-    public void setAlignment (int alignn)
-    {
-        checkWidget();
-        if (alignn !is DWT.LEFT && alignn !is DWT.RIGHT && alignn !is DWT.CENTER)
-        {
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }
-        if (this.alignn !is alignn)
-        {
-            this.alignn = alignn;
-            redraw();
-        }
-    }
-
-    public void setBackground (Color color)
-    {
-        super.setBackground(color);
-        // Are these settings the same as before?
-        if (backgroundImage is null && gradientColors is null && gradientPercents is null)
-        {
-            if (color is null)
-            {
-                if (background is null)
-                    return;
-            }
-            else
-            {
-                if (color.opEquals(background))
-                    return;
+    // Are these settings the same as before?
+    final Color background = getBackground();
+    if (backgroundImage is null) {
+        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;
             }
-        }
-        background = color;
-        backgroundImage = null;
-        gradientColors = null;
-        gradientPercents = null;
-        redraw();
-    }
-
-    /**
-     * Specify a gradient of colours to be drawn in the background of the CLabel.
-     * <p>For example, to draw a gradient that varies from dark blue to blue and then to
-     * white and stays white for the right half of the label, use the following call 
-     * to setBackground:</p>
-     * <pre>
-     *  clabel.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE), 
-     *                                 display.getSystemColor(DWT.COLOR_BLUE),
-     *                                 display.getSystemColor(DWT.COLOR_WHITE), 
-     *                                 display.getSystemColor(DWT.COLOR_WHITE)},
-     *                     new int[] {25, 50, 100});
-     * </pre>
-     *
-     * @param colors an array of Color that specifies the colors to appear in the gradient 
-     *               in order of appearance from left to right;  The value <code>null</code> 
-     *               clears the background gradient; the value <code>null</code> can be used 
-     *               inside the array of Color to specify the background color.
-     * @param percents an array of integers between 0 and 100 specifying the percent of the width 
-     *                 of the widget at which the color should change; the size of the percents 
-     *                 array must be one less than the size of the colors array.
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if the values of colors and percents are not consistent</li>
-     * </ul>
-     */
-    public void setBackground (Color[] colors, int[] percents)
-    {
-        setBackground(colors, percents, false);
-    }
-
-    /**
-     * Specify a gradient of colours to be drawn in the background of the CLabel.
-     * <p>For example, to draw a gradient that varies from dark blue to white in the vertical,
-     * direction use the following call 
-     * to setBackground:</p>
-     * <pre>
-     *  clabel.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE), 
-     *                                 display.getSystemColor(DWT.COLOR_WHITE)},
-     *                       new int[] {100}, true);
-     * </pre>
-     *
-     * @param colors an array of Color that specifies the colors to appear in the gradient 
-     *               in order of appearance from left/top to right/bottom;  The value <code>null</code> 
-     *               clears the background gradient; the value <code>null</code> can be used 
-     *               inside the array of Color to specify the background color.
-     * @param percents an array of integers between 0 and 100 specifying the percent of the width/height 
-     *                 of the widget at which the color should change; the size of the percents 
-     *                 array must be one less than the size of the colors array.
-     * @param vertical indicate the direction of the gradient.  True is vertical and false is horizontal.
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if the values of colors and percents are not consistent</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    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 = new Color[][colors[colors.length - 1]];
-                percents = new int[][];
-            }
-            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);
+            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;
         }
+    } else {
+        backgroundImage = null;
+    }
+    // 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();
+}
+/**
+ * Set the image to be drawn in the background of the label.
+ *
+ * @param image the image to be drawn in the background
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setBackground(Image image) {
+    checkWidget();
+    if (image is backgroundImage) return;
+    if (image !is null) {
+        gradientColors = null;
+        gradientPercents = null;
+    }
+    backgroundImage = image;
+    redraw();
 
-        // Are these settings the same as before?
-        const Color background = getBackground();
-        if (backgroundImage is null)
-        {
-            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;
-            }
-        }
-        else
-        {
-            backgroundImage = null;
-        }
-        // 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
+}
+public override void setFont(Font font) {
+    super.setFont(font);
+    redraw();
+}
+/**
+ * Set the label's Image.
+ * The value <code>null</code> clears it.
+ *
+ * @param image the image to be displayed in the label or null
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setImage(Image image) {
+    checkWidget();
+    if (image !is this.image) {
+        this.image = image;
         redraw();
     }
-
-    /**
-     * Set the image to be drawn in the background of the label.
-     * 
-     * @param image the image to be drawn in the background
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setBackground (Image image)
-    {
-        checkWidget();
-        if (image is backgroundImage)
-            return;
-        if (image !is null)
-        {
-            gradientColors = null;
-            gradientPercents = null;
-        }
-        backgroundImage = image;
-        redraw();
-
-    }
-
-    public void setFont (Font font)
-    {
-        super.setFont(font);
+}
+/**
+ * Set the label's text.
+ * The value <code>null</code> clears it.
+ *
+ * @param text the text to be displayed in the label or null
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setText(String text) {
+    checkWidget();
+    if (text is null) text = ""; //$NON-NLS-1$
+    if ( text !=/*eq*/ this.text) {
+        this.text = text;
         redraw();
     }
-
-    /**
-     * Set the label's Image.
-     * The value <code>null</code> clears it.
-     * 
-     * @param image the image to be displayed in the label or null
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setImage (Image image)
-    {
-        checkWidget();
-        if (image !is this.image)
-        {
-            this.image = image;
-            redraw();
+}
+public override void setToolTipText (String string) {
+    super.setToolTipText (string);
+    appToolTipText = super.getToolTipText();
+}
+/**
+ * Shorten the given text <code>t</code> so that its length doesn't exceed
+ * the given width. The default implementation replaces characters in the
+ * center of the original string with an ellipsis ("...").
+ * Override if you need a different strategy.
+ *
+ * @param gc the gc to use for text measurement
+ * @param t the text to shorten
+ * @param width the width to shorten the text to, in pixels
+ * @return the shortened text
+ */
+protected String shortenText(GC gc, String t, int width) {
+    if (t is null) return null;
+    int w = gc.textExtent(ELLIPSIS, DRAW_FLAGS).x;
+    if (width<=w) return t;
+    int l = t.length;
+    int max = l/2;
+    int min = 0;
+    int mid = (max+min)/2 - 1;
+    if (mid <= 0) return t;
+    TextLayout layout = new TextLayout (getDisplay());
+    layout.setText(t);
+    mid = validateOffset(layout, mid);
+    while (min < mid && mid < max) {
+        String s1 = t[0 .. mid].dup;
+        String s2 = t.substring(validateOffset(layout, l-mid), l);
+        int l1 = gc.textExtent(s1, DRAW_FLAGS).x;
+        int l2 = gc.textExtent(s2, DRAW_FLAGS).x;
+        if (l1+w+l2 > width) {
+            max = mid;
+            mid = validateOffset(layout, (max+min)/2);
+        } else if (l1+w+l2 < width) {
+            min = mid;
+            mid = validateOffset(layout, (max+min)/2);
+        } else {
+            min = max;
         }
     }
-
-    /**
-     * Set the label's text.
-     * The value <code>null</code> clears it.
-     * 
-     * @param text the text to be displayed in the label or null
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setText (String text)
-    {
-        checkWidget();
-        if (text is null)
-            text = ""; //$NON-NLS-1$
-        if (!text.opEquals(this.text))
-        {
-            this.text = text;
-            redraw();
+    String result = mid is 0 ? t : t.substring(0, mid) ~ ELLIPSIS ~ t.substring(validateOffset(layout, l-mid), l);
+    layout.dispose();
+    return result;
+}
+int validateOffset(TextLayout layout, int offset) {
+    int nextOffset = layout.getNextOffset(offset, DWT.MOVEMENT_CLUSTER);
+    if (nextOffset !is offset) return layout.getPreviousOffset(nextOffset, DWT.MOVEMENT_CLUSTER);
+    return offset;
+}
+private String[] splitString(String text) {
+    String[] lines = new String[1];
+    int start = 0, pos;
+    do {
+        pos = tango.text.Util.locate( text, '\n', start);
+        if (pos is text.length ) {
+            lines[lines.length - 1] = text[start .. $ ];
+        } else {
+            bool crlf = (pos > 0) && (text[ pos - 1 ] is '\r');
+            lines[lines.length - 1] = text[ start .. pos - (crlf ? 1 : 0)];
+            start = pos + 1;
+            String[] newLines = new String[lines.length+1];
+            System.arraycopy(lines, 0, newLines, 0, lines.length);
+            lines = newLines;
         }
-    }
-
-    public void setToolTipText (String String)
-    {
-        super.setToolTipText(String);
-        appToolTipText = super.getToolTipText();
-    }
-
-    /**
-     * Shorten the given text <code>t</code> so that its length doesn't exceed
-     * the given width. The default implementation replaces characters in the
-     * center of the original String with an ellipsis ("...").
-     * Override if you need a different strategy.
-     * 
-     * @param gc the gc to use for text measurement
-     * @param t the text to shorten
-     * @param width the width to shorten the text to, in pixels
-     * @return the shortened text
-     */
-    protected String shortenText (GC gc, String t, int width)
-    {
-        if (t is null)
-            return null;
-        int w = gc.textExtent(ELLIPSIS, DRAW_FLAGS).x;
-        if (width <= w)
-            return t;
-        int l = t.length();
-        int max = l / 2;
-        int min = 0;
-        int mid = (max + min) / 2 - 1;
-        if (mid <= 0)
-            return t;
-        TextLayout layout = new TextLayout(getDisplay());
-        layout.setText(t);
-        mid = validateOffset(layout, mid);
-        while (min < mid && mid < max)
-        {
-            String s1 = t.substring(0, mid);
-            String s2 = t.substring(validateOffset(layout, l - mid), l);
-            int l1 = gc.textExtent(s1, DRAW_FLAGS).x;
-            int l2 = gc.textExtent(s2, DRAW_FLAGS).x;
-            if (l1 + w + l2 > width)
-            {
-                max = mid;
-                mid = validateOffset(layout, (max + min) / 2);
-            }
-            else if (l1 + w + l2 < width)
-            {
-                min = mid;
-                mid = validateOffset(layout, (max + min) / 2);
-            }
-            else
-            {
-                min = max;
-            }
-        }
-        String
-                result = mid is 0 ? t : t.substring(0, mid) + ELLIPSIS + t.substring(
-                        validateOffset(layout, l - mid), l);
-        layout.dispose();
-        return result;
-    }
-
-    int validateOffset (TextLayout layout, int offset)
-    {
-        int nextOffset = layout.getNextOffset(offset, DWT.MOVEMENT_CLUSTER);
-        if (nextOffset !is offset)
-            return layout.getPreviousOffset(nextOffset, DWT.MOVEMENT_CLUSTER);
-        return offset;
-    }
-
-    private String[] splitString (String text)
-    {
-        String[] lines = new String[1];
-        int start = 0, pos;
-        do
-        {
-            pos = text.indexOf('\n', start);
-            if (pos is -1)
-            {
-                lines[lines.length - 1] = text.substring(start);
-            }
-            else
-            {
-                bool crlf = (pos > 0) && (text.charAt(pos - 1) is '\r');
-                lines[lines.length - 1] = text.substring(start,
-                        pos - (crlf ? 1 : 0));
-                start = pos + 1;
-                String[] newLines = new String[lines.length + 1];
-                System.arraycopy(lines, 0, newLines, 0, lines.length);
-                lines = newLines;
-            }
-        } while (pos !is -1);
-        return lines;
-    }
+    } while (pos !is text.length);
+    return lines;
 }
+}
--- a/dwt/custom/CLayoutData.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/CLayoutData.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
  * Copyright (c) 2005 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -7,12 +7,12 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.CLayoutData;
 
+
 import dwt.DWT;
 import dwt.graphics.Point;
 import dwt.widgets.Control;
@@ -22,29 +22,27 @@
     int defaultWidth = -1, defaultHeight = -1;
     int currentWhint, currentHhint, currentWidth = -1, currentHeight = -1;
 
-    Point computeSize (Control control, int wHint, int hHint, bool flushCache) {
-        if (flushCache)
-            flushCache();
-        if (wHint is DWT.DEFAULT && hHint is DWT.DEFAULT) {
-            if (defaultWidth is -1 || defaultHeight is -1) {
-                Point size = control.computeSize(wHint, hHint, flushCache);
-                defaultWidth = size.x;
-                defaultHeight = size.y;
-            }
-            return new Point(defaultWidth, defaultHeight);
+Point computeSize (Control control, int wHint, int hHint, bool flushCache_) {
+    if (flushCache_) flushCache();
+    if (wHint is DWT.DEFAULT && hHint is DWT.DEFAULT) {
+        if (defaultWidth is -1 || defaultHeight is -1) {
+            Point size = control.computeSize (wHint, hHint, flushCache_);
+            defaultWidth = size.x;
+            defaultHeight = size.y;
         }
-        if (currentWidth is -1 || currentHeight is -1 || wHint !is currentWhint || hHint !is currentHhint) {
-            Point size = control.computeSize(wHint, hHint, flushCache);
-            currentWhint = wHint;
-            currentHhint = hHint;
-            currentWidth = size.x;
-            currentHeight = size.y;
-        }
-        return new Point(currentWidth, currentHeight);
+        return new Point(defaultWidth, defaultHeight);
     }
-
-    void flushCache () {
-        defaultWidth = defaultHeight = -1;
-        currentWidth = currentHeight = -1;
+    if (currentWidth is -1 || currentHeight is -1 || wHint !is currentWhint || hHint !is currentHhint) {
+        Point size = control.computeSize (wHint, hHint, flushCache_);
+        currentWhint = wHint;
+        currentHhint = hHint;
+        currentWidth = size.x;
+        currentHeight = size.y;
     }
+    return new Point(currentWidth, currentHeight);
 }
+void flushCache () {
+    defaultWidth = defaultHeight = -1;
+    currentWidth = currentHeight = -1;
+}
+}
--- a/dwt/custom/CTabFolder.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/CTabFolder.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,9 +7,8 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.CTabFolder;
 
@@ -21,9 +20,6 @@
 import dwt.accessibility.AccessibleControlAdapter;
 import dwt.accessibility.AccessibleControlEvent;
 import dwt.accessibility.AccessibleEvent;
-import dwt.custom.CTabFolderListener;
-import dwt.custom.CTabFolder2Listener;
-import dwt.custom.CTabItem;
 import dwt.events.SelectionAdapter;
 import dwt.events.SelectionEvent;
 import dwt.events.SelectionListener;
@@ -45,9 +41,18 @@
 import dwt.widgets.Menu;
 import dwt.widgets.MenuItem;
 import dwt.widgets.TypedListener;
+import dwt.custom.CTabItem;
+import dwt.custom.CTabFolder2Listener;
+import dwt.custom.CTabFolderListener;
+import dwt.custom.CTabFolderLayout;
+import dwt.custom.CTabFolderEvent;
+
+import dwt.dwthelper.utils;
+import tango.util.Convert;
+static import tango.text.convert.Utf;
 
 /**
- * 
+ *
  * Instances of this class implement the notebook user interface
  * metaphor.  It allows the user to select a notebook page from
  * set of pages.
@@ -68,15 +73,18 @@
  * <dd>"CTabFolder2"</dd>
  * </dl>
  * <p>
- * Note: Only one of the styles TOP and BOTTOM 
+ * Note: Only one of the styles TOP and BOTTOM
  * may be specified.
  * </p><p>
  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
  * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#ctabfolder">CTabFolder, CTabItem snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: CustomControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 
-public class CTabFolder : Composite
-{
+public class CTabFolder : Composite {
 
     /**
      * marginWidth specifies the number of pixels of horizontal margin
@@ -94,43 +102,43 @@
     public int marginHeight = 0;
 
     /**
-     * A multiple of the tab height that specifies the minimum width to which a tab 
+     * A multiple of the tab height that specifies the minimum width to which a tab
      * will be compressed before scrolling arrows are used to navigate the tabs.
-     * 
+     *
      * NOTE This field is badly named and can not be fixed for backwards compatibility.
      * It should not be capitalized.
-     * 
+     *
      * @deprecated This field is no longer used.  See setMinimumCharacters(int)
      */
     public int MIN_TAB_WIDTH = 4;
 
     /**
      * Color of innermost line of drop shadow border.
-     * 
+     *
      * NOTE This field is badly named and can not be fixed for backwards compatibility.
      * It should be capitalized.
-     * 
+     *
      * @deprecated drop shadow border is no longer drawn in 3.0
      */
-    public static RGB borderInsideRGB = new RGB(132, 130, 132);
+    public static RGB borderInsideRGB;
     /**
      * Color of middle line of drop shadow border.
-     * 
+     *
      * NOTE This field is badly named and can not be fixed for backwards compatibility.
      * It should be capitalized.
-     * 
+     *
      * @deprecated drop shadow border is no longer drawn in 3.0
      */
-    public static RGB borderMiddleRGB = new RGB(143, 141, 138);
+    public static RGB borderMiddleRGB;
     /**
      * Color of outermost line of drop shadow border.
-     * 
+     *
      * NOTE This field is badly named and can not be fixed for backwards compatibility.
      * It should be capitalized.
-     * 
+     *
      * @deprecated drop shadow border is no longer drawn in 3.0
      */
-    public static RGB borderOutsideRGB = new RGB(171, 168, 165);
+    public static RGB borderOutsideRGB;
 
     /* sizing, positioning */
     int xClient, yClient;
@@ -142,17 +150,17 @@
     int minChars = 20;
 
     /* item management */
-    CTabItem items[] = new CTabItem[0];
+    CTabItem items[];
     int firstIndex = -1; // index of the left most visible tab.
     int selectedIndex = -1;
-    int[] priority = new int[0];
+    int[] priority;
     bool mru = false;
     Listener listener;
 
     /* External Listener management */
-    CTabFolder2Listener[] folderListeners = new CTabFolder2Listener[0];
+    CTabFolder2Listener[] folderListeners;
     // support for deprecated listener mechanism
-    CTabFolderListener[] tabListeners = new CTabFolderListener[0];
+    CTabFolderListener[] tabListeners;
 
     /* Selected item appearance */
     Image selectionBgImage;
@@ -160,17 +168,17 @@
     int[] selectionGradientPercents;
     bool selectionGradientVertical;
     Color selectionForeground;
-    Color selectionBackground; //selection fade end
+    Color selectionBackground;  //selection fade end
     Color selectionFadeStart;
 
-    Color selectionHighlightGradientBegin = null; //null is no highlight
+    Color selectionHighlightGradientBegin = null;  //null is no highlight
     //Although we are given new colours all the time to show different states (active, etc),
     //some of which may have a highlight and some not, we'd like to retain the highlight colours
     //as a cache so that we can reuse them if we're again told to show the highlight.
     //We are relying on the fact that only one tab state usually gets a highlight, so only
     //a single cache is required. If that happens to not be true, cache simply becomes less effective,
     //but we don't leak colours.
-    Color[] selectionHighlightGradientColorsCache = null; //null is a legal value, check on access
+    Color[] selectionHighlightGradientColorsCache = null;  //null is a legal value, check on access
 
     /* Unselected item appearance */
     Image bgImage;
@@ -185,23 +193,23 @@
     bool showClose = false;
     bool showUnselectedClose = true;
 
-    Rectangle chevronRect = new Rectangle(0, 0, 0, 0);
+    Rectangle chevronRect;
     int chevronImageState = NORMAL;
     bool showChevron = false;
     Menu showMenu;
 
     bool showMin = false;
-    Rectangle minRect = new Rectangle(0, 0, 0, 0);
+    Rectangle minRect;
     bool minimized = false;
     int minImageState = NORMAL;
 
     bool showMax = false;
-    Rectangle maxRect = new Rectangle(0, 0, 0, 0);
+    Rectangle maxRect;
     bool maximized = false;
     int maxImageState = NORMAL;
 
     Control topRight;
-    Rectangle topRightRect = new Rectangle(0, 0, 0, 0);
+    Rectangle topRightRect;
     int topRightAlignment = DWT.RIGHT;
 
     // borders and shapes
@@ -219,7 +227,7 @@
     int curveWidth = 0;
     int curveIndent = 0;
 
-    // when disposing CTabFolder, don't try to layout the items or 
+    // when disposing CTabFolder, don't try to layout the items or
     // change the selection as each child is destroyed.
     bool inDispose = false;
 
@@ -228,53 +236,36 @@
     Point oldSize;
     Font oldFont;
 
-    //   internal constants
+    // internal constants
     static const int DEFAULT_WIDTH = 64;
     static const int DEFAULT_HEIGHT = 64;
     static const int BUTTON_SIZE = 18;
 
-    static const int[]
-            TOP_LEFT_CORNER = new int[][0 , 6 , 1 , 5 , 1 , 4 , 4 , 1 , 5 , 1 , 6 , 0];
+    static const int[] TOP_LEFT_CORNER = [0,6, 1,5, 1,4, 4,1, 5,1, 6,0];
 
-    //  TOP_LEFT_CORNER_HILITE is laid out in reverse (ie. top to bottom)
-    //  so can fade in same direction as right swoop curve
-    static const int[]
-            TOP_LEFT_CORNER_HILITE = new int[][5 , 2 , 4 , 2 , 3 , 3 , 2 , 4 , 2 , 5 , 1 , 6];
+    //TOP_LEFT_CORNER_HILITE is laid out in reverse (ie. top to bottom)
+    //so can fade in same direction as right swoop curve
+    static const int[] TOP_LEFT_CORNER_HILITE = [5,2, 4,2, 3,3, 2,4, 2,5, 1,6];
 
-    static const int[]
-            TOP_RIGHT_CORNER = new int[][-6 , 0 , -5 , 1 , -4 , 1 , -1 , 4 , -1 , 5 , 0 , 6];
-    static const int[]
-            BOTTOM_LEFT_CORNER = new int[][0 , -6 , 1 , -5 , 1 , -4 , 4 , -1 , 5 , -1 , 6 , 0];
-    static const int[]
-            BOTTOM_RIGHT_CORNER = new int[][-6 , 0 , -5 , -1 , -4 , -1 , -1 , -4 , -1 , -5 , 0 , -6];
+    static const int[] TOP_RIGHT_CORNER = [-6,0, -5,1, -4,1, -1,4, -1,5, 0,6];
+    static const int[] BOTTOM_LEFT_CORNER = [0,-6, 1,-5, 1,-4, 4,-1, 5,-1, 6,0];
+    static const int[] BOTTOM_RIGHT_CORNER = [-6,0, -5,-1, -4,-1, -1,-4, -1,-5, 0,-6];
 
-    static const int[]
-            SIMPLE_TOP_LEFT_CORNER = new int[][0 , 2 , 1 , 1 , 2 , 0];
-    static const int[]
-            SIMPLE_TOP_RIGHT_CORNER = new int[][-2 , 0 , -1 , 1 , 0 , 2];
-    static const int[]
-            SIMPLE_BOTTOM_LEFT_CORNER = new int[][0 , -2 , 1 , -1 , 2 , 0];
-    static const int[]
-            SIMPLE_BOTTOM_RIGHT_CORNER = new int[][-2 , 0 , -1 , -1 , 0 , -2];
-    static const int[] SIMPLE_UNSELECTED_INNER_CORNER = new int[][0 , 0];
+    static const int[] SIMPLE_TOP_LEFT_CORNER = [0,2, 1,1, 2,0];
+    static const int[] SIMPLE_TOP_RIGHT_CORNER = [-2,0, -1,1, 0,2];
+    static const int[] SIMPLE_BOTTOM_LEFT_CORNER = [0,-2, 1,-1, 2,0];
+    static const int[] SIMPLE_BOTTOM_RIGHT_CORNER = [-2,0, -1,-1, 0,-2];
+    static const int[] SIMPLE_UNSELECTED_INNER_CORNER = [0,0];
 
-    static const int[]
-            TOP_LEFT_CORNER_BORDERLESS = new int[][0 , 6 , 1 , 5 , 1 , 4 , 4 , 1 , 5 , 1 , 6 , 0];
-    static const int[]
-            TOP_RIGHT_CORNER_BORDERLESS = new int[][-7 , 0 , -6 , 1 , -5 , 1 , -2 , 4 , -2 , 5 , -1 , 6];
-    static const int[]
-            BOTTOM_LEFT_CORNER_BORDERLESS = new int[][0 , -6 , 1 , -6 , 1 , -5 , 2 , -4 , 4 , -2 , 5 , -1 , 6 , -1 , 6 , 0];
-    static const int[]
-            BOTTOM_RIGHT_CORNER_BORDERLESS = new int[][-7 , 0 , -7 , -1 , -6 , -1 , -5 , -2 , -3 , -4 , -2 , -5 , -2 , -6 , -1 , -6];
+    static const int[] TOP_LEFT_CORNER_BORDERLESS = [0,6, 1,5, 1,4, 4,1, 5,1, 6,0];
+    static const int[] TOP_RIGHT_CORNER_BORDERLESS = [-7,0, -6,1, -5,1, -2,4, -2,5, -1,6];
+    static const int[] BOTTOM_LEFT_CORNER_BORDERLESS = [0,-6, 1,-6, 1,-5, 2,-4, 4,-2, 5,-1, 6,-1, 6,0];
+    static const int[] BOTTOM_RIGHT_CORNER_BORDERLESS = [-7,0, -7,-1, -6,-1, -5,-2, -3,-4, -2,-5, -2,-6, -1,-6];
 
-    static const int[]
-            SIMPLE_TOP_LEFT_CORNER_BORDERLESS = new int[][0 , 2 , 1 , 1 , 2 , 0];
-    static const int[]
-            SIMPLE_TOP_RIGHT_CORNER_BORDERLESS = new int[][-3 , 0 , -2 , 1 , -1 , 2];
-    static const int[]
-            SIMPLE_BOTTOM_LEFT_CORNER_BORDERLESS = new int[][0 , -3 , 1 , -2 , 2 , -1 , 3 , 0];
-    static const int[]
-            SIMPLE_BOTTOM_RIGHT_CORNER_BORDERLESS = new int[][-4 , 0 , -3 , -1 , -2 , -2 , -1 , -3];
+    static const int[] SIMPLE_TOP_LEFT_CORNER_BORDERLESS = [0,2, 1,1, 2,0];
+    static const int[] SIMPLE_TOP_RIGHT_CORNER_BORDERLESS= [-3,0, -2,1, -1,2];
+    static const int[] SIMPLE_BOTTOM_LEFT_CORNER_BORDERLESS = [0,-3, 1,-2, 2,-1, 3,0];
+    static const int[] SIMPLE_BOTTOM_RIGHT_CORNER_BORDERLESS = [-4,0, -3,-1, -2,-2, -1,-3];
 
     static const int SELECTION_FOREGROUND = DWT.COLOR_LIST_FOREGROUND;
     static const int SELECTION_BACKGROUND = DWT.COLOR_LIST_BACKGROUND;
@@ -288,2414 +279,2013 @@
     static const int NORMAL = 1;
     static const int HOT = 2;
     static const int SELECTED = 3;
-    static const RGB CLOSE_FILL = new RGB(252, 160, 160);
+    static const RGB CLOSE_FILL;
 
     static const int CHEVRON_CHILD_ID = 0;
     static const int MINIMIZE_CHILD_ID = 1;
     static const int MAXIMIZE_CHILD_ID = 2;
     static const int EXTRA_CHILD_ID_COUNT = 3;
 
-    /**
-     * Constructs a new instance of this class given its parent
-     * and a style value describing its behavior and appearance.
-     * <p>
-     * The style value is either one of the style constants defined in
-     * class <code>DWT</code> which is applicable to instances of this
-     * class, or must be built by <em>bitwise OR</em>'ing together 
-     * (that is, using the <code>int</code> "|" operator) two or more
-     * of those <code>DWT</code> style constants. The class description
-     * lists the style constants that are applicable to the class.
-     * Style bits are also inherited from superclasses.
-     * </p>
-     *
-     * @param parent a widget which will be the parent of the new instance (cannot be null)
-     * @param style the style of widget to construct
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
-     * </ul>
-     *
-     * @see DWT#TOP
-     * @see DWT#BOTTOM
-     * @see DWT#FLAT
-     * @see DWT#BORDER
-     * @see DWT#SINGLE
-     * @see DWT#MULTI
-     * @see #getStyle()
-     */
-    public this (Composite parent, int style)
-    {
-        super(parent, checkStyle(parent, style));
-        super.setLayout(new CTabFolderLayout());
-        int style2 = super.getStyle();
-        oldFont = getFont();
-        onBottom = (style2 & DWT.BOTTOM) !is 0;
-        showClose = (style2 & DWT.CLOSE) !is 0;
-        //  showMin = (style2 & DWT.MIN) !is 0; - conflicts with DWT.TOP
-        //  showMax = (style2 & DWT.MAX) !is 0; - conflicts with DWT.BOTTOM
-        single = (style2 & DWT.SINGLE) !is 0;
-        borderLeft = borderRight = (style & DWT.BORDER) !is 0 ? 1 : 0;
-        borderTop = onBottom ? borderLeft : 0;
-        borderBottom = onBottom ? 0 : borderLeft;
-        highlight_header = (style & DWT.FLAT) !is 0 ? 1 : 3;
-        highlight_margin = (style & DWT.FLAT) !is 0 ? 0 : 2;
-        //set up default colors
-        Display display = getDisplay();
-        selectionForeground = display.getSystemColor(SELECTION_FOREGROUND);
-        selectionBackground = display.getSystemColor(SELECTION_BACKGROUND);
-        borderColor = display.getSystemColor(BORDER1_COLOR);
-        updateTabHeight(false);
-
-        initAccessible();
-
-        // Add all listeners
-        listener = new class Listener
-        {
-            public void handleEvent (Event event)
-            {
-                switch (event.type)
-                {
-                    case DWT.Dispose:
-                        onDispose(event);
-                    break;
-                    case DWT.DragDetect:
-                        onDragDetect(event);
-                    break;
-                    case DWT.FocusIn:
-                        onFocus(event);
-                    break;
-                    case DWT.FocusOut:
-                        onFocus(event);
-                    break;
-                    case DWT.KeyDown:
-                        onKeyDown(event);
-                    break;
-                    case DWT.MouseDoubleClick:
-                        onMouseDoubleClick(event);
-                    break;
-                    case DWT.MouseDown:
-                        onMouse(event);
-                    break;
-                    case DWT.MouseEnter:
-                        onMouse(event);
-                    break;
-                    case DWT.MouseExit:
-                        onMouse(event);
-                    break;
-                    case DWT.MouseMove:
-                        onMouse(event);
-                    break;
-                    case DWT.MouseUp:
-                        onMouse(event);
-                    break;
-                    case DWT.Paint:
-                        onPaint(event);
-                    break;
-                    case DWT.Resize:
-                        onResize();
-                    break;
-                    case DWT.Traverse:
-                        onTraverse(event);
-                    break;
-                }
-            }
-        };
-
-        int[]
-                folderEvents = new int[][DWT.Dispose , DWT.DragDetect , DWT.FocusIn , DWT.FocusOut , DWT.KeyDown , DWT.MouseDoubleClick , DWT.MouseDown , DWT.MouseEnter , DWT.MouseExit , DWT.MouseMove , DWT.MouseUp , DWT.Paint , DWT.Resize , DWT.Traverse];
-        for (int i = 0; i < folderEvents.length; i++)
-        {
-            addListener(folderEvents[i], listener);
-        }
-    }
-
-    static int checkStyle (Composite parent, int style)
-    {
-        int
-                mask = DWT.CLOSE | DWT.TOP | DWT.BOTTOM | DWT.FLAT | DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT | DWT.SINGLE | DWT.MULTI;
-        style = style & mask;
-        // TOP and BOTTOM are mutually exclusive.
-        // TOP is the default
-        if ((style & DWT.TOP) !is 0)
-            style = style & ~DWT.BOTTOM;
-        // SINGLE and MULTI are mutually exclusive.
-        // MULTI is the default
-        if ((style & DWT.MULTI) !is 0)
-            style = style & ~DWT.SINGLE;
-        // reduce the flash by not redrawing the entire area on a Resize event
-        style |= DWT.NO_REDRAW_RESIZE;
-        //TEMPORARY CODE
-        /*
-         * The default background on carbon and some GTK themes is not a solid color 
-         * but a texture.  To show the correct default background, we must allow
-         * the operating system to draw it and therefore, we can not use the 
-         * NO_BACKGROUND style.  The NO_BACKGROUND style is not required on platforms
-         * that use double buffering which is true in both of these cases.
-         */
-        String platform = DWT.getPlatform();
-        if ("carbon".opEquals(platform) || "gtk".opEquals(platform))
-            return style; //$NON-NLS-1$ //$NON-NLS-2$
-
-        //TEMPORARY CODE
-        /*
-         * In Right To Left orientation on Windows, all GC calls that use a brush are drawing 
-         * offset by one pixel.  This results in some parts of the CTabFolder not drawing correctly.
-         * To alleviate some of the appearance problems, allow the OS to draw the background.
-         * This does not draw correctly but the result is less obviously wrong.
-         */
-        if ((style & DWT.RIGHT_TO_LEFT) !is 0)
-            return style;
-        if ((parent.getStyle() & DWT.MIRRORED) !is 0 && (style & DWT.LEFT_TO_RIGHT) is 0)
-            return style;
-
-        return style | DWT.NO_BACKGROUND;
-    }
-
-    static void fillRegion (GC gc, Region region)
-    {
-        // NOTE: region passed in to this function will be modified
-        Region clipping = new Region();
-        gc.getClipping(clipping);
-        region.intersect(clipping);
-        gc.setClipping(region);
-        gc.fillRectangle(region.getBounds());
-        gc.setClipping(clipping);
-        clipping.dispose();
-    }
-
-    /**
-     * 
-     * Adds the listener to the collection of listeners who will
-     * be notified when a tab item is closed, minimized, maximized,
-     * restored, or to show the list of items that are not 
-     * currently visible.
-     *
-     * @param listener the listener which should be notified
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     * </ul>
-     *
-     * @see CTabFolder2Listener
-     * @see #removeCTabFolder2Listener(CTabFolder2Listener)
-     * 
-     * @since 3.0
-     */
-    public void addCTabFolder2Listener (CTabFolder2Listener listener)
-    {
-        checkWidget();
-        if (listener is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        // add to array
-        CTabFolder2Listener[]
-                newListeners = new CTabFolder2Listener[folderListeners.length + 1];
-        System.arraycopy(folderListeners, 0, newListeners, 0,
-                folderListeners.length);
-        folderListeners = newListeners;
-        folderListeners[folderListeners.length - 1] = listener;
-    }
+static this(){
+    borderInsideRGB  = new RGB (132, 130, 132);
+    borderMiddleRGB  = new RGB (143, 141, 138);
+    borderOutsideRGB = new RGB (171, 168, 165);
+    CLOSE_FILL = new RGB(252, 160, 160);
+}
 
-    /**
-     * Adds the listener to the collection of listeners who will
-     * be notified when a tab item is closed.
-     *
-     * @param listener the listener which should be notified
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     * </ul>
-     *
-     * @see CTabFolderListener
-     * @see #removeCTabFolderListener(CTabFolderListener)
-     * 
-     * @deprecated use addCTabFolder2Listener(CTabFolder2Listener)
-     */
-    public void addCTabFolderListener (CTabFolderListener listener)
-    {
-        checkWidget();
-        if (listener is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        // add to array
-        CTabFolderListener[]
-                newTabListeners = new CTabFolderListener[tabListeners.length + 1];
-        System.arraycopy(tabListeners, 0, newTabListeners, 0,
-                tabListeners.length);
-        tabListeners = newTabListeners;
-        tabListeners[tabListeners.length - 1] = listener;
-        // display close button to be backwards compatible
-        if (!showClose)
-        {
-            showClose = true;
-            updateItems();
-            redraw();
-        }
-    }
-
-    /**  
-     * Adds the listener to the collection of listeners who will
-     * be notified when the user changes the receiver's selection, by sending
-     * it one of the messages defined in the <code>SelectionListener</code>
-     * interface.
-     * <p>
-     * <code>widgetSelected</code> is called when the user changes the selected tab.
-     * <code>widgetDefaultSelected</code> is not called.
-     * </p>
-     *
-     * @param listener the listener which should be notified when the user changes the receiver's selection
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see SelectionListener
-     * @see #removeSelectionListener
-     * @see SelectionEvent
-     */
-    public void addSelectionListener (SelectionListener listener)
-    {
-        checkWidget();
-        if (listener is null)
-        {
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        }
-        TypedListener typedListener = new TypedListener(listener);
-        addListener(DWT.Selection, typedListener);
-        addListener(DWT.DefaultSelection, typedListener);
-    }
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>DWT</code> which is applicable to instances of this
+ * class, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DWT</code> style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a widget which will be the parent of the new instance (cannot be null)
+ * @param style the style of widget to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * </ul>
+ *
+ * @see DWT#TOP
+ * @see DWT#BOTTOM
+ * @see DWT#FLAT
+ * @see DWT#BORDER
+ * @see DWT#SINGLE
+ * @see DWT#MULTI
+ * @see #getStyle()
+ */
+public this(Composite parent, int style) {
+    chevronRect = new Rectangle(0, 0, 0, 0);
+    minRect = new Rectangle(0, 0, 0, 0);
+    maxRect = new Rectangle(0, 0, 0, 0);
+    topRightRect = new Rectangle(0, 0, 0, 0);
+    super(parent, checkStyle (parent, style));
+    super.setLayout(new CTabFolderLayout());
+    int style2 = super.getStyle();
+    oldFont = getFont();
+    onBottom = (style2 & DWT.BOTTOM) !is 0;
+    showClose = (style2 & DWT.CLOSE) !is 0;
+//  showMin = (style2 & DWT.MIN) !is 0; - conflicts with DWT.TOP
+//  showMax = (style2 & DWT.MAX) !is 0; - conflicts with DWT.BOTTOM
+    single = (style2 & DWT.SINGLE) !is 0;
+    borderLeft = borderRight = (style & DWT.BORDER) !is 0 ? 1 : 0;
+    borderTop = onBottom ? borderLeft : 0;
+    borderBottom = onBottom ? 0 : borderLeft;
+    highlight_header = (style & DWT.FLAT) !is 0 ? 1 : 3;
+    highlight_margin = (style & DWT.FLAT) !is 0 ? 0 : 2;
+    //set up default colors
+    Display display = getDisplay();
+    selectionForeground = display.getSystemColor(SELECTION_FOREGROUND);
+    selectionBackground = display.getSystemColor(SELECTION_BACKGROUND);
+    borderColor = display.getSystemColor(BORDER1_COLOR);
+    updateTabHeight(false);
 
-    void antialias (int[] shape, RGB lineRGB, RGB innerRGB, RGB outerRGB, GC gc)
-    {
-        // Don't perform anti-aliasing on Mac and WPF because the platform
-        // already does it.  The simple style also does not require anti-aliasing.
-        if (simple || "carbon".opEquals(DWT.getPlatform()) || "wpf".opEquals(
-                DWT.getPlatform()))
-            return; //$NON-NLS-1$
-        // Don't perform anti-aliasing on low resolution displays
-        if (getDisplay().getDepth() < 15)
-            return;
-        if (outerRGB !is null)
-        {
-            int index = 0;
-            bool left = true;
-            int oldY = onBottom ? 0 : getSize().y;
-            int[] outer = new int[shape.length];
-            for (int i = 0; i < shape.length / 2; i++)
-            {
-                if (left && (index + 3 < shape.length))
-                {
-                    left = onBottom ? oldY <= shape[index + 3] : oldY >= shape[index + 3];
-                    oldY = shape[index + 1];
-                }
-                outer[index] = shape[index++] + (left ? -1 : +1);
-                outer[index] = shape[index++];
-            }
-            RGB from = lineRGB;
-            RGB to = outerRGB;
-            int red = from.red + 2 * (to.red - from.red) / 3;
-            int green = from.green + 2 * (to.green - from.green) / 3;
-            int blue = from.blue + 2 * (to.blue - from.blue) / 3;
-            Color color = new Color(getDisplay(), red, green, blue);
-            gc.setForeground(color);
-            gc.drawPolyline(outer);
-            color.dispose();
-        }
-        if (innerRGB !is null)
-        {
-            int[] inner = new int[shape.length];
-            int index = 0;
-            bool left = true;
-            int oldY = onBottom ? 0 : getSize().y;
-            for (int i = 0; i < shape.length / 2; i++)
-            {
-                if (left && (index + 3 < shape.length))
-                {
-                    left = onBottom ? oldY <= shape[index + 3] : oldY >= shape[index + 3];
-                    oldY = shape[index + 1];
-                }
-                inner[index] = shape[index++] + (left ? +1 : -1);
-                inner[index] = shape[index++];
-            }
-            RGB from = lineRGB;
-            RGB to = innerRGB;
-            int red = from.red + 2 * (to.red - from.red) / 3;
-            int green = from.green + 2 * (to.green - from.green) / 3;
-            int blue = from.blue + 2 * (to.blue - from.blue) / 3;
-            Color color = new Color(getDisplay(), red, green, blue);
-            gc.setForeground(color);
-            gc.drawPolyline(inner);
-            color.dispose();
-        }
-    }
-
-    public Rectangle computeTrim (int x, int y, int width, int height)
-    {
-        checkWidget();
-        int trimX = x - marginWidth - highlight_margin - borderLeft;
-        int
-                trimWidth = width + borderLeft + borderRight + 2 * marginWidth + 2 * highlight_margin;
-        if (minimized)
-        {
-            int
-                    trimY = onBottom ? y - borderTop : y - highlight_header - tabHeight - borderTop;
-            int
-                    trimHeight = borderTop + borderBottom + tabHeight + highlight_header;
-            return new Rectangle(trimX, trimY, trimWidth, trimHeight);
-        }
-        else
-        {
-            int
-                    trimY = onBottom ? y - marginHeight - highlight_margin - borderTop : y - marginHeight - highlight_header - tabHeight - borderTop;
-            int
-                    trimHeight = height + borderTop + borderBottom + 2 * marginHeight + tabHeight + highlight_header + highlight_margin;
-            return new Rectangle(trimX, trimY, trimWidth, trimHeight);
-        }
-    }
+    initAccessible();
 
-    void createItem (CTabItem item, int index)
-    {
-        if (0 > index || index > getItemCount())
-            DWT.error(DWT.ERROR_INVALID_RANGE);
-        item.parent = this;
-        CTabItem[] newItems = new CTabItem[items.length + 1];
-        System.arraycopy(items, 0, newItems, 0, index);
-        newItems[index] = item;
-        System.arraycopy(items, index, newItems, index + 1,
-                items.length - index);
-        items = newItems;
-        if (selectedIndex >= index)
-            selectedIndex++;
-        int[] newPriority = new int[priority.length + 1];
-        int next = 0, priorityIndex = priority.length;
-        for (int i = 0; i < priority.length; i++)
-        {
-            if (!mru && priority[i] is index)
-            {
-                priorityIndex = next++;
-            }
-            newPriority[next++] = priority[i] >= index ? priority[i] + 1 : priority[i];
-        }
-        newPriority[priorityIndex] = index;
-        priority = newPriority;
-
-        if (items.length is 1)
-        {
-            if (!updateTabHeight(false))
-                updateItems();
-            redraw();
-        }
-        else
-        {
-            updateItems();
-            redrawTabs();
-        }
-    }
-
-    void destroyItem (CTabItem item)
-    {
-        if (inDispose)
-            return;
-        int index = indexOf(item);
-        if (index is -1)
-            return;
-
-        if (items.length is 1)
-        {
-            items = new CTabItem[0];
-            priority = new int[0];
-            firstIndex = -1;
-            selectedIndex = -1;
-
-            Control control = item.getControl();
-            if (control !is null && !control.isDisposed())
-            {
-                control.setVisible(false);
-            }
-            setToolTipText(null);
-            setButtonBounds();
-            redraw();
-            return;
-        }
-
-        CTabItem[] newItems = new CTabItem[items.length - 1];
-        System.arraycopy(items, 0, newItems, 0, index);
-        System.arraycopy(items, index + 1, newItems, index,
-                items.length - index - 1);
-        items = newItems;
-
-        int[] newPriority = new int[priority.length - 1];
-        int next = 0;
-        for (int i = 0; i < priority.length; i++)
-        {
-            if (priority[i] is index)
-                continue;
-            newPriority[next++] = priority[i] > index ? priority[i] - 1 : priority[i];
-        }
-        priority = newPriority;
-
-        // move the selection if this item is selected
-        if (selectedIndex is index)
-        {
-            Control control = item.getControl();
-            selectedIndex = -1;
-            int nextSelection = mru ? priority[0] : Math.max(0, index - 1);
-            setSelection(nextSelection, true);
-            if (control !is null && !control.isDisposed())
-            {
-                control.setVisible(false);
+    // Add all listeners
+    listener = new class() Listener {
+        public void handleEvent(Event event) {
+            switch (event.type) {
+                case DWT.Dispose:          onDispose(event); break;
+                case DWT.DragDetect:       onDragDetect(event); break;
+                case DWT.FocusIn:          onFocus(event);  break;
+                case DWT.FocusOut:         onFocus(event);  break;
+                case DWT.KeyDown:          onKeyDown(event); break;
+                case DWT.MouseDoubleClick: onMouseDoubleClick(event); break;
+                case DWT.MouseDown:        onMouse(event);  break;
+                case DWT.MouseEnter:       onMouse(event);  break;
+                case DWT.MouseExit:        onMouse(event);  break;
+                case DWT.MouseMove:        onMouse(event); break;
+                case DWT.MouseUp:          onMouse(event); break;
+                case DWT.Paint:            onPaint(event);  break;
+                case DWT.Resize:           onResize();  break;
+                case DWT.Traverse:         onTraverse(event); break;
+                default:
             }
         }
-        else if (selectedIndex > index)
-        {
-            selectedIndex--;
+    };
+
+    int[] folderEvents = [
+        DWT.Dispose,
+        DWT.DragDetect,
+        DWT.FocusIn,
+        DWT.FocusOut,
+        DWT.KeyDown,
+        DWT.MouseDoubleClick,
+        DWT.MouseDown,
+        DWT.MouseEnter,
+        DWT.MouseExit,
+        DWT.MouseMove,
+        DWT.MouseUp,
+        DWT.Paint,
+        DWT.Resize,
+        DWT.Traverse,
+    ];
+    for (int i = 0; i < folderEvents.length; i++) {
+        addListener(folderEvents[i], listener);
+    }
+}
+static int checkStyle (Composite parent, int style) {
+    int mask = DWT.CLOSE | DWT.TOP | DWT.BOTTOM | DWT.FLAT | DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT | DWT.SINGLE | DWT.MULTI;
+    style = style & mask;
+    // TOP and BOTTOM are mutually exclusive.
+    // TOP is the default
+    if ((style & DWT.TOP) !is 0) style = style & ~DWT.BOTTOM;
+    // SINGLE and MULTI are mutually exclusive.
+    // MULTI is the default
+    if ((style & DWT.MULTI) !is 0) style = style & ~DWT.SINGLE;
+    // reduce the flash by not redrawing the entire area on a Resize event
+    style |= DWT.NO_REDRAW_RESIZE;
+    //TEMPORARY CODE
+    /*
+     * The default background on carbon and some GTK themes is not a solid color
+     * but a texture.  To show the correct default background, we must allow
+     * the operating system to draw it and therefore, we can not use the
+     * NO_BACKGROUND style.  The NO_BACKGROUND style is not required on platforms
+     * that use double buffering which is true in both of these cases.
+     */
+    String platform = DWT.getPlatform();
+    if ("carbon"==platform || "gtk"==platform) return style; //$NON-NLS-1$ //$NON-NLS-2$
+
+    //TEMPORARY CODE
+    /*
+     * In Right To Left orientation on Windows, all GC calls that use a brush are drawing
+     * offset by one pixel.  This results in some parts of the CTabFolder not drawing correctly.
+     * To alleviate some of the appearance problems, allow the OS to draw the background.
+     * This does not draw correctly but the result is less obviously wrong.
+     */
+    if ((style & DWT.RIGHT_TO_LEFT) !is 0) return style;
+    if ((parent.getStyle() & DWT.MIRRORED) !is 0 && (style & DWT.LEFT_TO_RIGHT) is 0) return style;
+
+    return style | DWT.NO_BACKGROUND;
+}
+static void fillRegion(GC gc, Region region) {
+    // NOTE: region passed in to this function will be modified
+    Region clipping = new Region();
+    gc.getClipping(clipping);
+    region.intersect(clipping);
+    gc.setClipping(region);
+    gc.fillRectangle(region.getBounds());
+    gc.setClipping(clipping);
+    clipping.dispose();
+}
+/**
+ *
+ * Adds the listener to the collection of listeners who will
+ * be notified when a tab item is closed, minimized, maximized,
+ * restored, or to show the list of items that are not
+ * currently visible.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @see CTabFolder2Listener
+ * @see #removeCTabFolder2Listener(CTabFolder2Listener)
+ *
+ * @since 3.0
+ */
+public void addCTabFolder2Listener(CTabFolder2Listener listener) {
+    checkWidget();
+    if (listener is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    // add to array
+    CTabFolder2Listener[] newListeners = new CTabFolder2Listener[folderListeners.length + 1];
+    SimpleType!(CTabFolder2Listener).arraycopy(folderListeners, 0, newListeners, 0, folderListeners.length);
+    folderListeners = newListeners;
+    folderListeners[folderListeners.length - 1] = listener;
+}
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when a tab item is closed.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @see CTabFolderListener
+ * @see #removeCTabFolderListener(CTabFolderListener)
+ *
+ * @deprecated use addCTabFolder2Listener(CTabFolder2Listener)
+ */
+public void addCTabFolderListener(CTabFolderListener listener) {
+    checkWidget();
+    if (listener is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    // add to array
+    CTabFolderListener[] newTabListeners = new CTabFolderListener[tabListeners.length + 1];
+    SimpleType!(CTabFolderListener).arraycopy(tabListeners, 0, newTabListeners, 0, tabListeners.length);
+    tabListeners = newTabListeners;
+    tabListeners[tabListeners.length - 1] = listener;
+    // display close button to be backwards compatible
+    if (!showClose) {
+        showClose = true;
+        updateItems();
+        redraw();
+    }
+}
+/**
+ * Adds the listener to the collection of listeners who will
+ * be notified when the user changes the receiver's selection, by sending
+ * it one of the messages defined in the <code>SelectionListener</code>
+ * interface.
+ * <p>
+ * <code>widgetSelected</code> is called when the user changes the selected tab.
+ * <code>widgetDefaultSelected</code> is not called.
+ * </p>
+ *
+ * @param listener the listener which should be notified when the user changes the receiver's selection
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see SelectionListener
+ * @see #removeSelectionListener
+ * @see SelectionEvent
+ */
+public void addSelectionListener(SelectionListener listener) {
+    checkWidget();
+    if (listener is null) {
+        DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    }
+    TypedListener typedListener = new TypedListener(listener);
+    addListener(DWT.Selection, typedListener);
+    addListener(DWT.DefaultSelection, typedListener);
+}
+void antialias (int[] shape, RGB lineRGB, RGB innerRGB, RGB outerRGB, GC gc){
+    // Don't perform anti-aliasing on Mac and WPF because the platform
+    // already does it.  The simple style also does not require anti-aliasing.
+    if (simple || "carbon".equals(DWT.getPlatform()) || "wpf".equals(DWT.getPlatform())) return; //$NON-NLS-1$
+    // Don't perform anti-aliasing on low resolution displays
+    if (getDisplay().getDepth() < 15) return;
+    if (outerRGB !is null) {
+        int index = 0;
+        bool left = true;
+        int oldY = onBottom ? 0 : getSize().y;
+        int[] outer = new int[shape.length];
+        for (int i = 0; i < shape.length/2; i++) {
+            if (left && (index + 3 < shape.length)) {
+                left = onBottom ? oldY <= shape[index+3] : oldY >= shape[index+3];
+                oldY = shape[index+1];
+            }
+            outer[index] = shape[index] + (left ? -1 : +1);
+            index++;
+            outer[index] = shape[index];
+            index++;
         }
+        RGB from = lineRGB;
+        RGB to = outerRGB;
+        int red = from.red + 2*(to.red - from.red)/3;
+        int green = from.green + 2*(to.green - from.green)/3;
+        int blue = from.blue + 2*(to.blue - from.blue)/3;
+        Color color = new Color(getDisplay(), red, green, blue);
+        gc.setForeground(color);
+        gc.drawPolyline(outer);
+        color.dispose();
+    }
+    if (innerRGB !is null) {
+        int[] inner = new int[shape.length];
+        int index = 0;
+        bool left = true;
+        int oldY = onBottom ? 0 : getSize().y;
+        for (int i = 0; i < shape.length/2; i++) {
+            if (left && (index + 3 < shape.length)) {
+                left = onBottom ? oldY <= shape[index+3] : oldY >= shape[index+3];
+                oldY = shape[index+1];
+            }
+            inner[index] = shape[index] + (left ? +1 : -1);
+            index++;
+            inner[index] = shape[index];
+            index++;
+        }
+        RGB from = lineRGB;
+        RGB to = innerRGB;
+        int red = from.red + 2*(to.red - from.red)/3;
+        int green = from.green + 2*(to.green - from.green)/3;
+        int blue = from.blue + 2*(to.blue - from.blue)/3;
+        Color color = new Color(getDisplay(), red, green, blue);
+        gc.setForeground(color);
+        gc.drawPolyline(inner);
+        color.dispose();
+    }
+}
+public override Rectangle computeTrim (int x, int y, int width, int height) {
+    checkWidget();
+    int trimX = x - marginWidth - highlight_margin - borderLeft;
+    int trimWidth = width + borderLeft + borderRight + 2*marginWidth + 2*highlight_margin;
+    if (minimized) {
+        int trimY = onBottom ? y - borderTop : y - highlight_header - tabHeight - borderTop;
+        int trimHeight = borderTop + borderBottom + tabHeight + highlight_header;
+        return new Rectangle (trimX, trimY, trimWidth, trimHeight);
+    } else {
+        int trimY = onBottom ? y - marginHeight - highlight_margin - borderTop: y - marginHeight - highlight_header - tabHeight - borderTop;
+        int trimHeight = height + borderTop + borderBottom + 2*marginHeight + tabHeight + highlight_header + highlight_margin;
+        return new Rectangle (trimX, trimY, trimWidth, trimHeight);
+    }
+}
+void createItem (CTabItem item, int index) {
+    if (0 > index || index > getItemCount ())DWT.error (DWT.ERROR_INVALID_RANGE);
+    item.parent = this;
+    CTabItem[] newItems = new CTabItem [items.length + 1];
+    System.arraycopy(items, 0, newItems, 0, index);
+    newItems[index] = item;
+    System.arraycopy(items, index, newItems, index + 1, items.length - index);
+    items = newItems;
+    if (selectedIndex >= index) selectedIndex ++;
+    int[] newPriority = new int[priority.length + 1];
+    int next = 0,  priorityIndex = priority.length;
+    for (int i = 0; i < priority.length; i++) {
+        if (!mru && priority[i] is index) {
+            priorityIndex = next++;
+        }
+        newPriority[next++] = priority[i] >= index ? priority[i] + 1 : priority[i];
+    }
+    newPriority[priorityIndex] = index;
+    priority = newPriority;
 
+    if (items.length is 1) {
+        if (!updateTabHeight(false)) updateItems();
+        redraw();
+    } else {
         updateItems();
         redrawTabs();
     }
+}
+void destroyItem (CTabItem item) {
+    if (inDispose) return;
+    int index = indexOf(item);
+    if (index is -1) return;
 
-    void drawBackground (GC gc, int[] shape, bool selected)
-    {
-        Color
-                defaultBackground = selected ? selectionBackground : getBackground();
-        Image image = selected ? selectionBgImage : bgImage;
-        Color[] colors = selected ? selectionGradientColors : gradientColors;
-        int[]
-                percents = selected ? selectionGradientPercents : gradientPercents;
-        bool vertical = selected ? selectionGradientVertical : gradientVertical;
-        Point size = getSize();
-        int width = size.x;
-        int height = tabHeight + highlight_header;
-        int x = 0;
-        if (borderLeft > 0)
-        {
-            x += 1;
-            width -= 2;
+    if (items.length is 1) {
+        items = new CTabItem[0];
+        priority = new int[0];
+        firstIndex = -1;
+        selectedIndex = -1;
+
+        Control control = item.getControl();
+        if (control !is null && !control.isDisposed()) {
+            control.setVisible(false);
         }
-        int y = onBottom ? size.y - borderBottom - height : borderTop;
-        drawBackground(gc, shape, x, y, width, height, defaultBackground,
-                image, colors, percents, vertical);
+        setToolTipText(null);
+        setButtonBounds();
+        redraw();
+        return;
+    }
+
+    CTabItem[] newItems = new CTabItem [items.length - 1];
+    System.arraycopy(items, 0, newItems, 0, index);
+    System.arraycopy(items, index + 1, newItems, index, items.length - index - 1);
+    items = newItems;
+
+    int[] newPriority = new int[priority.length - 1];
+    int next = 0;
+    for (int i = 0; i < priority.length; i++) {
+        if (priority [i] is index) continue;
+        newPriority[next++] = priority[i] > index ? priority[i] - 1 : priority [i];
+    }
+    priority = newPriority;
+
+    // move the selection if this item is selected
+    if (selectedIndex is index) {
+        Control control = item.getControl();
+        selectedIndex = -1;
+        int nextSelection = mru ? priority[0] : Math.max(0, index - 1);
+        setSelection(nextSelection, true);
+        if (control !is null && !control.isDisposed()) {
+            control.setVisible(false);
+        }
+    } else if (selectedIndex > index) {
+        selectedIndex --;
     }
 
-    void drawBackground (GC gc, int[] shape, int x, int y, int width,
-            int height, Color defaultBackground, Image image, Color[] colors,
-            int[] percents, bool vertical)
-    {
-        Region clipping = new Region();
-        gc.getClipping(clipping);
-        Region region = new Region();
-        region.add(shape);
-        region.intersect(clipping);
-        gc.setClipping(region);
+    updateItems();
+    redrawTabs();
+}
+void drawBackground(GC gc, int[] shape, bool selected) {
+    Color defaultBackground = selected ? selectionBackground : getBackground();
+    Image image = selected ? selectionBgImage : bgImage;
+    Color[] colors = selected ? selectionGradientColors : gradientColors;
+    int[] percents = selected ? selectionGradientPercents : gradientPercents;
+    bool vertical = selected ? selectionGradientVertical : gradientVertical;
+    Point size = getSize();
+    int width = size.x;
+    int height = tabHeight + highlight_header;
+    int x = 0;
+    if (borderLeft > 0) {
+        x += 1; width -= 2;
+    }
+    int y = onBottom ? size.y - borderBottom - height : borderTop;
+    drawBackground(gc, shape, x, y, width, height, defaultBackground, image, colors, percents, vertical);
+}
+void drawBackground(GC gc, int[] shape, int x, int y, int width, int height, Color defaultBackground, Image image, Color[] colors, int[] percents, bool vertical) {
+    Region clipping = new Region();
+    gc.getClipping(clipping);
+    Region region = new Region();
+    region.add(shape);
+    region.intersect(clipping);
+    gc.setClipping(region);
 
-        if (image !is null)
-        {
-            // draw the background image in shape
-            gc.setBackground(defaultBackground);
+    if (image !is null) {
+        // draw the background image in shape
+        gc.setBackground(defaultBackground);
+        gc.fillRectangle(x, y, width, height);
+        Rectangle imageRect = image.getBounds();
+        gc.drawImage(image, imageRect.x, imageRect.y, imageRect.width, imageRect.height, x, y, width, height);
+    } else if (colors !is null) {
+        // draw gradient
+        if (colors.length is 1) {
+            Color background = colors[0] !is null ? colors[0] : defaultBackground;
+            gc.setBackground(background);
             gc.fillRectangle(x, y, width, height);
-            Rectangle imageRect = image.getBounds();
-            gc.drawImage(image, imageRect.x, imageRect.y, imageRect.width,
-                    imageRect.height, x, y, width, height);
-        }
-        else if (colors !is null)
-        {
-            // draw gradient
-            if (colors.length is 1)
-            {
-                Color
-                        background = colors[0] !is null ? colors[0] : defaultBackground;
-                gc.setBackground(background);
-                gc.fillRectangle(x, y, width, height);
-            }
-            else
-            {
-                if (vertical)
-                {
-                    if (onBottom)
-                    {
-                        int pos = 0;
-                        if (percents[percents.length - 1] < 100)
-                        {
-                            pos = percents[percents.length - 1] * height / 100;
-                            gc.setBackground(defaultBackground);
-                            gc.fillRectangle(x, y, width, pos);
-                        }
-                        Color lastColor = colors[colors.length - 1];
-                        if (lastColor is null)
-                            lastColor = defaultBackground;
-                        for (int i = percents.length - 1; i >= 0; i--)
-                        {
-                            gc.setForeground(lastColor);
-                            lastColor = colors[i];
-                            if (lastColor is null)
-                                lastColor = defaultBackground;
-                            gc.setBackground(lastColor);
-                            int gradientHeight = percents[i] * height / 100;
-                            gc.fillGradientRectangle(x, y + pos, width,
-                                    gradientHeight, true);
-                            pos += gradientHeight;
-                        }
+        } else {
+            if (vertical) {
+                if (onBottom) {
+                    int pos = 0;
+                    if (percents[percents.length - 1] < 100) {
+                        pos = percents[percents.length - 1] * height / 100;
+                        gc.setBackground(defaultBackground);
+                        gc.fillRectangle(x, y, width, pos);
                     }
-                    else
-                    {
-                        Color lastColor = colors[0];
-                        if (lastColor is null)
-                            lastColor = defaultBackground;
-                        int pos = 0;
-                        for (int i = 0; i < percents.length; i++)
-                        {
-                            gc.setForeground(lastColor);
-                            lastColor = colors[i + 1];
-                            if (lastColor is null)
-                                lastColor = defaultBackground;
-                            gc.setBackground(lastColor);
-                            int gradientHeight = percents[i] * height / 100;
-                            gc.fillGradientRectangle(x, y + pos, width,
-                                    gradientHeight, true);
-                            pos += gradientHeight;
-                        }
-                        if (pos < height)
-                        {
-                            gc.setBackground(defaultBackground);
-                            gc.fillRectangle(x, pos, width, height - pos + 1);
-                        }
+                    Color lastColor = colors[colors.length-1];
+                    if (lastColor is null) lastColor = defaultBackground;
+                    for (int i = percents.length-1; i >= 0; i--) {
+                        gc.setForeground(lastColor);
+                        lastColor = colors[i];
+                        if (lastColor is null) lastColor = defaultBackground;
+                        gc.setBackground(lastColor);
+                        int gradientHeight = percents[i] * height / 100;
+                        gc.fillGradientRectangle(x, y+pos, width, gradientHeight, true);
+                        pos += gradientHeight;
+                    }
+                } else {
+                    Color lastColor = colors[0];
+                    if (lastColor is null) lastColor = defaultBackground;
+                    int pos = 0;
+                    for (int i = 0; i < percents.length; i++) {
+                        gc.setForeground(lastColor);
+                        lastColor = colors[i + 1];
+                        if (lastColor is null) lastColor = defaultBackground;
+                        gc.setBackground(lastColor);
+                        int gradientHeight = percents[i] * height / 100;
+                        gc.fillGradientRectangle(x, y+pos, width, gradientHeight, true);
+                        pos += gradientHeight;
+                    }
+                    if (pos < height) {
+                        gc.setBackground(defaultBackground);
+                        gc.fillRectangle(x, pos, width, height-pos+1);
                     }
                 }
-                else
-                {   //horizontal gradient
-                    y = 0;
-                    height = getSize().y;
-                    Color lastColor = colors[0];
-                    if (lastColor is null)
-                        lastColor = defaultBackground;
-                    int pos = 0;
-                    for (int i = 0; i < percents.length; ++i)
-                    {
-                        gc.setForeground(lastColor);
-                        lastColor = colors[i + 1];
-                        if (lastColor is null)
-                            lastColor = defaultBackground;
-                        gc.setBackground(lastColor);
-                        int gradientWidth = (percents[i] * width / 100) - pos;
-                        gc.fillGradientRectangle(x + pos, y, gradientWidth,
-                                height, false);
-                        pos += gradientWidth;
-                    }
-                    if (pos < width)
-                    {
-                        gc.setBackground(defaultBackground);
-                        gc.fillRectangle(x + pos, y, width - pos, height);
-                    }
+            } else { //horizontal gradient
+                y = 0;
+                height = getSize().y;
+                Color lastColor = colors[0];
+                if (lastColor is null) lastColor = defaultBackground;
+                int pos = 0;
+                for (int i = 0; i < percents.length; ++i) {
+                    gc.setForeground(lastColor);
+                    lastColor = colors[i + 1];
+                    if (lastColor is null) lastColor = defaultBackground;
+                    gc.setBackground(lastColor);
+                    int gradientWidth = (percents[i] * width / 100) - pos;
+                    gc.fillGradientRectangle(x+pos, y, gradientWidth, height, false);
+                    pos += gradientWidth;
+                }
+                if (pos < width) {
+                    gc.setBackground(defaultBackground);
+                    gc.fillRectangle(x+pos, y, width-pos, height);
                 }
             }
         }
-        else
-        {
-            // draw a solid background using default background in shape
-            if ((getStyle() & DWT.NO_BACKGROUND) !is 0 || !defaultBackground.opEquals(
-                    getBackground()))
-            {
-                gc.setBackground(defaultBackground);
-                gc.fillRectangle(x, y, width, height);
+    } else {
+        // draw a solid background using default background in shape
+        if ((getStyle() & DWT.NO_BACKGROUND) !is 0 || defaultBackground!=getBackground()) {
+            gc.setBackground(defaultBackground);
+            gc.fillRectangle(x, y, width, height);
+        }
+    }
+    gc.setClipping(clipping);
+    clipping.dispose();
+    region.dispose();
+}
+void drawBody(Event event) {
+    GC gc = event.gc;
+    Point size = getSize();
+
+    // fill in body
+    if (!minimized){
+        int width = size.x  - borderLeft - borderRight - 2*highlight_margin;
+        int height = size.y - borderTop - borderBottom - tabHeight - highlight_header - highlight_margin;
+        // Draw highlight margin
+        if (highlight_margin > 0) {
+            int[] shape = null;
+            if (onBottom) {
+                int x1 = borderLeft;
+                int y1 = borderTop;
+                int x2 = size.x - borderRight;
+                int y2 = size.y - borderBottom - tabHeight - highlight_header;
+                shape = [x1,y1, x2,y1, x2,y2, x2-highlight_margin,y2,
+                                   x2-highlight_margin, y1+highlight_margin, x1+highlight_margin,y1+highlight_margin,
+                                   x1+highlight_margin,y2, x1,y2];
+            } else {
+                int x1 = borderLeft;
+                int y1 = borderTop + tabHeight + highlight_header;
+                int x2 = size.x - borderRight;
+                int y2 = size.y - borderBottom;
+                shape = [x1,y1, x1+highlight_margin,y1, x1+highlight_margin,y2-highlight_margin,
+                                   x2-highlight_margin,y2-highlight_margin, x2-highlight_margin,y1,
+                                   x2,y1, x2,y2, x1,y2];
+            }
+            // If horizontal gradient, show gradient across the whole area
+            if (selectedIndex !is -1 && selectionGradientColors !is null && selectionGradientColors.length > 1 && !selectionGradientVertical) {
+                drawBackground(gc, shape, true);
+            } else if (selectedIndex is -1 && gradientColors !is null && gradientColors.length > 1 && !gradientVertical) {
+                drawBackground(gc, shape, false);
+            } else {
+                gc.setBackground(selectedIndex is -1 ? getBackground() : selectionBackground);
+                gc.fillPolygon(shape);
             }
         }
-        gc.setClipping(clipping);
-        clipping.dispose();
-        region.dispose();
-    }
-
-    void drawBody (Event event)
-    {
-        GC gc = event.gc;
-        Point size = getSize();
-
-        // fill in body
-        if (!minimized)
-        {
-            int
-                    width = size.x - borderLeft - borderRight - 2 * highlight_margin;
-            int
-                    height = size.y - borderTop - borderBottom - tabHeight - highlight_header - highlight_margin;
-            // Draw highlight margin
-            if (highlight_margin > 0)
-            {
-                int[] shape = null;
-                if (onBottom)
-                {
-                    int x1 = borderLeft;
-                    int y1 = borderTop;
-                    int x2 = size.x - borderRight;
-                    int
-                            y2 = size.y - borderBottom - tabHeight - highlight_header;
-                    shape = new int[][x1 , y1 , x2 , y1 , x2 , y2 , x2 - highlight_margin , y2 , x2 - highlight_margin , y1 + highlight_margin , x1 + highlight_margin , y1 + highlight_margin , x1 + highlight_margin , y2 , x1 , y2];
-                }
-                else
-                {
-                    int x1 = borderLeft;
-                    int y1 = borderTop + tabHeight + highlight_header;
-                    int x2 = size.x - borderRight;
-                    int y2 = size.y - borderBottom;
-                    shape = new int[][x1 , y1 , x1 + highlight_margin , y1 , x1 + highlight_margin , y2 - highlight_margin , x2 - highlight_margin , y2 - highlight_margin , x2 - highlight_margin , y1 , x2 , y1 , x2 , y2 , x1 , y2];
-                }
-                // If horizontal gradient, show gradient across the whole area
-                if (selectedIndex !is -1 && selectionGradientColors !is null && selectionGradientColors.length > 1 && !selectionGradientVertical)
-                {
-                    drawBackground(gc, shape, true);
-                }
-                else if (selectedIndex is -1 && gradientColors !is null && gradientColors.length > 1 && !gradientVertical)
-                {
-                    drawBackground(gc, shape, false);
-                }
-                else
-                {
-                    gc.setBackground(
-                            selectedIndex is -1 ? getBackground() : selectionBackground);
-                    gc.fillPolygon(shape);
-                }
-            }
-            //Draw client area
-            if ((getStyle() & DWT.NO_BACKGROUND) !is 0)
-            {
-                gc.setBackground(getBackground());
-                gc.fillRectangle(xClient - marginWidth, yClient - marginHeight,
-                        width, height);
-            }
+        //Draw client area
+        if ((getStyle() & DWT.NO_BACKGROUND) !is 0) {
+            gc.setBackground(getBackground());
+            gc.fillRectangle(xClient - marginWidth, yClient - marginHeight, width, height);
         }
-        else
-        {
-            if ((getStyle() & DWT.NO_BACKGROUND) !is 0)
-            {
-                int
-                        height = borderTop + tabHeight + highlight_header + borderBottom;
-                if (size.y > height)
-                {
-                    gc.setBackground(getParent().getBackground());
-                    gc.fillRectangle(0, height, size.x, size.y - height);
-                }
-            }
-        }
-
-        //draw 1 pixel border around outside
-        if (borderLeft > 0)
-        {
-            gc.setForeground(borderColor);
-            int x1 = borderLeft - 1;
-            int x2 = size.x - borderRight;
-            int y1 = onBottom ? borderTop - 1 : borderTop + tabHeight;
-            int
-                    y2 = onBottom ? size.y - tabHeight - borderBottom - 1 : size.y - borderBottom;
-            gc.drawLine(x1, y1, x1, y2); // left
-            gc.drawLine(x2, y1, x2, y2); // right
-            if (onBottom)
-            {
-                gc.drawLine(x1, y1, x2, y1); // top
-            }
-            else
-            {
-                gc.drawLine(x1, y2, x2, y2); // bottom
+    } else {
+        if ((getStyle() & DWT.NO_BACKGROUND) !is 0) {
+            int height = borderTop + tabHeight + highlight_header + borderBottom;
+            if (size.y > height) {
+                gc.setBackground(getParent().getBackground());
+                gc.fillRectangle(0, height, size.x, size.y - height);
             }
         }
     }
 
-    void drawChevron (GC gc)
-    {
-        if (chevronRect.width is 0 || chevronRect.height is 0)
-            return;
-        // draw chevron (10x7)
-        Display display = getDisplay();
-        Point dpi = display.getDPI();
-        int fontHeight = 72 * 10 / dpi.y;
-        FontData fd = getFont().getFontData()[0];
-        fd.setHeight(fontHeight);
-        Font f = new Font(display, fd);
-        int fHeight = f.getFontData()[0].getHeight() * dpi.y / 72;
-        int indent = Math.max(2, (chevronRect.height - fHeight - 4) / 2);
-        int x = chevronRect.x + 2;
-        int y = chevronRect.y + indent;
-        int count;
-        if (single)
-        {
-            count = selectedIndex is -1 ? items.length : items.length - 1;
+    //draw 1 pixel border around outside
+    if (borderLeft > 0) {
+        gc.setForeground(borderColor);
+        int x1 = borderLeft - 1;
+        int x2 = size.x - borderRight;
+        int y1 = onBottom ? borderTop - 1 : borderTop + tabHeight;
+        int y2 = onBottom ? size.y - tabHeight - borderBottom - 1 : size.y - borderBottom;
+        gc.drawLine(x1, y1, x1, y2); // left
+        gc.drawLine(x2, y1, x2, y2); // right
+        if (onBottom) {
+            gc.drawLine(x1, y1, x2, y1); // top
+        } else {
+            gc.drawLine(x1, y2, x2, y2); // bottom
+        }
+    }
+}
+
+void drawChevron(GC gc) {
+    if (chevronRect.width is 0 || chevronRect.height is 0) return;
+    // draw chevron (10x7)
+    Display display = getDisplay();
+    Point dpi = display.getDPI();
+    int fontHeight = 72 * 10 / dpi.y;
+    FontData fd = getFont().getFontData()[0];
+    fd.setHeight(fontHeight);
+    Font f = new Font(display, fd);
+    int fHeight = f.getFontData()[0].getHeight() * dpi.y / 72;
+    int indent = Math.max(2, (chevronRect.height - fHeight - 4) /2);
+    int x = chevronRect.x + 2;
+    int y = chevronRect.y + indent;
+    int count;
+    if (single) {
+        count = selectedIndex is -1 ? items.length : items.length - 1;
+    } else {
+        int showCount = 0;
+        while (showCount < priority.length && items[priority[showCount]].showing) {
+            showCount++;
+        }
+        count = items.length - showCount;
+    }
+    String chevronString = count > 99 ? "99+" : to!(String)(count); //$NON-NLS-1$
+    switch (chevronImageState) {
+        case NORMAL: {
+            Color chevronBorder = single ? getSelectionForeground() : getForeground();
+            gc.setForeground(chevronBorder);
+            gc.setFont(f);
+            gc.drawLine(x,y,     x+2,y+2);
+            gc.drawLine(x+2,y+2, x,y+4);
+            gc.drawLine(x+1,y,   x+3,y+2);
+            gc.drawLine(x+3,y+2, x+1,y+4);
+            gc.drawLine(x+4,y,   x+6,y+2);
+            gc.drawLine(x+6,y+2, x+5,y+4);
+            gc.drawLine(x+5,y,   x+7,y+2);
+            gc.drawLine(x+7,y+2, x+4,y+4);
+            gc.drawString(chevronString, x+7, y+3, true);
+            break;
         }
-        else
-        {
-            int showCount = 0;
-            while (showCount < priority.length && items[priority[showCount]].showing)
-            {
-                showCount++;
+        case HOT: {
+            gc.setForeground(display.getSystemColor(BUTTON_BORDER));
+            gc.setBackground(display.getSystemColor(BUTTON_FILL));
+            gc.setFont(f);
+            gc.fillRoundRectangle(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, 6, 6);
+            gc.drawRoundRectangle(chevronRect.x, chevronRect.y, chevronRect.width - 1, chevronRect.height - 1, 6, 6);
+            gc.drawLine(x,y,     x+2,y+2);
+            gc.drawLine(x+2,y+2, x,y+4);
+            gc.drawLine(x+1,y,   x+3,y+2);
+            gc.drawLine(x+3,y+2, x+1,y+4);
+            gc.drawLine(x+4,y,   x+6,y+2);
+            gc.drawLine(x+6,y+2, x+5,y+4);
+            gc.drawLine(x+5,y,   x+7,y+2);
+            gc.drawLine(x+7,y+2, x+4,y+4);
+            gc.drawString(chevronString, x+7, y+3, true);
+            break;
+        }
+        case SELECTED: {
+            gc.setForeground(display.getSystemColor(BUTTON_BORDER));
+            gc.setBackground(display.getSystemColor(BUTTON_FILL));
+            gc.setFont(f);
+            gc.fillRoundRectangle(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, 6, 6);
+            gc.drawRoundRectangle(chevronRect.x, chevronRect.y, chevronRect.width - 1, chevronRect.height - 1, 6, 6);
+            gc.drawLine(x+1,y+1, x+3,y+3);
+            gc.drawLine(x+3,y+3, x+1,y+5);
+            gc.drawLine(x+2,y+1, x+4,y+3);
+            gc.drawLine(x+4,y+3, x+2,y+5);
+            gc.drawLine(x+5,y+1, x+7,y+3);
+            gc.drawLine(x+7,y+3, x+6,y+5);
+            gc.drawLine(x+6,y+1, x+8,y+3);
+            gc.drawLine(x+8,y+3, x+5,y+5);
+            gc.drawString(chevronString, x+8, y+4, true);
+            break;
+        }
+        default:
+    }
+    f.dispose();
+}
+void drawMaximize(GC gc) {
+    if (maxRect.width is 0 || maxRect.height is 0) return;
+    Display display = getDisplay();
+    // 5x4 or 7x9
+    int x = maxRect.x + (CTabFolder.BUTTON_SIZE - 10)/2;
+    int y = maxRect.y + 3;
+
+    gc.setForeground(display.getSystemColor(BUTTON_BORDER));
+    gc.setBackground(display.getSystemColor(BUTTON_FILL));
+
+    switch (maxImageState) {
+        case NORMAL: {
+            if (!maximized) {
+                gc.fillRectangle(x, y, 9, 9);
+                gc.drawRectangle(x, y, 9, 9);
+                gc.drawLine(x+1, y+2, x+8, y+2);
+            } else {
+                gc.fillRectangle(x, y+3, 5, 4);
+                gc.fillRectangle(x+2, y, 5, 4);
+                gc.drawRectangle(x, y+3, 5, 4);
+                gc.drawRectangle(x+2, y, 5, 4);
+                gc.drawLine(x+3, y+1, x+6, y+1);
+                gc.drawLine(x+1, y+4, x+4, y+4);
             }
-            count = items.length - showCount;
+            break;
         }
-        String chevronString = count > 99 ? "99+" : String.valueOf(count); //$NON-NLS-1$
-        switch (chevronImageState)
-        {
-            case NORMAL:
-            {
-                Color
-                        chevronBorder = single ? getSelectionForeground() : getForeground();
-                gc.setForeground(chevronBorder);
-                gc.setFont(f);
-                gc.drawLine(x, y, x + 2, y + 2);
-                gc.drawLine(x + 2, y + 2, x, y + 4);
-                gc.drawLine(x + 1, y, x + 3, y + 2);
-                gc.drawLine(x + 3, y + 2, x + 1, y + 4);
-                gc.drawLine(x + 4, y, x + 6, y + 2);
-                gc.drawLine(x + 6, y + 2, x + 5, y + 4);
-                gc.drawLine(x + 5, y, x + 7, y + 2);
-                gc.drawLine(x + 7, y + 2, x + 4, y + 4);
-                gc.drawString(chevronString, x + 7, y + 3, true);
-                break;
+        case HOT: {
+            gc.fillRoundRectangle(maxRect.x, maxRect.y, maxRect.width, maxRect.height, 6, 6);
+            gc.drawRoundRectangle(maxRect.x, maxRect.y, maxRect.width - 1, maxRect.height - 1, 6, 6);
+            if (!maximized) {
+                gc.fillRectangle(x, y, 9, 9);
+                gc.drawRectangle(x, y, 9, 9);
+                gc.drawLine(x+1, y+2, x+8, y+2);
+            } else {
+                gc.fillRectangle(x, y+3, 5, 4);
+                gc.fillRectangle(x+2, y, 5, 4);
+                gc.drawRectangle(x, y+3, 5, 4);
+                gc.drawRectangle(x+2, y, 5, 4);
+                gc.drawLine(x+3, y+1, x+6, y+1);
+                gc.drawLine(x+1, y+4, x+4, y+4);
+            }
+            break;
+        }
+        case SELECTED: {
+            gc.fillRoundRectangle(maxRect.x, maxRect.y, maxRect.width, maxRect.height, 6, 6);
+            gc.drawRoundRectangle(maxRect.x, maxRect.y, maxRect.width - 1, maxRect.height - 1, 6, 6);
+            if (!maximized) {
+                gc.fillRectangle(x+1, y+1, 9, 9);
+                gc.drawRectangle(x+1, y+1, 9, 9);
+                gc.drawLine(x+2, y+3, x+9, y+3);
+            } else {
+                gc.fillRectangle(x+1, y+4, 5, 4);
+                gc.fillRectangle(x+3, y+1, 5, 4);
+                gc.drawRectangle(x+1, y+4, 5, 4);
+                gc.drawRectangle(x+3, y+1, 5, 4);
+                gc.drawLine(x+4, y+2, x+7, y+2);
+                gc.drawLine(x+2, y+5, x+5, y+5);
+            }
+            break;
+        }
+        default:
+    }
+}
+void drawMinimize(GC gc) {
+    if (minRect.width is 0 || minRect.height is 0) return;
+    Display display = getDisplay();
+    // 5x4 or 9x3
+    int x = minRect.x + (BUTTON_SIZE - 10)/2;
+    int y = minRect.y + 3;
+
+    gc.setForeground(display.getSystemColor(BUTTON_BORDER));
+    gc.setBackground(display.getSystemColor(BUTTON_FILL));
+
+    switch (minImageState) {
+        case NORMAL: {
+            if (!minimized) {
+                gc.fillRectangle(x, y, 9, 3);
+                gc.drawRectangle(x, y, 9, 3);
+            } else {
+                gc.fillRectangle(x, y+3, 5, 4);
+                gc.fillRectangle(x+2, y, 5, 4);
+                gc.drawRectangle(x, y+3, 5, 4);
+                gc.drawRectangle(x+2, y, 5, 4);
+                gc.drawLine(x+3, y+1, x+6, y+1);
+                gc.drawLine(x+1, y+4, x+4, y+4);
             }
-            case HOT:
-            {
-                gc.setForeground(display.getSystemColor(BUTTON_BORDER));
-                gc.setBackground(display.getSystemColor(BUTTON_FILL));
-                gc.setFont(f);
-                gc.fillRoundRectangle(chevronRect.x, chevronRect.y,
-                        chevronRect.width, chevronRect.height, 6, 6);
-                gc.drawRoundRectangle(chevronRect.x, chevronRect.y,
-                        chevronRect.width - 1, chevronRect.height - 1, 6, 6);
-                gc.drawLine(x, y, x + 2, y + 2);
-                gc.drawLine(x + 2, y + 2, x, y + 4);
-                gc.drawLine(x + 1, y, x + 3, y + 2);
-                gc.drawLine(x + 3, y + 2, x + 1, y + 4);
-                gc.drawLine(x + 4, y, x + 6, y + 2);
-                gc.drawLine(x + 6, y + 2, x + 5, y + 4);
-                gc.drawLine(x + 5, y, x + 7, y + 2);
-                gc.drawLine(x + 7, y + 2, x + 4, y + 4);
-                gc.drawString(chevronString, x + 7, y + 3, true);
-                break;
+            break;
+        }
+        case HOT: {
+            gc.fillRoundRectangle(minRect.x, minRect.y, minRect.width, minRect.height, 6, 6);
+            gc.drawRoundRectangle(minRect.x, minRect.y, minRect.width - 1, minRect.height - 1, 6, 6);
+            if (!minimized) {
+                gc.fillRectangle(x, y, 9, 3);
+                gc.drawRectangle(x, y, 9, 3);
+            } else {
+                gc.fillRectangle(x, y+3, 5, 4);
+                gc.fillRectangle(x+2, y, 5, 4);
+                gc.drawRectangle(x, y+3, 5, 4);
+                gc.drawRectangle(x+2, y, 5, 4);
+                gc.drawLine(x+3, y+1, x+6, y+1);
+                gc.drawLine(x+1, y+4, x+4, y+4);
+            }
+            break;
+        }
+        case SELECTED: {
+            gc.fillRoundRectangle(minRect.x, minRect.y, minRect.width, minRect.height, 6, 6);
+            gc.drawRoundRectangle(minRect.x, minRect.y, minRect.width - 1, minRect.height - 1, 6, 6);
+            if (!minimized) {
+                gc.fillRectangle(x+1, y+1, 9, 3);
+                gc.drawRectangle(x+1, y+1, 9, 3);
+            } else {
+                gc.fillRectangle(x+1, y+4, 5, 4);
+                gc.fillRectangle(x+3, y+1, 5, 4);
+                gc.drawRectangle(x+1, y+4, 5, 4);
+                gc.drawRectangle(x+3, y+1, 5, 4);
+                gc.drawLine(x+4, y+2, x+7, y+2);
+                gc.drawLine(x+2, y+5, x+5, y+5);
             }
-            case SELECTED:
-            {
-                gc.setForeground(display.getSystemColor(BUTTON_BORDER));
-                gc.setBackground(display.getSystemColor(BUTTON_FILL));
-                gc.setFont(f);
-                gc.fillRoundRectangle(chevronRect.x, chevronRect.y,
-                        chevronRect.width, chevronRect.height, 6, 6);
-                gc.drawRoundRectangle(chevronRect.x, chevronRect.y,
-                        chevronRect.width - 1, chevronRect.height - 1, 6, 6);
-                gc.drawLine(x + 1, y + 1, x + 3, y + 3);
-                gc.drawLine(x + 3, y + 3, x + 1, y + 5);
-                gc.drawLine(x + 2, y + 1, x + 4, y + 3);
-                gc.drawLine(x + 4, y + 3, x + 2, y + 5);
-                gc.drawLine(x + 5, y + 1, x + 7, y + 3);
-                gc.drawLine(x + 7, y + 3, x + 6, y + 5);
-                gc.drawLine(x + 6, y + 1, x + 8, y + 3);
-                gc.drawLine(x + 8, y + 3, x + 5, y + 5);
-                gc.drawString(chevronString, x + 8, y + 4, true);
-                break;
-            }
+            break;
         }
-        f.dispose();
+        default:
+    }
+}
+void drawTabArea(Event event) {
+    GC gc = event.gc;
+    Point size = getSize();
+    int[] shape = null;
+
+    if (tabHeight is 0) {
+        int style = getStyle();
+        if ((style & DWT.FLAT) !is 0 && (style & DWT.BORDER) is 0) return;
+        int x1 = borderLeft - 1;
+        int x2 = size.x - borderRight;
+        int y1 = onBottom ? size.y - borderBottom - highlight_header - 1 : borderTop + highlight_header;
+        int y2 = onBottom ? size.y - borderBottom : borderTop;
+        if (borderLeft > 0 && onBottom) y2 -= 1;
+
+        shape = [x1, y1, x1,y2, x2,y2, x2,y1];
+
+        // If horizontal gradient, show gradient across the whole area
+        if (selectedIndex !is -1 && selectionGradientColors !is null && selectionGradientColors.length > 1 && !selectionGradientVertical) {
+            drawBackground(gc, shape, true);
+        } else if (selectedIndex is -1 && gradientColors !is null && gradientColors.length > 1 && !gradientVertical) {
+            drawBackground(gc, shape, false);
+        } else {
+            gc.setBackground(selectedIndex is -1 ? getBackground() : selectionBackground);
+            gc.fillPolygon(shape);
+        }
+
+        //draw 1 pixel border
+        if (borderLeft > 0) {
+            gc.setForeground(borderColor);
+            gc.drawPolyline(shape);
+        }
+        return;
     }
 
-    void drawMaximize (GC gc)
-    {
-        if (maxRect.width is 0 || maxRect.height is 0)
-            return;
-        Display display = getDisplay();
-        // 5x4 or 7x9
-        int x = maxRect.x + (CTabFolder.BUTTON_SIZE - 10) / 2;
-        int y = maxRect.y + 3;
-
-        gc.setForeground(display.getSystemColor(BUTTON_BORDER));
-        gc.setBackground(display.getSystemColor(BUTTON_FILL));
+    int x = Math.max(0, borderLeft - 1);
+    int y = onBottom ? size.y - borderBottom - tabHeight : borderTop;
+    int width = size.x - borderLeft - borderRight + 1;
+    int height = tabHeight - 1;
 
-        switch (maxImageState)
-        {
-            case NORMAL:
-            {
-                if (!maximized)
-                {
-                    gc.fillRectangle(x, y, 9, 9);
-                    gc.drawRectangle(x, y, 9, 9);
-                    gc.drawLine(x + 1, y + 2, x + 8, y + 2);
-                }
-                else
-                {
-                    gc.fillRectangle(x, y + 3, 5, 4);
-                    gc.fillRectangle(x + 2, y, 5, 4);
-                    gc.drawRectangle(x, y + 3, 5, 4);
-                    gc.drawRectangle(x + 2, y, 5, 4);
-                    gc.drawLine(x + 3, y + 1, x + 6, y + 1);
-                    gc.drawLine(x + 1, y + 4, x + 4, y + 4);
-                }
-                break;
-            }
-            case HOT:
-            {
-                gc.fillRoundRectangle(maxRect.x, maxRect.y, maxRect.width,
-                        maxRect.height, 6, 6);
-                gc.drawRoundRectangle(maxRect.x, maxRect.y, maxRect.width - 1,
-                        maxRect.height - 1, 6, 6);
-                if (!maximized)
-                {
-                    gc.fillRectangle(x, y, 9, 9);
-                    gc.drawRectangle(x, y, 9, 9);
-                    gc.drawLine(x + 1, y + 2, x + 8, y + 2);
-                }
-                else
-                {
-                    gc.fillRectangle(x, y + 3, 5, 4);
-                    gc.fillRectangle(x + 2, y, 5, 4);
-                    gc.drawRectangle(x, y + 3, 5, 4);
-                    gc.drawRectangle(x + 2, y, 5, 4);
-                    gc.drawLine(x + 3, y + 1, x + 6, y + 1);
-                    gc.drawLine(x + 1, y + 4, x + 4, y + 4);
-                }
-                break;
-            }
-            case SELECTED:
-            {
-                gc.fillRoundRectangle(maxRect.x, maxRect.y, maxRect.width,
-                        maxRect.height, 6, 6);
-                gc.drawRoundRectangle(maxRect.x, maxRect.y, maxRect.width - 1,
-                        maxRect.height - 1, 6, 6);
-                if (!maximized)
-                {
-                    gc.fillRectangle(x + 1, y + 1, 9, 9);
-                    gc.drawRectangle(x + 1, y + 1, 9, 9);
-                    gc.drawLine(x + 2, y + 3, x + 9, y + 3);
-                }
-                else
-                {
-                    gc.fillRectangle(x + 1, y + 4, 5, 4);
-                    gc.fillRectangle(x + 3, y + 1, 5, 4);
-                    gc.drawRectangle(x + 1, y + 4, 5, 4);
-                    gc.drawRectangle(x + 3, y + 1, 5, 4);
-                    gc.drawLine(x + 4, y + 2, x + 7, y + 2);
-                    gc.drawLine(x + 2, y + 5, x + 5, y + 5);
-                }
-                break;
-            }
+    // Draw Tab Header
+    if (onBottom) {
+        int[] left, right;
+        if ((getStyle() & DWT.BORDER) !is 0) {
+            left = simple ? SIMPLE_BOTTOM_LEFT_CORNER : BOTTOM_LEFT_CORNER;
+            right = simple ? SIMPLE_BOTTOM_RIGHT_CORNER : BOTTOM_RIGHT_CORNER;
+        } else {
+            left = simple ? SIMPLE_BOTTOM_LEFT_CORNER_BORDERLESS : BOTTOM_LEFT_CORNER_BORDERLESS;
+            right = simple ? SIMPLE_BOTTOM_RIGHT_CORNER_BORDERLESS : BOTTOM_RIGHT_CORNER_BORDERLESS;
+        }
+        shape = new int[left.length + right.length + 4];
+        int index = 0;
+        shape[index++] = x;
+        shape[index++] = y-highlight_header;
+        for (int i = 0; i < left.length/2; i++) {
+            shape[index++] = x+left[2*i];
+            shape[index++] = y+height+left[2*i+1];
+            if (borderLeft is 0) shape[index-1] += 1;
+        }
+        for (int i = 0; i < right.length/2; i++) {
+            shape[index++] = x+width+right[2*i];
+            shape[index++] = y+height+right[2*i+1];
+            if (borderLeft is 0) shape[index-1] += 1;
         }
+        shape[index++] = x+width;
+        shape[index++] = y-highlight_header;
+    } else {
+        int[] left, right;
+        if ((getStyle() & DWT.BORDER) !is 0) {
+            left = simple ? SIMPLE_TOP_LEFT_CORNER : TOP_LEFT_CORNER;
+            right = simple ? SIMPLE_TOP_RIGHT_CORNER : TOP_RIGHT_CORNER;
+        } else {
+            left = simple ? SIMPLE_TOP_LEFT_CORNER_BORDERLESS : TOP_LEFT_CORNER_BORDERLESS;
+            right = simple ? SIMPLE_TOP_RIGHT_CORNER_BORDERLESS : TOP_RIGHT_CORNER_BORDERLESS;
+        }
+        shape = new int[left.length + right.length + 4];
+        int index = 0;
+        shape[index++] = x;
+        shape[index++] = y+height+highlight_header + 1;
+        for (int i = 0; i < left.length/2; i++) {
+            shape[index++] = x+left[2*i];
+            shape[index++] = y+left[2*i+1];
+        }
+        for (int i = 0; i < right.length/2; i++) {
+            shape[index++] = x+width+right[2*i];
+            shape[index++] = y+right[2*i+1];
+        }
+        shape[index++] = x+width;
+        shape[index++] = y+height+highlight_header + 1;
     }
+    // Fill in background
+    bool bkSelected = single && selectedIndex !is -1;
+    drawBackground(gc, shape, bkSelected);
+    // Fill in parent background for non-rectangular shape
+    Region r = new Region();
+    r.add(new Rectangle(x, y, width + 1, height + 1));
+    r.subtract(shape);
+    gc.setBackground(getParent().getBackground());
+    fillRegion(gc, r);
+    r.dispose();
 
-    void drawMinimize (GC gc)
-    {
-        if (minRect.width is 0 || minRect.height is 0)
-            return;
-        Display display = getDisplay();
-        // 5x4 or 9x3
-        int x = minRect.x + (BUTTON_SIZE - 10) / 2;
-        int y = minRect.y + 3;
-
-        gc.setForeground(display.getSystemColor(BUTTON_BORDER));
-        gc.setBackground(display.getSystemColor(BUTTON_FILL));
-
-        switch (minImageState)
-        {
-            case NORMAL:
-            {
-                if (!minimized)
-                {
-                    gc.fillRectangle(x, y, 9, 3);
-                    gc.drawRectangle(x, y, 9, 3);
-                }
-                else
-                {
-                    gc.fillRectangle(x, y + 3, 5, 4);
-                    gc.fillRectangle(x + 2, y, 5, 4);
-                    gc.drawRectangle(x, y + 3, 5, 4);
-                    gc.drawRectangle(x + 2, y, 5, 4);
-                    gc.drawLine(x + 3, y + 1, x + 6, y + 1);
-                    gc.drawLine(x + 1, y + 4, x + 4, y + 4);
-                }
-                break;
-            }
-            case HOT:
-            {
-                gc.fillRoundRectangle(minRect.x, minRect.y, minRect.width,
-                        minRect.height, 6, 6);
-                gc.drawRoundRectangle(minRect.x, minRect.y, minRect.width - 1,
-                        minRect.height - 1, 6, 6);
-                if (!minimized)
-                {
-                    gc.fillRectangle(x, y, 9, 3);
-                    gc.drawRectangle(x, y, 9, 3);
-                }
-                else
-                {
-                    gc.fillRectangle(x, y + 3, 5, 4);
-                    gc.fillRectangle(x + 2, y, 5, 4);
-                    gc.drawRectangle(x, y + 3, 5, 4);
-                    gc.drawRectangle(x + 2, y, 5, 4);
-                    gc.drawLine(x + 3, y + 1, x + 6, y + 1);
-                    gc.drawLine(x + 1, y + 4, x + 4, y + 4);
-                }
-                break;
-            }
-            case SELECTED:
-            {
-                gc.fillRoundRectangle(minRect.x, minRect.y, minRect.width,
-                        minRect.height, 6, 6);
-                gc.drawRoundRectangle(minRect.x, minRect.y, minRect.width - 1,
-                        minRect.height - 1, 6, 6);
-                if (!minimized)
-                {
-                    gc.fillRectangle(x + 1, y + 1, 9, 3);
-                    gc.drawRectangle(x + 1, y + 1, 9, 3);
-                }
-                else
-                {
-                    gc.fillRectangle(x + 1, y + 4, 5, 4);
-                    gc.fillRectangle(x + 3, y + 1, 5, 4);
-                    gc.drawRectangle(x + 1, y + 4, 5, 4);
-                    gc.drawRectangle(x + 3, y + 1, 5, 4);
-                    gc.drawLine(x + 4, y + 2, x + 7, y + 2);
-                    gc.drawLine(x + 2, y + 5, x + 5, y + 5);
-                }
-                break;
+    // Draw the unselected tabs.
+    if (!single) {
+        for (int i=0; i < items.length; i++) {
+            if (i !is selectedIndex && event.getBounds().intersects(items[i].getBounds())) {
+                items[i].onPaint(gc, false);
             }
         }
     }
 
-    void drawTabArea (Event event)
-    {
-        GC gc = event.gc;
-        Point size = getSize();
-        int[] shape = null;
-
-        if (tabHeight is 0)
-        {
-            int style = getStyle();
-            if ((style & DWT.FLAT) !is 0 && (style & DWT.BORDER) is 0)
-                return;
-            int x1 = borderLeft - 1;
-            int x2 = size.x - borderRight;
-            int
-                    y1 = onBottom ? size.y - borderBottom - highlight_header - 1 : borderTop + highlight_header;
-            int y2 = onBottom ? size.y - borderBottom : borderTop;
-            if (borderLeft > 0 && onBottom)
-                y2 -= 1;
-
-            shape = new int[][x1 , y1 , x1 , y2 , x2 , y2 , x2 , y1];
-
-            // If horizontal gradient, show gradient across the whole area
-            if (selectedIndex !is -1 && selectionGradientColors !is null && selectionGradientColors.length > 1 && !selectionGradientVertical)
-            {
-                drawBackground(gc, shape, true);
-            }
-            else if (selectedIndex is -1 && gradientColors !is null && gradientColors.length > 1 && !gradientVertical)
-            {
-                drawBackground(gc, shape, false);
-            }
-            else
-            {
-                gc.setBackground(
-                        selectedIndex is -1 ? getBackground() : selectionBackground);
-                gc.fillPolygon(shape);
-            }
-
-            //draw 1 pixel border
-            if (borderLeft > 0)
-            {
-                gc.setForeground(borderColor);
-                gc.drawPolyline(shape);
-            }
-            return;
-        }
-
-        int x = Math.max(0, borderLeft - 1);
-        int y = onBottom ? size.y - borderBottom - tabHeight : borderTop;
-        int width = size.x - borderLeft - borderRight + 1;
-        int height = tabHeight - 1;
-
-        // Draw Tab Header
-        if (onBottom)
-        {
-            int[] left, right;
-            if ((getStyle() & DWT.BORDER) !is 0)
-            {
-                left = simple ? SIMPLE_BOTTOM_LEFT_CORNER : BOTTOM_LEFT_CORNER;
-                right = simple ? SIMPLE_BOTTOM_RIGHT_CORNER : BOTTOM_RIGHT_CORNER;
-            }
-            else
-            {
-                left = simple ? SIMPLE_BOTTOM_LEFT_CORNER_BORDERLESS : BOTTOM_LEFT_CORNER_BORDERLESS;
-                right = simple ? SIMPLE_BOTTOM_RIGHT_CORNER_BORDERLESS : BOTTOM_RIGHT_CORNER_BORDERLESS;
-            }
-            shape = new int[left.length + right.length + 4];
-            int index = 0;
-            shape[index++] = x;
-            shape[index++] = y - highlight_header;
-            for (int i = 0; i < left.length / 2; i++)
-            {
-                shape[index++] = x + left[2 * i];
-                shape[index++] = y + height + left[2 * i + 1];
-                if (borderLeft is 0)
-                    shape[index - 1] += 1;
-            }
-            for (int i = 0; i < right.length / 2; i++)
-            {
-                shape[index++] = x + width + right[2 * i];
-                shape[index++] = y + height + right[2 * i + 1];
-                if (borderLeft is 0)
-                    shape[index - 1] += 1;
-            }
-            shape[index++] = x + width;
-            shape[index++] = y - highlight_header;
-        }
-        else
-        {
-            int[] left, right;
-            if ((getStyle() & DWT.BORDER) !is 0)
-            {
-                left = simple ? SIMPLE_TOP_LEFT_CORNER : TOP_LEFT_CORNER;
-                right = simple ? SIMPLE_TOP_RIGHT_CORNER : TOP_RIGHT_CORNER;
-            }
-            else
-            {
-                left = simple ? SIMPLE_TOP_LEFT_CORNER_BORDERLESS : TOP_LEFT_CORNER_BORDERLESS;
-                right = simple ? SIMPLE_TOP_RIGHT_CORNER_BORDERLESS : TOP_RIGHT_CORNER_BORDERLESS;
-            }
-            shape = new int[left.length + right.length + 4];
-            int index = 0;
-            shape[index++] = x;
-            shape[index++] = y + height + highlight_header + 1;
-            for (int i = 0; i < left.length / 2; i++)
-            {
-                shape[index++] = x + left[2 * i];
-                shape[index++] = y + left[2 * i + 1];
-            }
-            for (int i = 0; i < right.length / 2; i++)
-            {
-                shape[index++] = x + width + right[2 * i];
-                shape[index++] = y + right[2 * i + 1];
-            }
-            shape[index++] = x + width;
-            shape[index++] = y + height + highlight_header + 1;
-        }
-        // Fill in background
-        bool bkSelected = single && selectedIndex !is -1;
-        drawBackground(gc, shape, bkSelected);
-        // Fill in parent background for non-rectangular shape
-        Region r = new Region();
-        r.add(new Rectangle(x, y, width + 1, height + 1));
-        r.subtract(shape);
-        gc.setBackground(getParent().getBackground());
-        fillRegion(gc, r);
-        r.dispose();
-
-        // Draw the unselected tabs.
-        if (!single)
-        {
-            for (int i = 0; i < items.length; i++)
-            {
-                if (i !is selectedIndex && event.getBounds().intersects(
-                        items[i].getBounds()))
-                {
-                    items[i].onPaint(gc, false);
-                }
-            }
-        }
-
-        // Draw selected tab
-        if (selectedIndex !is -1)
-        {
-            CTabItem item = items[selectedIndex];
-            item.onPaint(gc, true);
-        }
-        else
-        {
-            // if no selected tab - draw line across bottom of all tabs
-            int x1 = borderLeft;
-            int
-                    y1 = (onBottom) ? size.y - borderBottom - tabHeight - 1 : borderTop + tabHeight;
-            int x2 = size.x - borderRight;
-            gc.setForeground(borderColor);
-            gc.drawLine(x1, y1, x2, y1);
-        }
-
-        // Draw Buttons
-        drawChevron(gc);
-        drawMinimize(gc);
-        drawMaximize(gc);
-
-        // Draw border line
-        if (borderLeft > 0)
-        {
-            RGB outside = getParent().getBackground().getRGB();
-            antialias(shape, borderColor.getRGB(), null, outside, gc);
-            gc.setForeground(borderColor);
-            gc.drawPolyline(shape);
-        }
-    }
-
-    /**
-     * Returns <code>true</code> if the receiver's border is visible.
-     *
-     * @return the receiver's border visibility state
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public bool getBorderVisible ()
-    {
-        checkWidget();
-        return borderLeft is 1;
-    }
-
-    public Rectangle getClientArea ()
-    {
-        checkWidget();
-        if (minimized)
-            return new Rectangle(xClient, yClient, 0, 0);
-        Point size = getSize();
-        int
-                width = size.x - borderLeft - borderRight - 2 * marginWidth - 2 * highlight_margin;
-        int
-                height = size.y - borderTop - borderBottom - 2 * marginHeight - highlight_margin - highlight_header;
-        height -= tabHeight;
-        return new Rectangle(xClient, yClient, width, height);
-    }
-
-    /**
-     * Return the tab that is located at the specified index.
-     * 
-     * @param index the index of the tab item
-     * @return the item at the specified index
-     * 
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_INVALID_RANGE - if the index is out of range</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     * </ul>
-     */
-    public CTabItem getItem (int index)
-    {
-        //checkWidget();
-        if (index < 0 || index >= items.length)
-            DWT.error(DWT.ERROR_INVALID_RANGE);
-        return items[index];
-    }
-
-    /**
-     * Gets the item at a point in the widget.
-     *
-     * @param pt the point in coordinates relative to the CTabFolder
-     * @return the item at a point or null
-     * 
-     * @exception DWTException <ul>
-     *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     *  </ul>
-     */
-    public CTabItem getItem (Point pt)
-    {
-        //checkWidget();
-        if (items.length is 0)
-            return null;
-        Point size = getSize();
-        if (size.x <= borderLeft + borderRight)
-            return null;
-        if (showChevron && chevronRect.contains(pt))
-            return null;
-        for (int i = 0; i < priority.length; i++)
-        {
-            CTabItem item = items[priority[i]];
-            Rectangle rect = item.getBounds();
-            if (rect.contains(pt))
-                return item;
-        }
-        return null;
-    }
-
-    /**
-     * Return the number of tabs in the folder.
-     * 
-     * @return the number of tabs in the folder
-     * 
-     * @exception DWTException <ul>
-     *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     *  </ul>
-     */
-    public int getItemCount ()
-    {
-        //checkWidget();
-        return items.length;
-    }
-
-    /**
-     * Return the tab items.
-     * 
-     * @return the tab items
-     * 
-     * @exception DWTException <ul>
-     *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     *  </ul>
-     */
-    public CTabItem[] getItems ()
-    {
-        //checkWidget();
-        CTabItem[] tabItems = new CTabItem[items.length];
-        System.arraycopy(items, 0, tabItems, 0, items.length);
-        return tabItems;
-    }
-
-    /*
-     * Return the lowercase of the first non-'&' character following
-     * an '&' character in the given String. If there are no '&'
-     * characters in the given String, return '\0'.
-     */
-    char _findMnemonic (String String)
-    {
-        if (String is null)
-            return '\0';
-        int index = 0;
-        int length = String.length();
-        do
-        {
-            while (index < length && String.charAt(index) !is '&')
-                index++;
-            if (++index >= length)
-                return '\0';
-            if (String.charAt(index) !is '&')
-                return Character.toLowerCase(String.charAt(index));
-            index++;
-        } while (index < length);
-        return '\0';
-    }
-
-    String stripMnemonic (String String)
-    {
-        int index = 0;
-        int length = String.length();
-        do
-        {
-            while ((index < length) && (String.charAt(index) !is '&'))
-                index++;
-            if (++index >= length)
-                return String;
-            if (String.charAt(index) !is '&')
-            {
-                return String.substring(0, index - 1) + String.substring(index,
-                        length);
-            }
-            index++;
-        } while (index < length);
-        return String;
-    }
-
-    /**
-     * Returns <code>true</code> if the receiver is minimized.
-     *
-     * @return the receiver's minimized state
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public bool getMinimized ()
-    {
-        checkWidget();
-        return minimized;
+    // Draw selected tab
+    if (selectedIndex !is -1) {
+        CTabItem item = items[selectedIndex];
+        item.onPaint(gc, true);
+    } else {
+        // if no selected tab - draw line across bottom of all tabs
+        int x1 = borderLeft;
+        int y1 = (onBottom) ? size.y - borderBottom - tabHeight - 1 : borderTop + tabHeight;
+        int x2 = size.x - borderRight;
+        gc.setForeground(borderColor);
+        gc.drawLine(x1, y1, x2, y1);
     }
 
-    /**
-     * Returns <code>true</code> if the minimize button
-     * is visible.
-     *
-     * @return the visibility of the minimized button
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public bool getMinimizeVisible ()
-    {
-        checkWidget();
-        return showMin;
-    }
-
-    /** 
-     * Returns the number of characters that will
-     * appear in a fully compressed tab.
-     * 
-     * @return number of characters that will appear in a fully compressed tab
-     * 
-     * @since 3.0
-     */
-    public int getMinimumCharacters ()
-    {
-        checkWidget();
-        return minChars;
-    }
-
-    /**
-     * Returns <code>true</code> if the receiver is maximized.
-     * <p>
-     *
-     * @return the receiver's maximized state
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public bool getMaximized ()
-    {
-        checkWidget();
-        return maximized;
-    }
-
-    /**
-     * Returns <code>true</code> if the maximize button
-     * is visible.
-     *
-     * @return the visibility of the maximized button
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public bool getMaximizeVisible ()
-    {
-        checkWidget();
-        return showMax;
-    }
-
-    /**
-     * Returns <code>true</code> if the receiver displays most
-     * recently used tabs and <code>false</code> otherwise.
-     * <p>
-     * When there is not enough horizontal space to show all the tabs,
-     * by default, tabs are shown sequentially from left to right in 
-     * order of their index.  When the MRU visibility is turned on,
-     * the tabs that are visible will be the tabs most recently selected.
-     * Tabs will still maintain their left to right order based on index 
-     * but only the most recently selected tabs are visible.
-     * <p>
-     * For example, consider a CTabFolder that contains "Tab 1", "Tab 2",
-     * "Tab 3" and "Tab 4" (in order by index).  The user selects
-     * "Tab 1" and then "Tab 3".  If the CTabFolder is now
-     * compressed so that only two tabs are visible, by default, 
-     * "Tab 2" and "Tab 3" will be shown ("Tab 3" since it is currently 
-     * selected and "Tab 2" because it is the previous item in index order).
-     * If MRU visibility is enabled, the two visible tabs will be "Tab 1"
-     * and "Tab 3" (in that order from left to right).</p>
-     *
-     * @return the receiver's header's visibility state
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.1
-     */
-    public bool getMRUVisible ()
-    {
-        checkWidget();
-        return mru;
-    }
-
-    int getRightItemEdge ()
-    {
-        int x = getSize().x - borderRight - 3;
-        if (showMin)
-            x -= BUTTON_SIZE;
-        if (showMax)
-            x -= BUTTON_SIZE;
-        if (showChevron)
-            x -= 3 * BUTTON_SIZE / 2;
-        if (topRight !is null && topRightAlignment !is DWT.FILL)
-        {
-            Point rightSize = topRight.computeSize(DWT.DEFAULT, DWT.DEFAULT);
-            x -= rightSize.x + 3;
-        }
-        return Math.max(0, x);
-    }
-
-    /**
-     * Return the selected tab item, or null if there is no selection.
-     * 
-     * @return the selected tab item, or null if none has been selected
-     * 
-     * @exception DWTException <ul>
-     *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     *  </ul>
-     */
-    public CTabItem getSelection ()
-    {
-        //checkWidget();
-        if (selectedIndex is -1)
-            return null;
-        return items[selectedIndex];
-    }
-
-    /**
-     * Returns the receiver's selection background color.
-     *
-     * @return the selection background color of the receiver
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public Color getSelectionBackground ()
-    {
-        checkWidget();
-        return selectionBackground;
-    }
-
-    /**
-     * Returns the receiver's selection foreground color.
-     *
-     * @return the selection foreground color of the receiver
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public Color getSelectionForeground ()
-    {
-        checkWidget();
-        return selectionForeground;
-    }
+    // Draw Buttons
+    drawChevron(gc);
+    drawMinimize(gc);
+    drawMaximize(gc);
 
-    /**
-     * Return the index of the selected tab item, or -1 if there
-     * is no selection.
-     * 
-     * @return the index of the selected tab item or -1
-     * 
-     * @exception DWTException <ul>
-     *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     *  </ul>
-     */
-    public int getSelectionIndex ()
-    {
-        //checkWidget();
-        return selectedIndex;
+    // Draw border line
+    if (borderLeft > 0) {
+        RGB outside = getParent().getBackground().getRGB();
+        antialias(shape, borderColor.getRGB(), null, outside, gc);
+        gc.setForeground(borderColor);
+        gc.drawPolyline(shape);
     }
-
-    /**
-     * Returns <code>true</code> if the CTabFolder is rendered
-     * with a simple, traditional shape.
-     * 
-     * @return <code>true</code> if the CTabFolder is rendered with a simple shape
-     * 
-     * @since 3.0
-     */
-    public bool getSimple ()
-    {
-        checkWidget();
-        return simple;
-    }
-
-    /**
-     * Returns <code>true</code> if the CTabFolder only displays the selected tab
-     * and <code>false</code> if the CTabFolder displays multiple tabs.
-     * 
-     * @return <code>true</code> if the CTabFolder only displays the selected tab and <code>false</code> if the CTabFolder displays multiple tabs
-     * 
-     * @since 3.0
-     */
-    public bool getSingle ()
-    {
-        checkWidget();
-        return single;
+}
+/**
+ * Returns <code>true</code> if the receiver's border is visible.
+ *
+ * @return the receiver's border visibility state
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public bool getBorderVisible() {
+    checkWidget();
+    return borderLeft is 1;
+}
+public override Rectangle getClientArea() {
+    checkWidget();
+    if (minimized) return new Rectangle(xClient, yClient, 0, 0);
+    Point size = getSize();
+    int width = size.x  - borderLeft - borderRight - 2*marginWidth - 2*highlight_margin;
+    int height = size.y - borderTop - borderBottom - 2*marginHeight - highlight_margin - highlight_header;
+    height -= tabHeight;
+    return new Rectangle(xClient, yClient, width, height);
+}
+/**
+ * Return the tab that is located at the specified index.
+ *
+ * @param index the index of the tab item
+ * @return the item at the specified index
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_RANGE - if the index is out of range</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ */
+public CTabItem getItem (int index) {
+    //checkWidget();
+    if (index  < 0 || index >= items.length)
+        DWT.error(DWT.ERROR_INVALID_RANGE);
+    return items [index];
+}
+/**
+ * Gets the item at a point in the widget.
+ *
+ * @param pt the point in coordinates relative to the CTabFolder
+ * @return the item at a point or null
+ *
+ * @exception DWTException <ul>
+ *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ *  </ul>
+ */
+public CTabItem getItem (Point pt) {
+    //checkWidget();
+    if (items.length is 0) return null;
+    Point size = getSize();
+    if (size.x <= borderLeft + borderRight) return null;
+    if (showChevron && chevronRect.contains(pt)) return null;
+    for (int i = 0; i < priority.length; i++) {
+        CTabItem item = items[priority[i]];
+        Rectangle rect = item.getBounds();
+        if (rect.contains(pt)) return item;
     }
-
-    public int getStyle ()
-    {
-        int style = super.getStyle();
-        style &= ~(DWT.TOP | DWT.BOTTOM);
-        style |= onBottom ? DWT.BOTTOM : DWT.TOP;
-        style &= ~(DWT.SINGLE | DWT.MULTI);
-        style |= single ? DWT.SINGLE : DWT.MULTI;
-        if (borderLeft !is 0)
-            style |= DWT.BORDER;
-        style &= ~DWT.CLOSE;
-        if (showClose)
-            style |= DWT.CLOSE;
-        return style;
+    return null;
+}
+/**
+ * Return the number of tabs in the folder.
+ *
+ * @return the number of tabs in the folder
+ *
+ * @exception DWTException <ul>
+ *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ *  </ul>
+ */
+public int getItemCount(){
+    //checkWidget();
+    return items.length;
+}
+/**
+ * Return the tab items.
+ *
+ * @return the tab items
+ *
+ * @exception DWTException <ul>
+ *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ *  </ul>
+ */
+public CTabItem [] getItems() {
+    //checkWidget();
+    CTabItem[] tabItems = new CTabItem [items.length];
+    System.arraycopy(items, 0, tabItems, 0, items.length);
+    return tabItems;
+}
+/*
+ * Return the lowercase of the first non-'&' character following
+ * an '&' character in the given string. If there are no '&'
+ * characters in the given string, return '\0'.
+ */
+dchar _findMnemonic (String string) {
+    if (string is null) return '\0';
+    int index = 0;
+    int length_ = string.length;
+    do {
+        while (index < length_ && string[index] !is '&') index++;
+        if (++index >= length_) return '\0';
+        if (string[index] !is '&') return CharacterFirstToLower(string[index..$]);
+        index++;
+    } while (index < length_);
+    return '\0';
+}
+String stripMnemonic (String string) {
+    int index = 0;
+    int length_ = string.length;
+    do {
+        while ((index < length_) && (string[index] !is '&')) index++;
+        if (++index >= length_) return string;
+        if (string[index] !is '&') {
+            return string.substring(0, index-1) ~ string.substring(index, length_);
+        }
+        index++;
+    } while (index < length_);
+    return string;
+}
+/**
+ * Returns <code>true</code> if the receiver is minimized.
+ *
+ * @return the receiver's minimized state
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public bool getMinimized() {
+    checkWidget();
+    return minimized;
+}
+/**
+ * Returns <code>true</code> if the minimize button
+ * is visible.
+ *
+ * @return the visibility of the minimized button
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public bool getMinimizeVisible() {
+    checkWidget();
+    return showMin;
+}
+/**
+ * Returns the number of characters that will
+ * appear in a fully compressed tab.
+ *
+ * @return number of characters that will appear in a fully compressed tab
+ *
+ * @since 3.0
+ */
+public int getMinimumCharacters() {
+    checkWidget();
+    return minChars;
+}
+/**
+ * Returns <code>true</code> if the receiver is maximized.
+ * <p>
+ *
+ * @return the receiver's maximized state
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public bool getMaximized() {
+    checkWidget();
+    return maximized;
+}
+/**
+ * Returns <code>true</code> if the maximize button
+ * is visible.
+ *
+ * @return the visibility of the maximized button
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public bool getMaximizeVisible() {
+    checkWidget();
+    return showMax;
+}
+/**
+ * Returns <code>true</code> if the receiver displays most
+ * recently used tabs and <code>false</code> otherwise.
+ * <p>
+ * When there is not enough horizontal space to show all the tabs,
+ * by default, tabs are shown sequentially from left to right in
+ * order of their index.  When the MRU visibility is turned on,
+ * the tabs that are visible will be the tabs most recently selected.
+ * Tabs will still maintain their left to right order based on index
+ * but only the most recently selected tabs are visible.
+ * <p>
+ * For example, consider a CTabFolder that contains "Tab 1", "Tab 2",
+ * "Tab 3" and "Tab 4" (in order by index).  The user selects
+ * "Tab 1" and then "Tab 3".  If the CTabFolder is now
+ * compressed so that only two tabs are visible, by default,
+ * "Tab 2" and "Tab 3" will be shown ("Tab 3" since it is currently
+ * selected and "Tab 2" because it is the previous item in index order).
+ * If MRU visibility is enabled, the two visible tabs will be "Tab 1"
+ * and "Tab 3" (in that order from left to right).</p>
+ *
+ * @return the receiver's header's visibility state
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public bool getMRUVisible() {
+    checkWidget();
+    return mru;
+}
+int getRightItemEdge (){
+    int x = getSize().x - borderRight - 3;
+    if (showMin) x -= BUTTON_SIZE;
+    if (showMax) x -= BUTTON_SIZE;
+    if (showChevron) x -= 3*BUTTON_SIZE/2;
+    if (topRight !is null && topRightAlignment !is DWT.FILL) {
+        Point rightSize = topRight.computeSize(DWT.DEFAULT, DWT.DEFAULT);
+        x -= rightSize.x + 3;
     }
-
-    /**
-     * Returns the height of the tab
-     * 
-     * @return the height of the tab
-     * 
-     * @exception DWTException <ul>
-     *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     *  </ul>
-     */
-    public int getTabHeight ()
-    {
-        checkWidget();
-        if (fixedTabHeight !is DWT.DEFAULT)
-            return fixedTabHeight;
-        return tabHeight - 1; // -1 for line drawn across top of tab
-    }
-
-    /**
-     * Returns the position of the tab.  Possible values are DWT.TOP or DWT.BOTTOM.
-     * 
-     * @return the position of the tab
-     * 
-     * @exception DWTException <ul>
-     *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     *  </ul>
-     */
-    public int getTabPosition ()
-    {
-        checkWidget();
-        return onBottom ? DWT.BOTTOM : DWT.TOP;
-    }
+    return Math.max(0, x);
+}
+/**
+ * Return the selected tab item, or null if there is no selection.
+ *
+ * @return the selected tab item, or null if none has been selected
+ *
+ * @exception DWTException <ul>
+ *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ *  </ul>
+ */
+public CTabItem getSelection() {
+    //checkWidget();
+    if (selectedIndex is -1) return null;
+    return items[selectedIndex];
+}
+/**
+ * Returns the receiver's selection background color.
+ *
+ * @return the selection background color of the receiver
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public Color getSelectionBackground() {
+    checkWidget();
+    return selectionBackground;
+}
+/**
+ * Returns the receiver's selection foreground color.
+ *
+ * @return the selection foreground color of the receiver
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public Color getSelectionForeground() {
+    checkWidget();
+    return selectionForeground;
+}
+/**
+ * Return the index of the selected tab item, or -1 if there
+ * is no selection.
+ *
+ * @return the index of the selected tab item or -1
+ *
+ * @exception DWTException <ul>
+ *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ *  </ul>
+ */
+public int getSelectionIndex() {
+    //checkWidget();
+    return selectedIndex;
+}
+/**
+ * Returns <code>true</code> if the CTabFolder is rendered
+ * with a simple, traditional shape.
+ *
+ * @return <code>true</code> if the CTabFolder is rendered with a simple shape
+ *
+ * @since 3.0
+ */
+public bool getSimple() {
+    checkWidget();
+    return simple;
+}
+/**
+ * Returns <code>true</code> if the CTabFolder only displays the selected tab
+ * and <code>false</code> if the CTabFolder displays multiple tabs.
+ *
+ * @return <code>true</code> if the CTabFolder only displays the selected tab and <code>false</code> if the CTabFolder displays multiple tabs
+ *
+ * @since 3.0
+ */
+public bool getSingle() {
+    checkWidget();
+    return single;
+}
 
-    /**
-     * Returns the control in the top right corner of the tab folder. 
-     * Typically this is a close button or a composite with a menu and close button.
-     *
-     * @return the control in the top right corner of the tab folder or null
-     * 
-     * @exception  DWTException <ul>
-     *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     *  </ul>
-     *
-     * @since 2.1
-     */
-    public Control getTopRight ()
-    {
-        checkWidget();
-        return topRight;
-    }
-
-    /**
-     * Returns <code>true</code> if the close button appears 
-     * when the user hovers over an unselected tabs.
-     * 
-     * @return <code>true</code> if the close button appears on unselected tabs
-     * 
-     * @since 3.0
-     */
-    public bool getUnselectedCloseVisible ()
-    {
-        checkWidget();
-        return showUnselectedClose;
-    }
-
-    /**
-     * Returns <code>true</code> if an image appears 
-     * in unselected tabs.
-     * 
-     * @return <code>true</code> if an image appears in unselected tabs
-     * 
-     * @since 3.0
-     */
-    public bool getUnselectedImageVisible ()
-    {
-        checkWidget();
-        return showUnselectedImage;
+public override int getStyle() {
+    int style = super.getStyle();
+    style &= ~(DWT.TOP | DWT.BOTTOM);
+    style |= onBottom ? DWT.BOTTOM : DWT.TOP;
+    style &= ~(DWT.SINGLE | DWT.MULTI);
+    style |= single ? DWT.SINGLE : DWT.MULTI;
+    if (borderLeft !is 0) style |= DWT.BORDER;
+    style &= ~DWT.CLOSE;
+    if (showClose) style |= DWT.CLOSE;
+    return style;
+}
+/**
+ * Returns the height of the tab
+ *
+ * @return the height of the tab
+ *
+ * @exception DWTException <ul>
+ *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ *  </ul>
+ */
+public int getTabHeight(){
+    checkWidget();
+    if (fixedTabHeight !is DWT.DEFAULT) return fixedTabHeight;
+    return tabHeight - 1; // -1 for line drawn across top of tab
+}
+/**
+ * Returns the position of the tab.  Possible values are DWT.TOP or DWT.BOTTOM.
+ *
+ * @return the position of the tab
+ *
+ * @exception DWTException <ul>
+ *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ *  </ul>
+ */
+public int getTabPosition(){
+    checkWidget();
+    return onBottom ? DWT.BOTTOM : DWT.TOP;
+}
+/**
+ * Returns the control in the top right corner of the tab folder.
+ * Typically this is a close button or a composite with a menu and close button.
+ *
+ * @return the control in the top right corner of the tab folder or null
+ *
+ * @exception  DWTException <ul>
+ *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ *  </ul>
+ *
+ * @since 2.1
+ */
+public Control getTopRight() {
+    checkWidget();
+    return topRight;
+}
+/**
+ * Returns <code>true</code> if the close button appears
+ * when the user hovers over an unselected tabs.
+ *
+ * @return <code>true</code> if the close button appears on unselected tabs
+ *
+ * @since 3.0
+ */
+public bool getUnselectedCloseVisible() {
+    checkWidget();
+    return showUnselectedClose;
+}
+/**
+ * Returns <code>true</code> if an image appears
+ * in unselected tabs.
+ *
+ * @return <code>true</code> if an image appears in unselected tabs
+ *
+ * @since 3.0
+ */
+public bool getUnselectedImageVisible() {
+    checkWidget();
+    return showUnselectedImage;
+}
+/**
+ * Return the index of the specified tab or -1 if the tab is not
+ * in the receiver.
+ *
+ * @param item the tab item for which the index is required
+ *
+ * @return the index of the specified tab item or -1
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ */
+public int indexOf(CTabItem item) {
+    checkWidget();
+    if (item is null) {
+        DWT.error(DWT.ERROR_NULL_ARGUMENT);
     }
-
-    /**
-     * Return the index of the specified tab or -1 if the tab is not 
-     * in the receiver.
-     * 
-     * @param item the tab item for which the index is required
-     * 
-     * @return the index of the specified tab item or -1
-     * 
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     * </ul>
-     */
-    public int indexOf (CTabItem item)
-    {
-        checkWidget();
-        if (item is null)
-        {
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        }
-        for (int i = 0; i < items.length; i++)
-        {
-            if (items[i] is item)
-                return i;
-        }
-        return -1;
+    for (int i = 0; i < items.length; i++) {
+        if (items[i] is item) return i;
     }
-
-    void initAccessible ()
-    {
-        const Accessible accessible = getAccessible();
-        accessible.addAccessibleListener(new class AccessibleAdapter
-        {
-            public void getName (AccessibleEvent e)
-            {
-                String name = null;
-                int childID = e.childID;
-                if (childID >= 0 && childID < items.length)
-                {
-                    name = stripMnemonic(items[childID].getText());
-                }
-                else if (childID is items.length + CHEVRON_CHILD_ID)
-                {
-                    name = DWT.getMessage("DWT_ShowList"); //$NON-NLS-1$
-            }
-            else if (childID is items.length + MINIMIZE_CHILD_ID)
-            {
-                name = minimized ? DWT.getMessage("DWT_Restore") : DWT.getMessage(
-                        "DWT_Minimize"); //$NON-NLS-1$ //$NON-NLS-2$
-            }
-            else if (childID is items.length + MAXIMIZE_CHILD_ID)
-            {
-                name = maximized ? DWT.getMessage("DWT_Restore") : DWT.getMessage(
-                        "DWT_Maximize"); //$NON-NLS-1$ //$NON-NLS-2$
+    return -1;
+}
+void initAccessible() {
+    Accessible accessible = getAccessible();
+    accessible.addAccessibleListener(new class() AccessibleAdapter {
+        public void getName(AccessibleEvent e) {
+            String name = null;
+            int childID = e.childID;
+            if (childID >= 0 && childID < items.length) {
+                name = stripMnemonic(items[childID].getText());
+            } else if (childID is items.length + CHEVRON_CHILD_ID) {
+                name = DWT.getMessage("SWT_ShowList"); //$NON-NLS-1$
+            } else if (childID is items.length + MINIMIZE_CHILD_ID) {
+                name = minimized ? DWT.getMessage("SWT_Restore") : DWT.getMessage("SWT_Minimize"); //$NON-NLS-1$ //$NON-NLS-2$
+            } else if (childID is items.length + MAXIMIZE_CHILD_ID) {
+                name = maximized ? DWT.getMessage("SWT_Restore") : DWT.getMessage("SWT_Maximize"); //$NON-NLS-1$ //$NON-NLS-2$
             }
             e.result = name;
         }
 
-        public void getHelp (AccessibleEvent e)
-        {
+        public void getHelp(AccessibleEvent e) {
             String help = null;
             int childID = e.childID;
-            if (childID is ACC.CHILDID_SELF)
-            {
+            if (childID is ACC.CHILDID_SELF) {
                 help = getToolTipText();
-            }
-            else if (childID >= 0 && childID < items.length)
-            {
+            } else if (childID >= 0 && childID < items.length) {
                 help = items[childID].getToolTipText();
             }
             e.result = help;
         }
 
-        public void getKeyboardShortcut (AccessibleEvent e)
-        {
+        public void getKeyboardShortcut(AccessibleEvent e) {
             String shortcut = null;
             int childID = e.childID;
-            if (childID >= 0 && childID < items.length)
-            {
+            if (childID >= 0 && childID < items.length) {
                 String text = items[childID].getText();
-                if (text !is null)
-                {
-                    char mnemonic = _findMnemonic(text);
-                    if (mnemonic !is '\0')
-                    {
-                        shortcut = "Alt+" + mnemonic; //$NON-NLS-1$
+                if (text !is null) {
+                    dchar mnemonic = _findMnemonic(text);
+                    if (mnemonic !is '\0') {
+                        shortcut = "Alt+"~tango.text.convert.Utf.toString([mnemonic]); //$NON-NLS-1$
                     }
                 }
             }
             e.result = shortcut;
         }
-    }   );
-
-        accessible.addAccessibleControlListener(
-                new class AccessibleControlAdapter
-                {
-                    public void getChildAtPoint (AccessibleControlEvent e)
-                    {
-                        Point testPoint = toControl(e.x, e.y);
-                        int childID = ACC.CHILDID_NONE;
-                        for (int i = 0; i < items.length; i++)
-                        {
-                            if (items[i].getBounds().contains(testPoint))
-                            {
-                                childID = i;
-                                break;
-                            }
-                        }
-                        if (childID is ACC.CHILDID_NONE)
-                        {
-                            if (showChevron && chevronRect.contains(testPoint))
-                            {
-                                childID = items.length + CHEVRON_CHILD_ID;
-                            }
-                            else if (showMin && minRect.contains(testPoint))
-                            {
-                                childID = items.length + MINIMIZE_CHILD_ID;
-                            }
-                            else if (showMax && maxRect.contains(testPoint))
-                            {
-                                childID = items.length + MAXIMIZE_CHILD_ID;
-                            }
-                            else
-                            {
-                                Rectangle location = getBounds();
-                                location.height = location.height - getClientArea().height;
-                                if (location.contains(testPoint))
-                                {
-                                    childID = ACC.CHILDID_SELF;
-                                }
-                            }
-                        }
-                        e.childID = childID;
-                    }
-
-                    public void getLocation (AccessibleControlEvent e)
-                    {
-                        Rectangle location = null;
-                        Point pt = null;
-                        int childID = e.childID;
-                        if (childID is ACC.CHILDID_SELF)
-                        {
-                            location = getBounds();
-                            pt = getParent().toDisplay(location.x, location.y);
-                        }
-                        else
-                        {
-                            if (childID >= 0 && childID < items.length && items[childID].isShowing())
-                            {
-                                location = items[childID].getBounds();
-                            }
-                            else if (showChevron && childID is items.length + CHEVRON_CHILD_ID)
-                            {
-                                location = chevronRect;
-                            }
-                            else if (showMin && childID is items.length + MINIMIZE_CHILD_ID)
-                            {
-                                location = minRect;
-                            }
-                            else if (showMax && childID is items.length + MAXIMIZE_CHILD_ID)
-                            {
-                                location = maxRect;
-                            }
-                            if (location !is null)
-                            {
-                                pt = toDisplay(location.x, location.y);
-                            }
-                        }
-                        if (location !is null && pt !is null)
-                        {
-                            e.x = pt.x;
-                            e.y = pt.y;
-                            e.width = location.width;
-                            e.height = location.height;
-                        }
-                    }
-
-                    public void getChildCount (AccessibleControlEvent e)
-                    {
-                        e.detail = items.length + EXTRA_CHILD_ID_COUNT;
-                    }
-
-                    public void getDefaultAction (AccessibleControlEvent e)
-                    {
-                        String action = null;
-                        int childID = e.childID;
-                        if (childID >= 0 && childID < items.length)
-                        {
-                            action = DWT.getMessage("DWT_Switch"); //$NON-NLS-1$
-                        }
-                        if (childID >= items.length && childID < items.length + EXTRA_CHILD_ID_COUNT)
-                        {
-                            action = DWT.getMessage("DWT_Press"); //$NON-NLS-1$
-                        }
-                        e.result = action;
-                    }
+    });
 
-                    public void getFocus (AccessibleControlEvent e)
-                    {
-                        int childID = ACC.CHILDID_NONE;
-                        if (isFocusControl())
-                        {
-                            if (selectedIndex is -1)
-                            {
-                                childID = ACC.CHILDID_SELF;
-                            }
-                            else
-                            {
-                                childID = selectedIndex;
-                            }
-                        }
-                        e.childID = childID;
-                    }
-
-                    public void getRole (AccessibleControlEvent e)
-                    {
-                        int role = 0;
-                        int childID = e.childID;
-                        if (childID is ACC.CHILDID_SELF)
-                        {
-                            role = ACC.ROLE_TABFOLDER;
-                        }
-                        else if (childID >= 0 && childID < items.length)
-                        {
-                            role = ACC.ROLE_TABITEM;
-                        }
-                        else if (childID >= items.length && childID < items.length + EXTRA_CHILD_ID_COUNT)
-                        {
-                            role = ACC.ROLE_PUSHBUTTON;
-                        }
-                        e.detail = role;
-                    }
-
-                    public void getSelection (AccessibleControlEvent e)
-                    {
-                        e.childID = (selectedIndex is -1) ? ACC.CHILDID_NONE : selectedIndex;
-                    }
-
-                    public void getState (AccessibleControlEvent e)
-                    {
-                        int state = 0;
-                        int childID = e.childID;
-                        if (childID is ACC.CHILDID_SELF)
-                        {
-                            state = ACC.STATE_NORMAL;
-                        }
-                        else if (childID >= 0 && childID < items.length)
-                        {
-                            state = ACC.STATE_SELECTABLE;
-                            if (isFocusControl())
-                            {
-                                state |= ACC.STATE_FOCUSABLE;
-                            }
-                            if (selectedIndex is childID)
-                            {
-                                state |= ACC.STATE_SELECTED;
-                                if (isFocusControl())
-                                {
-                                    state |= ACC.STATE_FOCUSED;
-                                }
-                            }
-                        }
-                        else if (childID is items.length + CHEVRON_CHILD_ID)
-                        {
-                            state = showChevron ? ACC.STATE_NORMAL : ACC.STATE_INVISIBLE;
-                        }
-                        else if (childID is items.length + MINIMIZE_CHILD_ID)
-                        {
-                            state = showMin ? ACC.STATE_NORMAL : ACC.STATE_INVISIBLE;
-                        }
-                        else if (childID is items.length + MAXIMIZE_CHILD_ID)
-                        {
-                            state = showMax ? ACC.STATE_NORMAL : ACC.STATE_INVISIBLE;
-                        }
-                        e.detail = state;
-                    }
-
-                    public void getChildren (AccessibleControlEvent e)
-                    {
-                        int childIdCount = items.length + EXTRA_CHILD_ID_COUNT;
-                        Object[] children = new Object[childIdCount];
-                        for (int i = 0; i < childIdCount; i++)
-                        {
-                            children[i] = new Integer(i);
-                        }
-                        e.children = children;
-                    }
-                });
-
-        addListener(DWT.Selection, new class(accessible) Listener
-        {
-
-            Accessible accessible;
-
-            this (Accessible accessible)
-            {
-                this.accessible = accessible;
+    accessible.addAccessibleControlListener(new class() AccessibleControlAdapter {
+        public void getChildAtPoint(AccessibleControlEvent e) {
+            Point testPoint = toControl(e.x, e.y);
+            int childID = ACC.CHILDID_NONE;
+            for (int i = 0; i < items.length; i++) {
+                if (items[i].getBounds().contains(testPoint)) {
+                    childID = i;
+                    break;
+                }
             }
-
-            public void handleEvent (Event event)
-            {
-                if (isFocusControl())
-                {
-                    if (selectedIndex is -1)
-                    {
-                        accessible.setFocus(ACC.CHILDID_SELF);
-                    }
-                    else
-                    {
-                        accessible.setFocus(selectedIndex);
+            if (childID is ACC.CHILDID_NONE) {
+                if (showChevron && chevronRect.contains(testPoint)) {
+                    childID = items.length + CHEVRON_CHILD_ID;
+                } else if (showMin && minRect.contains(testPoint)) {
+                    childID = items.length + MINIMIZE_CHILD_ID;
+                } else if (showMax && maxRect.contains(testPoint)) {
+                    childID = items.length + MAXIMIZE_CHILD_ID;
+                } else {
+                    Rectangle location = getBounds();
+                    location.height = location.height - getClientArea().height;
+                    if (location.contains(testPoint)) {
+                        childID = ACC.CHILDID_SELF;
                     }
                 }
             }
-        });
-
-        addListener(DWT.FocusIn, new class(accessible) Listener
-        {
+            e.childID = childID;
+        }
 
-            Accessible accessible;
-
-            this (Accessible accessible)
-            {
-                this.accessible = accessible;
+        public void getLocation(AccessibleControlEvent e) {
+            Rectangle location = null;
+            Point pt = null;
+            int childID = e.childID;
+            if (childID is ACC.CHILDID_SELF) {
+                location = getBounds();
+                pt = getParent().toDisplay(location.x, location.y);
+            } else {
+                if (childID >= 0 && childID < items.length && items[childID].isShowing()) {
+                    location = items[childID].getBounds();
+                } else if (showChevron && childID is items.length + CHEVRON_CHILD_ID) {
+                    location = chevronRect;
+                } else if (showMin && childID is items.length + MINIMIZE_CHILD_ID) {
+                    location = minRect;
+                } else if (showMax && childID is items.length + MAXIMIZE_CHILD_ID) {
+                    location = maxRect;
+                }
+                if (location !is null) {
+                    pt = toDisplay(location.x, location.y);
+                }
             }
+            if (location !is null && pt !is null) {
+                e.x = pt.x;
+                e.y = pt.y;
+                e.width = location.width;
+                e.height = location.height;
+            }
+        }
 
-            public void handleEvent (Event event)
-            {
-                if (selectedIndex is -1)
-                {
-                    accessible.setFocus(ACC.CHILDID_SELF);
-                }
-                else
-                {
-                    accessible.setFocus(selectedIndex);
+        public void getChildCount(AccessibleControlEvent e) {
+            e.detail = items.length + EXTRA_CHILD_ID_COUNT;
+        }
+
+        public void getDefaultAction(AccessibleControlEvent e) {
+            String action = null;
+            int childID = e.childID;
+            if (childID >= 0 && childID < items.length) {
+                action = DWT.getMessage ("SWT_Switch"); //$NON-NLS-1$
+            }
+            if (childID >= items.length && childID < items.length + EXTRA_CHILD_ID_COUNT) {
+                action = DWT.getMessage ("SWT_Press"); //$NON-NLS-1$
+            }
+            e.result = action;
+        }
+
+        public void getFocus(AccessibleControlEvent e) {
+            int childID = ACC.CHILDID_NONE;
+            if (isFocusControl()) {
+                if (selectedIndex is -1) {
+                    childID = ACC.CHILDID_SELF;
+                } else {
+                    childID = selectedIndex;
                 }
             }
-        });
-    }
+            e.childID = childID;
+        }
+
+        public void getRole(AccessibleControlEvent e) {
+            int role = 0;
+            int childID = e.childID;
+            if (childID is ACC.CHILDID_SELF) {
+                role = ACC.ROLE_TABFOLDER;
+            } else if (childID >= 0 && childID < items.length) {
+                role = ACC.ROLE_TABITEM;
+            } else if (childID >= items.length && childID < items.length + EXTRA_CHILD_ID_COUNT) {
+                role = ACC.ROLE_PUSHBUTTON;
+            }
+            e.detail = role;
+        }
+
+        public void getSelection(AccessibleControlEvent e) {
+            e.childID = (selectedIndex is -1) ? ACC.CHILDID_NONE : selectedIndex;
+        }
+
+        public void getState(AccessibleControlEvent e) {
+            int state = 0;
+            int childID = e.childID;
+            if (childID is ACC.CHILDID_SELF) {
+                state = ACC.STATE_NORMAL;
+            } else if (childID >= 0 && childID < items.length) {
+                state = ACC.STATE_SELECTABLE;
+                if (isFocusControl()) {
+                    state |= ACC.STATE_FOCUSABLE;
+                }
+                if (selectedIndex is childID) {
+                    state |= ACC.STATE_SELECTED;
+                    if (isFocusControl()) {
+                        state |= ACC.STATE_FOCUSED;
+                    }
+                }
+            } else if (childID is items.length + CHEVRON_CHILD_ID) {
+                state = showChevron ? ACC.STATE_NORMAL : ACC.STATE_INVISIBLE;
+            } else if (childID is items.length + MINIMIZE_CHILD_ID) {
+                state = showMin ? ACC.STATE_NORMAL : ACC.STATE_INVISIBLE;
+            } else if (childID is items.length + MAXIMIZE_CHILD_ID) {
+                state = showMax ? ACC.STATE_NORMAL : ACC.STATE_INVISIBLE;
+            }
+            e.detail = state;
+        }
+
+        public void getChildren(AccessibleControlEvent e) {
+            int childIdCount = items.length + EXTRA_CHILD_ID_COUNT;
+            Object[] children = new Object[childIdCount];
+            for (int i = 0; i < childIdCount; i++) {
+                children[i] = new Integer(i);
+            }
+            e.children = children;
+        }
+    });
 
-    void onKeyDown (Event event)
-    {
-        switch (event.keyCode)
-        {
-            case DWT.ARROW_LEFT:
-            case DWT.ARROW_RIGHT:
-                int count = items.length;
-                if (count is 0)
-                    return;
-                if (selectedIndex is -1)
-                    return;
-                int
-                        leadKey = (getStyle() & DWT.RIGHT_TO_LEFT) !is 0 ? DWT.ARROW_RIGHT : DWT.ARROW_LEFT;
-                int offset = event.keyCode is leadKey ? -1 : 1;
-                int index;
-                if (!mru)
-                {
-                    index = selectedIndex + offset;
+    addListener(DWT.Selection, new class(accessible) Listener {
+        Accessible acc;
+        this( Accessible a ){
+            this.acc = a;
+        }
+        public void handleEvent(Event event) {
+            if (isFocusControl()) {
+                if (selectedIndex is -1) {
+                    acc.setFocus(ACC.CHILDID_SELF);
+                } else {
+                    acc.setFocus(selectedIndex);
                 }
-                else
-                {
-                    int[] visible = new int[items.length];
-                    int idx = 0;
-                    int current = -1;
-                    for (int i = 0; i < items.length; i++)
-                    {
-                        if (items[i].showing)
-                        {
-                            if (i is selectedIndex)
-                                current = idx;
-                            visible[idx++] = i;
+            }
+        }
+    });
+
+    addListener(DWT.FocusIn, new class(accessible) Listener {
+        Accessible acc;
+        this( Accessible a ){ this.acc = a; }
+        public void handleEvent(Event event) {
+            if (selectedIndex is -1) {
+                acc.setFocus(ACC.CHILDID_SELF);
+            } else {
+                acc.setFocus(selectedIndex);
+            }
+        }
+    });
+}
+
+void onKeyDown (Event event) {
+    switch (event.keyCode) {
+        case DWT.ARROW_LEFT:
+        case DWT.ARROW_RIGHT:
+            int count = items.length;
+            if (count is 0) return;
+            if (selectedIndex  is -1) return;
+            int leadKey = (getStyle() & DWT.RIGHT_TO_LEFT) !is 0 ? DWT.ARROW_RIGHT : DWT.ARROW_LEFT;
+            int offset =  event.keyCode is leadKey ? -1 : 1;
+            int index;
+            if (!mru) {
+                index = selectedIndex + offset;
+            } else {
+                int[] visible = new int[items.length];
+                int idx = 0;
+                int current = -1;
+                for (int i = 0; i < items.length; i++) {
+                    if (items[i].showing) {
+                        if (i is selectedIndex) current = idx;
+                        visible [idx++] = i;
+                    }
+                }
+                if (current + offset >= 0 && current + offset < idx){
+                    index = visible [current + offset];
+                } else {
+                    if (showChevron) {
+                        CTabFolderEvent e = new CTabFolderEvent(this);
+                        e.widget = this;
+                        e.time = event.time;
+                        e.x = chevronRect.x;
+                        e.y = chevronRect.y;
+                        e.width = chevronRect.width;
+                        e.height = chevronRect.height;
+                        e.doit = true;
+                        for (int i = 0; i < folderListeners.length; i++) {
+                            folderListeners[i].showList(e);
+                        }
+                        if (e.doit && !isDisposed()) {
+                            showList(chevronRect);
                         }
                     }
-                    if (current + offset >= 0 && current + offset < idx)
-                    {
-                        index = visible[current + offset];
-                    }
-                    else
-                    {
-                        if (showChevron)
-                        {
-                            CTabFolderEvent e = new CTabFolderEvent(this);
-                            e.widget = this;
-                            e.time = event.time;
-                            e.x = chevronRect.x;
-                            e.y = chevronRect.y;
-                            e.width = chevronRect.width;
-                            e.height = chevronRect.height;
-                            e.doit = true;
-                            for (int i = 0; i < folderListeners.length; i++)
-                            {
-                                folderListeners[i].showList(e);
-                            }
-                            if (e.doit && !isDisposed())
-                            {
-                                showList(chevronRect);
-                            }
-                        }
-                        return;
-                    }
+                    return;
                 }
-                if (index < 0 || index >= count)
-                    return;
-                setSelection(index, true);
-                forceFocus();
+            }
+            if (index < 0 || index >= count) return;
+            setSelection (index, true);
+            forceFocus();
+        default:
+    }
+}
+void onDispose(Event event) {
+    removeListener(DWT.Dispose, listener);
+    notifyListeners(DWT.Dispose, event);
+    event.type = DWT.None;
+    /*
+     * Usually when an item is disposed, destroyItem will change the size of the items array,
+     * reset the bounds of all the tabs and manage the widget associated with the tab.
+     * Since the whole folder is being disposed, this is not necessary.  For speed
+     * the inDispose flag is used to skip over this part of the item dispose.
+     */
+    inDispose = true;
+
+    if (showMenu !is null && !showMenu.isDisposed()) {
+        showMenu.dispose();
+        showMenu = null;
+    }
+    int length = items.length;
+    for (int i = 0; i < length; i++) {
+        if (items[i] !is null) {
+            items[i].dispose();
         }
     }
 
-    void onDispose (Event event)
-    {
-        removeListener(DWT.Dispose, listener);
-        notifyListeners(DWT.Dispose, event);
-        event.type = DWT.None;
-        /*
-         * Usually when an item is disposed, destroyItem will change the size of the items array, 
-         * reset the bounds of all the tabs and manage the widget associated with the tab.
-         * Since the whole folder is being disposed, this is not necessary.  For speed
-         * the inDispose flag is used to skip over this part of the item dispose.
-         */
-        inDispose = true;
+    selectionGradientColors = null;
+    selectionGradientPercents = null;
+    selectionBgImage = null;
 
-        if (showMenu !is null && !showMenu.isDisposed())
-        {
-            showMenu.dispose();
-            showMenu = null;
-        }
-        int length = items.length;
-        for (int i = 0; i < length; i++)
-        {
-            if (items[i] !is null)
-            {
-                items[i].dispose();
+    selectionBackground = null;
+    selectionForeground = null;
+    disposeSelectionHighlightGradientColors();
+}
+void onDragDetect(Event event) {
+    bool consume = false;
+    if (chevronRect.contains(event.x, event.y) ||
+        minRect.contains(event.x, event.y) ||
+        maxRect.contains(event.x, event.y)){
+        consume = true;
+    } else {
+        for (int i = 0; i < items.length; i++) {
+            if (items[i].closeRect.contains(event.x, event.y)) {
+                    consume = true;
+                    break;
             }
         }
-
-        selectionGradientColors = null;
-        selectionGradientPercents = null;
-        selectionBgImage = null;
-
-        selectionBackground = null;
-        selectionForeground = null;
-        disposeSelectionHighlightGradientColors();
+    }
+    if (consume) {
+        event.type = DWT.None;
     }
-
-    void onDragDetect (Event event)
-    {
-        bool consume = false;
-        if (chevronRect.contains(event.x, event.y) || minRect.contains(event.x,
-                event.y) || maxRect.contains(event.x, event.y))
-        {
-            consume = true;
-        }
-        else
-        {
-            for (int i = 0; i < items.length; i++)
-            {
-                if (items[i].closeRect.contains(event.x, event.y))
-                {
-                    consume = true;
-                    break;
+}
+void onFocus(Event event) {
+    checkWidget();
+    if (selectedIndex >= 0) {
+        redraw();
+    } else {
+        setSelection(0, true);
+    }
+}
+bool onMnemonic (Event event) {
+    auto key = event.character;
+    for (int i = 0; i < items.length; i++) {
+        if (items[i] !is null) {
+            auto mnemonic = _findMnemonic (items[i].getText ());
+            if (mnemonic !is '\0') {
+                if ( CharacterToLower(key) is mnemonic) {
+                    setSelection(i, true);
+                    return true;
                 }
             }
         }
-        if (consume)
-        {
-            event.type = DWT.None;
-        }
     }
-
-    void onFocus (Event event)
-    {
-        checkWidget();
-        if (selectedIndex >= 0)
-        {
-            redraw();
-        }
-        else
-        {
-            setSelection(0, true);
+    return false;
+}
+void onMouseDoubleClick(Event event) {
+    if (event.button !is 1 ||
+        (event.stateMask & DWT.BUTTON2) !is 0 ||
+        (event.stateMask & DWT.BUTTON3) !is 0) return;
+    Event e = new Event();
+    e.item = getItem(new Point(event.x, event.y));
+    if (e.item !is null) {
+        notifyListeners(DWT.DefaultSelection, e);
+    }
+}
+void onMouse(Event event) {
+    int x = event.x, y = event.y;
+    switch (event.type) {
+        case DWT.MouseEnter: {
+            setToolTipText(null);
+            break;
         }
-    }
-
-    bool onMnemonic (Event event)
-    {
-        char key = event.character;
-        for (int i = 0; i < items.length; i++)
-        {
-            if (items[i] !is null)
-            {
-                char mnemonic = _findMnemonic(items[i].getText());
-                if (mnemonic !is '\0')
-                {
-                    if (Character.toLowerCase(key) is mnemonic)
-                    {
-                        setSelection(i, true);
-                        return true;
+        case DWT.MouseExit: {
+            if (minImageState !is NORMAL) {
+                minImageState = NORMAL;
+                redraw(minRect.x, minRect.y, minRect.width, minRect.height, false);
+            }
+            if (maxImageState !is NORMAL) {
+                maxImageState = NORMAL;
+                redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false);
+            }
+            if (chevronImageState !is NORMAL) {
+                chevronImageState = NORMAL;
+                redraw(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, false);
+            }
+            for (int i=0; i<items.length; i++) {
+                CTabItem item = items[i];
+                if (i !is selectedIndex && item.closeImageState !is NONE) {
+                    item.closeImageState = NONE;
+                    redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
+                }
+                if (i is selectedIndex && item.closeImageState !is NORMAL) {
+                    item.closeImageState = NORMAL;
+                    redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
+                }
+            }
+            break;
+        }
+        case DWT.MouseDown: {
+            if (minRect.contains(x, y)) {
+                if (event.button !is 1) return;
+                minImageState = SELECTED;
+                redraw(minRect.x, minRect.y, minRect.width, minRect.height, false);
+                update();
+                return;
+            }
+            if (maxRect.contains(x, y)) {
+                if (event.button !is 1) return;
+                maxImageState = SELECTED;
+                redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false);
+                update();
+                return;
+            }
+            if (chevronRect.contains(x, y)) {
+                if (event.button !is 1) return;
+                if (chevronImageState !is HOT) {
+                    chevronImageState = HOT;
+                } else {
+                    chevronImageState = SELECTED;
+                }
+                redraw(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, false);
+                update();
+                return;
+            }
+            CTabItem item = null;
+            if (single) {
+                if (selectedIndex !is -1) {
+                    Rectangle bounds = items[selectedIndex].getBounds();
+                    if (bounds.contains(x, y)){
+                        item = items[selectedIndex];
+                    }
+                }
+            } else {
+                for (int i=0; i<items.length; i++) {
+                    Rectangle bounds = items[i].getBounds();
+                    if (bounds.contains(x, y)){
+                        item = items[i];
                     }
                 }
             }
-        }
-        return false;
-    }
-
-    void onMouseDoubleClick (Event event)
-    {
-        if (event.button !is 1 || (event.stateMask & DWT.BUTTON2) !is 0 || (event.stateMask & DWT.BUTTON3) !is 0)
-            return;
-        Event e = new Event();
-        e.item = getItem(new Point(event.x, event.y));
-        if (e.item !is null)
-        {
-            notifyListeners(DWT.DefaultSelection, e);
-        }
-    }
-
-    void onMouse (Event event)
-    {
-        int x = event.x, y = event.y;
-        switch (event.type)
-        {
-            case DWT.MouseEnter:
-            {
-                setToolTipText(null);
-                break;
-            }
-            case DWT.MouseExit:
-            {
-                if (minImageState !is NORMAL)
-                {
-                    minImageState = NORMAL;
-                    redraw(minRect.x, minRect.y, minRect.width, minRect.height,
-                            false);
-                }
-                if (maxImageState !is NORMAL)
-                {
-                    maxImageState = NORMAL;
-                    redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height,
-                            false);
-                }
-                if (chevronImageState !is NORMAL)
-                {
-                    chevronImageState = NORMAL;
-                    redraw(chevronRect.x, chevronRect.y, chevronRect.width,
-                            chevronRect.height, false);
-                }
-                for (int i = 0; i < items.length; i++)
-                {
-                    CTabItem item = items[i];
-                    if (i !is selectedIndex && item.closeImageState !is NONE)
-                    {
-                        item.closeImageState = NONE;
-                        redraw(item.closeRect.x, item.closeRect.y,
-                                item.closeRect.width, item.closeRect.height,
-                                false);
-                    }
-                    if (i is selectedIndex && item.closeImageState !is NORMAL)
-                    {
-                        item.closeImageState = NORMAL;
-                        redraw(item.closeRect.x, item.closeRect.y,
-                                item.closeRect.width, item.closeRect.height,
-                                false);
-                    }
-                }
-                break;
-            }
-            case DWT.MouseDown:
-            {
-                if (minRect.contains(x, y))
-                {
-                    if (event.button !is 1)
-                        return;
-                    minImageState = SELECTED;
-                    redraw(minRect.x, minRect.y, minRect.width, minRect.height,
-                            false);
+            if (item !is null) {
+                if (item.closeRect.contains(x,y)){
+                    if (event.button !is 1) return;
+                    item.closeImageState = SELECTED;
+                    redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
                     update();
                     return;
                 }
-                if (maxRect.contains(x, y))
-                {
-                    if (event.button !is 1)
-                        return;
-                    maxImageState = SELECTED;
-                    redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height,
-                            false);
-                    update();
-                    return;
+                int index = indexOf(item);
+                if (item.showing){
+                    setSelection(index, true);
+                }
+                return;
+            }
+            break;
+        }
+        case DWT.MouseMove: {
+            _setToolTipText(event.x, event.y);
+            bool close = false, minimize = false, maximize = false, chevron = false;
+            if (minRect.contains(x, y)) {
+                minimize = true;
+                if (minImageState !is SELECTED && minImageState !is HOT) {
+                    minImageState = HOT;
+                    redraw(minRect.x, minRect.y, minRect.width, minRect.height, false);
+                }
+            }
+            if (maxRect.contains(x, y)) {
+                maximize = true;
+                if (maxImageState !is SELECTED && maxImageState !is HOT) {
+                    maxImageState = HOT;
+                    redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false);
                 }
-                if (chevronRect.contains(x, y))
-                {
-                    if (event.button !is 1)
-                        return;
-                    if (chevronImageState !is HOT)
-                    {
-                        chevronImageState = HOT;
-                    }
-                    else
-                    {
-                        chevronImageState = SELECTED;
-                    }
-                    redraw(chevronRect.x, chevronRect.y, chevronRect.width,
-                            chevronRect.height, false);
-                    update();
-                    return;
+            }
+            if (chevronRect.contains(x, y)) {
+                chevron = true;
+                if (chevronImageState !is SELECTED && chevronImageState !is HOT) {
+                    chevronImageState = HOT;
+                    redraw(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, false);
                 }
-                CTabItem item = null;
-                if (single)
-                {
-                    if (selectedIndex !is -1)
-                    {
-                        Rectangle bounds = items[selectedIndex].getBounds();
-                        if (bounds.contains(x, y))
-                        {
-                            item = items[selectedIndex];
+            }
+            if (minImageState !is NORMAL && !minimize) {
+                minImageState = NORMAL;
+                redraw(minRect.x, minRect.y, minRect.width, minRect.height, false);
+            }
+            if (maxImageState !is NORMAL && !maximize) {
+                maxImageState = NORMAL;
+                redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false);
+            }
+            if (chevronImageState !is NORMAL && !chevron) {
+                chevronImageState = NORMAL;
+                redraw(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, false);
+            }
+            for (int i=0; i<items.length; i++) {
+                CTabItem item = items[i];
+                close = false;
+                if (item.getBounds().contains(x, y)) {
+                    close = true;
+                    if (item.closeRect.contains(x, y)) {
+                        if (item.closeImageState !is SELECTED && item.closeImageState !is HOT) {
+                            item.closeImageState = HOT;
+                            redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
+                        }
+                    } else {
+                        if (item.closeImageState !is NORMAL) {
+                            item.closeImageState = NORMAL;
+                            redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
                         }
                     }
                 }
-                else
-                {
-                    for (int i = 0; i < items.length; i++)
-                    {
-                        Rectangle bounds = items[i].getBounds();
-                        if (bounds.contains(x, y))
-                        {
-                            item = items[i];
-                        }
+                if (i !is selectedIndex && item.closeImageState !is NONE && !close) {
+                    item.closeImageState = NONE;
+                    redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
+                }
+                if (i is selectedIndex && item.closeImageState !is NORMAL && !close) {
+                    item.closeImageState = NORMAL;
+                    redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
+                }
+            }
+            break;
+        }
+        case DWT.MouseUp: {
+            if (event.button !is 1) return;
+            if (chevronRect.contains(x, y)) {
+                bool selected = chevronImageState is SELECTED;
+                if (!selected) return;
+                CTabFolderEvent e = new CTabFolderEvent(this);
+                e.widget = this;
+                e.time = event.time;
+                e.x = chevronRect.x;
+                e.y = chevronRect.y;
+                e.width = chevronRect.width;
+                e.height = chevronRect.height;
+                e.doit = true;
+                for (int i = 0; i < folderListeners.length; i++) {
+                    folderListeners[i].showList(e);
+                }
+                if (e.doit && !isDisposed()) {
+                    showList(chevronRect);
+                }
+                return;
+            }
+            if (minRect.contains(x, y)) {
+                bool selected = minImageState is SELECTED;
+                minImageState = HOT;
+                redraw(minRect.x, minRect.y, minRect.width, minRect.height, false);
+                if (!selected) return;
+                CTabFolderEvent e = new CTabFolderEvent(this);
+                e.widget = this;
+                e.time = event.time;
+                for (int i = 0; i < folderListeners.length; i++) {
+                    if (minimized) {
+                        folderListeners[i].restore(e);
+                    } else {
+                        folderListeners[i].minimize(e);
                     }
                 }
-                if (item !is null)
-                {
-                    if (item.closeRect.contains(x, y))
-                    {
-                        if (event.button !is 1)
-                            return;
-                        item.closeImageState = SELECTED;
-                        redraw(item.closeRect.x, item.closeRect.y,
-                                item.closeRect.width, item.closeRect.height,
-                                false);
-                        update();
-                        return;
+                return;
+            }
+            if (maxRect.contains(x, y)) {
+                bool selected = maxImageState is SELECTED;
+                maxImageState = HOT;
+                redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false);
+                if (!selected) return;
+                CTabFolderEvent e = new CTabFolderEvent(this);
+                e.widget = this;
+                e.time = event.time;
+                for (int i = 0; i < folderListeners.length; i++) {
+                    if (maximized) {
+                        folderListeners[i].restore(e);
+                    } else {
+                        folderListeners[i].maximize(e);
+                    }
+                }
+                return;
+            }
+            CTabItem item = null;
+            if (single) {
+                if (selectedIndex !is -1) {
+                    Rectangle bounds = items[selectedIndex].getBounds();
+                    if (bounds.contains(x, y)){
+                        item = items[selectedIndex];
+                    }
+                }
+            } else {
+                for (int i=0; i<items.length; i++) {
+                    Rectangle bounds = items[i].getBounds();
+                    if (bounds.contains(x, y)){
+                        item = items[i];
                     }
-                    int index = indexOf(item);
-                    if (item.showing)
-                    {
-                        setSelection(index, true);
+                }
+            }
+            if (item !is null) {
+                if (item.closeRect.contains(x,y)) {
+                    bool selected = item.closeImageState is SELECTED;
+                    item.closeImageState = HOT;
+                    redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
+                    if (!selected) return;
+                    CTabFolderEvent e = new CTabFolderEvent(this);
+                    e.widget = this;
+                    e.time = event.time;
+                    e.item = item;
+                    e.doit = true;
+                    for (int j = 0; j < folderListeners.length; j++) {
+                        CTabFolder2Listener listener = folderListeners[j];
+                        listener.close(e);
+                    }
+                    for (int j = 0; j < tabListeners.length; j++) {
+                        CTabFolderListener listener = tabListeners[j];
+                        listener.itemClosed(e);
+                    }
+                    if (e.doit) item.dispose();
+                    if (!isDisposed() && item.isDisposed()) {
+                        Display display = getDisplay();
+                        Point pt = display.getCursorLocation();
+                        pt = display.map(null, this, pt.x, pt.y);
+                        CTabItem nextItem = getItem(pt);
+                        if (nextItem !is null) {
+                            if (nextItem.closeRect.contains(pt)) {
+                                if (nextItem.closeImageState !is SELECTED && nextItem.closeImageState !is HOT) {
+                                    nextItem.closeImageState = HOT;
+                                    redraw(nextItem.closeRect.x, nextItem.closeRect.y, nextItem.closeRect.width, nextItem.closeRect.height, false);
+                                }
+                            } else {
+                                if (nextItem.closeImageState !is NORMAL) {
+                                    nextItem.closeImageState = NORMAL;
+                                    redraw(nextItem.closeRect.x, nextItem.closeRect.y, nextItem.closeRect.width, nextItem.closeRect.height, false);
+                                }
+                            }
+                        }
                     }
                     return;
                 }
-                break;
             }
-            case DWT.MouseMove:
-            {
-                _setToolTipText(event.x, event.y);
-                bool close = false, minimize = false, maximize = false,
-                        chevron = false;
-                if (minRect.contains(x, y))
-                {
-                    minimize = true;
-                    if (minImageState !is SELECTED && minImageState !is HOT)
-                    {
-                        minImageState = HOT;
-                        redraw(minRect.x, minRect.y, minRect.width,
-                                minRect.height, false);
-                    }
-                }
-                if (maxRect.contains(x, y))
-                {
-                    maximize = true;
-                    if (maxImageState !is SELECTED && maxImageState !is HOT)
-                    {
-                        maxImageState = HOT;
-                        redraw(maxRect.x, maxRect.y, maxRect.width,
-                                maxRect.height, false);
-                    }
-                }
-                if (chevronRect.contains(x, y))
-                {
-                    chevron = true;
-                    if (chevronImageState !is SELECTED && chevronImageState !is HOT)
-                    {
-                        chevronImageState = HOT;
-                        redraw(chevronRect.x, chevronRect.y, chevronRect.width,
-                                chevronRect.height, false);
-                    }
-                }
-                if (minImageState !is NORMAL && !minimize)
-                {
-                    minImageState = NORMAL;
-                    redraw(minRect.x, minRect.y, minRect.width, minRect.height,
-                            false);
-                }
-                if (maxImageState !is NORMAL && !maximize)
-                {
-                    maxImageState = NORMAL;
-                    redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height,
-                            false);
-                }
-                if (chevronImageState !is NORMAL && !chevron)
-                {
-                    chevronImageState = NORMAL;
-                    redraw(chevronRect.x, chevronRect.y, chevronRect.width,
-                            chevronRect.height, false);
+        default:
+        }
+    }
+}
+bool onPageTraversal(Event event) {
+    int count = items.length;
+    if (count is 0) return false;
+    int index = selectedIndex;
+    if (index  is -1) {
+        index = 0;
+    } else {
+        int offset = (event.detail is DWT.TRAVERSE_PAGE_NEXT) ? 1 : -1;
+        if (!mru) {
+            index = (selectedIndex + offset + count) % count;
+        } else {
+            int[] visible = new int[items.length];
+            int idx = 0;
+            int current = -1;
+            for (int i = 0; i < items.length; i++) {
+                if (items[i].showing) {
+                    if (i is selectedIndex) current = idx;
+                    visible [idx++] = i;
                 }
-                for (int i = 0; i < items.length; i++)
-                {
-                    CTabItem item = items[i];
-                    close = false;
-                    if (item.getBounds().contains(x, y))
-                    {
-                        close = true;
-                        if (item.closeRect.contains(x, y))
-                        {
-                            if (item.closeImageState !is SELECTED && item.closeImageState !is HOT)
-                            {
-                                item.closeImageState = HOT;
-                                redraw(item.closeRect.x, item.closeRect.y,
-                                        item.closeRect.width,
-                                        item.closeRect.height, false);
-                            }
-                        }
-                        else
-                        {
-                            if (item.closeImageState !is NORMAL)
-                            {
-                                item.closeImageState = NORMAL;
-                                redraw(item.closeRect.x, item.closeRect.y,
-                                        item.closeRect.width,
-                                        item.closeRect.height, false);
-                            }
-                        }
-                    }
-                    if (i !is selectedIndex && item.closeImageState !is NONE && !close)
-                    {
-                        item.closeImageState = NONE;
-                        redraw(item.closeRect.x, item.closeRect.y,
-                                item.closeRect.width, item.closeRect.height,
-                                false);
-                    }
-                    if (i is selectedIndex && item.closeImageState !is NORMAL && !close)
-                    {
-                        item.closeImageState = NORMAL;
-                        redraw(item.closeRect.x, item.closeRect.y,
-                                item.closeRect.width, item.closeRect.height,
-                                false);
-                    }
-                }
-                break;
             }
-            case DWT.MouseUp:
-            {
-                if (event.button !is 1)
-                    return;
-                if (chevronRect.contains(x, y))
-                {
-                    bool selected = chevronImageState is SELECTED;
-                    if (!selected)
-                        return;
+            if (current + offset >= 0 && current + offset < idx){
+                index = visible [current + offset];
+            } else {
+                if (showChevron) {
                     CTabFolderEvent e = new CTabFolderEvent(this);
                     e.widget = this;
                     e.time = event.time;
@@ -2704,2391 +2294,1788 @@
                     e.width = chevronRect.width;
                     e.height = chevronRect.height;
                     e.doit = true;
-                    for (int i = 0; i < folderListeners.length; i++)
-                    {
+                    for (int i = 0; i < folderListeners.length; i++) {
                         folderListeners[i].showList(e);
                     }
-                    if (e.doit && !isDisposed())
-                    {
+                    if (e.doit && !isDisposed()) {
                         showList(chevronRect);
                     }
-                    return;
-                }
-                if (minRect.contains(x, y))
-                {
-                    bool selected = minImageState is SELECTED;
-                    minImageState = HOT;
-                    redraw(minRect.x, minRect.y, minRect.width, minRect.height,
-                            false);
-                    if (!selected)
-                        return;
-                    CTabFolderEvent e = new CTabFolderEvent(this);
-                    e.widget = this;
-                    e.time = event.time;
-                    for (int i = 0; i < folderListeners.length; i++)
-                    {
-                        if (minimized)
-                        {
-                            folderListeners[i].restore(e);
-                        }
-                        else
-                        {
-                            folderListeners[i].minimize(e);
-                        }
-                    }
-                    return;
-                }
-                if (maxRect.contains(x, y))
-                {
-                    bool selected = maxImageState is SELECTED;
-                    maxImageState = HOT;
-                    redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height,
-                            false);
-                    if (!selected)
-                        return;
-                    CTabFolderEvent e = new CTabFolderEvent(this);
-                    e.widget = this;
-                    e.time = event.time;
-                    for (int i = 0; i < folderListeners.length; i++)
-                    {
-                        if (maximized)
-                        {
-                            folderListeners[i].restore(e);
-                        }
-                        else
-                        {
-                            folderListeners[i].maximize(e);
-                        }
-                    }
-                    return;
-                }
-                CTabItem item = null;
-                if (single)
-                {
-                    if (selectedIndex !is -1)
-                    {
-                        Rectangle bounds = items[selectedIndex].getBounds();
-                        if (bounds.contains(x, y))
-                        {
-                            item = items[selectedIndex];
-                        }
-                    }
                 }
-                else
-                {
-                    for (int i = 0; i < items.length; i++)
-                    {
-                        Rectangle bounds = items[i].getBounds();
-                        if (bounds.contains(x, y))
-                        {
-                            item = items[i];
-                        }
-                    }
-                }
-                if (item !is null)
-                {
-                    if (item.closeRect.contains(x, y))
-                    {
-                        bool selected = item.closeImageState is SELECTED;
-                        item.closeImageState = HOT;
-                        redraw(item.closeRect.x, item.closeRect.y,
-                                item.closeRect.width, item.closeRect.height,
-                                false);
-                        if (!selected)
-                            return;
-                        CTabFolderEvent e = new CTabFolderEvent(this);
-                        e.widget = this;
-                        e.time = event.time;
-                        e.item = item;
-                        e.doit = true;
-                        for (int j = 0; j < folderListeners.length; j++)
-                        {
-                            CTabFolder2Listener listener = folderListeners[j];
-                            listener.close(e);
-                        }
-                        for (int j = 0; j < tabListeners.length; j++)
-                        {
-                            CTabFolderListener listener = tabListeners[j];
-                            listener.itemClosed(e);
-                        }
-                        if (e.doit)
-                            item.dispose();
-                        if (!isDisposed() && item.isDisposed())
-                        {
-                            Display display = getDisplay();
-                            Point pt = display.getCursorLocation();
-                            pt = display.map(null, this, pt.x, pt.y);
-                            CTabItem nextItem = getItem(pt);
-                            if (nextItem !is null)
-                            {
-                                if (nextItem.closeRect.contains(pt))
-                                {
-                                    if (nextItem.closeImageState !is SELECTED && nextItem.closeImageState !is HOT)
-                                    {
-                                        nextItem.closeImageState = HOT;
-                                        redraw(nextItem.closeRect.x,
-                                                nextItem.closeRect.y,
-                                                nextItem.closeRect.width,
-                                                nextItem.closeRect.height,
-                                                false);
-                                    }
-                                }
-                                else
-                                {
-                                    if (nextItem.closeImageState !is NORMAL)
-                                    {
-                                        nextItem.closeImageState = NORMAL;
-                                        redraw(nextItem.closeRect.x,
-                                                nextItem.closeRect.y,
-                                                nextItem.closeRect.width,
-                                                nextItem.closeRect.height,
-                                                false);
-                                    }
-                                }
-                            }
-                        }
-                        return;
-                    }
-                }
+                return true;
             }
         }
     }
+    setSelection (index, true);
+    return true;
+}
+void onPaint(Event event) {
+    if (inDispose) return;
+    Font font = getFont();
+    if (oldFont is null || oldFont!=font) {
+        // handle case where  default font changes
+        oldFont = font;
+        if (!updateTabHeight(false)) {
+            updateItems();
+            redraw();
+            return;
+        }
+    }
 
-    bool onPageTraversal (Event event)
-    {
-        int count = items.length;
-        if (count is 0)
-            return false;
-        int index = selectedIndex;
-        if (index is -1)
-        {
-            index = 0;
-        }
-        else
-        {
-            int offset = (event.detail is DWT.TRAVERSE_PAGE_NEXT) ? 1 : -1;
-            if (!mru)
-            {
-                index = (selectedIndex + offset + count) % count;
-            }
-            else
-            {
-                int[] visible = new int[items.length];
-                int idx = 0;
-                int current = -1;
-                for (int i = 0; i < items.length; i++)
-                {
-                    if (items[i].showing)
-                    {
-                        if (i is selectedIndex)
-                            current = idx;
-                        visible[idx++] = i;
-                    }
-                }
-                if (current + offset >= 0 && current + offset < idx)
-                {
-                    index = visible[current + offset];
-                }
-                else
-                {
-                    if (showChevron)
-                    {
-                        CTabFolderEvent e = new CTabFolderEvent(this);
-                        e.widget = this;
-                        e.time = event.time;
-                        e.x = chevronRect.x;
-                        e.y = chevronRect.y;
-                        e.width = chevronRect.width;
-                        e.height = chevronRect.height;
-                        e.doit = true;
-                        for (int i = 0; i < folderListeners.length; i++)
-                        {
-                            folderListeners[i].showList(e);
-                        }
-                        if (e.doit && !isDisposed())
-                        {
-                            showList(chevronRect);
-                        }
-                    }
-                    return true;
-                }
-            }
-        }
-        setSelection(index, true);
-        return true;
-    }
+    GC gc = event.gc;
+    Font gcFont = gc.getFont();
+    Color gcBackground = gc.getBackground();
+    Color gcForeground = gc.getForeground();
+
+// Useful for debugging paint problems
+//{
+//Point size = getSize();
+//gc.setBackground(getDisplay().getSystemColor(DWT.COLOR_GREEN));
+//gc.fillRectangle(-10, -10, size.x + 20, size.y+20);
+//}
+
+    drawBody(event);
 
-    void onPaint (Event event)
-    {
-        if (inDispose)
-            return;
-        Font font = getFont();
-        if (oldFont is null || !oldFont.opEquals(font))
-        {
-            // handle case where  default font changes
-            oldFont = font;
-            if (!updateTabHeight(false))
-            {
-                updateItems();
-                redraw();
-                return;
-            }
-        }
+    gc.setFont(gcFont);
+    gc.setForeground(gcForeground);
+    gc.setBackground(gcBackground);
+
+    drawTabArea(event);
+
+    gc.setFont(gcFont);
+    gc.setForeground(gcForeground);
+    gc.setBackground(gcBackground);
+}
+
+void onResize() {
+    if (updateItems()) redrawTabs();
 
-        GC gc = event.gc;
-        Font gcFont = gc.getFont();
-        Color gcBackground = gc.getBackground();
-        Color gcForeground = gc.getForeground();
-
-        // Useful for debugging paint problems
-        //{
-        //Point size = getSize();   
-        //gc.setBackground(getDisplay().getSystemColor(DWT.COLOR_GREEN));
-        //gc.fillRectangle(-10, -10, size.x + 20, size.y+20);
-        //}
-
-        drawBody(event);
-
-        gc.setFont(gcFont);
-        gc.setForeground(gcForeground);
-        gc.setBackground(gcBackground);
-
-        drawTabArea(event);
-
-        gc.setFont(gcFont);
-        gc.setForeground(gcForeground);
-        gc.setBackground(gcBackground);
-    }
-
-    void onResize ()
-    {
-        if (updateItems())
-            redrawTabs();
-
-        Point size = getSize();
-        if (oldSize is null)
-        {
+    Point size = getSize();
+    if (oldSize is null) {
+        redraw();
+    } else {
+        if (onBottom && size.y !is oldSize.y) {
             redraw();
+        } else {
+            int x1 = Math.min(size.x, oldSize.x);
+            if (size.x !is oldSize.x) x1 -= borderRight + highlight_margin + 2;
+            if (!simple) x1 -= 5; // rounded top right corner
+            int y1 = Math.min(size.y, oldSize.y);
+            if (size.y !is oldSize.y) y1 -= borderBottom + highlight_margin;
+            int x2 = Math.max(size.x, oldSize.x);
+            int y2 = Math.max(size.y, oldSize.y);
+            redraw(0, y1, x2, y2 - y1, false);
+            redraw(x1, 0, x2 - x1, y2, false);
         }
-        else
-        {
-            if (onBottom && size.y !is oldSize.y)
-            {
-                redraw();
-            }
-            else
-            {
-                int x1 = Math.min(size.x, oldSize.x);
-                if (size.x !is oldSize.x)
-                    x1 -= borderRight + highlight_margin + 2;
-                if (!simple)
-                    x1 -= 5; // rounded top right corner
-                int y1 = Math.min(size.y, oldSize.y);
-                if (size.y !is oldSize.y)
-                    y1 -= borderBottom + highlight_margin;
-                int x2 = Math.max(size.x, oldSize.x);
-                int y2 = Math.max(size.y, oldSize.y);
-                redraw(0, y1, x2, y2 - y1, false);
-                redraw(x1, 0, x2 - x1, y2, false);
-            }
-        }
-        oldSize = size;
+    }
+    oldSize = size;
+}
+void onTraverse (Event event) {
+    switch (event.detail) {
+        case DWT.TRAVERSE_ESCAPE:
+        case DWT.TRAVERSE_RETURN:
+        case DWT.TRAVERSE_TAB_NEXT:
+        case DWT.TRAVERSE_TAB_PREVIOUS:
+            Control focusControl = getDisplay().getFocusControl();
+            if (focusControl is this) event.doit = true;
+            break;
+        case DWT.TRAVERSE_MNEMONIC:
+            event.doit = onMnemonic(event);
+            if (event.doit) event.detail = DWT.TRAVERSE_NONE;
+            break;
+        case DWT.TRAVERSE_PAGE_NEXT:
+        case DWT.TRAVERSE_PAGE_PREVIOUS:
+            event.doit = onPageTraversal(event);
+            event.detail = DWT.TRAVERSE_NONE;
+            break;
+        default:
     }
-
-    void onTraverse (Event event)
-    {
-        switch (event.detail)
-        {
-            case DWT.TRAVERSE_ESCAPE:
-            case DWT.TRAVERSE_RETURN:
-            case DWT.TRAVERSE_TAB_NEXT:
-            case DWT.TRAVERSE_TAB_PREVIOUS:
-                Control focusControl = getDisplay().getFocusControl();
-                if (focusControl is this)
-                    event.doit = true;
-            break;
-            case DWT.TRAVERSE_MNEMONIC:
-                event.doit = onMnemonic(event);
-                if (event.doit)
-                    event.detail = DWT.TRAVERSE_NONE;
-            break;
-            case DWT.TRAVERSE_PAGE_NEXT:
-            case DWT.TRAVERSE_PAGE_PREVIOUS:
-                event.doit = onPageTraversal(event);
-                event.detail = DWT.TRAVERSE_NONE;
+}
+void redrawTabs() {
+    Point size = getSize();
+    if (onBottom) {
+        redraw(0, size.y - borderBottom - tabHeight - highlight_header - 1, size.x, borderBottom + tabHeight + highlight_header + 1, false);
+    } else {
+        redraw(0, 0, size.x, borderTop + tabHeight + highlight_header + 1, false);
+    }
+}
+/**
+ * Removes the listener.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @see #addCTabFolder2Listener(CTabFolder2Listener)
+ *
+ * @since 3.0
+ */
+public void removeCTabFolder2Listener(CTabFolder2Listener listener) {
+    checkWidget();
+    if (listener is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    if (folderListeners.length is 0) return;
+    int index = -1;
+    for (int i = 0; i < folderListeners.length; i++) {
+        if (listener is folderListeners[i]){
+            index = i;
             break;
         }
     }
-
-    void redrawTabs ()
-    {
-        Point size = getSize();
-        if (onBottom)
-        {
-            redraw(0, size.y - borderBottom - tabHeight - highlight_header - 1,
-                    size.x, borderBottom + tabHeight + highlight_header + 1,
-                    false);
+    if (index is -1) return;
+    if (folderListeners.length is 1) {
+        folderListeners = new CTabFolder2Listener[0];
+        return;
+    }
+    CTabFolder2Listener[] newTabListeners = new CTabFolder2Listener[folderListeners.length - 1];
+    SimpleType!(CTabFolder2Listener).arraycopy(folderListeners, 0, newTabListeners, 0, index);
+    SimpleType!(CTabFolder2Listener).arraycopy(folderListeners, index + 1, newTabListeners, index, folderListeners.length - index - 1);
+    folderListeners = newTabListeners;
+}
+/**
+ * Removes the listener.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @deprecated see removeCTabFolderCloseListener(CTabFolderListener)
+ */
+public void removeCTabFolderListener(CTabFolderListener listener) {
+    checkWidget();
+    if (listener is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    if (tabListeners.length is 0) return;
+    int index = -1;
+    for (int i = 0; i < tabListeners.length; i++) {
+        if (listener is tabListeners[i]){
+            index = i;
+            break;
         }
-        else
-        {
-            redraw(0, 0, size.x, borderTop + tabHeight + highlight_header + 1,
-                    false);
+    }
+    if (index is -1) return;
+    if (tabListeners.length is 1) {
+        tabListeners = new CTabFolderListener[0];
+        return;
+    }
+    CTabFolderListener[] newTabListeners = new CTabFolderListener[tabListeners.length - 1];
+    SimpleType!(CTabFolderListener).arraycopy(tabListeners, 0, newTabListeners, 0, index);
+    SimpleType!(CTabFolderListener).arraycopy(tabListeners, index + 1, newTabListeners, index, tabListeners.length - index - 1);
+    tabListeners = newTabListeners;
+}
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the user changes the receiver's selection.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see SelectionListener
+ * @see #addSelectionListener
+ */
+public void removeSelectionListener(SelectionListener listener) {
+    checkWidget();
+    if (listener is null) {
+        DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    }
+    removeListener(DWT.Selection, listener);
+    removeListener(DWT.DefaultSelection, listener);
+}
+public override void setBackground (Color color) {
+    super.setBackground(color);
+    redraw();
+}
+/**
+ * Specify a gradient of colours to be drawn in the background of the unselected tabs.
+ * For example to draw a gradient that varies from dark blue to blue and then to
+ * white, use the following call to setBackground:
+ * <pre>
+ *  cfolder.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE),
+ *                                 display.getSystemColor(DWT.COLOR_BLUE),
+ *                                 display.getSystemColor(DWT.COLOR_WHITE),
+ *                                 display.getSystemColor(DWT.COLOR_WHITE)},
+ *                     new int[] {25, 50, 100});
+ * </pre>
+ *
+ * @param colors an array of Color that specifies the colors to appear in the gradient
+ *               in order of appearance left to right.  The value <code>null</code> clears the
+ *               background gradient. The value <code>null</code> can be used inside the array of
+ *               Color to specify the background color.
+ * @param percents an array of integers between 0 and 100 specifying the percent of the width
+ *                 of the widget at which the color should change.  The size of the percents array must be one
+ *                 less than the size of the colors array.
+ *
+ * @exception DWTException <ul>
+ *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ *  </ul>
+ *
+ * @since 3.0
+ */
+void setBackground(Color[] colors, int[] percents) {
+    setBackground(colors, percents, false);
+}
+/**
+ * Specify a gradient of colours to be drawn in the background of the unselected tab.
+ * For example to draw a vertical gradient that varies from dark blue to blue and then to
+ * white, use the following call to setBackground:
+ * <pre>
+ *  cfolder.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE),
+ *                                 display.getSystemColor(DWT.COLOR_BLUE),
+ *                                 display.getSystemColor(DWT.COLOR_WHITE),
+ *                                 display.getSystemColor(DWT.COLOR_WHITE)},
+ *                        new int[] {25, 50, 100}, true);
+ * </pre>
+ *
+ * @param colors an array of Color that specifies the colors to appear in the gradient
+ *               in order of appearance left to right.  The value <code>null</code> clears the
+ *               background gradient. The value <code>null</code> can be used inside the array of
+ *               Color to specify the background color.
+ * @param percents an array of integers between 0 and 100 specifying the percent of the width
+ *                 of the widget at which the color should change.  The size of the percents array must be one
+ *                 less than the size of the colors array.
+ *
+ * @param vertical indicate the direction of the gradient.  True is vertical and false is horizontal.
+ *
+ * @exception DWTException <ul>
+ *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ *  </ul>
+ *
+ * @since 3.0
+ */
+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);
+        }
+        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);
+            }
+        }
+        if (getDisplay().getDepth() < 15) {
+            // Don't use gradients on low color displays
+            colors = [colors[colors.length - 1]];
+            percents = null;
         }
     }
 
-    /**  
-     * Removes the listener.
-     *
-     * @param listener the listener
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     * </ul>
-     * 
-     * @see #addCTabFolder2Listener(CTabFolder2Listener)
-     * 
-     * @since 3.0
-     */
-    public void removeCTabFolder2Listener (CTabFolder2Listener listener)
-    {
-        checkWidget();
-        if (listener is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        if (folderListeners.length is 0)
-            return;
-        int index = -1;
-        for (int i = 0; i < folderListeners.length; i++)
-        {
-            if (listener is folderListeners[i])
-            {
-                index = i;
-                break;
+    // Are these settings the same as before?
+    if (bgImage is null) {
+        if ((gradientColors !is null) && (colors !is null) &&
+            (gradientColors.length is colors.length)) {
+            bool same = false;
+            for (int i = 0; i < gradientColors.length; i++) {
+                if (gradientColors[i] is null) {
+                    same = colors[i] is null;
+                } else {
+                    same = cast(bool)(gradientColors[i]==colors[i]);
+                }
+                if (!same) break;
             }
-        }
-        if (index is -1)
-            return;
-        if (folderListeners.length is 1)
-        {
-            folderListeners = new CTabFolder2Listener[0];
-            return;
-        }
-        CTabFolder2Listener[]
-                newTabListeners = new CTabFolder2Listener[folderListeners.length - 1];
-        System.arraycopy(folderListeners, 0, newTabListeners, 0, index);
-        System.arraycopy(folderListeners, index + 1, newTabListeners, index,
-                folderListeners.length - index - 1);
-        folderListeners = newTabListeners;
-    }
-
-    /**  
-     * Removes the listener.
-     *
-     * @param listener the listener
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     * </ul>
-     * 
-     * @deprecated see removeCTabFolderCloseListener(CTabFolderListener)
-     */
-    public void removeCTabFolderListener (CTabFolderListener listener)
-    {
-        checkWidget();
-        if (listener is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        if (tabListeners.length is 0)
-            return;
-        int index = -1;
-        for (int i = 0; i < tabListeners.length; i++)
-        {
-            if (listener is tabListeners[i])
-            {
-                index = i;
-                break;
+            if (same) {
+                for (int i = 0; i < gradientPercents.length; i++) {
+                    same = gradientPercents[i] is percents[i];
+                    if (!same) break;
+                }
             }
-        }
-        if (index is -1)
-            return;
-        if (tabListeners.length is 1)
-        {
-            tabListeners = new CTabFolderListener[0];
-            return;
-        }
-        CTabFolderListener[]
-                newTabListeners = new CTabFolderListener[tabListeners.length - 1];
-        System.arraycopy(tabListeners, 0, newTabListeners, 0, index);
-        System.arraycopy(tabListeners, index + 1, newTabListeners, index,
-                tabListeners.length - index - 1);
-        tabListeners = newTabListeners;
-    }
-
-    /**  
-     * Removes the listener from the collection of listeners who will
-     * be notified when the user changes the receiver's selection.
-     *
-     * @param listener the listener which should no longer be notified
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see SelectionListener
-     * @see #addSelectionListener
-     */
-    public void removeSelectionListener (SelectionListener listener)
-    {
-        checkWidget();
-        if (listener is null)
-        {
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
+            if (same && this.gradientVertical is vertical) return;
         }
-        removeListener(DWT.Selection, listener);
-        removeListener(DWT.DefaultSelection, listener);
-    }
-
-    public void setBackground (Color color)
-    {
-        super.setBackground(color);
-        redraw();
+    } else {
+        bgImage = null;
     }
-
-    /**
-     * Specify a gradient of colours to be drawn in the background of the unselected tabs.
-     * For example to draw a gradient that varies from dark blue to blue and then to
-     * white, use the following call to setBackground:
-     * <pre>
-     *  cfolder.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE), 
-     *                                 display.getSystemColor(DWT.COLOR_BLUE),
-     *                                 display.getSystemColor(DWT.COLOR_WHITE), 
-     *                                 display.getSystemColor(DWT.COLOR_WHITE)},
-     *                     new int[] {25, 50, 100});
-     * </pre>
-     *
-     * @param colors an array of Color that specifies the colors to appear in the gradient 
-     *               in order of appearance left to right.  The value <code>null</code> clears the
-     *               background gradient. The value <code>null</code> can be used inside the array of 
-     *               Color to specify the background color.
-     * @param percents an array of integers between 0 and 100 specifying the percent of the width 
-     *                 of the widget at which the color should change.  The size of the percents array must be one 
-     *                 less than the size of the colors array.
-     * 
-     * @exception DWTException <ul>
-     *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     *  </ul>
-     *
-     * @since 3.0
-     */
-    void setBackground (Color[] colors, int[] percents)
-    {
-        setBackground(colors, percents, false);
+    // Store the new settings
+    if (colors is null) {
+        gradientColors = null;
+        gradientPercents = null;
+        gradientVertical = false;
+        setBackground(cast(Color)null);
+    } else {
+        gradientColors = new Color[colors.length];
+        for (int i = 0; i < colors.length; ++i) {
+            gradientColors[i] = colors[i];
+        }
+        gradientPercents = new int[percents.length];
+        for (int i = 0; i < percents.length; ++i) {
+            gradientPercents[i] = percents[i];
+        }
+        gradientVertical = vertical;
+        setBackground(gradientColors[gradientColors.length-1]);
     }
 
-    /**
-     * Specify a gradient of colours to be drawn in the background of the unselected tab.
-     * For example to draw a vertical gradient that varies from dark blue to blue and then to
-     * white, use the following call to setBackground:
-     * <pre>
-     *  cfolder.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE), 
-     *                                 display.getSystemColor(DWT.COLOR_BLUE),
-     *                                 display.getSystemColor(DWT.COLOR_WHITE), 
-     *                                 display.getSystemColor(DWT.COLOR_WHITE)},
-     *                        new int[] {25, 50, 100}, true);
-     * </pre>
-     *
-     * @param colors an array of Color that specifies the colors to appear in the gradient 
-     *               in order of appearance left to right.  The value <code>null</code> clears the
-     *               background gradient. The value <code>null</code> can be used inside the array of 
-     *               Color to specify the background color.
-     * @param percents an array of integers between 0 and 100 specifying the percent of the width 
-     *                 of the widget at which the color should change.  The size of the percents array must be one 
-     *                 less than the size of the colors array.
-     * 
-     * @param vertical indicate the direction of the gradient.  True is vertical and false is horizontal. 
-     * 
-     * @exception DWTException <ul>
-     *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     *  </ul>
-     *
-     * @since 3.0
-     */
-    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);
-            }
-            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);
-                }
-            }
-            if (getDisplay().getDepth() < 15)
-            {
-                // Don't use gradients on low color displays
-                colors = new Color[][colors[colors.length - 1]];
-                percents = new int[][];
-            }
-        }
+    // Refresh with the new settings
+    redraw();
+}
 
-        // Are these settings the same as before?
-        if (bgImage is null)
-        {
-            if ((gradientColors !is null) && (colors !is null) && (gradientColors.length is colors.length))
-            {
-                bool same = false;
-                for (int i = 0; i < gradientColors.length; i++)
-                {
-                    if (gradientColors[i] is null)
-                    {
-                        same = colors[i] is null;
-                    }
-                    else
-                    {
-                        same = gradientColors[i].opEquals(colors[i]);
-                    }
-                    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;
-            }
-        }
-        else
-        {
-            bgImage = null;
-        }
-        // Store the new settings
-        if (colors is null)
-        {
-            gradientColors = null;
-            gradientPercents = null;
-            gradientVertical = false;
-            setBackground(cast(Color) null);
-        }
-        else
-        {
-            gradientColors = new Color[colors.length];
-            for (int i = 0; i < colors.length; ++i)
-            {
-                gradientColors[i] = colors[i];
-            }
-            gradientPercents = new int[percents.length];
-            for (int i = 0; i < percents.length; ++i)
-            {
-                gradientPercents[i] = percents[i];
-            }
-            gradientVertical = vertical;
-            setBackground(gradientColors[gradientColors.length - 1]);
-        }
-
-        // Refresh with the new settings
-        redraw();
+/**
+ * Set the image to be drawn in the background of the unselected tab.  Image
+ * is stretched or compressed to cover entire unselected tab area.
+ *
+ * @param image the image to be drawn in the background
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+void setBackground(Image image) {
+    checkWidget();
+    if (image is bgImage) return;
+    if (image !is null) {
+        gradientColors = null;
+        gradientPercents = null;
+    }
+    bgImage = image;
+    redraw();
+}
+/**
+ * Toggle the visibility of the border
+ *
+ * @param show true if the border should be displayed
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setBorderVisible(bool show) {
+    checkWidget();
+    if ((borderLeft is 1) is show) return;
+    borderLeft = borderRight = show ? 1 : 0;
+    borderTop = onBottom ? borderLeft : 0;
+    borderBottom = onBottom ? 0 : borderLeft;
+    Rectangle rectBefore = getClientArea();
+    updateItems();
+    Rectangle rectAfter = getClientArea();
+    if (rectBefore!=rectAfter) {
+        notifyListeners(DWT.Resize, new Event());
+    }
+    redraw();
+}
+void setButtonBounds() {
+    Point size = getSize();
+    int oldX, oldY, oldWidth, oldHeight;
+    // max button
+    oldX = maxRect.x;
+    oldY = maxRect.y;
+    oldWidth = maxRect.width;
+    oldHeight = maxRect.height;
+    maxRect.x = maxRect.y = maxRect.width = maxRect.height = 0;
+    if (showMax) {
+        maxRect.x = size.x - borderRight - BUTTON_SIZE - 3;
+        if (borderRight > 0) maxRect.x += 1;
+        maxRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - BUTTON_SIZE)/2: borderTop + (tabHeight - BUTTON_SIZE)/2;
+        maxRect.width = BUTTON_SIZE;
+        maxRect.height = BUTTON_SIZE;
+    }
+    if (oldX !is maxRect.x || oldWidth !is maxRect.width ||
+        oldY !is maxRect.y || oldHeight !is maxRect.height) {
+        int left = Math.min(oldX, maxRect.x);
+        int right = Math.max(oldX + oldWidth, maxRect.x + maxRect.width);
+        int top = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1;
+        redraw(left, top, right - left, tabHeight, false);
     }
 
-    /**
-     * Set the image to be drawn in the background of the unselected tab.  Image
-     * is stretched or compressed to cover entire unselected tab area.
-     * 
-     * @param image the image to be drawn in the background
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @since 3.0
-     */
-    void setBackground (Image image)
-    {
-        checkWidget();
-        if (image is bgImage)
-            return;
-        if (image !is null)
-        {
-            gradientColors = null;
-            gradientPercents = null;
-        }
-        bgImage = image;
-        redraw();
+    // min button
+    oldX = minRect.x;
+    oldY = minRect.y;
+    oldWidth = minRect.width;
+    oldHeight = minRect.height;
+    minRect.x = minRect.y = minRect.width = minRect.height = 0;
+    if (showMin) {
+        minRect.x = size.x - borderRight - maxRect.width - BUTTON_SIZE - 3;
+        if (borderRight > 0) minRect.x += 1;
+        minRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - BUTTON_SIZE)/2: borderTop + (tabHeight - BUTTON_SIZE)/2;
+        minRect.width = BUTTON_SIZE;
+        minRect.height = BUTTON_SIZE;
     }
-
-    /**
-     * Toggle the visibility of the border
-     * 
-     * @param show true if the border should be displayed
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setBorderVisible (bool show)
-    {
-        checkWidget();
-        if ((borderLeft is 1) is show)
-            return;
-        borderLeft = borderRight = show ? 1 : 0;
-        borderTop = onBottom ? borderLeft : 0;
-        borderBottom = onBottom ? 0 : borderLeft;
-        Rectangle rectBefore = getClientArea();
-        updateItems();
-        Rectangle rectAfter = getClientArea();
-        if (!rectBefore.opEquals(rectAfter))
-        {
-            notifyListeners(DWT.Resize, new Event());
-        }
-        redraw();
+    if (oldX !is minRect.x || oldWidth !is minRect.width ||
+        oldY !is minRect.y || oldHeight !is minRect.height) {
+        int left = Math.min(oldX, minRect.x);
+        int right = Math.max(oldX + oldWidth, minRect.x + minRect.width);
+        int top = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1;
+        redraw(left, top, right - left, tabHeight, false);
     }
 
-    void setButtonBounds ()
-    {
-        Point size = getSize();
-        int oldX, oldY, oldWidth, oldHeight;
-        // max button
-        oldX = maxRect.x;
-        oldY = maxRect.y;
-        oldWidth = maxRect.width;
-        oldHeight = maxRect.height;
-        maxRect.x = maxRect.y = maxRect.width = maxRect.height = 0;
-        if (showMax)
-        {
-            maxRect.x = size.x - borderRight - BUTTON_SIZE - 3;
-            if (borderRight > 0)
-                maxRect.x += 1;
-            maxRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - BUTTON_SIZE) / 2 : borderTop + (tabHeight - BUTTON_SIZE) / 2;
-            maxRect.width = BUTTON_SIZE;
-            maxRect.height = BUTTON_SIZE;
-        }
-        if (oldX !is maxRect.x || oldWidth !is maxRect.width || oldY !is maxRect.y || oldHeight !is maxRect.height)
-        {
-            int left = Math.min(oldX, maxRect.x);
-            int right = Math.max(oldX + oldWidth, maxRect.x + maxRect.width);
-            int
-                    top = onBottom ? size.y - borderBottom - tabHeight : borderTop + 1;
-            redraw(left, top, right - left, tabHeight, false);
-        }
-
-        // min button
-        oldX = minRect.x;
-        oldY = minRect.y;
-        oldWidth = minRect.width;
-        oldHeight = minRect.height;
-        minRect.x = minRect.y = minRect.width = minRect.height = 0;
-        if (showMin)
-        {
-            minRect.x = size.x - borderRight - maxRect.width - BUTTON_SIZE - 3;
-            if (borderRight > 0)
-                minRect.x += 1;
-            minRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - BUTTON_SIZE) / 2 : borderTop + (tabHeight - BUTTON_SIZE) / 2;
-            minRect.width = BUTTON_SIZE;
-            minRect.height = BUTTON_SIZE;
-        }
-        if (oldX !is minRect.x || oldWidth !is minRect.width || oldY !is minRect.y || oldHeight !is minRect.height)
-        {
-            int left = Math.min(oldX, minRect.x);
-            int right = Math.max(oldX + oldWidth, minRect.x + minRect.width);
-            int
-                    top = onBottom ? size.y - borderBottom - tabHeight : borderTop + 1;
-            redraw(left, top, right - left, tabHeight, false);
-        }
-
-        // top right control
-        oldX = topRightRect.x;
-        oldY = topRightRect.y;
-        oldWidth = topRightRect.width;
-        oldHeight = topRightRect.height;
-        topRightRect.x = topRightRect.y = topRightRect.width = topRightRect.height = 0;
-        if (topRight !is null)
-        {
-            switch (topRightAlignment)
-            {
-                case DWT.FILL:
-                {
-                    int
-                            rightEdge = size.x - borderRight - 3 - maxRect.width - minRect.width;
-                    if (!simple && borderRight > 0 && !showMax && !showMin)
-                        rightEdge -= 2;
-                    if (single)
-                    {
-                        if (items.length is 0 || selectedIndex is -1)
-                        {
-                            topRightRect.x = borderLeft + 3;
-                            topRightRect.width = rightEdge - topRightRect.x;
-                        }
-                        else
-                        {
-                            // fill size is 0 if item compressed
-                            CTabItem item = items[selectedIndex];
-                            if (item.x + item.width + 7 + 3 * BUTTON_SIZE / 2 >= rightEdge)
-                                break;
-                            topRightRect.x = item.x + item.width + 7 + 3 * BUTTON_SIZE / 2;
-                            topRightRect.width = rightEdge - topRightRect.x;
-                        }
+    // top right control
+    oldX = topRightRect.x;
+    oldY = topRightRect.y;
+    oldWidth = topRightRect.width;
+    oldHeight = topRightRect.height;
+    topRightRect.x = topRightRect.y = topRightRect.width = topRightRect.height = 0;
+    if (topRight !is null) {
+        switch (topRightAlignment) {
+            case DWT.FILL: {
+                int rightEdge = size.x - borderRight - 3 - maxRect.width - minRect.width;
+                if (!simple && borderRight > 0 && !showMax && !showMin) rightEdge -= 2;
+                if (single) {
+                    if (items.length is 0 || selectedIndex is -1) {
+                        topRightRect.x = borderLeft + 3;
+                        topRightRect.width = rightEdge - topRightRect.x;
+                    } else {
+                        // fill size is 0 if item compressed
+                        CTabItem item = items[selectedIndex];
+                        if (item.x + item.width + 7 + 3*BUTTON_SIZE/2 >= rightEdge) break;
+                        topRightRect.x = item.x + item.width + 7 + 3*BUTTON_SIZE/2;
+                        topRightRect.width = rightEdge - topRightRect.x;
                     }
-                    else
-                    {
-                        // fill size is 0 if chevron showing
-                        if (showChevron)
-                            break;
-                        if (items.length is 0)
-                        {
-                            topRightRect.x = borderLeft + 3;
-                        }
-                        else
-                        {
-                            CTabItem item = items[items.length - 1];
-                            topRightRect.x = item.x + item.width;
-                            if (!simple && items.length - 1 is selectedIndex)
-                                topRightRect.x += curveWidth - curveIndent;
-                        }
-                        topRightRect.width = Math.max(0,
-                                rightEdge - topRightRect.x);
+                } else {
+                    // fill size is 0 if chevron showing
+                    if (showChevron) break;
+                    if (items.length is 0) {
+                        topRightRect.x = borderLeft + 3;
+                    } else {
+                        CTabItem item = items[items.length - 1];
+                        topRightRect.x = item.x + item.width;
+                        if (!simple && items.length - 1 is selectedIndex) topRightRect.x += curveWidth - curveIndent;
                     }
-                    topRightRect.y = onBottom ? size.y - borderBottom - tabHeight : borderTop + 1;
-                    topRightRect.height = tabHeight - 1;
-                    break;
+                    topRightRect.width = Math.max(0, rightEdge - topRightRect.x);
                 }
-                case DWT.RIGHT:
-                {
-                    Point topRightSize = topRight.computeSize(DWT.DEFAULT,
-                            tabHeight, false);
-                    int
-                            rightEdge = size.x - borderRight - 3 - maxRect.width - minRect.width;
-                    if (!simple && borderRight > 0 && !showMax && !showMin)
-                        rightEdge -= 2;
-                    topRightRect.x = rightEdge - topRightSize.x;
-                    topRightRect.width = topRightSize.x;
-                    topRightRect.y = onBottom ? size.y - borderBottom - tabHeight : borderTop + 1;
-                    topRightRect.height = tabHeight - 1;
-                }
+                topRightRect.y = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1;
+                topRightRect.height = tabHeight - 1;
+                break;
             }
-            topRight.setBounds(topRightRect);
-        }
-        if (oldX !is topRightRect.x || oldWidth !is topRightRect.width || oldY !is topRightRect.y || oldHeight !is topRightRect.height)
-        {
-            int left = Math.min(oldX, topRightRect.x);
-            int right = Math.max(oldX + oldWidth,
-                    topRightRect.x + topRightRect.width);
-            int
-                    top = onBottom ? size.y - borderBottom - tabHeight : borderTop + 1;
-            redraw(left, top, right - left, tabHeight, false);
-        }
-
-        // chevron button
-        oldX = chevronRect.x;
-        oldY = chevronRect.y;
-        oldWidth = chevronRect.width;
-        oldHeight = chevronRect.height;
-        chevronRect.x = chevronRect.y = chevronRect.height = chevronRect.width = 0;
-        if (single)
-        {
-            if (selectedIndex is -1 || items.length > 1)
-            {
-                chevronRect.width = 3 * BUTTON_SIZE / 2;
-                chevronRect.height = BUTTON_SIZE;
-                chevronRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - chevronRect.height) / 2 : borderTop + (tabHeight - chevronRect.height) / 2;
-                if (selectedIndex is -1)
-                {
-                    chevronRect.x = size.x - borderRight - 3 - minRect.width - maxRect.width - topRightRect.width - chevronRect.width;
-                }
-                else
-                {
-                    CTabItem item = items[selectedIndex];
-                    int
-                            w = size.x - borderRight - 3 - minRect.width - maxRect.width - chevronRect.width;
-                    if (topRightRect.width > 0)
-                        w -= topRightRect.width + 3;
-                    chevronRect.x = Math.min(item.x + item.width + 3, w);
-                }
-                if (borderRight > 0)
-                    chevronRect.x += 1;
+            case DWT.RIGHT: {
+                Point topRightSize = topRight.computeSize(DWT.DEFAULT, tabHeight, false);
+                int rightEdge = size.x - borderRight - 3 - maxRect.width - minRect.width;
+                if (!simple && borderRight > 0 && !showMax && !showMin) rightEdge -= 2;
+                topRightRect.x = rightEdge - topRightSize.x;
+                topRightRect.width = topRightSize.x;
+                topRightRect.y = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1;
+                topRightRect.height = tabHeight - 1;
             }
+            default:
         }
-        else
-        {
-            if (showChevron)
-            {
-                chevronRect.width = 3 * BUTTON_SIZE / 2;
-                chevronRect.height = BUTTON_SIZE;
-                int i = 0, lastIndex = -1;
-                while (i < priority.length && items[priority[i]].showing)
-                {
-                    lastIndex = Math.max(lastIndex, priority[i++]);
-                }
-                if (lastIndex is -1)
-                    lastIndex = firstIndex;
-                CTabItem lastItem = items[lastIndex];
-                int w = lastItem.x + lastItem.width + 3;
-                if (!simple && lastIndex is selectedIndex)
-                    w += curveWidth - 2 * curveIndent;
-                chevronRect.x = Math.min(w, getRightItemEdge());
-                chevronRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - chevronRect.height) / 2 : borderTop + (tabHeight - chevronRect.height) / 2;
-            }
-        }
-        if (oldX !is chevronRect.x || oldWidth !is chevronRect.width || oldY !is chevronRect.y || oldHeight !is chevronRect.height)
-        {
-            int left = Math.min(oldX, chevronRect.x);
-            int right = Math.max(oldX + oldWidth,
-                    chevronRect.x + chevronRect.width);
-            int
-                    top = onBottom ? size.y - borderBottom - tabHeight : borderTop + 1;
-            redraw(left, top, right - left, tabHeight, false);
-        }
+        topRight.setBounds(topRightRect);
     }
-
-    public void setFont (Font font)
-    {
-        checkWidget();
-        if (font !is null && font.opEquals(getFont()))
-            return;
-        super.setFont(font);
-        oldFont = getFont();
-        if (!updateTabHeight(false))
-        {
-            updateItems();
-            redraw();
-        }
-    }
-
-    public void setForeground (Color color)
-    {
-        super.setForeground(color);
-        redraw();
-    }
-
-    /**
-     * Display an insert marker before or after the specified tab item. 
-     * 
-     * A value of null will clear the mark.
-     * 
-     * @param item the item with which the mark is associated or null
-     * 
-     * @param after true if the mark should be displayed after the specified item
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setInsertMark (CTabItem item, bool after)
-    {
-        checkWidget();
+    if (oldX !is topRightRect.x || oldWidth !is topRightRect.width ||
+        oldY !is topRightRect.y || oldHeight !is topRightRect.height) {
+        int left = Math.min(oldX, topRightRect.x);
+        int right = Math.max(oldX + oldWidth, topRightRect.x + topRightRect.width);
+        int top = onBottom ? size.y - borderBottom - tabHeight : borderTop + 1;
+        redraw(left, top, right - left, tabHeight, false);
     }
 
-    /**
-     * Display an insert marker before or after the specified tab item.
-     * 
-     * A value of -1 will clear the mark.
-     * 
-     * @param index the index of the item with which the mark is associated or null
-     * 
-     * @param after true if the mark should be displayed after the specified item
-     * 
-     * @exception IllegalArgumentException<ul>
-     * </ul>
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setInsertMark (int index, bool after)
-    {
-        checkWidget();
-        if (index < -1 || index >= getItemCount())
-        {
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    // chevron button
+    oldX = chevronRect.x;
+    oldY = chevronRect.y;
+    oldWidth = chevronRect.width;
+    oldHeight = chevronRect.height;
+    chevronRect.x = chevronRect.y = chevronRect.height = chevronRect.width = 0;
+    if (single) {
+        if (selectedIndex is -1 || items.length > 1) {
+            chevronRect.width = 3*BUTTON_SIZE/2;
+            chevronRect.height = BUTTON_SIZE;
+            chevronRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - chevronRect.height)/2 : borderTop + (tabHeight - chevronRect.height)/2;
+            if (selectedIndex is -1) {
+                chevronRect.x = size.x - borderRight - 3 - minRect.width - maxRect.width - topRightRect.width - chevronRect.width;
+            } else {
+                CTabItem item = items[selectedIndex];
+                int w = size.x - borderRight - 3 - minRect.width - maxRect.width - chevronRect.width;
+                if (topRightRect.width > 0) w -= topRightRect.width + 3;
+                chevronRect.x = Math.min(item.x + item.width + 3, w);
+            }
+            if (borderRight > 0) chevronRect.x += 1;
+        }
+    } else {
+        if (showChevron) {
+            chevronRect.width = 3*BUTTON_SIZE/2;
+            chevronRect.height = BUTTON_SIZE;
+            int i = 0, lastIndex = -1;
+            while (i < priority.length && items[priority[i]].showing) {
+                lastIndex = Math.max(lastIndex, priority[i++]);
+            }
+            if (lastIndex is -1) lastIndex = firstIndex;
+            CTabItem lastItem = items[lastIndex];
+            int w = lastItem.x + lastItem.width + 3;
+            if (!simple && lastIndex is selectedIndex) w += curveWidth - 2*curveIndent;
+            chevronRect.x = Math.min(w, getRightItemEdge());
+            chevronRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - chevronRect.height)/2 : borderTop + (tabHeight - chevronRect.height)/2;
         }
     }
-
-    bool setItemLocation ()
-    {
-        bool changed = false;
-        if (items.length is 0)
-            return false;
-        Point size = getSize();
-        int y = onBottom ? Math.max(borderBottom,
-                size.y - borderBottom - tabHeight) : borderTop;
-        if (single)
-        {
-            int defaultX = getDisplay().getBounds().width + 10; // off screen
-            for (int i = 0; i < items.length; i++)
-            {
-                CTabItem item = items[i];
-                if (i is selectedIndex)
-                {
-                    firstIndex = selectedIndex;
-                    int oldX = item.x, oldY = item.y;
-                    item.x = borderLeft;
-                    item.y = y;
-                    item.showing = true;
-                    if (showClose || item.showClose)
-                    {
-                        item.closeRect.x = borderLeft + CTabItem.LEFT_MARGIN;
-                        item.closeRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - BUTTON_SIZE) / 2 : borderTop + (tabHeight - BUTTON_SIZE) / 2;
-                    }
-                    if (item.x !is oldX || item.y !is oldY)
-                        changed = true;
-                }
-                else
-                {
-                    item.x = defaultX;
-                    item.showing = false;
+    if (oldX !is chevronRect.x || oldWidth !is chevronRect.width ||
+        oldY !is chevronRect.y || oldHeight !is chevronRect.height) {
+        int left = Math.min(oldX, chevronRect.x);
+        int right = Math.max(oldX + oldWidth, chevronRect.x + chevronRect.width);
+        int top = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1;
+        redraw(left, top, right - left, tabHeight, false);
+    }
+}
+public override void setFont(Font font) {
+    checkWidget();
+    if (font !is null && font==getFont()) return;
+    super.setFont(font);
+    oldFont = getFont();
+    if (!updateTabHeight(false)) {
+        updateItems();
+        redraw();
+    }
+}
+public override void setForeground (Color color) {
+    super.setForeground(color);
+    redraw();
+}
+/**
+ * Display an insert marker before or after the specified tab item.
+ *
+ * A value of null will clear the mark.
+ *
+ * @param item the item with which the mark is associated or null
+ *
+ * @param after true if the mark should be displayed after the specified item
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setInsertMark(CTabItem item, bool after) {
+    checkWidget();
+}
+/**
+ * Display an insert marker before or after the specified tab item.
+ *
+ * A value of -1 will clear the mark.
+ *
+ * @param index the index of the item with which the mark is associated or null
+ *
+ * @param after true if the mark should be displayed after the specified item
+ *
+ * @exception IllegalArgumentException<ul>
+ * </ul>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setInsertMark(int index, bool after) {
+    checkWidget();
+    if (index < -1 || index >= getItemCount()) {
+        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+}
+bool setItemLocation() {
+    bool changed = false;
+    if (items.length is 0) return false;
+    Point size = getSize();
+    int y = onBottom ? Math.max(borderBottom, size.y - borderBottom - tabHeight) : borderTop;
+    if (single) {
+        int defaultX = getDisplay().getBounds().width + 10; // off screen
+        for (int i = 0; i < items.length; i++) {
+            CTabItem item = items[i];
+            if (i is selectedIndex) {
+                firstIndex = selectedIndex;
+                int oldX = item.x, oldY = item.y;
+                item.x = borderLeft;
+                item.y = y;
+                item.showing = true;
+                if (showClose || item.showClose) {
+                    item.closeRect.x = borderLeft + CTabItem.LEFT_MARGIN;
+                    item.closeRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - BUTTON_SIZE)/2: borderTop + (tabHeight - BUTTON_SIZE)/2;
                 }
-            }
-        }
-        else
-        {
-            int rightItemEdge = getRightItemEdge();
-            int maxWidth = rightItemEdge - borderLeft;
-            int width = 0;
-            for (int i = 0; i < priority.length; i++)
-            {
-                CTabItem item = items[priority[i]];
-                width += item.width;
-                item.showing = i is 0 ? true : item.width > 0 && width <= maxWidth;
-                if (!simple && priority[i] is selectedIndex)
-                    width += curveWidth - 2 * curveIndent;
-            }
-            int x = 0;
-            int defaultX = getDisplay().getBounds().width + 10; // off screen
-            firstIndex = items.length - 1;
-            for (int i = 0; i < items.length; i++)
-            {
-                CTabItem item = items[i];
-                if (!item.showing)
-                {
-                    if (item.x !is defaultX)
-                        changed = true;
-                    item.x = defaultX;
-                }
-                else
-                {
-                    firstIndex = Math.min(firstIndex, i);
-                    if (item.x !is x || item.y !is y)
-                        changed = true;
-                    item.x = x;
-                    item.y = y;
-                    if (i is selectedIndex)
-                    {
-                        int edge = Math.min(item.x + item.width, rightItemEdge);
-                        item.closeRect.x = edge - CTabItem.RIGHT_MARGIN - BUTTON_SIZE;
-                    }
-                    else
-                    {
-                        item.closeRect.x = item.x + item.width - CTabItem.RIGHT_MARGIN - BUTTON_SIZE;
-                    }
-                    item.closeRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - BUTTON_SIZE) / 2 : borderTop + (tabHeight - BUTTON_SIZE) / 2;
-                    x = x + item.width;
-                    if (!simple && i is selectedIndex)
-                        x += curveWidth - 2 * curveIndent;
-                }
+                if (item.x !is oldX || item.y !is oldY) changed = true;
+            } else {
+                item.x = defaultX;
+                item.showing = false;
             }
         }
-        return changed;
-    }
-
-    bool setItemSize ()
-    {
-        bool changed = false;
-        if (isDisposed())
-            return changed;
-        Point size = getSize();
-        if (size.x <= 0 || size.y <= 0)
-            return changed;
-        xClient = borderLeft + marginWidth + highlight_margin;
-        if (onBottom)
-        {
-            yClient = borderTop + highlight_margin + marginHeight;
-        }
-        else
-        {
-            yClient = borderTop + tabHeight + highlight_header + marginHeight;
+    } else {
+        int rightItemEdge = getRightItemEdge();
+        int maxWidth = rightItemEdge - borderLeft;
+        int width = 0;
+        for (int i = 0; i < priority.length; i++) {
+            CTabItem item = items[priority[i]];
+            width += item.width;
+            item.showing = i is 0 ? true : item.width > 0 && width <= maxWidth;
+            if (!simple && priority[i] is selectedIndex) width += curveWidth - 2*curveIndent;
         }
-        showChevron = false;
-        if (single)
-        {
-            showChevron = true;
-            if (selectedIndex !is -1)
-            {
-                CTabItem tab = items[selectedIndex];
-                GC gc = new GC(this);
-                int width = tab.preferredWidth(gc, true, false);
-                gc.dispose();
-                width = Math.min(width, getRightItemEdge() - borderLeft);
-                if (tab.height !is tabHeight || tab.width !is width)
-                {
-                    changed = true;
-                    tab.shortenedText = null;
-                    tab.shortenedTextWidth = 0;
-                    tab.height = tabHeight;
-                    tab.width = width;
-                    tab.closeRect.width = tab.closeRect.height = 0;
-                    if (showClose || tab.showClose)
-                    {
-                        tab.closeRect.width = BUTTON_SIZE;
-                        tab.closeRect.height = BUTTON_SIZE;
-                    }
+        int x = 0;
+        int defaultX = getDisplay().getBounds().width + 10; // off screen
+        firstIndex = items.length - 1;
+        for (int i = 0; i < items.length; i++) {
+            CTabItem item = items[i];
+            if (!item.showing) {
+                if (item.x !is defaultX) changed = true;
+                item.x = defaultX;
+            } else {
+                firstIndex = Math.min(firstIndex, i);
+                if (item.x !is x || item.y !is y) changed = true;
+                item.x = x;
+                item.y = y;
+                if (i is selectedIndex) {
+                    int edge = Math.min(item.x + item.width, rightItemEdge);
+                    item.closeRect.x = edge - CTabItem.RIGHT_MARGIN - BUTTON_SIZE;
+                } else {
+                    item.closeRect.x = item.x + item.width - CTabItem.RIGHT_MARGIN - BUTTON_SIZE;
                 }
-            }
-            return changed;
-        }
-
-        if (items.length is 0)
-            return changed;
-
-        int[] widths;
-        GC gc = new GC(this);
-        int tabAreaWidth = size.x - borderLeft - borderRight - 3;
-        if (showMin)
-            tabAreaWidth -= BUTTON_SIZE;
-        if (showMax)
-            tabAreaWidth -= BUTTON_SIZE;
-        if (topRightAlignment is DWT.RIGHT && topRight !is null)
-        {
-            Point rightSize = topRight.computeSize(DWT.DEFAULT, DWT.DEFAULT,
-                    false);
-            tabAreaWidth -= rightSize.x + 3;
-        }
-        if (!simple)
-            tabAreaWidth -= curveWidth - 2 * curveIndent;
-        tabAreaWidth = Math.max(0, tabAreaWidth);
-
-        // First, try the minimum tab size at full compression.
-        int minWidth = 0;
-        int[] minWidths = new int[items.length];
-        for (int i = 0; i < priority.length; i++)
-        {
-            int index = priority[i];
-            minWidths[index] = items[index].preferredWidth(gc,
-                    index is selectedIndex, true);
-            minWidth += minWidths[index];
-            if (minWidth > tabAreaWidth)
-                break;
-        }
-        if (minWidth > tabAreaWidth)
-        {
-            // full compression required and a chevron
-            showChevron = items.length > 1;
-            if (showChevron)
-                tabAreaWidth -= 3 * BUTTON_SIZE / 2;
-            widths = minWidths;
-            int index = selectedIndex !is -1 ? selectedIndex : 0;
-            if (tabAreaWidth < widths[index])
-            {
-                widths[index] = Math.max(0, tabAreaWidth);
+                item.closeRect.y = onBottom ? size.y - borderBottom - tabHeight + (tabHeight - BUTTON_SIZE)/2: borderTop + (tabHeight - BUTTON_SIZE)/2;
+                x = x + item.width;
+                if (!simple && i is selectedIndex) x += curveWidth - 2*curveIndent;
             }
         }
-        else
-        {
-            int maxWidth = 0;
-            int[] maxWidths = new int[items.length];
-            for (int i = 0; i < items.length; i++)
-            {
-                maxWidths[i] = items[i].preferredWidth(gc, i is selectedIndex,
-                        false);
-                maxWidth += maxWidths[i];
-            }
-            if (maxWidth <= tabAreaWidth)
-            {
-                // no compression required
-                widths = maxWidths;
-            }
-            else
-            {
-                // determine compression for each item
-                int extra = (tabAreaWidth - minWidth) / items.length;
-                while (true)
-                {
-                    int large = 0, totalWidth = 0;
-                    for (int i = 0; i < items.length; i++)
-                    {
-                        if (maxWidths[i] > minWidths[i] + extra)
-                        {
-                            totalWidth += minWidths[i] + extra;
-                            large++;
-                        }
-                        else
-                        {
-                            totalWidth += maxWidths[i];
-                        }
-                    }
-                    if (totalWidth >= tabAreaWidth)
-                    {
-                        extra--;
-                        break;
-                    }
-                    if (large is 0 || tabAreaWidth - totalWidth < large)
-                        break;
-                    extra++;
-                }
-                widths = new int[items.length];
-                for (int i = 0; i < items.length; i++)
-                {
-                    widths[i] = Math.min(maxWidths[i], minWidths[i] + extra);
-                }
-            }
-        }
-        gc.dispose();
-
-        for (int i = 0; i < items.length; i++)
-        {
-            CTabItem tab = items[i];
-            int width = widths[i];
-            if (tab.height !is tabHeight || tab.width !is width)
-            {
+    }
+    return changed;
+}
+bool setItemSize() {
+    bool changed = false;
+    if (isDisposed()) return changed;
+    Point size = getSize();
+    if (size.x <= 0 || size.y <= 0) return changed;
+    xClient = borderLeft + marginWidth + highlight_margin;
+    if (onBottom) {
+        yClient = borderTop + highlight_margin + marginHeight;
+    } else {
+        yClient = borderTop + tabHeight + highlight_header + marginHeight;
+    }
+    showChevron = false;
+    if (single) {
+        showChevron = true;
+        if (selectedIndex !is -1) {
+            CTabItem tab = items[selectedIndex];
+            GC gc = new GC(this);
+            int width = tab.preferredWidth(gc, true, false);
+            gc.dispose();
+            width = Math.min(width, getRightItemEdge() - borderLeft);
+            if (tab.height !is tabHeight || tab.width !is width) {
                 changed = true;
                 tab.shortenedText = null;
                 tab.shortenedTextWidth = 0;
                 tab.height = tabHeight;
                 tab.width = width;
                 tab.closeRect.width = tab.closeRect.height = 0;
-                if (showClose || tab.showClose)
-                {
-                    if (i is selectedIndex || showUnselectedClose)
-                    {
-                        tab.closeRect.width = BUTTON_SIZE;
-                        tab.closeRect.height = BUTTON_SIZE;
-                    }
+                if (showClose || tab.showClose) {
+                    tab.closeRect.width = BUTTON_SIZE;
+                    tab.closeRect.height = BUTTON_SIZE;
                 }
             }
         }
         return changed;
     }
 
-    /**
-     * Marks the receiver's maximize button as visible if the argument is <code>true</code>,
-     * and marks it invisible otherwise. 
-     *
-     * @param visible the new visibility state
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setMaximizeVisible (bool visible)
-    {
-        checkWidget();
-        if (showMax is visible)
-            return;
-        // display maximize button
-        showMax = visible;
-        updateItems();
-        redraw();
+    if (items.length is 0) return changed;
+
+    int[] widths;
+    GC gc = new GC(this);
+    int tabAreaWidth = size.x - borderLeft - borderRight - 3;
+    if (showMin) tabAreaWidth -= BUTTON_SIZE;
+    if (showMax) tabAreaWidth -= BUTTON_SIZE;
+    if (topRightAlignment is DWT.RIGHT && topRight !is null) {
+        Point rightSize = topRight.computeSize(DWT.DEFAULT, DWT.DEFAULT, false);
+        tabAreaWidth -= rightSize.x + 3;
+    }
+    if (!simple) tabAreaWidth -= curveWidth - 2*curveIndent;
+    tabAreaWidth = Math.max(0, tabAreaWidth);
+
+    // First, try the minimum tab size at full compression.
+    int minWidth = 0;
+    int[] minWidths = new int[items.length];
+    for (int i = 0; i < priority.length; i++) {
+        int index = priority[i];
+        minWidths[index] = items[index].preferredWidth(gc, index is selectedIndex, true);
+        minWidth += minWidths[index];
+        if (minWidth > tabAreaWidth) break;
+    }
+    if (minWidth > tabAreaWidth) {
+        // full compression required and a chevron
+        showChevron = items.length > 1;
+        if (showChevron) tabAreaWidth -= 3*BUTTON_SIZE/2;
+        widths = minWidths;
+        int index = selectedIndex !is -1 ? selectedIndex : 0;
+        if (tabAreaWidth < widths[index]) {
+            widths[index] = Math.max(0, tabAreaWidth);
+        }
+    } else {
+        int maxWidth = 0;
+        int[] maxWidths = new int[items.length];
+        for (int i = 0; i < items.length; i++) {
+            maxWidths[i] = items[i].preferredWidth(gc, i is selectedIndex, false);
+            maxWidth += maxWidths[i];
+        }
+        if (maxWidth <= tabAreaWidth) {
+            // no compression required
+            widths = maxWidths;
+        } else {
+            // determine compression for each item
+            int extra = (tabAreaWidth - minWidth) / items.length;
+            while (true) {
+                int large = 0, totalWidth = 0;
+                for (int i = 0 ; i < items.length; i++) {
+                    if (maxWidths[i] > minWidths[i] + extra) {
+                        totalWidth += minWidths[i] + extra;
+                        large++;
+                    } else {
+                        totalWidth += maxWidths[i];
+                    }
+                }
+                if (totalWidth >= tabAreaWidth) {
+                    extra--;
+                    break;
+                }
+                if (large is 0 || tabAreaWidth - totalWidth < large) break;
+                extra++;
+            }
+            widths = new int[items.length];
+            for (int i = 0; i < items.length; i++) {
+                widths[i] = Math.min(maxWidths[i], minWidths[i] + extra);
+            }
+        }
+    }
+    gc.dispose();
+
+    for (int i = 0; i < items.length; i++) {
+        CTabItem tab = items[i];
+        int width = widths[i];
+        if (tab.height !is tabHeight || tab.width !is width) {
+            changed = true;
+            tab.shortenedText = null;
+            tab.shortenedTextWidth = 0;
+            tab.height = tabHeight;
+            tab.width = width;
+            tab.closeRect.width = tab.closeRect.height = 0;
+            if (showClose || tab.showClose) {
+                if (i is selectedIndex || showUnselectedClose) {
+                    tab.closeRect.width = BUTTON_SIZE;
+                    tab.closeRect.height = BUTTON_SIZE;
+                }
+            }
+        }
     }
+    return changed;
+}
+/**
+ * Marks the receiver's maximize button as visible if the argument is <code>true</code>,
+ * and marks it invisible otherwise.
+ *
+ * @param visible the new visibility state
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setMaximizeVisible(bool visible) {
+    checkWidget();
+    if (showMax is visible) return;
+    // display maximize button
+    showMax = visible;
+    updateItems();
+    redraw();
+}
+/**
+ * Sets the layout which is associated with the receiver to be
+ * the argument which may be null.
+ * <p>
+ * Note: No Layout can be set on this Control because it already
+ * manages the size and position of its children.
+ * </p>
+ *
+ * @param layout the receiver's new layout or null
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public override void setLayout (Layout layout) {
+    checkWidget();
+    return;
+}
+/**
+ * Sets the maximized state of the receiver.
+ *
+ * @param maximize the new maximized state
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setMaximized(bool maximize) {
+    checkWidget ();
+    if (this.maximized is maximize) return;
+    if (maximize && this.minimized) setMinimized(false);
+    this.maximized = maximize;
+    redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false);
+}
+/**
+ * Marks the receiver's minimize button as visible if the argument is <code>true</code>,
+ * and marks it invisible otherwise.
+ *
+ * @param visible the new visibility state
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setMinimizeVisible(bool visible) {
+    checkWidget();
+    if (showMin is visible) return;
+    // display minimize button
+    showMin = visible;
+    updateItems();
+    redraw();
+}
+/**
+ * Sets the minimized state of the receiver.
+ *
+ * @param minimize the new minimized state
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setMinimized(bool minimize) {
+    checkWidget ();
+    if (this.minimized is minimize) return;
+    if (minimize && this.maximized) setMaximized(false);
+    this.minimized = minimize;
+    redraw(minRect.x, minRect.y, minRect.width, minRect.height, false);
+}
 
-    /**
-     * Sets the layout which is associated with the receiver to be
-     * the argument which may be null.
-     * <p>
-     * Note: No Layout can be set on this Control because it already
-     * manages the size and position of its children.
-     * </p>
-     *
-     * @param layout the receiver's new layout or null
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setLayout (Layout layout)
-    {
-        checkWidget();
+/**
+ * Sets the minimum number of characters that will
+ * be displayed in a fully compressed tab.
+ *
+ * @param count the minimum number of characters that will be displayed in a fully compressed tab
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ *    <li>ERROR_INVALID_RANGE - if the count is less than zero</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setMinimumCharacters(int count) {
+    checkWidget ();
+    if (count < 0) DWT.error(DWT.ERROR_INVALID_RANGE);
+    if (minChars is count) return;
+    minChars = count;
+    if (updateItems()) redrawTabs();
+}
+
+/**
+ * When there is not enough horizontal space to show all the tabs,
+ * by default, tabs are shown sequentially from left to right in
+ * order of their index.  When the MRU visibility is turned on,
+ * the tabs that are visible will be the tabs most recently selected.
+ * Tabs will still maintain their left to right order based on index
+ * but only the most recently selected tabs are visible.
+ * <p>
+ * For example, consider a CTabFolder that contains "Tab 1", "Tab 2",
+ * "Tab 3" and "Tab 4" (in order by index).  The user selects
+ * "Tab 1" and then "Tab 3".  If the CTabFolder is now
+ * compressed so that only two tabs are visible, by default,
+ * "Tab 2" and "Tab 3" will be shown ("Tab 3" since it is currently
+ * selected and "Tab 2" because it is the previous item in index order).
+ * If MRU visibility is enabled, the two visible tabs will be "Tab 1"
+ * and "Tab 3" (in that order from left to right).</p>
+ *
+ * @param show the new visibility state
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setMRUVisible(bool show) {
+    checkWidget();
+    if (mru is show) return;
+    mru = show;
+    if (!mru) {
+        int idx = firstIndex;
+        int next = 0;
+        for (int i = firstIndex; i < items.length; i++) {
+            priority[next++] = i;
+        }
+        for (int i = 0; i < idx; i++) {
+            priority[next++] = i;
+        }
+        if (updateItems()) redrawTabs();
+    }
+}
+/**
+ * Set the selection to the tab at the specified item.
+ *
+ * @param item the tab item to be selected
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ * </ul>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ */
+public void setSelection(CTabItem item) {
+    checkWidget();
+    if (item is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    int index = indexOf(item);
+    setSelection(index);
+}
+/**
+ * Set the selection to the tab at the specified index.
+ *
+ * @param index the index of the tab item to be selected
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setSelection(int index) {
+    checkWidget();
+    if (index < 0 || index >= items.length) return;
+    CTabItem selection = items[index];
+    if (selectedIndex is index) {
+        showItem(selection);
         return;
     }
 
-    /**
-     * Sets the maximized state of the receiver.
-     *
-     * @param maximize the new maximized state
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @since 3.0
-     */
-    public void setMaximized (bool maximize)
-    {
-        checkWidget();
-        if (this.maximized is maximize)
-            return;
-        if (maximize && this.minimized)
-            setMinimized(false);
-        this.maximized = maximize;
-        redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false);
+    int oldIndex = selectedIndex;
+    selectedIndex = index;
+    if (oldIndex !is -1) {
+        items[oldIndex].closeImageState = NONE;
     }
+    selection.closeImageState = NORMAL;
+    selection.showing = false;
 
-    /**
-     * Marks the receiver's minimize button as visible if the argument is <code>true</code>,
-     * and marks it invisible otherwise. 
-     *
-     * @param visible the new visibility state
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setMinimizeVisible (bool visible)
-    {
-        checkWidget();
-        if (showMin is visible)
-            return;
-        // display minimize button
-        showMin = visible;
-        updateItems();
-        redraw();
+    Control newControl = selection.control;
+    Control oldControl = null;
+    if (oldIndex !is -1) {
+        oldControl = items[oldIndex].control;
     }
 
-    /**
-     * Sets the minimized state of the receiver.
-     *
-     * @param minimize the new minimized state
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @since 3.0
-     */
-    public void setMinimized (bool minimize)
-    {
-        checkWidget();
-        if (this.minimized is minimize)
-            return;
-        if (minimize && this.maximized)
-            setMaximized(false);
-        this.minimized = minimize;
-        redraw(minRect.x, minRect.y, minRect.width, minRect.height, false);
+    if (newControl !is oldControl) {
+        if (newControl !is null && !newControl.isDisposed()) {
+            newControl.setBounds(getClientArea());
+            newControl.setVisible(true);
+        }
+        if (oldControl !is null && !oldControl.isDisposed()) {
+            oldControl.setVisible(false);
+        }
+    }
+    showItem(selection);
+    redraw();
+}
+void setSelection(int index, bool notify) {
+    int oldSelectedIndex = selectedIndex;
+    setSelection(index);
+    if (notify && selectedIndex !is oldSelectedIndex && selectedIndex !is -1) {
+        Event event = new Event();
+        event.item = getItem(selectedIndex);
+        notifyListeners(DWT.Selection, event);
+    }
+}
+/**
+ * Sets the receiver's selection background color to the color specified
+ * by the argument, or to the default system color for the control
+ * if the argument is null.
+ *
+ * @param color the new color (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setSelectionBackground (Color color) {
+    checkWidget();
+    setSelectionHighlightGradientColor(null);
+    if (selectionBackground is color) return;
+    if (color is null) color = getDisplay().getSystemColor(SELECTION_BACKGROUND);
+    selectionBackground = color;
+    if (selectedIndex > -1) redraw();
+}
+/**
+ * Specify a gradient of colours to be draw in the background of the selected tab.
+ * For example to draw a gradient that varies from dark blue to blue and then to
+ * white, use the following call to setBackground:
+ * <pre>
+ *  cfolder.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE),
+ *                                 display.getSystemColor(DWT.COLOR_BLUE),
+ *                                 display.getSystemColor(DWT.COLOR_WHITE),
+ *                                 display.getSystemColor(DWT.COLOR_WHITE)},
+ *                     new int[] {25, 50, 100});
+ * </pre>
+ *
+ * @param colors an array of Color that specifies the colors to appear in the gradient
+ *               in order of appearance left to right.  The value <code>null</code> clears the
+ *               background gradient. The value <code>null</code> can be used inside the array of
+ *               Color to specify the background color.
+ * @param percents an array of integers between 0 and 100 specifying the percent of the width
+ *                 of the widget at which the color should change.  The size of the percents array must be one
+ *                 less than the size of the colors array.
+ *
+ * @exception DWTException <ul>
+ *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ *  </ul>
+ */
+public void setSelectionBackground(Color[] colors, int[] percents) {
+    setSelectionBackground(colors, percents, false);
+}
+/**
+ * Specify a gradient of colours to be draw in the background of the selected tab.
+ * For example to draw a vertical gradient that varies from dark blue to blue and then to
+ * white, use the following call to setBackground:
+ * <pre>
+ *  cfolder.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE),
+ *                                 display.getSystemColor(DWT.COLOR_BLUE),
+ *                                 display.getSystemColor(DWT.COLOR_WHITE),
+ *                                 display.getSystemColor(DWT.COLOR_WHITE)},
+ *                        new int[] {25, 50, 100}, true);
+ * </pre>
+ *
+ * @param colors an array of Color that specifies the colors to appear in the gradient
+ *               in order of appearance left to right.  The value <code>null</code> clears the
+ *               background gradient. The value <code>null</code> can be used inside the array of
+ *               Color to specify the background color.
+ * @param percents an array of integers between 0 and 100 specifying the percent of the width
+ *                 of the widget at which the color should change.  The size of the percents array must be one
+ *                 less than the size of the colors array.
+ *
+ * @param vertical indicate the direction of the gradient.  True is vertical and false is horizontal.
+ *
+ * @exception DWTException <ul>
+ *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ *  </ul>
+ *
+ * @since 3.0
+ */
+public void setSelectionBackground(Color[] colors, int[] percents, bool vertical) {
+    checkWidget();
+    int colorsLength;
+    Color highlightBeginColor = null;  //null is no highlight
+
+    if (colors !is null) {
+        //The colors array can optionally have an extra entry which describes the highlight top color
+        //Thus its either one or two larger than the percents array
+        if (percents is null ||
+                ! ((percents.length is colors.length - 1) || (percents.length is colors.length - 2))){
+            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+        }
+        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);
+            }
+        }
+        //If the colors is exactly two more than percents then last is highlight
+        //Keep track of *real* colorsLength (minus the highlight)
+        if(percents.length is colors.length - 2) {
+            highlightBeginColor = colors[colors.length - 1];
+            colorsLength = colors.length - 1;
+        } else {
+            colorsLength = colors.length;
+        }
+        if (getDisplay().getDepth() < 15) {
+            // Don't use gradients on low color displays
+            colors = [colors[colorsLength - 1]];
+            colorsLength = colors.length;
+            percents = null;
+        }
+    } else {
+        colorsLength = 0;
     }
 
-    /**
-     * Sets the minimum number of characters that will 
-     * be displayed in a fully compressed tab.
-     * 
-     * @param count the minimum number of characters that will be displayed in a fully compressed tab
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     *    <li>ERROR_INVALID_RANGE - if the count is less than zero</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setMinimumCharacters (int count)
-    {
-        checkWidget();
-        if (count < 0)
-            DWT.error(DWT.ERROR_INVALID_RANGE);
-        if (minChars is count)
-            return;
-        minChars = count;
-        if (updateItems())
-            redrawTabs();
+    // Are these settings the same as before?
+    if (selectionBgImage is null) {
+        if ((selectionGradientColors !is null) && (colors !is null) &&
+            (selectionGradientColors.length is colorsLength)) {
+            bool same = false;
+            for (int i = 0; i < selectionGradientColors.length; i++) {
+                if (selectionGradientColors[i] is null) {
+                    same = colors[i] is null;
+                } else {
+                    same = cast(bool)(selectionGradientColors[i]==colors[i]);
+                }
+                if (!same) break;
+            }
+            if (same) {
+                for (int i = 0; i < selectionGradientPercents.length; i++) {
+                    same = selectionGradientPercents[i] is percents[i];
+                    if (!same) break;
+                }
+            }
+            if (same && this.selectionGradientVertical is vertical) return;
+        }
+    } else {
+        selectionBgImage = null;
+    }
+    // Store the new settings
+    if (colors is null) {
+        selectionGradientColors = null;
+        selectionGradientPercents = null;
+        selectionGradientVertical = false;
+        setSelectionBackground(cast(Color)null);
+        setSelectionHighlightGradientColor(null);
+    } else {
+        selectionGradientColors = new Color[colorsLength];
+        for (int i = 0; i < colorsLength; ++i) {
+            selectionGradientColors[i] = colors[i];
+        }
+        selectionGradientPercents = new int[percents.length];
+        for (int i = 0; i < percents.length; ++i) {
+            selectionGradientPercents[i] = percents[i];
+        }
+        selectionGradientVertical = vertical;
+        setSelectionBackground(selectionGradientColors[selectionGradientColors.length-1]);
+        setSelectionHighlightGradientColor(highlightBeginColor);
     }
 
-    /**
-     * When there is not enough horizontal space to show all the tabs,
-     * by default, tabs are shown sequentially from left to right in 
-     * order of their index.  When the MRU visibility is turned on,
-     * the tabs that are visible will be the tabs most recently selected.
-     * Tabs will still maintain their left to right order based on index 
-     * but only the most recently selected tabs are visible.
-     * <p>
-     * For example, consider a CTabFolder that contains "Tab 1", "Tab 2",
-     * "Tab 3" and "Tab 4" (in order by index).  The user selects
-     * "Tab 1" and then "Tab 3".  If the CTabFolder is now
-     * compressed so that only two tabs are visible, by default, 
-     * "Tab 2" and "Tab 3" will be shown ("Tab 3" since it is currently 
-     * selected and "Tab 2" because it is the previous item in index order).
-     * If MRU visibility is enabled, the two visible tabs will be "Tab 1"
-     * and "Tab 3" (in that order from left to right).</p>
-     *
-     * @param show the new visibility state
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.1
-     */
-    public void setMRUVisible (bool show)
-    {
-        checkWidget();
-        if (mru is show)
-            return;
-        mru = show;
-        if (!mru)
-        {
-            int idx = firstIndex;
-            int next = 0;
-            for (int i = firstIndex; i < items.length; i++)
-            {
-                priority[next++] = i;
+    // Refresh with the new settings
+    if (selectedIndex > -1) redraw();
+}
+
+/*
+ * Set the color for the highlight start for selected tabs.
+ * Update the cache of highlight gradient colors if required.
+ */
+
+void setSelectionHighlightGradientColor(Color start) {
+    //Set to null to match all the early return cases.
+    //For early returns, don't realloc the cache, we may get a cache hit next time we're given the highlight
+    selectionHighlightGradientBegin = null;
+
+    if(start is null)
+        return;
+
+    //don't bother on low colour
+    if (getDisplay().getDepth() < 15)
+        return;
+
+    //don't bother if we don't have a background gradient
+    if(selectionGradientColors.length < 2)
+        return;
+
+    //OK we know its a valid gradient now
+    selectionHighlightGradientBegin = start;
+
+    if(! isSelectionHighlightColorsCacheHit(start))
+        createSelectionHighlightGradientColors(start);  //if no cache hit then compute new ones
+}
+
+/*
+ * Return true if given start color, the cache of highlight colors we have
+ * would match the highlight colors we'd compute.
+ */
+bool isSelectionHighlightColorsCacheHit(Color start) {
+
+    if(selectionHighlightGradientColorsCache is null)
+        return false;
+
+    //this case should never happen but check to be safe before accessing array indexes
+    if(selectionHighlightGradientColorsCache.length < 2)
+        return false;
+
+    Color highlightBegin = selectionHighlightGradientColorsCache[0];
+    Color highlightEnd = selectionHighlightGradientColorsCache[selectionHighlightGradientColorsCache.length - 1];
+
+    if( highlightBegin!=start)
+        return false;
+
+    //Compare number of colours we have vs. we'd compute
+    if(selectionHighlightGradientColorsCache.length !is tabHeight)
+        return false;
+
+    //Compare existing highlight end to what it would be (selectionBackground)
+    if( highlightEnd!=selectionBackground)
+        return false;
+
+    return true;
+}
+
+/**
+ * Set the image to be drawn in the background of the selected tab.  Image
+ * is stretched or compressed to cover entire selection tab area.
+ *
+ * @param image the image to be drawn in the background
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setSelectionBackground(Image image) {
+    checkWidget();
+    setSelectionHighlightGradientColor(null);
+    if (image is selectionBgImage) return;
+    if (image !is null) {
+        selectionGradientColors = null;
+        selectionGradientPercents = null;
+        disposeSelectionHighlightGradientColors();
+    }
+    selectionBgImage = image;
+    if (selectedIndex > -1) redraw();
+}
+/**
+ * Set the foreground color of the selected tab.
+ *
+ * @param color the color of the text displayed in the selected tab
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setSelectionForeground (Color color) {
+    checkWidget();
+    if (selectionForeground is color) return;
+    if (color is null) color = getDisplay().getSystemColor(SELECTION_FOREGROUND);
+    selectionForeground = color;
+    if (selectedIndex > -1) redraw();
+}
+
+/*
+ * Allocate colors for the highlight line.
+ * Colours will be a gradual blend ranging from to.
+ * Blend length will be tab height.
+ * Recompute this if tab height changes.
+ * Could remain null if there'd be no gradient (start=end or low colour display)
+ */
+void createSelectionHighlightGradientColors(Color start) {
+    disposeSelectionHighlightGradientColors(); //dispose if existing
+
+    if(start is null)  //shouldn't happen but just to be safe
+        return;
+
+    //alloc colours for entire height to ensure it matches wherever we stop drawing
+    int fadeGradientSize = tabHeight;
+
+    RGB from = start.getRGB();
+    RGB to = selectionBackground.getRGB();
+
+    selectionHighlightGradientColorsCache = new Color[fadeGradientSize];
+    int denom = fadeGradientSize - 1;
+
+    for (int i = 0; i < fadeGradientSize; i++) {
+        int propFrom = denom - i;
+        int propTo = i;
+        int red = (to.red * propTo + from.red * propFrom) / denom;
+        int green = (to.green * propTo  + from.green * propFrom) / denom;
+        int blue = (to.blue * propTo  + from.blue * propFrom) / denom;
+        selectionHighlightGradientColorsCache[i] = new Color(getDisplay(), red, green, blue);
+    }
+}
+
+void disposeSelectionHighlightGradientColors() {
+    if(selectionHighlightGradientColorsCache is null)
+        return;
+    for (int i = 0; i < selectionHighlightGradientColorsCache.length; i++) {
+        selectionHighlightGradientColorsCache[i].dispose();
+    }
+    selectionHighlightGradientColorsCache = null;
+}
+
+/*
+ * Return the gradient start color for selected tabs, which is the start of the tab fade
+ * (end is selectionBackground).
+ */
+Color getSelectionBackgroundGradientBegin() {
+    if (selectionGradientColors is null)
+        return getSelectionBackground();
+    if (selectionGradientColors.length is 0)
+        return getSelectionBackground();
+    return selectionGradientColors[0];
+}
+
+/**
+ * Sets the shape that the CTabFolder will use to render itself.
+ *
+ * @param simple <code>true</code> if the CTabFolder should render itself in a simple, traditional style
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setSimple(bool simple) {
+    checkWidget();
+    if (this.simple !is simple) {
+        this.simple = simple;
+        Rectangle rectBefore = getClientArea();
+        updateItems();
+        Rectangle rectAfter = getClientArea();
+        if (rectBefore!=rectAfter) {
+            notifyListeners(DWT.Resize, new Event());
+        }
+        redraw();
+    }
+}
+/**
+ * Sets the number of tabs that the CTabFolder should display
+ *
+ * @param single <code>true</code> if only the selected tab should be displayed otherwise, multiple tabs will be shown.
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setSingle(bool single) {
+    checkWidget();
+    if (this.single !is single) {
+        this.single = single;
+        if (!single) {
+            for (int i = 0; i < items.length; i++) {
+                if (i !is selectedIndex && items[i].closeImageState is NORMAL) {
+                    items[i].closeImageState = NONE;
+                }
             }
-            for (int i = 0; i < idx; i++)
-            {
-                priority[next++] = i;
-            }
-            if (updateItems())
-                redrawTabs();
+        }
+        Rectangle rectBefore = getClientArea();
+        updateItems();
+        Rectangle rectAfter = getClientArea();
+        if (rectBefore!=rectAfter) {
+            notifyListeners(DWT.Resize, new Event());
+        }
+        redraw();
+    }
+}
+/**
+ * Specify a fixed height for the tab items.  If no height is specified,
+ * the default height is the height of the text or the image, whichever
+ * is greater. Specifying a height of -1 will revert to the default height.
+ *
+ * @param height the pixel value of the height or -1
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if called with a height of less than 0</li>
+ * </ul>
+ */
+public void setTabHeight(int height) {
+    checkWidget();
+    if (height < -1) {
+        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    fixedTabHeight = height;
+    updateTabHeight(false);
+}
+/**
+ * Specify whether the tabs should appear along the top of the folder
+ * or along the bottom of the folder.
+ *
+ * @param position <code>DWT.TOP</code> for tabs along the top or <code>DWT.BOTTOM</code> for tabs along the bottom
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the position value is not either DWT.TOP or DWT.BOTTOM</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setTabPosition(int position) {
+    checkWidget();
+    if (position !is DWT.TOP && position !is DWT.BOTTOM) {
+        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    if (onBottom !is (position is DWT.BOTTOM)) {
+        onBottom = position is DWT.BOTTOM;
+        borderTop = onBottom ? borderLeft : 0;
+        borderBottom = onBottom ? 0 : borderRight;
+        updateTabHeight(true);
+        Rectangle rectBefore = getClientArea();
+        updateItems();
+        Rectangle rectAfter = getClientArea();
+        if (rectBefore!=rectAfter) {
+            notifyListeners(DWT.Resize, new Event());
+        }
+        redraw();
+    }
+}
+/**
+ * Set the control that appears in the top right corner of the tab folder.
+ * Typically this is a close button or a composite with a Menu and close button.
+ * The topRight control is optional.  Setting the top right control to null will
+ * remove it from the tab folder.
+ *
+ * @param control the control to be displayed in the top right corner or null
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the control is not a child of this CTabFolder</li>
+ * </ul>
+ *
+ * @since 2.1
+ */
+public void setTopRight(Control control) {
+    setTopRight(control, DWT.RIGHT);
+}
+/**
+ * Set the control that appears in the top right corner of the tab folder.
+ * Typically this is a close button or a composite with a Menu and close button.
+ * The topRight control is optional.  Setting the top right control to null
+ * will remove it from the tab folder.
+ * <p>
+ * The alignment parameter sets the layout of the control in the tab area.
+ * <code>DWT.RIGHT</code> will cause the control to be positioned on the far
+ * right of the folder and it will have its default size.  <code>DWT.FILL</code>
+ * will size the control to fill all the available space to the right of the
+ * last tab.  If there is no available space, the control will not be visible.
+ * </p>
+ *
+ * @param control the control to be displayed in the top right corner or null
+ * @param alignment <code>DWT.RIGHT</code> or <code>DWT.FILL</code>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the control is not a child of this CTabFolder</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setTopRight(Control control, int alignment) {
+    checkWidget();
+    if (alignment !is DWT.RIGHT && alignment !is DWT.FILL) {
+        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    if (control !is null && control.getParent() !is this) {
+        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    topRight = control;
+    topRightAlignment = alignment;
+    if (updateItems()) redraw();
+}
+/**
+ * Specify whether the close button appears
+ * when the user hovers over an unselected tabs.
+ *
+ * @param visible <code>true</code> makes the close button appear
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setUnselectedCloseVisible(bool visible) {
+    checkWidget();
+    if (showUnselectedClose is visible) return;
+    // display close button when mouse hovers
+    showUnselectedClose = visible;
+    updateItems();
+    redraw();
+}
+/**
+ * Specify whether the image appears on unselected tabs.
+ *
+ * @param visible <code>true</code> makes the image appear
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setUnselectedImageVisible(bool visible) {
+    checkWidget();
+    if (showUnselectedImage is visible) return;
+    // display image on unselected items
+    showUnselectedImage = visible;
+    updateItems();
+    redraw();
+}
+/**
+ * Shows the item.  If the item is already showing in the receiver,
+ * this method simply returns.  Otherwise, the items are scrolled until
+ * the item is visible.
+ *
+ * @param item the item to be shown
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see CTabFolder#showSelection()
+ *
+ * @since 2.0
+ */
+public void showItem (CTabItem item) {
+    checkWidget();
+    if (item is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    if (item.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    int index = indexOf(item);
+    if (index is -1) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    int idx = -1;
+    for (int i = 0; i < priority.length; i++) {
+        if (priority[i] is index) {
+            idx = i;
+            break;
         }
     }
-
-    /**
-     * Set the selection to the tab at the specified item.
-     * 
-     * @param item the tab item to be selected
-     * 
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
-     * </ul>
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     * </ul>
-     */
-    public void setSelection (CTabItem item)
-    {
-        checkWidget();
-        if (item is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        int index = indexOf(item);
-        setSelection(index);
+    if (mru) {
+        // move to front of mru order
+        int[] newPriority = new int[priority.length];
+        System.arraycopy(priority, 0, newPriority, 1, idx);
+        System.arraycopy(priority, idx+1, newPriority, idx+1, priority.length - idx - 1);
+        newPriority[0] = index;
+        priority = newPriority;
+    }
+    if (item.isShowing()) return;
+    updateItems(index);
+    redrawTabs();
+}
+void showList (Rectangle rect) {
+    if (items.length is 0 || !showChevron) return;
+    if (showMenu is null || showMenu.isDisposed()) {
+        showMenu = new Menu(this);
+    } else {
+        MenuItem[] items = showMenu.getItems();
+        for (int i = 0; i < items.length; i++) {
+            items[i].dispose();
+        }
     }
+    static const String id = "CTabFolder_showList_Index"; //$NON-NLS-1$
+    for (int i = 0; i < items.length; i++) {
+        CTabItem tab = items[i];
+        if (tab.showing) continue;
+        MenuItem item = new MenuItem(showMenu, DWT.NONE);
+        item.setText(tab.getText());
+        item.setImage(tab.getImage());
+        item.setData(id, tab);
+        item.addSelectionListener(new class() SelectionAdapter {
+            public void widgetSelected(SelectionEvent e) {
+                MenuItem menuItem = cast(MenuItem)e.widget;
+                int index = indexOf(cast(CTabItem)menuItem.getData(id));
+                this.outer.setSelection(index, true);
+            }
+        });
+    }
+    int x = rect.x;
+    int y = rect.y + rect.height;
+    Point location = getDisplay().map(this, null, x, y);
+    showMenu.setLocation(location.x, location.y);
+    showMenu.setVisible(true);
+}
+/**
+ * Shows the selection.  If the selection is already showing in the receiver,
+ * this method simply returns.  Otherwise, the items are scrolled until
+ * the selection is visible.
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see CTabFolder#showItem(CTabItem)
+ *
+ * @since 2.0
+ */
+public void showSelection () {
+    checkWidget ();
+    if (selectedIndex !is -1) {
+        showItem(getSelection());
+    }
+}
 
-    /**
-     * Set the selection to the tab at the specified index.
-     * 
-     * @param index the index of the tab item to be selected
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setSelection (int index)
-    {
-        checkWidget();
-        if (index < 0 || index >= items.length)
-            return;
-        CTabItem selection = items[index];
-        if (selectedIndex is index)
-        {
-            showItem(selection);
-            return;
-        }
+void _setToolTipText (int x, int y) {
+    String oldTip = getToolTipText();
+    String newTip = _getToolTip(x, y);
+    if (newTip is null || newTip!=oldTip) {
+        setToolTipText(newTip);
+    }
+}
 
-        int oldIndex = selectedIndex;
-        selectedIndex = index;
-        if (oldIndex !is -1)
-        {
-            items[oldIndex].closeImageState = NONE;
-        }
-        selection.closeImageState = NORMAL;
-        selection.showing = false;
+bool updateItems() {
+    return updateItems(selectedIndex);
+}
 
-        Control newControl = selection.control;
-        Control oldControl = null;
-        if (oldIndex !is -1)
-        {
-            oldControl = items[oldIndex].control;
-        }
-
-        if (newControl !is oldControl)
-        {
-            if (newControl !is null && !newControl.isDisposed())
-            {
-                newControl.setBounds(getClientArea());
-                newControl.setVisible(true);
+bool updateItems(int showIndex) {
+    if (!single && !mru && showIndex !is -1) {
+        // make sure selected item will be showing
+        int firstIndex = showIndex;
+        if (priority[0] < showIndex) {
+            int maxWidth = getRightItemEdge() - borderLeft;
+            if (!simple) maxWidth -= curveWidth - 2*curveIndent;
+            int width = 0;
+            int[] widths = new int[items.length];
+            GC gc = new GC(this);
+            for (int i = priority[0]; i <= showIndex; i++) {
+                widths[i] = items[i].preferredWidth(gc, i is selectedIndex, true);
+                width += widths[i];
+                if (width > maxWidth) break;
             }
-            if (oldControl !is null && !oldControl.isDisposed())
-            {
-                oldControl.setVisible(false);
+            if (width > maxWidth) {
+                width = 0;
+                for (int i = showIndex; i >= 0; i--) {
+                    if (widths[i] is 0) widths[i] = items[i].preferredWidth(gc, i is selectedIndex, true);
+                    width += widths[i];
+                    if (width > maxWidth) break;
+                    firstIndex = i;
+                }
+            } else {
+                firstIndex = priority[0];
+                for (int i = showIndex + 1; i < items.length; i++) {
+                    widths[i] = items[i].preferredWidth(gc, i is selectedIndex, true);
+                    width += widths[i];
+                    if (width >= maxWidth) break;
+                }
+                if (width < maxWidth) {
+                    for (int i = priority[0] - 1; i >= 0; i--) {
+                        if (widths[i] is 0) widths[i] = items[i].preferredWidth(gc, i is selectedIndex, true);
+                        width += widths[i];
+                        if (width > maxWidth) break;
+                        firstIndex = i;
+                    }
+                }
             }
+            gc.dispose();
         }
-        showItem(selection);
-        redraw();
-    }
-
-    void setSelection (int index, bool notify)
-    {
-        int oldSelectedIndex = selectedIndex;
-        setSelection(index);
-        if (notify && selectedIndex !is oldSelectedIndex && selectedIndex !is -1)
-        {
-            Event event = new Event();
-            event.item = getItem(selectedIndex);
-            notifyListeners(DWT.Selection, event);
+        if (firstIndex !is priority[0]) {
+            int index = 0;
+            for (int i = firstIndex; i < items.length; i++) {
+                priority[index++] = i;
+            }
+            for (int i = 0; i < firstIndex; i++) {
+                priority[index++] = i;
+            }
         }
     }
 
-    /**
-     * Sets the receiver's selection background color to the color specified
-     * by the argument, or to the default system color for the control
-     * if the argument is null.
-     *
-     * @param color the new color (or null)
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> 
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @since 3.0
-     */
-    public void setSelectionBackground (Color color)
-    {
-        checkWidget();
-        setSelectionHighlightGradientColor(null);
-        if (selectionBackground is color)
-            return;
-        if (color is null)
-            color = getDisplay().getSystemColor(SELECTION_BACKGROUND);
-        selectionBackground = color;
-        if (selectedIndex > -1)
-            redraw();
-    }
-
-    /**
-     * Specify a gradient of colours to be draw in the background of the selected tab.
-     * For example to draw a gradient that varies from dark blue to blue and then to
-     * white, use the following call to setBackground:
-     * <pre>
-     *  cfolder.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE), 
-     *                                 display.getSystemColor(DWT.COLOR_BLUE),
-     *                                 display.getSystemColor(DWT.COLOR_WHITE), 
-     *                                 display.getSystemColor(DWT.COLOR_WHITE)},
-     *                     new int[] {25, 50, 100});
-     * </pre>
-     *
-     * @param colors an array of Color that specifies the colors to appear in the gradient 
-     *               in order of appearance left to right.  The value <code>null</code> clears the
-     *               background gradient. The value <code>null</code> can be used inside the array of 
-     *               Color to specify the background color.
-     * @param percents an array of integers between 0 and 100 specifying the percent of the width 
-     *                 of the widget at which the color should change.  The size of the percents array must be one 
-     *                 less than the size of the colors array.
-     * 
-     * @exception DWTException <ul>
-     *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     *  </ul>
-     */
-    public void setSelectionBackground (Color[] colors, int[] percents)
-    {
-        setSelectionBackground(colors, percents, false);
+    bool oldShowChevron = showChevron;
+    bool changed = setItemSize();
+    changed |= setItemLocation();
+    setButtonBounds();
+    changed |= showChevron !is oldShowChevron;
+    if (changed && getToolTipText() !is null) {
+        Point pt = getDisplay().getCursorLocation();
+        pt = toControl(pt);
+        _setToolTipText(pt.x, pt.y);
     }
-
-    /**
-     * Specify a gradient of colours to be draw in the background of the selected tab.
-     * For example to draw a vertical gradient that varies from dark blue to blue and then to
-     * white, use the following call to setBackground:
-     * <pre>
-     *  cfolder.setBackground(new Color[]{display.getSystemColor(DWT.COLOR_DARK_BLUE), 
-     *                                 display.getSystemColor(DWT.COLOR_BLUE),
-     *                                 display.getSystemColor(DWT.COLOR_WHITE), 
-     *                                 display.getSystemColor(DWT.COLOR_WHITE)},
-     *                        new int[] {25, 50, 100}, true);
-     * </pre>
-     *
-     * @param colors an array of Color that specifies the colors to appear in the gradient 
-     *               in order of appearance left to right.  The value <code>null</code> clears the
-     *               background gradient. The value <code>null</code> can be used inside the array of 
-     *               Color to specify the background color.
-     * @param percents an array of integers between 0 and 100 specifying the percent of the width 
-     *                 of the widget at which the color should change.  The size of the percents array must be one 
-     *                 less than the size of the colors array.
-     * 
-     * @param vertical indicate the direction of the gradient.  True is vertical and false is horizontal. 
-     * 
-     * @exception DWTException <ul>
-     *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
-     *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
-     *  </ul>
-     *
-     * @since 3.0
-     */
-    public void setSelectionBackground (Color[] colors, int[] percents,
-            bool vertical)
-    {
-        checkWidget();
-        int colorsLength;
-        Color highlightBeginColor = null; //null is no highlight
-
-        if (colors !is null)
-        {
-            //The colors array can optionally have an extra entry which describes the highlight top color
-            //Thus its either one or two larger than the percents array
-            if (percents is null || !((percents.length is colors.length - 1) || (percents.length is colors.length - 2)))
-            {
-                DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-            }
-            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);
-                }
-            }
-            //If the colors is exactly two more than percents then last is highlight
-            //Keep track of *real* colorsLength (minus the highlight)
-            if (percents.length is colors.length - 2)
-            {
-                highlightBeginColor = colors[colors.length - 1];
-                colorsLength = colors.length - 1;
-            }
-            else
-            {
-                colorsLength = colors.length;
-            }
-            if (getDisplay().getDepth() < 15)
-            {
-                // Don't use gradients on low color displays
-                colors = new Color[][colors[colorsLength - 1]];
-                colorsLength = colors.length;
-                percents = new int[][];
-            }
-        }
-        else
-        {
-            colorsLength = 0;
-        }
-
-        // Are these settings the same as before?
-        if (selectionBgImage is null)
-        {
-            if ((selectionGradientColors !is null) && (colors !is null) && (selectionGradientColors.length is colorsLength))
-            {
-                bool same = false;
-                for (int i = 0; i < selectionGradientColors.length; i++)
-                {
-                    if (selectionGradientColors[i] is null)
-                    {
-                        same = colors[i] is null;
-                    }
-                    else
-                    {
-                        same = selectionGradientColors[i].opEquals(colors[i]);
-                    }
-                    if (!same)
-                        break;
-                }
-                if (same)
-                {
-                    for (int i = 0; i < selectionGradientPercents.length; i++)
-                    {
-                        same = selectionGradientPercents[i] is percents[i];
-                        if (!same)
-                            break;
-                    }
-                }
-                if (same && this.selectionGradientVertical is vertical)
-                    return;
+    return changed;
+}
+bool updateTabHeight(bool force){
+    int style = getStyle();
+    if (fixedTabHeight is 0 && (style & DWT.FLAT) !is 0 && (style & DWT.BORDER) is 0) highlight_header = 0;
+    int oldHeight = tabHeight;
+    if (fixedTabHeight !is DWT.DEFAULT) {
+        tabHeight = fixedTabHeight is 0 ? 0 : fixedTabHeight + 1; // +1 for line drawn across top of tab
+    } else {
+        int tempHeight = 0;
+        GC gc = new GC(this);
+        if (items.length is 0) {
+            tempHeight = gc.textExtent("Default", CTabItem.FLAGS).y + CTabItem.TOP_MARGIN + CTabItem.BOTTOM_MARGIN; //$NON-NLS-1$
+        } else {
+            for (int i=0; i < items.length; i++) {
+                tempHeight = Math.max(tempHeight, items[i].preferredHeight(gc));
             }
         }
-        else
-        {
-            selectionBgImage = null;
-        }
-        // Store the new settings
-        if (colors is null)
-        {
-            selectionGradientColors = null;
-            selectionGradientPercents = null;
-            selectionGradientVertical = false;
-            setSelectionBackground(cast(Color) null);
-            setSelectionHighlightGradientColor(null);
-        }
-        else
-        {
-            selectionGradientColors = new Color[colorsLength];
-            for (int i = 0; i < colorsLength; ++i)
-            {
-                selectionGradientColors[i] = colors[i];
-            }
-            selectionGradientPercents = new int[percents.length];
-            for (int i = 0; i < percents.length; ++i)
-            {
-                selectionGradientPercents[i] = percents[i];
-            }
-            selectionGradientVertical = vertical;
-            setSelectionBackground(
-                    selectionGradientColors[selectionGradientColors.length - 1]);
-            setSelectionHighlightGradientColor(highlightBeginColor);
-        }
-
-        // Refresh with the new settings
-        if (selectedIndex > -1)
-            redraw();
-    }
-
-    /*
-     * Set the color for the highlight start for selected tabs.
-     * Update the cache of highlight gradient colors if required.
-     */
-
-    void setSelectionHighlightGradientColor (Color start)
-    {
-        //Set to null to match all the early return cases.
-        //For early returns, don't realloc the cache, we may get a cache hit next time we're given the highlight
-        selectionHighlightGradientBegin = null;
-
-        if (start is null)
-            return;
-
-        //don't bother on low colour
-        if (getDisplay().getDepth() < 15)
-            return;
-
-        //don't bother if we don't have a background gradient
-        if (selectionGradientColors.length < 2)
-            return;
-
-        //OK we know its a valid gradient now
-        selectionHighlightGradientBegin = start;
-
-        if (!isSelectionHighlightColorsCacheHit(start))
-            createSelectionHighlightGradientColors(start); //if no cache hit then compute new ones
+        gc.dispose();
+        tabHeight =  tempHeight;
     }
-
-    /*
-     * Return true if given start color, the cache of highlight colors we have
-     * would match the highlight colors we'd compute.
-     */
-    bool isSelectionHighlightColorsCacheHit (Color start)
-    {
-
-        if (selectionHighlightGradientColorsCache is null)
-            return false;
-
-        //this case should never happen but check to be safe before accessing array indexes
-        if (selectionHighlightGradientColorsCache.length < 2)
-            return false;
-
-        Color highlightBegin = selectionHighlightGradientColorsCache[0];
-        Color
-                highlightEnd = selectionHighlightGradientColorsCache[selectionHighlightGradientColorsCache.length - 1];
-
-        if (!highlightBegin.opEquals(start))
-            return false;
-
-        //Compare number of colours we have vs. we'd compute
-        if (selectionHighlightGradientColorsCache.length !is tabHeight)
-            return false;
-
-        //Compare existing highlight end to what it would be (selectionBackground)
-        if (!highlightEnd.opEquals(selectionBackground))
-            return false;
-
-        return true;
-    }
-
-    /**
-     * Set the image to be drawn in the background of the selected tab.  Image
-     * is stretched or compressed to cover entire selection tab area.
-     * 
-     * @param image the image to be drawn in the background
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setSelectionBackground (Image image)
-    {
-        checkWidget();
-        setSelectionHighlightGradientColor(null);
-        if (image is selectionBgImage)
-            return;
-        if (image !is null)
-        {
-            selectionGradientColors = null;
-            selectionGradientPercents = null;
-            disposeSelectionHighlightGradientColors();
-        }
-        selectionBgImage = image;
-        if (selectedIndex > -1)
-            redraw();
-    }
-
-    /**
-     * Set the foreground color of the selected tab.
-     * 
-     * @param color the color of the text displayed in the selected tab
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setSelectionForeground (Color color)
-    {
-        checkWidget();
-        if (selectionForeground is color)
-            return;
-        if (color is null)
-            color = getDisplay().getSystemColor(SELECTION_FOREGROUND);
-        selectionForeground = color;
-        if (selectedIndex > -1)
-            redraw();
-    }
-
-    /*
-     * Allocate colors for the highlight line.
-     * Colours will be a gradual blend ranging from to.
-     * Blend length will be tab height.
-     * Recompute this if tab height changes.
-     * Could remain null if there'd be no gradient (start=end or low colour display)
-     */
-    void createSelectionHighlightGradientColors (Color start)
-    {
-        disposeSelectionHighlightGradientColors(); //dispose if existing
-
-        if (start is null)
-            //shouldn't happen but just to be safe
-            return;
-
-        //alloc colours for entire height to ensure it matches wherever we stop drawing
-        int fadeGradientSize = tabHeight;
-
-        RGB from = start.getRGB();
-        RGB to = selectionBackground.getRGB();
-
-        selectionHighlightGradientColorsCache = new Color[fadeGradientSize];
-        int denom = fadeGradientSize - 1;
+    if (!force && tabHeight is oldHeight) return false;
 
-        for (int i = 0; i < fadeGradientSize; i++)
-        {
-            int propFrom = denom - i;
-            int propTo = i;
-            int red = (to.red * propTo + from.red * propFrom) / denom;
-            int green = (to.green * propTo + from.green * propFrom) / denom;
-            int blue = (to.blue * propTo + from.blue * propFrom) / denom;
-            selectionHighlightGradientColorsCache[i] = new Color(getDisplay(),
-                    red, green, blue);
-        }
-    }
-
-    void disposeSelectionHighlightGradientColors ()
-    {
-        if (selectionHighlightGradientColorsCache is null)
-            return;
-        for (int i = 0; i < selectionHighlightGradientColorsCache.length; i++)
-        {
-            selectionHighlightGradientColorsCache[i].dispose();
-        }
-        selectionHighlightGradientColorsCache = null;
-    }
-
-    /*
-     * Return the gradient start color for selected tabs, which is the start of the tab fade
-     * (end is selectionBackground).
-     */
-    Color getSelectionBackgroundGradientBegin ()
-    {
-        if (selectionGradientColors is null)
-            return getSelectionBackground();
-        if (selectionGradientColors.length is 0)
-            return getSelectionBackground();
-        return selectionGradientColors[0];
-    }
-
-    /**
-     * Sets the shape that the CTabFolder will use to render itself.  
-     * 
-     * @param simple <code>true</code> if the CTabFolder should render itself in a simple, traditional style
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @since 3.0
-     */
-    public void setSimple (bool simple)
-    {
-        checkWidget();
-        if (this.simple !is simple)
-        {
-            this.simple = simple;
-            Rectangle rectBefore = getClientArea();
-            updateItems();
-            Rectangle rectAfter = getClientArea();
-            if (!rectBefore.opEquals(rectAfter))
-            {
-                notifyListeners(DWT.Resize, new Event());
-            }
-            redraw();
-        }
-    }
-
-    /**
-     * Sets the number of tabs that the CTabFolder should display
-     * 
-     * @param single <code>true</code> if only the selected tab should be displayed otherwise, multiple tabs will be shown.
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setSingle (bool single)
-    {
-        checkWidget();
-        if (this.single !is single)
-        {
-            this.single = single;
-            if (!single)
-            {
-                for (int i = 0; i < items.length; i++)
-                {
-                    if (i !is selectedIndex && items[i].closeImageState is NORMAL)
-                    {
-                        items[i].closeImageState = NONE;
-                    }
-                }
-            }
-            Rectangle rectBefore = getClientArea();
-            updateItems();
-            Rectangle rectAfter = getClientArea();
-            if (!rectBefore.opEquals(rectAfter))
-            {
-                notifyListeners(DWT.Resize, new Event());
-            }
-            redraw();
-        }
-    }
-
-    /**
-     * Specify a fixed height for the tab items.  If no height is specified,
-     * the default height is the height of the text or the image, whichever 
-     * is greater. Specifying a height of -1 will revert to the default height.
-     * 
-     * @param height the pixel value of the height or -1
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if called with a height of less than 0</li>
-     * </ul>
-     */
-    public void setTabHeight (int height)
-    {
-        checkWidget();
-        if (height < -1)
-        {
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }
-        fixedTabHeight = height;
-        updateTabHeight(false);
-    }
-
-    /**
-     * Specify whether the tabs should appear along the top of the folder 
-     * or along the bottom of the folder.
-     * 
-     * @param position <code>DWT.TOP</code> for tabs along the top or <code>DWT.BOTTOM</code> for tabs along the bottom
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if the position value is not either DWT.TOP or DWT.BOTTOM</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setTabPosition (int position)
-    {
-        checkWidget();
-        if (position !is DWT.TOP && position !is DWT.BOTTOM)
-        {
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }
-        if (onBottom !is (position is DWT.BOTTOM))
-        {
-            onBottom = position is DWT.BOTTOM;
-            borderTop = onBottom ? borderLeft : 0;
-            borderBottom = onBottom ? 0 : borderRight;
-            updateTabHeight(true);
-            Rectangle rectBefore = getClientArea();
-            updateItems();
-            Rectangle rectAfter = getClientArea();
-            if (!rectBefore.opEquals(rectAfter))
-            {
-                notifyListeners(DWT.Resize, new Event());
-            }
-            redraw();
-        }
-    }
-
-    /**
-     * Set the control that appears in the top right corner of the tab folder.
-     * Typically this is a close button or a composite with a Menu and close button. 
-     * The topRight control is optional.  Setting the top right control to null will 
-     * remove it from the tab folder.
-     * 
-     * @param control the control to be displayed in the top right corner or null
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if the control is not a child of this CTabFolder</li>
-     * </ul>
-     * 
-     * @since 2.1
-     */
-    public void setTopRight (Control control)
-    {
-        setTopRight(control, DWT.RIGHT);
-    }
+    oldSize = null;
+    if (onBottom) {
+        int d = tabHeight - 12;
+        curve = [0,13+d, 0,12+d, 2,12+d, 3,11+d, 5,11+d, 6,10+d, 7,10+d, 9,8+d, 10,8+d,
+                          11,7+d, 11+d,7,
+                          12+d,6, 13+d,6, 15+d,4, 16+d,4, 17+d,3, 19+d,3, 20+d,2, 22+d,2, 23+d,1];
+        curveWidth = 26+d;
+        curveIndent = curveWidth/3;
+    } else {
+        int d = tabHeight - 12;
+        curve = [0,0, 0,1, 2,1, 3,2, 5,2, 6,3, 7,3, 9,5, 10,5,
+                          11,6, 11+d,6+d,
+                          12+d,7+d, 13+d,7+d, 15+d,9+d, 16+d,9+d, 17+d,10+d, 19+d,10+d, 20+d,11+d, 22+d,11+d, 23+d,12+d];
+        curveWidth = 26+d;
+        curveIndent = curveWidth/3;
 
-    /**
-     * Set the control that appears in the top right corner of the tab folder.
-     * Typically this is a close button or a composite with a Menu and close button. 
-     * The topRight control is optional.  Setting the top right control to null 
-     * will remove it from the tab folder.
-     * <p>
-     * The alignment parameter sets the layout of the control in the tab area.
-     * <code>DWT.RIGHT</code> will cause the control to be positioned on the far 
-     * right of the folder and it will have its default size.  <code>DWT.FILL</code> 
-     * will size the control to fill all the available space to the right of the
-     * last tab.  If there is no available space, the control will not be visible.
-     * </p>
-     *
-     * @param control the control to be displayed in the top right corner or null
-     * @param alignment <code>DWT.RIGHT</code> or <code>DWT.FILL</code> 
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if the control is not a child of this CTabFolder</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setTopRight (Control control, int alignment)
-    {
-        checkWidget();
-        if (alignment !is DWT.RIGHT && alignment !is DWT.FILL)
-        {
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }
-        if (control !is null && control.getParent() !is this)
-        {
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }
-        topRight = control;
-        topRightAlignment = alignment;
-        if (updateItems())
-            redraw();
-    }
-
-    /**
-     * Specify whether the close button appears 
-     * when the user hovers over an unselected tabs.
-     * 
-     * @param visible <code>true</code> makes the close button appear
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setUnselectedCloseVisible (bool visible)
-    {
-        checkWidget();
-        if (showUnselectedClose is visible)
-            return;
-        // display close button when mouse hovers
-        showUnselectedClose = visible;
-        updateItems();
-        redraw();
-    }
-
-    /**
-     * Specify whether the image appears on unselected tabs.
-     * 
-     * @param visible <code>true</code> makes the image appear
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setUnselectedImageVisible (bool visible)
-    {
-        checkWidget();
-        if (showUnselectedImage is visible)
-            return;
-        // display image on unselected items
-        showUnselectedImage = visible;
-        updateItems();
-        redraw();
-    }
-
-    /**
-     * Shows the item.  If the item is already showing in the receiver,
-     * this method simply returns.  Otherwise, the items are scrolled until
-     * the item is visible.
-     * 
-     * @param item the item to be shown
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
-     *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see CTabFolder#showSelection()
-     *
-     * @since 2.0
-     */
-    public void showItem (CTabItem item)
-    {
-        checkWidget();
-        if (item is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        if (item.isDisposed())
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        int index = indexOf(item);
-        if (index is -1)
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        int idx = -1;
-        for (int i = 0; i < priority.length; i++)
-        {
-            if (priority[i] is index)
-            {
-                idx = i;
-                break;
-            }
-        }
-        if (mru)
-        {
-            // move to front of mru order
-            int[] newPriority = new int[priority.length];
-            System.arraycopy(priority, 0, newPriority, 1, idx);
-            System.arraycopy(priority, idx + 1, newPriority, idx + 1,
-                    priority.length - idx - 1);
-            newPriority[0] = index;
-            priority = newPriority;
-        }
-        if (item.isShowing())
-            return;
-        updateItems(index);
-        redrawTabs();
-    }
-
-    void showList (Rectangle rect)
-    {
-        if (items.length is 0 || !showChevron)
-            return;
-        if (showMenu is null || showMenu.isDisposed())
-        {
-            showMenu = new Menu(this);
-        }
-        else
-        {
-            MenuItem[] items = showMenu.getItems();
-            for (int i = 0; i < items.length; i++)
-            {
-                items[i].dispose();
-            }
-        }
-        const String id = "CTabFolder_showList_Index"; //$NON-NLS-1$
-        for (int i = 0; i < items.length; i++)
-        {
-            CTabItem tab = items[i];
-            if (tab.showing)
-                continue;
-            MenuItem item = new MenuItem(showMenu, DWT.NONE);
-            item.setText(tab.getText());
-            item.setImage(tab.getImage());
-            item.setData(id, tab);
-            item.addSelectionListener(new class SelectionAdapter
-            {
-                public void widgetSelected (SelectionEvent e)
-                {
-                    MenuItem menuItem = cast(MenuItem) e.widget;
-                    int index = indexOf(cast(CTabItem) menuItem.getData(id));
-                    this.setSelection(index, true);
-                }
-            });
-        }
-        int x = rect.x;
-        int y = rect.y + rect.height;
-        Point location = getDisplay().map(this, null, x, y);
-        showMenu.setLocation(location.x, location.y);
-        showMenu.setVisible(true);
-    }
+        //this could be static but since values depend on curve, better to keep in one place
+        topCurveHighlightStart = [
+                0, 2,  1, 2,  2, 2,
+                3, 3,  4, 3,  5, 3,
+                6, 4,  7, 4,
+                8, 5,
+                9, 6, 10, 6];
 
-    /**
-     * Shows the selection.  If the selection is already showing in the receiver,
-     * this method simply returns.  Otherwise, the items are scrolled until
-     * the selection is visible.
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     *
-     * @see CTabFolder#showItem(CTabItem)
-     * 
-     * @since 2.0
-     */
-    public void showSelection ()
-    {
-        checkWidget();
-        if (selectedIndex !is -1)
-        {
-            showItem(getSelection());
-        }
-    }
-
-    void _setToolTipText (int x, int y)
-    {
-        String oldTip = getToolTipText();
-        String newTip = _getToolTip(x, y);
-        if (newTip is null || !newTip.opEquals(oldTip))
-        {
-            setToolTipText(newTip);
-        }
-    }
-
-    bool updateItems ()
-    {
-        return updateItems(selectedIndex);
+        //also, by adding in 'd' here we save some math cost when drawing the curve
+        topCurveHighlightEnd = [
+                10+d, 6+d,
+                11+d, 7+d,
+                12+d, 8+d,  13+d, 8+d,
+                14+d, 9+d,
+                15+d, 10+d,  16+d, 10+d,
+                17+d, 11+d,  18+d, 11+d,  19+d, 11+d,
+                20+d, 12+d,  21+d, 12+d,  22+d,  12+d ];
     }
-
-    bool updateItems (int showIndex)
-    {
-        if (!single && !mru && showIndex !is -1)
-        {
-            // make sure selected item will be showing
-            int firstIndex = showIndex;
-            if (priority[0] < showIndex)
-            {
-                int maxWidth = getRightItemEdge() - borderLeft;
-                if (!simple)
-                    maxWidth -= curveWidth - 2 * curveIndent;
-                int width = 0;
-                int[] widths = new int[items.length];
-                GC gc = new GC(this);
-                for (int i = priority[0]; i <= showIndex; i++)
-                {
-                    widths[i] = items[i].preferredWidth(gc, i is selectedIndex,
-                            true);
-                    width += widths[i];
-                    if (width > maxWidth)
-                        break;
-                }
-                if (width > maxWidth)
-                {
-                    width = 0;
-                    for (int i = showIndex; i >= 0; i--)
-                    {
-                        if (widths[i] is 0)
-                            widths[i] = items[i].preferredWidth(gc,
-                                    i is selectedIndex, true);
-                        width += widths[i];
-                        if (width > maxWidth)
-                            break;
-                        firstIndex = i;
-                    }
-                }
-                else
-                {
-                    firstIndex = priority[0];
-                    for (int i = showIndex + 1; i < items.length; i++)
-                    {
-                        widths[i] = items[i].preferredWidth(gc,
-                                i is selectedIndex, true);
-                        width += widths[i];
-                        if (width >= maxWidth)
-                            break;
-                    }
-                    if (width < maxWidth)
-                    {
-                        for (int i = priority[0] - 1; i >= 0; i--)
-                        {
-                            if (widths[i] is 0)
-                                widths[i] = items[i].preferredWidth(gc,
-                                        i is selectedIndex, true);
-                            width += widths[i];
-                            if (width > maxWidth)
-                                break;
-                            firstIndex = i;
-                        }
-                    }
-                }
-                gc.dispose();
-            }
-            if (firstIndex !is priority[0])
-            {
-                int index = 0;
-                for (int i = firstIndex; i < items.length; i++)
-                {
-                    priority[index++] = i;
-                }
-                for (int i = 0; i < firstIndex; i++)
-                {
-                    priority[index++] = i;
-                }
-            }
-        }
-
-        bool oldShowChevron = showChevron;
-        bool changed = setItemSize();
-        changed |= setItemLocation();
-        setButtonBounds();
-        changed |= showChevron !is oldShowChevron;
-        if (changed && getToolTipText() !is null)
-        {
-            Point pt = getDisplay().getCursorLocation();
-            pt = toControl(pt);
-            _setToolTipText(pt.x, pt.y);
-        }
-        return changed;
+    notifyListeners(DWT.Resize, new Event());
+    return true;
+}
+String _getToolTip(int x, int y) {
+    if (showMin && minRect.contains(x, y)) return minimized ? DWT.getMessage("SWT_Restore") : DWT.getMessage("SWT_Minimize"); //$NON-NLS-1$ //$NON-NLS-2$
+    if (showMax && maxRect.contains(x, y)) return maximized ? DWT.getMessage("SWT_Restore") : DWT.getMessage("SWT_Maximize"); //$NON-NLS-1$ //$NON-NLS-2$
+    if (showChevron && chevronRect.contains(x, y)) return DWT.getMessage("SWT_ShowList"); //$NON-NLS-1$
+    CTabItem item = getItem(new Point (x, y));
+    if (item is null) return null;
+    if (!item.showing) return null;
+    if ((showClose || item.showClose) && item.closeRect.contains(x, y)) {
+        return DWT.getMessage("SWT_Close"); //$NON-NLS-1$
     }
-
-    bool updateTabHeight (bool force)
-    {
-        int style = getStyle();
-        if (fixedTabHeight is 0 && (style & DWT.FLAT) !is 0 && (style & DWT.BORDER) is 0)
-            highlight_header = 0;
-        int oldHeight = tabHeight;
-        if (fixedTabHeight !is DWT.DEFAULT)
-        {
-            tabHeight = fixedTabHeight is 0 ? 0 : fixedTabHeight + 1; // +1 for line drawn across top of tab
-        }
-        else
-        {
-            int tempHeight = 0;
-            GC gc = new GC(this);
-            if (items.length is 0)
-            {
-                tempHeight = gc.textExtent("Default", CTabItem.FLAGS).y + CTabItem.TOP_MARGIN + CTabItem.BOTTOM_MARGIN; //$NON-NLS-1$
-            }
-            else
-            {
-                for (int i = 0; i < items.length; i++)
-                {
-                    tempHeight = Math.max(tempHeight, items[i].preferredHeight(
-                            gc));
-                }
-            }
-            gc.dispose();
-            tabHeight = tempHeight;
-        }
-        if (!force && tabHeight is oldHeight)
-            return false;
-
-        oldSize = null;
-        if (onBottom)
-        {
-            int d = tabHeight - 12;
-            curve = new int[][0 , 13 + d , 0 , 12 + d , 2 , 12 + d , 3 , 11 + d , 5 , 11 + d , 6 , 10 + d , 7 , 10 + d , 9 , 8 + d , 10 , 8 + d , 11 , 7 + d , 11 + d , 7 , 12 + d , 6 , 13 + d , 6 , 15 + d , 4 , 16 + d , 4 , 17 + d , 3 , 19 + d , 3 , 20 + d , 2 , 22 + d , 2 , 23 + d , 1];
-            curveWidth = 26 + d;
-            curveIndent = curveWidth / 3;
-        }
-        else
-        {
-            int d = tabHeight - 12;
-            curve = new int[][0 , 0 , 0 , 1 , 2 , 1 , 3 , 2 , 5 , 2 , 6 , 3 , 7 , 3 , 9 , 5 , 10 , 5 , 11 , 6 , 11 + d , 6 + d , 12 + d , 7 + d , 13 + d , 7 + d , 15 + d , 9 + d , 16 + d , 9 + d , 17 + d , 10 + d , 19 + d , 10 + d , 20 + d , 11 + d , 22 + d , 11 + d , 23 + d , 12 + d];
-            curveWidth = 26 + d;
-            curveIndent = curveWidth / 3;
-
-            //this could be static but since values depend on curve, better to keep in one place
-            topCurveHighlightStart = new int[][0 , 2 , 1 , 2 , 2 , 2 , 3 , 3 , 4 , 3 , 5 , 3 , 6 , 4 , 7 , 4 , 8 , 5 , 9 , 6 , 10 , 6];
-
-            //also, by adding in 'd' here we save some math cost when drawing the curve
-            topCurveHighlightEnd = new int[][10 + d , 6 + d , 11 + d , 7 + d , 12 + d , 8 + d , 13 + d , 8 + d , 14 + d , 9 + d , 15 + d , 10 + d , 16 + d , 10 + d , 17 + d , 11 + d , 18 + d , 11 + d , 19 + d , 11 + d , 20 + d , 12 + d , 21 + d , 12 + d , 22 + d , 12 + d];
-        }
-        notifyListeners(DWT.Resize, new Event());
-        return true;
-    }
-
-    String _getToolTip (int x, int y)
-    {
-        if (showMin && minRect.contains(x, y))
-            return minimized ? DWT.getMessage("DWT_Restore") : DWT.getMessage(
-                    "DWT_Minimize"); //$NON-NLS-1$ //$NON-NLS-2$
-        if (showMax && maxRect.contains(x, y))
-            return maximized ? DWT.getMessage("DWT_Restore") : DWT.getMessage(
-                    "DWT_Maximize"); //$NON-NLS-1$ //$NON-NLS-2$
-        if (showChevron && chevronRect.contains(x, y))
-            return DWT.getMessage("DWT_ShowList"); //$NON-NLS-1$
-        CTabItem item = getItem(new Point(x, y));
-        if (item is null)
-            return null;
-        if (!item.showing)
-            return null;
-        if ((showClose || item.showClose) && item.closeRect.contains(x, y))
-        {
-            return DWT.getMessage("DWT_Close"); //$NON-NLS-1$
-        }
-        return item.getToolTipText();
-    }
+    return item.getToolTipText();
 }
+}
--- a/dwt/custom/CTabFolder2Adapter.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/CTabFolder2Adapter.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,12 +7,10 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.CTabFolder2Adapter;
-
 import dwt.custom.CTabFolder2Listener;
 import dwt.custom.CTabFolderEvent;
 
@@ -20,74 +18,70 @@
  * This adapter class provides default implementations for the
  * methods described by the <code>CTabFolder2Listener</code> interface.
  * <p>
- * Classes that wish to dealF with <code>CTabFolderEvent</code>s can
+ * Classes that wish to deal with <code>CTabFolderEvent</code>s can
  * extend this class and override only the methods which they are
  * interested in.
  * </p>
  *
  * @see CTabFolder2Listener
  * @see CTabFolderEvent
- * 
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
  * @since 3.0
  */
 public class CTabFolder2Adapter : CTabFolder2Listener {
 
-    /**
-     * Sent when the user clicks on the close button of an item in the CTabFolder.  The item being closed is specified
-     * in the event.item field. Setting the event.doit field to false will stop  the CTabItem from closing. 
-     * When the CTabItem is closed, it is disposed.  The contents of the CTabItem (see CTabItem#setControl) will be 
-     * made not visible when the CTabItem is closed.
-     * <p>
-     * The default behaviour is to close the CTabItem.
-     * </p>
-     * 
-     * @param event an event indicating the item being closed
-     */
-    public void close (CTabFolderEvent event) {
-    }
+/**
+ * Sent when the user clicks on the close button of an item in the CTabFolder.  The item being closed is specified
+ * in the event.item field. Setting the event.doit field to false will stop  the CTabItem from closing.
+ * When the CTabItem is closed, it is disposed.  The contents of the CTabItem (see CTabItem#setControl) will be
+ * made not visible when the CTabItem is closed.
+ * <p>
+ * The default behaviour is to close the CTabItem.
+ * </p>
+ *
+ * @param event an event indicating the item being closed
+ */
+public void close(CTabFolderEvent event){}
 
-    /**
-     * Sent when the user clicks on the minimize button of a CTabFolder.
-     * <p>
-     * The default behaviour is to do nothing.
-     * </p>
-     * 
-     * @param event an event containing information about the minimize
-     */
-    public void minimize (CTabFolderEvent event) {
-    }
+/**
+ * Sent when the user clicks on the minimize button of a CTabFolder.
+ * <p>
+ * The default behaviour is to do nothing.
+ * </p>
+ *
+ * @param event an event containing information about the minimize
+ */
+public void minimize(CTabFolderEvent event){}
 
-    /**
-     * Sent when the user clicks on the maximize button of a CTabFolder.
-     * <p>
-     * The default behaviour is to do nothing.
-     * </p>
-     * 
-     * @param event an event containing information about the maximize
-     */
-    public void maximize (CTabFolderEvent event) {
-    }
+/**
+ * Sent when the user clicks on the maximize button of a CTabFolder.
+ * <p>
+ * The default behaviour is to do nothing.
+ * </p>
+ *
+ * @param event an event containing information about the maximize
+ */
+public void maximize(CTabFolderEvent event){}
 
-    /**
-     * Sent when the user clicks on the restore button of a CTabFolder.
-     * <p>
-     * The default behaviour is to do nothing.
-     * </p>
-     * 
-     * @param event an event containing information about the restore
-     */
-    public void restore (CTabFolderEvent event) {
-    }
+/**
+ * Sent when the user clicks on the restore button of a CTabFolder.
+ * <p>
+ * The default behaviour is to do nothing.
+ * </p>
+ *
+ * @param event an event containing information about the restore
+ */
+public void restore(CTabFolderEvent event){}
 
-    /**
-     * Sent when the user clicks on the chevron button of a CTabFolder.
-     * <p>
-     * The default behaviour is to show a list of items that are not currently 
-     * visible and to change the selection based on the item selected from the list.
-     * </p>
-     * 
-     * @param event an event containing information about the show list
-     */
-    public void showList (CTabFolderEvent event) {
-    }
+/**
+ * Sent when the user clicks on the chevron button of a CTabFolder.
+ * <p>
+ * The default behaviour is to show a list of items that are not currently
+ * visible and to change the selection based on the item selected from the list.
+ * </p>
+ *
+ * @param event an event containing information about the show list
+ */
+public void showList(CTabFolderEvent event){}
 }
--- a/dwt/custom/CTabFolder2Listener.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/CTabFolder2Listener.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
  * Copyright (c) 2000, 2004 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -7,18 +7,20 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.CTabFolder2Listener;
 
+import dwt.internal.DWTEventListener;
 import dwt.custom.CTabFolderEvent;
-import dwt.internal.DWTEventListener;
+
+import tango.core.Traits;
+import tango.core.Tuple;
 
 /**
  * Classes which implement this interface provide methods
- * that deal with the events that are generated by the CTabFolder 
+ * that deal with the events that are generated by the CTabFolder
  * control.
  * <p>
  * After creating an instance of a class that :
@@ -31,86 +33,163 @@
  *
  * @see CTabFolder2Adapter
  * @see CTabFolderEvent
- * 
+ *
  * @since 3.0
  */
 public interface CTabFolder2Listener : DWTEventListener {
+    public enum {
+        MINIMIZE,
+        MAXIMIZE,
+        SHOWLIST,
+        RESTORE,
+        CLOSE
+    }
 
-    /**
-     * Sent when the user clicks on the close button of an item in the CTabFolder.
-     * The item being closed is specified in the event.item field. 
-     * Setting the event.doit field to false will stop the CTabItem from closing. 
-     * When the CTabItem is closed, it is disposed.  The contents of the 
-     * CTabItem (see CTabItem.setControl) will be made not visible when
-     * the CTabItem is closed.
-     * 
-     * @param event an event indicating the item being closed
-     */
-    public void close (CTabFolderEvent event);
+/**
+ * Sent when the user clicks on the close button of an item in the CTabFolder.
+ * The item being closed is specified in the event.item field.
+ * Setting the event.doit field to false will stop the CTabItem from closing.
+ * When the CTabItem is closed, it is disposed.  The contents of the
+ * CTabItem (see CTabItem.setControl) will be made not visible when
+ * the CTabItem is closed.
+ *
+ * @param event an event indicating the item being closed
+ */
+public void close(CTabFolderEvent event);
+
+/**
+ * Sent when the user clicks on the minimize button of a CTabFolder.
+ * The state of the CTabFolder does not change automatically - it
+ * is up to the application to change the state of the CTabFolder
+ * in response to this event using CTabFolder.setMinimized(true).
+ *
+ * @param event an event containing information about the minimize
+ *
+ * @see CTabFolder#getMinimized()
+ * @see CTabFolder#setMinimized(bool)
+ * @see CTabFolder#setMinimizeVisible(bool)
+ */
+public void minimize(CTabFolderEvent event);
 
-    /**
-     * Sent when the user clicks on the minimize button of a CTabFolder.
-     * The state of the CTabFolder does not change automatically - it 
-     * is up to the application to change the state of the CTabFolder
-     * in response to this event using CTabFolder.setMinimized(true).
-     * 
-     * @param event an event containing information about the minimize
-     * 
-     * @see CTabFolder#getMinimized()
-     * @see CTabFolder#setMinimized(bool)
-     * @see CTabFolder#setMinimizeVisible(bool)
-     */
-    public void minimize (CTabFolderEvent event);
+/**
+ * Sent when the user clicks on the maximize button of a CTabFolder.
+ * The state of the CTabFolder does not change automatically - it
+ * is up to the application to change the state of the CTabFolder
+ * in response to this event using CTabFolder.setMaximized(true).
+ *
+ * @param event an event containing information about the maximize
+ *
+ * @see CTabFolder#getMaximized()
+ * @see CTabFolder#setMaximized(bool)
+ * @see CTabFolder#setMaximizeVisible(bool)
+ */
+public void maximize(CTabFolderEvent event);
+
+/**
+ * Sent when the user clicks on the restore button of a CTabFolder.
+ * This event is sent either to restore the CTabFolder from the
+ * minimized state or from the maximized state.  To determine
+ * which restore is requested, use CTabFolder.getMinimized() or
+ * CTabFolder.getMaximized() to determine the current state.
+ * The state of the CTabFolder does not change automatically - it
+ * is up to the application to change the state of the CTabFolder
+ * in response to this event using CTabFolder.setMaximized(false)
+ * or CTabFolder.setMinimized(false).
+ *
+ * @param event an event containing information about the restore
+ *
+ * @see CTabFolder#getMinimized()
+ * @see CTabFolder#getMaximized()
+ * @see CTabFolder#setMinimized(bool)
+ * @see CTabFolder#setMinimizeVisible(bool)
+ * @see CTabFolder#setMaximized(bool)
+ * @see CTabFolder#setMaximizeVisible(bool)
+ */
+public void restore(CTabFolderEvent event);
 
-    /**
-     * Sent when the user clicks on the maximize button of a CTabFolder.
-     * The state of the CTabFolder does not change automatically - it 
-     * is up to the application to change the state of the CTabFolder
-     * in response to this event using CTabFolder.setMaximized(true).
-     * 
-     * @param event an event containing information about the maximize
-     * 
-     * @see CTabFolder#getMaximized()
-     * @see CTabFolder#setMaximized(bool)
-     * @see CTabFolder#setMaximizeVisible(bool)
-     */
-    public void maximize (CTabFolderEvent event);
+/**
+ * Sent when the user clicks on the chevron button of the CTabFolder.
+ * A chevron appears in the CTabFolder when there are more tabs
+ * than can be displayed at the current widget size.  To select a
+ * tab that is not currently visible, the user clicks on the
+ * chevron and selects a tab item from a list.  By default, the
+ * CTabFolder provides a list of all the items that are not currently
+ * visible, however, the application can provide its own list by setting
+ * the event.doit field to <code>false</code> and displaying a selection list.
+ *
+ * @param event an event containing information about the show list
+ *
+ * @see CTabFolder#setSelection(CTabItem)
+ */
+public void showList(CTabFolderEvent event);
+}
+
+
+
+/// Helper class for the dgListener template function
+private class _DgCTabFolder2ListenerT(Dg,T...) : CTabFolder2Listener {
+
+    alias ParameterTupleOf!(Dg) DgArgs;
+    static assert( is(DgArgs == Tuple!(CTabFolderEvent,T)),
+                "Delegate args not correct: "~DgArgs.stringof~" vs. (Event,"~T.stringof~")" );
+
+    Dg dg;
+    T  t;
+    int type;
+
+    private this( int type, Dg dg, T t ){
+        this.type = type;
+        this.dg = dg;
+        static if( T.length > 0 ){
+            this.t = t;
+        }
+    }
 
-    /**
-     * Sent when the user clicks on the restore button of a CTabFolder.
-     * This event is sent either to restore the CTabFolder from the 
-     * minimized state or from the maximized state.  To determine
-     * which restore is requested, use CTabFolder.getMinimized() or
-     * CTabFolder.getMaximized() to determine the current state.
-     * The state of the CTabFolder does not change automatically - it 
-     * is up to the application to change the state of the CTabFolder
-     * in response to this event using CTabFolder.setMaximized(false)
-     * or CTabFolder.setMinimized(false).
-     * 
-     * @param event an event containing information about the restore
-     * 
-     * @see CTabFolder#getMinimized()
-     * @see CTabFolder#getMaximized()
-     * @see CTabFolder#setMinimized(bool)
-     * @see CTabFolder#setMinimizeVisible(bool)
-     * @see CTabFolder#setMaximized(bool)
-     * @see CTabFolder#setMaximizeVisible(bool)
-     */
-    public void restore (CTabFolderEvent event);
+    void itemClosed( CTabFolderEvent e ){
+        dg(e,t);
+    }
+    public void close(CTabFolderEvent e){
+        if( type is CTabFolder2Listener.CLOSE ){
+            dg(e,t);
+        }
+    }
+    public void minimize(CTabFolderEvent e){
+        if( type is CTabFolder2Listener.MINIMIZE ){
+            dg(e,t);
+        }
+    }
+    public void maximize(CTabFolderEvent e){
+        if( type is CTabFolder2Listener.MAXIMIZE ){
+            dg(e,t);
+        }
+    }
+    public void restore(CTabFolderEvent e){
+        if( type is CTabFolder2Listener.RESTORE ){
+            dg(e,t);
+        }
+    }
+    public void showList(CTabFolderEvent e){
+        if( type is CTabFolder2Listener.SHOWLIST ){
+            dg(e,t);
+        }
+    }
+}
 
-    /**
-     * Sent when the user clicks on the chevron button of the CTabFolder.
-     * A chevron appears in the CTabFolder when there are more tabs 
-     * than can be displayed at the current widget size.  To select a 
-     * tab that is not currently visible, the user clicks on the
-     * chevron and selects a tab item from a list.  By default, the
-     * CTabFolder provides a list of all the items that are not currently
-     * visible, however, the application can provide its own list by setting 
-     * the event.doit field to <code>false</code> and displaying a selection list.
-     * 
-     * @param event an event containing information about the show list  
-     * 
-     * @see CTabFolder#setSelection(CTabItem)
-     */
-    public void showList (CTabFolderEvent event);
+/++
+ + dgListener creates a class implementing the Listener interface and delegating the call to
+ + handleEvent to the users delegate. This template function will store also additional parameters.
+ +
+ + Examle of usage:
+ + ---
+ + void handleTextEvent ( Event e, int inset ) {
+ +     // ...
+ + }
+ + text.addListener (DWT.FocusOut, dgListener( &handleTextEvent, inset ));
+ + ---
+ +/
+CTabFolder2Listener dgCTabFolder2Listener( Dg, T... )( int type, Dg dg, T args ){
+    return new _DgCTabFolder2ListenerT!( Dg, T )( type, dg, args );
 }
+
+
+
--- a/dwt/custom/CTabFolderAdapter.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/CTabFolderAdapter.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,16 +7,22 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.CTabFolderAdapter;
-
 import dwt.custom.CTabFolderEvent;
 import dwt.custom.CTabFolderListener;
 
+
+/**
+ * This adapter class provides a default implementation for the
+ * method described by the <code>CTabFolderListener</code> interface.
+ * 
+ * @see CTabFolderListener
+ * @see CTabFolderEvent
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
 public class CTabFolderAdapter : CTabFolderListener {
-    public void itemClosed (CTabFolderEvent event) {
-    }
+    public void itemClosed(CTabFolderEvent event){}
 }
--- a/dwt/custom/CTabFolderEvent.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/CTabFolderEvent.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,19 +7,24 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.CTabFolderEvent;
 
+import dwt.dwthelper.utils;
+
+
+
 import dwt.events.TypedEvent;
 import dwt.widgets.Widget;
 
-import dwt.dwthelper.utils;
+import tango.util.Convert;
 
 /**
- * 
+ * This event is sent when an event is generated in the CTabFolder.
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> 
  */
 public class CTabFolderEvent : TypedEvent {
     /**
@@ -37,52 +42,58 @@
     /**
      * The widget-relative, x coordinate of the chevron button
      * at the time of the event.  Applies to the showList event.
-     * 
+     *
      * @since 3.0
      */
     public int x;
     /**
      * The widget-relative, y coordinate of the chevron button
      * at the time of the event.  Applies to the showList event.
-     * 
+     *
      * @since 3.0
      */
     public int y;
     /**
      * The width of the chevron button at the time of the event.
      * Applies to the showList event.
-     * 
+     *
      * @since 3.0
      */
     public int width;
     /**
      * The height of the chevron button at the time of the event.
      * Applies to the showList event.
-     * 
+     *
      * @since 3.0
      */
     public int height;
 
     static final long serialVersionUID = 3760566386225066807L;
 
-    /**
-     * Constructs a new instance of this class.
-     *
-     * @param w the widget that fired the event
-     */
-    this (Widget w) {
-        super(w);
-    }
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param w the widget that fired the event
+ */
+this(Widget w) {
+    super(w);
+}
 
-    /**
-     * Returns a String containing a concise, human-readable
-     * description of the receiver.
-     *
-     * @return a String representation of the event
-     */
-    public String toString () {
-        String str = super.toString();
-        return str.substring(0, str.length - 1) // remove trailing '}'
-        + " item=" + item + " doit=" + doit + " x=" + x + " y=" + y + " width=" + width + " height=" + height + "}";
-    }
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+public override String toString() {
+    String string = super.toString ();
+    return string[0.. $ - 1] // remove trailing '}'
+        ~ " item=" ~ to!(String)(item)
+        ~ " doit=" ~ to!(String)(doit)
+        ~ " x=" ~ to!(String)(x)
+        ~ " y=" ~ to!(String)(y)
+        ~ " width=" ~ to!(String)(width)
+        ~ " height=" ~ to!(String)(height)
+        ~ "}";
 }
+}
--- a/dwt/custom/CTabFolderLayout.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/CTabFolderLayout.d	Tue Oct 07 16:29:55 2008 +0200
@@ -7,97 +7,85 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.CTabFolderLayout;
 
-import Math = tango.math.Math;
+import dwt.dwthelper.utils;
 
 import dwt.DWT;
-import dwt.custom.CTabFolder;
-import dwt.custom.CTabItem;
 import dwt.graphics.GC;
 import dwt.graphics.Point;
 import dwt.widgets.Composite;
 import dwt.widgets.Control;
 import dwt.widgets.Layout;
+import dwt.custom.CTabFolder;
+import dwt.custom.CTabItem;
 
 /**
  * This class provides the layout for CTabFolder
- * 
+ *
  * @see CTabFolder
  */
 class CTabFolderLayout : Layout {
-    protected Point computeSize (Composite composite, int wHint, int hHint, bool flushCache) {
-        CTabFolder folder = cast(CTabFolder) composite;
-        CTabItem[] items = folder.items;
-        // preferred width of tab area to show all tabs
-        int tabW = 0;
-        GC gc = new GC(folder);
-        for (int i = 0; i < items.length; i++) {
-            if (folder.single) {
-                tabW = Math.max(tabW, items[i].preferredWidth(gc, true, false));
-            }
-            else {
-                tabW += items[i].preferredWidth(gc, i is folder.selectedIndex, false);
-            }
-        }
-        gc.dispose();
-        tabW += 3;
-        if (folder.showMax)
-            tabW += CTabFolder.BUTTON_SIZE;
-        if (folder.showMin)
-            tabW += CTabFolder.BUTTON_SIZE;
-        if (folder.single)
-            tabW += 3 * CTabFolder.BUTTON_SIZE / 2; //chevron
-        if (folder.topRight !is null) {
-            Point pt = folder.topRight.computeSize(DWT.DEFAULT, folder.tabHeight, flushCache);
-            tabW += 3 + pt.x;
+protected override Point computeSize(Composite composite, int wHint, int hHint, bool flushCache) {
+    CTabFolder folder = cast(CTabFolder)composite;
+    CTabItem[] items = folder.items;
+    // preferred width of tab area to show all tabs
+    int tabW = 0;
+    GC gc = new GC(folder);
+    for (int i = 0; i < items.length; i++) {
+        if (folder.single) {
+            tabW = Math.max(tabW, items[i].preferredWidth(gc, true, false));
+        } else {
+            tabW += items[i].preferredWidth(gc, i is folder.selectedIndex, false);
         }
-        if (!folder.single && !folder.simple)
-            tabW += folder.curveWidth - 2 * folder.curveIndent;
+    }
+    gc.dispose();
+    tabW += 3;
+    if (folder.showMax) tabW += CTabFolder.BUTTON_SIZE;
+    if (folder.showMin) tabW += CTabFolder.BUTTON_SIZE;
+    if (folder.single) tabW += 3*CTabFolder.BUTTON_SIZE/2; //chevron
+    if (folder.topRight !is null) {
+        Point pt = folder.topRight.computeSize(DWT.DEFAULT, folder.tabHeight, flushCache);
+        tabW += 3 + pt.x;
+    }
+    if (!folder.single && !folder.simple) tabW += folder.curveWidth - 2*folder.curveIndent;
 
-        int controlW = 0;
-        int controlH = 0;
-        // preferred size of controls in tab items
-        for (int i = 0; i < items.length; i++) {
-            Control control = items[i].getControl();
-            if (control !is null && !control.isDisposed()) {
-                Point size = control.computeSize(wHint, hHint, flushCache);
-                controlW = Math.max(controlW, size.x);
-                controlH = Math.max(controlH, size.y);
-            }
+    int controlW = 0;
+    int controlH = 0;
+    // preferred size of controls in tab items
+    for (int i = 0; i < items.length; i++) {
+        Control control = items[i].getControl();
+        if (control !is null && !control.isDisposed()){
+            Point size = control.computeSize (wHint, hHint, flushCache);
+            controlW = Math.max (controlW, size.x);
+            controlH = Math.max (controlH, size.y);
         }
-
-        int minWidth = Math.max(tabW, controlW);
-        int minHeight = (folder.minimized) ? 0 : controlH;
-        if (minWidth is 0)
-            minWidth = CTabFolder.DEFAULT_WIDTH;
-        if (minHeight is 0)
-            minHeight = CTabFolder.DEFAULT_HEIGHT;
-
-        if (wHint !is DWT.DEFAULT)
-            minWidth = wHint;
-        if (hHint !is DWT.DEFAULT)
-            minHeight = hHint;
-
-        return new Point(minWidth, minHeight);
     }
 
-    protected bool flushCache (Control control) {
-        return true;
-    }
+    int minWidth = Math.max(tabW, controlW);
+    int minHeight = (folder.minimized) ? 0 : controlH;
+    if (minWidth is 0) minWidth = CTabFolder.DEFAULT_WIDTH;
+    if (minHeight is 0) minHeight = CTabFolder.DEFAULT_HEIGHT;
+
+    if (wHint !is DWT.DEFAULT) minWidth  = wHint;
+    if (hHint !is DWT.DEFAULT) minHeight = hHint;
 
-    protected void layout (Composite composite, bool flushCache) {
-        CTabFolder folder = cast(CTabFolder) composite;
-        // resize content
-        if (folder.selectedIndex !is -1) {
-            Control control = folder.items[folder.selectedIndex].getControl();
-            if (control !is null && !control.isDisposed()) {
-                control.setBounds(folder.getClientArea());
-            }
+    return new Point (minWidth, minHeight);
+}
+protected override bool flushCache(Control control) {
+    return true;
+}
+protected override void layout(Composite composite, bool flushCache) {
+    CTabFolder folder = cast(CTabFolder)composite;
+    // resize content
+    if (folder.selectedIndex !is -1) {
+        Control control = folder.items[folder.selectedIndex].getControl();
+        if (control !is null && !control.isDisposed()) {
+            control.setBounds(folder.getClientArea());
         }
     }
 }
+}
--- a/dwt/custom/CTabFolderListener.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/CTabFolderListener.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
  * Copyright (c) 2000, 2005 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -7,14 +7,16 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.CTabFolderListener;
 
+import dwt.internal.DWTEventListener;
 import dwt.custom.CTabFolderEvent;
-import dwt.internal.DWTEventListener;
+
+import tango.core.Traits;
+import tango.core.Tuple;
 
 /**
  * Classes which implement this interface provide a method
@@ -31,15 +33,58 @@
  */
 public interface CTabFolderListener : DWTEventListener {
 
-    /**
-     * Sent when the user clicks on the close button of an item in the CTabFolder.  The item being closed is specified
-     * in the event.item field. Setting the event.doit field to false will stop the CTabItem from closing. 
-     * When the CTabItem is closed, it is disposed.  The contents of the CTabItem (see CTabItem.setControl) will be 
-     * made not visible when the CTabItem is closed.
-     * 
-     * @param event an event indicating the item being closed
-     * 
-     * @see CTabItem#setControl
-     */
-    public void itemClosed (CTabFolderEvent event);
+/**
+ * Sent when the user clicks on the close button of an item in the CTabFolder.  The item being closed is specified
+ * in the event.item field. Setting the event.doit field to false will stop the CTabItem from closing.
+ * When the CTabItem is closed, it is disposed.  The contents of the CTabItem (see CTabItem.setControl) will be
+ * made not visible when the CTabItem is closed.
+ *
+ * @param event an event indicating the item being closed
+ *
+ * @see CTabItem#setControl
+ */
+public void itemClosed(CTabFolderEvent event);
 }
+
+
+
+/// Helper class for the dgListener template function
+private class _DgCTabFolderListenerT(Dg,T...) : CTabFolderListener {
+
+    alias ParameterTupleOf!(Dg) DgArgs;
+    static assert( is(DgArgs == Tuple!(CTabFolderEvent,T)),
+                "Delegate args not correct" );
+
+    Dg dg;
+    T  t;
+
+    private this( Dg dg, T t ){
+        this.dg = dg;
+        static if( T.length > 0 ){
+            this.t = t;
+        }
+    }
+
+    void itemClosed( CTabFolderEvent e ){
+        dg(e,t);
+    }
+}
+
+/++
+ + dgListener creates a class implementing the Listener interface and delegating the call to
+ + handleEvent to the users delegate. This template function will store also additional parameters.
+ +
+ + Examle of usage:
+ + ---
+ + void handleTextEvent (Event e, int inset ) {
+ +     // ...
+ + }
+ + text.addListener (DWT.FocusOut, dgListener( &handleTextEvent, inset ));
+ + ---
+ +/
+CTabFolderListener dgCTabFolderListener( Dg, T... )( Dg dg, T args ){
+    return new _DgCTabFolderListenerT!( Dg, T )( dg, args );
+}
+
+
+
--- a/dwt/custom/CTabItem.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/CTabItem.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,15 +7,17 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.CTabItem;
+
+import dwt.dwthelper.utils;
+
+
 
 import dwt.DWT;
 import dwt.DWTException;
-import dwt.custom.CTabFolder;
 import dwt.graphics.Color;
 import dwt.graphics.Font;
 import dwt.graphics.GC;
@@ -28,13 +30,12 @@
 import dwt.widgets.Display;
 import dwt.widgets.Item;
 import dwt.widgets.Widget;
-
-import dwt.dwthelper.utils;
+import dwt.custom.CTabFolder;
 
 /**
  * Instances of this class represent a selectable user interface object
  * that represent a page in a notebook widget.
- * 
+ *
  * <dl>
  * <dt><b>Styles:</b></dt>
  * <dd>DWT.CLOSE</dd>
@@ -44,10 +45,13 @@
  * <p>
  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
  * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#ctabfolder">CTabFolder, CTabItem snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 public class CTabItem : Item {
     CTabFolder parent;
-    int x, y, width, height = 0;
+    int x,y,width,height = 0;
     Control control; // the tab page
 
     String toolTipText;
@@ -58,7 +62,7 @@
     Font font;
     Image disabledImage;
 
-    Rectangle closeRect = new Rectangle(0, 0, 0, 0);
+    Rectangle closeRect;
     int closeImageState = CTabFolder.NONE;
     bool showClose = false;
     bool showing = false;
@@ -72,1061 +76,998 @@
     static final int FLAGS = DWT.DRAW_TRANSPARENT | DWT.DRAW_MNEMONIC;
     static final String ELLIPSIS = "..."; //$NON-NLS-1$ // could use the ellipsis glyph on some platforms "\u2026"
 
-    /**
-     * Constructs a new instance of this class given its parent
-     * (which must be a <code>CTabFolder</code>) and a style value
-     * describing its behavior and appearance. The item is added
-     * to the end of the items maintained by its parent.
-     * <p>
-     * The style value is either one of the style constants defined in
-     * class <code>DWT</code> which is applicable to instances of this
-     * class, or must be built by <em>bitwise OR</em>'ing together 
-     * (that is, using the <code>int</code> "|" operator) two or more
-     * of those <code>DWT</code> style constants. The class description
-     * lists the style constants that are applicable to the class.
-     * Style bits are also inherited from superclasses.
-     * </p>
-     *
-     * @param parent a CTabFolder which will be the parent of the new instance (cannot be null)
-     * @param style the style of control to construct
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
-     * </ul>
-     *
-     * @see DWT
-     * @see Widget#getStyle()
-     */
-    public this (CTabFolder parent, int style) {
-        this(parent, style, parent.getItemCount());
-    }
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>CTabFolder</code>) and a style value
+ * describing its behavior and appearance. The item is added
+ * to the end of the items maintained by its parent.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>DWT</code> which is applicable to instances of this
+ * class, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DWT</code> style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a CTabFolder which will be the parent of the new instance (cannot be null)
+ * @param style the style of control to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * </ul>
+ *
+ * @see DWT
+ * @see Widget#getStyle()
+ */
+public this (CTabFolder parent, int style) {
+    this(parent, style, parent.getItemCount());
+}
+/**
+ * Constructs a new instance of this class given its parent
+ * (which must be a <code>CTabFolder</code>), a style value
+ * describing its behavior and appearance, and the index
+ * at which to place it in the items maintained by its parent.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>DWT</code> which is applicable to instances of this
+ * class, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>DWT</code> style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a CTabFolder which will be the parent of the new instance (cannot be null)
+ * @param style the style of control to construct
+ * @param index the zero-relative index to store the receiver in its parent
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * </ul>
+ *
+ * @see DWT
+ * @see Widget#getStyle()
+ */
+public this (CTabFolder parent, int style, int index) {
+    closeRect = new Rectangle(0, 0, 0, 0);
+    super (parent, style);
+    showClose = (style & DWT.CLOSE) !is 0;
+    parent.createItem (this, index);
+}
+
+/*
+ * Return whether to use ellipses or just truncate labels
+ */
+bool useEllipses() {
+    return parent.simple;
+}
+
+String shortenText(GC gc, String text, int width) {
+    return useEllipses()
+        ? shortenText(gc, text, width, ELLIPSIS)
+        : shortenText(gc, text, width, ""); //$NON-NLS-1$
+}
 
-    /**
-     * Constructs a new instance of this class given its parent
-     * (which must be a <code>CTabFolder</code>), a style value
-     * describing its behavior and appearance, and the index
-     * at which to place it in the items maintained by its parent.
-     * <p>
-     * The style value is either one of the style constants defined in
-     * class <code>DWT</code> which is applicable to instances of this
-     * class, or must be built by <em>bitwise OR</em>'ing together 
-     * (that is, using the <code>int</code> "|" operator) two or more
-     * of those <code>DWT</code> style constants. The class description
-     * lists the style constants that are applicable to the class.
-     * Style bits are also inherited from superclasses.
-     * </p>
-     *
-     * @param parent a CTabFolder which will be the parent of the new instance (cannot be null)
-     * @param style the style of control to construct
-     * @param index the zero-relative index to store the receiver in its parent
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
-     *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
-     * </ul>
-     *
-     * @see DWT
-     * @see Widget#getStyle()
-     */
-    public this (CTabFolder parent, int style, int index) {
-        super(parent, style);
-        showClose = (style & DWT.CLOSE) !is 0;
-        parent.createItem(this, index);
+String shortenText(GC gc, String text, int width, String ellipses) {
+    if (gc.textExtent(text, FLAGS).x <= width) return text;
+    int ellipseWidth = gc.textExtent(ellipses, FLAGS).x;
+    int length = text.length;
+    TextLayout layout = new TextLayout(getDisplay());
+    layout.setText(text);
+    int end = layout.getPreviousOffset(length, DWT.MOVEMENT_CLUSTER);
+    while (end > 0) {
+        text = text[ 0 .. end ];
+        int l = gc.textExtent(text, FLAGS).x;
+        if (l + ellipseWidth <= width) {
+            break;
+        }
+        end = layout.getPreviousOffset(end, DWT.MOVEMENT_CLUSTER);
     }
+    layout.dispose();
+    return end is 0 ? text.substring(0, 1) : text ~ ellipses;
+}
 
-    /*
-     * Return whether to use ellipses or just truncate labels
-     */
-    bool useEllipses () {
-        return parent.simple;
+public override void dispose() {
+    if (isDisposed ()) return;
+    //if (!isValidThread ()) error (DWT.ERROR_THREAD_INVALID_ACCESS);
+    parent.destroyItem(this);
+    super.dispose();
+    parent = null;
+    control = null;
+    toolTipText = null;
+    shortenedText = null;
+    font = null;
+}
+void drawClose(GC gc) {
+    if (closeRect.width is 0 || closeRect.height is 0) return;
+    Display display = getDisplay();
+
+    // draw X 9x9
+    int indent = Math.max(1, (CTabFolder.BUTTON_SIZE-9)/2);
+    int x = closeRect.x + indent;
+    int y = closeRect.y + indent;
+    y += parent.onBottom ? -1 : 1;
+
+    Color closeBorder = display.getSystemColor(CTabFolder.BUTTON_BORDER);
+    switch (closeImageState) {
+        case CTabFolder.NORMAL: {
+            int[] shape = [x,y, x+2,y, x+4,y+2, x+5,y+2, x+7,y, x+9,y,
+                                     x+9,y+2, x+7,y+4, x+7,y+5, x+9,y+7, x+9,y+9,
+                                     x+7,y+9, x+5,y+7, x+4,y+7, x+2,y+9, x,y+9,
+                                     x,y+7, x+2,y+5, x+2,y+4, x,y+2];
+            gc.setBackground(display.getSystemColor(CTabFolder.BUTTON_FILL));
+            gc.fillPolygon(shape);
+            gc.setForeground(closeBorder);
+            gc.drawPolygon(shape);
+            break;
+        }
+        case CTabFolder.HOT: {
+            int[] shape = [x,y, x+2,y, x+4,y+2, x+5,y+2, x+7,y, x+9,y,
+                                     x+9,y+2, x+7,y+4, x+7,y+5, x+9,y+7, x+9,y+9,
+                                     x+7,y+9, x+5,y+7, x+4,y+7, x+2,y+9, x,y+9,
+                                     x,y+7, x+2,y+5, x+2,y+4, x,y+2];
+            Color fill = new Color(display, CTabFolder.CLOSE_FILL);
+            gc.setBackground(fill);
+            gc.fillPolygon(shape);
+            fill.dispose();
+            gc.setForeground(closeBorder);
+            gc.drawPolygon(shape);
+            break;
+        }
+        case CTabFolder.SELECTED: {
+            int[] shape = [x+1,y+1, x+3,y+1, x+5,y+3, x+6,y+3, x+8,y+1, x+10,y+1,
+                                     x+10,y+3, x+8,y+5, x+8,y+6, x+10,y+8, x+10,y+10,
+                                     x+8,y+10, x+6,y+8, x+5,y+8, x+3,y+10, x+1,y+10,
+                                     x+1,y+8, x+3,y+6, x+3,y+5, x+1,y+3];
+            Color fill = new Color(display, CTabFolder.CLOSE_FILL);
+            gc.setBackground(fill);
+            gc.fillPolygon(shape);
+            fill.dispose();
+            gc.setForeground(closeBorder);
+            gc.drawPolygon(shape);
+            break;
+        }
+        case CTabFolder.NONE: {
+            int[] shape = [x,y, x+10,y, x+10,y+10, x,y+10];
+            if (parent.gradientColors !is null && !parent.gradientVertical) {
+                parent.drawBackground(gc, shape, false);
+            } else {
+                Color defaultBackground = parent.getBackground();
+                Image image = parent.bgImage;
+                Color[] colors = parent.gradientColors;
+                int[] percents = parent.gradientPercents;
+                bool vertical = parent.gradientVertical;
+                parent.drawBackground(gc, shape, x, y, 10, 10, defaultBackground, image, colors, percents, vertical);
+            }
+            break;
+        }
+        default:
     }
+}
+void drawSelected(GC gc ) {
+    Point size = parent.getSize();
+    int rightEdge = Math.min (x + width, parent.getRightItemEdge());
 
-    String shortenText (GC gc, String text, int width) {
-        return useEllipses() ? shortenText(gc, text, width, ELLIPSIS) : shortenText(gc, text, width, ""); //$NON-NLS-1$
+    //   Draw selection border across all tabs
+    int xx = parent.borderLeft;
+    int yy = parent.onBottom ? size.y - parent.borderBottom - parent.tabHeight - parent.highlight_header : parent.borderTop + parent.tabHeight + 1;
+    int ww = size.x - parent.borderLeft - parent.borderRight;
+    int hh = parent.highlight_header - 1;
+    int[] shape = [xx,yy, xx+ww,yy, xx+ww,yy+hh, xx,yy+hh];
+    if (parent.selectionGradientColors !is null && !parent.selectionGradientVertical) {
+        parent.drawBackground(gc, shape, true);
+    } else {
+        gc.setBackground(parent.selectionBackground);
+        gc.fillRectangle(xx, yy, ww, hh);
     }
 
-    String shortenText (GC gc, String text, int width, String ellipses) {
-        if (gc.textExtent(text, FLAGS).x <= width)
-            return text;
-        int ellipseWidth = gc.textExtent(ellipses, FLAGS).x;
-        int length = text.length;
-        TextLayout layout = new TextLayout(getDisplay());
-        layout.setText(text);
-        int end = layout.getPreviousOffset(length, DWT.MOVEMENT_CLUSTER);
-        while (end > 0) {
-            text = text.substring(0, end);
-            int l = gc.textExtent(text, FLAGS).x;
-            if (l + ellipseWidth <= width) {
-                break;
-            }
-            end = layout.getPreviousOffset(end, DWT.MOVEMENT_CLUSTER);
+    if (parent.single) {
+        if (!showing) return;
+    } else {
+        // if selected tab scrolled out of view or partially out of view
+        // just draw bottom line
+        if (!showing){
+            int x1 = Math.max(0, parent.borderLeft - 1);
+            int y1 = (parent.onBottom) ? y - 1 : y + height;
+            int x2 = size.x - parent.borderRight;
+            gc.setForeground(CTabFolder.borderColor);
+            gc.drawLine(x1, y1, x2, y1);
+            return;
         }
-        layout.dispose();
-        return end is 0 ? text.substring(0, 1) : text + ellipses;
-    }
+
+        // draw selected tab background and outline
+        shape = null;
+        if (this.parent.onBottom) {
+            int[] left = parent.simple ? CTabFolder.SIMPLE_BOTTOM_LEFT_CORNER : CTabFolder.BOTTOM_LEFT_CORNER;
+            int[] right = parent.simple ? CTabFolder.SIMPLE_BOTTOM_RIGHT_CORNER : parent.curve;
+            if (parent.borderLeft is 0 && parent.indexOf(this) is parent.firstIndex) {
+                left = [x, y+height];
+            }
+            shape = new int[left.length+right.length+8];
+            int index = 0;
+            shape[index++] = x; // first point repeated here because below we reuse shape to draw outline
+            shape[index++] = y - 1;
+            shape[index++] = x;
+            shape[index++] = y - 1;
+            for (int i = 0; i < left.length/2; i++) {
+                shape[index++] = x + left[2*i];
+                shape[index++] = y + height + left[2*i+1] - 1;
+            }
+            for (int i = 0; i < right.length/2; i++) {
+                shape[index++] = parent.simple ? rightEdge - 1 + right[2*i] : rightEdge - parent.curveIndent + right[2*i];
+                shape[index++] = parent.simple ? y + height + right[2*i+1] - 1 : y + right[2*i+1] - 2;
+            }
+            shape[index++] = parent.simple ? rightEdge - 1 : rightEdge + parent.curveWidth - parent.curveIndent;
+            shape[index++] = y - 1;
+            shape[index++] = parent.simple ? rightEdge - 1 : rightEdge + parent.curveWidth - parent.curveIndent;
+            shape[index++] = y - 1;
+        } else {
+            int[] left = parent.simple ? CTabFolder.SIMPLE_TOP_LEFT_CORNER : CTabFolder.TOP_LEFT_CORNER;
+            int[] right = parent.simple ? CTabFolder.SIMPLE_TOP_RIGHT_CORNER : parent.curve;
+            if (parent.borderLeft is 0 && parent.indexOf(this) is parent.firstIndex) {
+                left = [x, y];
+            }
+            shape = new int[left.length+right.length+8];
+            int index = 0;
+            shape[index++] = x; // first point repeated here because below we reuse shape to draw outline
+            shape[index++] = y + height + 1;
+            shape[index++] = x;
+            shape[index++] = y + height + 1;
+            for (int i = 0; i < left.length/2; i++) {
+                shape[index++] = x + left[2*i];
+                shape[index++] = y + left[2*i+1];
+            }
+            for (int i = 0; i < right.length/2; i++) {
+                shape[index++] = parent.simple ? rightEdge - 1 + right[2*i] : rightEdge - parent.curveIndent + right[2*i];
+                shape[index++] = y + right[2*i+1];
+            }
+            shape[index++] = parent.simple ? rightEdge - 1 : rightEdge + parent.curveWidth - parent.curveIndent;
+            shape[index++] = y + height + 1;
+            shape[index++] = parent.simple ? rightEdge - 1 : rightEdge + parent.curveWidth - parent.curveIndent;
+            shape[index++] = y + height + 1;
+        }
 
-    public void dispose () {
-        if (isDisposed())
-            return;
-        //if (!isValidThread ()) error (DWT.ERROR_THREAD_INVALID_ACCESS);
-        parent.destroyItem(this);
-        super.dispose();
-        parent = null;
-        control = null;
-        toolTipText = null;
-        shortenedText = null;
-        font = null;
+        Rectangle clipping = gc.getClipping();
+        Rectangle bounds = getBounds();
+        bounds.height += 1;
+        if (parent.onBottom) bounds.y -= 1;
+        bool tabInPaint = clipping.intersects(bounds);
+
+        if (tabInPaint) {
+            // fill in tab background
+            if (parent.selectionGradientColors !is null && !parent.selectionGradientVertical) {
+                parent.drawBackground(gc, shape, true);
+            } else {
+                Color defaultBackground = parent.selectionBackground;
+                Image image = parent.selectionBgImage;
+                Color[] colors = parent.selectionGradientColors;
+                int[] percents = parent.selectionGradientPercents;
+                bool vertical = parent.selectionGradientVertical;
+                xx = x;
+                yy = parent.onBottom ? y -1 : y + 1;
+                ww = width;
+                hh = height;
+                if (!parent.single && !parent.simple) ww += parent.curveWidth - parent.curveIndent;
+                parent.drawBackground(gc, shape, xx, yy, ww, hh, defaultBackground, image, colors, percents, vertical);
+            }
+        }
+
+        //Highlight MUST be drawn before the outline so that outline can cover it in the right spots (start of swoop)
+        //otherwise the curve looks jagged
+        drawHighlight(gc, rightEdge);
+
+        // draw outline
+        shape[0] = Math.max(0, parent.borderLeft - 1);
+        if (parent.borderLeft is 0 && parent.indexOf(this) is parent.firstIndex) {
+            shape[1] = parent.onBottom ? y + height - 1 : y;
+            shape[5] = shape[3] = shape[1];
+        }
+        shape[shape.length - 2] = size.x - parent.borderRight + 1;
+        for (int i = 0; i < shape.length/2; i++) {
+            if (shape[2*i + 1] is y + height + 1) shape[2*i + 1] -= 1;
+        }
+        RGB inside = parent.selectionBackground.getRGB();
+        if (parent.selectionBgImage !is null ||
+            (parent.selectionGradientColors !is null && parent.selectionGradientColors.length > 1)) {
+            inside = null;
+        }
+        RGB outside = parent.getBackground().getRGB();
+        if (parent.bgImage !is null ||
+            (parent.gradientColors !is null && parent.gradientColors.length > 1)) {
+            outside = null;
+        }
+        parent.antialias(shape, CTabFolder.borderColor.getRGB(), inside, outside, gc);
+        gc.setForeground(CTabFolder.borderColor);
+        gc.drawPolyline(shape);
+
+        if (!tabInPaint) return;
     }
 
-    void drawClose (GC gc) {
-        if (closeRect.width is 0 || closeRect.height is 0)
-            return;
-        Display display = getDisplay();
-
-        // draw X 9x9
-        int indent = Math.max(1, (CTabFolder.BUTTON_SIZE - 9) / 2);
-        int x = closeRect.x + indent;
-        int y = closeRect.y + indent;
-        y += parent.onBottom ? -1 : 1;
-
-        Color closeBorder = display.getSystemColor(CTabFolder.BUTTON_BORDER);
-        switch (closeImageState) {
-            case CTabFolder.NORMAL: {
-                int[] shape = new int[]
-                {
-                    x , y , x + 2 , y , x + 4 , y + 2 , x + 5 , y + 2 , x + 7 , y , x + 9 , y , x + 9 , y + 2 , x + 7 , y + 4 , x + 7 , y + 5 , x + 9 , y + 7 , x + 9 , y + 9 , x + 7 , y + 9 , x + 5 , y + 7 , x + 4 , y + 7 , x + 2 , y + 9 , x , y + 9 , x , y + 7 , x + 2 , y + 5 , x + 2 , y + 4 , x , y + 2
-                };
-                gc.setBackground(display.getSystemColor(CTabFolder.BUTTON_FILL));
-                gc.fillPolygon(shape);
-                gc.setForeground(closeBorder);
-                gc.drawPolygon(shape);
-                break;
-            }
-            case CTabFolder.HOT: {
-                int[] shape = new int[]
-                {
-                    x , y , x + 2 , y , x + 4 , y + 2 , x + 5 , y + 2 , x + 7 , y , x + 9 , y , x + 9 , y + 2 , x + 7 , y + 4 , x + 7 , y + 5 , x + 9 , y + 7 , x + 9 , y + 9 , x + 7 , y + 9 , x + 5 , y + 7 , x + 4 , y + 7 , x + 2 , y + 9 , x , y + 9 , x , y + 7 , x + 2 , y + 5 , x + 2 , y + 4 , x , y + 2
-                };
-                Color fill = new Color(display, CTabFolder.CLOSE_FILL);
-                gc.setBackground(fill);
-                gc.fillPolygon(shape);
-                fill.dispose();
-                gc.setForeground(closeBorder);
-                gc.drawPolygon(shape);
-                break;
-            }
-            case CTabFolder.SELECTED: {
-                int[] shape = new int[]
-                {
-                    x + 1 , y + 1 , x + 3 , y + 1 , x + 5 , y + 3 , x + 6 , y + 3 , x + 8 , y + 1 , x + 10 , y + 1 , x + 10 , y + 3 , x + 8 , y + 5 , x + 8 , y + 6 , x + 10 , y + 8 , x + 10 , y + 10 , x + 8 , y + 10 , x + 6 , y + 8 , x + 5 , y + 8 , x + 3 , y + 10 , x + 1 , y + 10 , x + 1 , y + 8 , x + 3 , y + 6 , x + 3 , y + 5 , x + 1 , y + 3
-                };
-                Color fill = new Color(display, CTabFolder.CLOSE_FILL);
-                gc.setBackground(fill);
-                gc.fillPolygon(shape);
-                fill.dispose();
-                gc.setForeground(closeBorder);
-                gc.drawPolygon(shape);
-                break;
-            }
-            case CTabFolder.NONE: {
-                int[] shape = new int[]
-                {
-                    x , y , x + 10 , y , x + 10 , y + 10 , x , y + 10
-                };
-                if (parent.gradientColors !is null && !parent.gradientVertical) {
-                    parent.drawBackground(gc, shape, false);
-                }
-                else {
-                    Color defaultBackground = parent.getBackground();
-                    Image image = parent.bgImage;
-                    Color[] colors = parent.gradientColors;
-                    int[] percents = parent.gradientPercents;
-                    bool vertical = parent.gradientVertical;
-                    parent.drawBackground(gc, shape, x, y, 10, 10, defaultBackground, image, colors, percents, vertical);
-                }
-                break;
-            }
+    // draw Image
+    int xDraw = x + LEFT_MARGIN;
+    if (parent.single && (parent.showClose || showClose)) xDraw += CTabFolder.BUTTON_SIZE;
+    Image image = getImage();
+    if (image !is null) {
+        Rectangle imageBounds = image.getBounds();
+        // only draw image if it won't overlap with close button
+        int maxImageWidth = rightEdge - xDraw - RIGHT_MARGIN;
+        if (!parent.single && closeRect.width > 0) maxImageWidth -= closeRect.width + INTERNAL_SPACING;
+        if (imageBounds.width < maxImageWidth) {
+            int imageX = xDraw;
+            int imageY = y + (height - imageBounds.height) / 2;
+            imageY += parent.onBottom ? -1 : 1;
+            gc.drawImage(image, imageX, imageY);
+            xDraw += imageBounds.width + INTERNAL_SPACING;
         }
     }
 
-    void drawSelected (GC gc) {
-        Point size = parent.getSize();
-        int rightEdge = Math.min(x + width, parent.getRightItemEdge());
+    // draw Text
+    int textWidth = rightEdge - xDraw - RIGHT_MARGIN;
+    if (!parent.single && closeRect.width > 0) textWidth -= closeRect.width + INTERNAL_SPACING;
+    if (textWidth > 0) {
+        Font gcFont = gc.getFont();
+        gc.setFont(font is null ? parent.getFont() : font);
 
-        //   Draw selection border across all tabs
-        int xx = parent.borderLeft;
-        int
-                yy = parent.onBottom ? size.y - parent.borderBottom - parent.tabHeight - parent.highlight_header : parent.borderTop + parent.tabHeight + 1;
-        int ww = size.x - parent.borderLeft - parent.borderRight;
-        int hh = parent.highlight_header - 1;
-        int[] shape = new int[]
-        {
-            xx , yy , xx + ww , yy , xx + ww , yy + hh , xx , yy + hh
-        };
-        if (parent.selectionGradientColors !is null && !parent.selectionGradientVertical) {
-            parent.drawBackground(gc, shape, true);
-        }
-        else {
-            gc.setBackground(parent.selectionBackground);
-            gc.fillRectangle(xx, yy, ww, hh);
-        }
-
-        if (parent.single) {
-            if (!showing)
-                return;
+        if (shortenedText is null || shortenedTextWidth !is textWidth) {
+            shortenedText = shortenText(gc, getText(), textWidth);
+            shortenedTextWidth = textWidth;
         }
-        else {
-            // if selected tab scrolled out of view or partially out of view
-            // just draw bottom line
-            if (!showing) {
-                int x1 = Math.max(0, parent.borderLeft - 1);
-                int y1 = (parent.onBottom) ? y - 1 : y + height;
-                int x2 = size.x - parent.borderRight;
-                gc.setForeground(CTabFolder.borderColor);
-                gc.drawLine(x1, y1, x2, y1);
-                return;
-            }
+        Point extent = gc.textExtent(shortenedText, FLAGS);
+        int textY = y + (height - extent.y) / 2;
+        textY += parent.onBottom ? -1 : 1;
+
+        gc.setForeground(parent.selectionForeground);
+        gc.drawText(shortenedText, xDraw, textY, FLAGS);
+        gc.setFont(gcFont);
 
-            // draw selected tab background and outline
-            shape = null;
-            if (this.parent.onBottom) {
-                int[] left = parent.simple ? CTabFolder.SIMPLE_BOTTOM_LEFT_CORNER : CTabFolder.BOTTOM_LEFT_CORNER;
-                int[] right = parent.simple ? CTabFolder.SIMPLE_BOTTOM_RIGHT_CORNER : parent.curve;
-                if (parent.borderLeft is 0 && parent.indexOf(this) is parent.firstIndex) {
-                    left = new int[]
-                    {
-                        x , y + height
-                    };
-                }
-                shape = new int[left.length + right.length + 8];
-                int index = 0;
-                shape[index++] = x; // first point repeated here because below we reuse shape to draw outline
-                shape[index++] = y - 1;
-                shape[index++] = x;
-                shape[index++] = y - 1;
-                for (int i = 0; i < left.length / 2; i++) {
-                    shape[index++] = x + left[2 * i];
-                    shape[index++] = y + height + left[2 * i + 1] - 1;
-                }
-                for (int i = 0; i < right.length / 2; i++) {
-                    shape[index++] = parent.simple ? rightEdge - 1 + right[2 * i] : rightEdge - parent.curveIndent + right[2 * i];
-                    shape[index++] = parent.simple ? y + height + right[2 * i + 1] - 1 : y + right[2 * i + 1] - 2;
-                }
-                shape[index++] = parent.simple ? rightEdge - 1 : rightEdge + parent.curveWidth - parent.curveIndent;
-                shape[index++] = y - 1;
-                shape[index++] = parent.simple ? rightEdge - 1 : rightEdge + parent.curveWidth - parent.curveIndent;
-                shape[index++] = y - 1;
+        // draw a Focus rectangle
+        if (parent.isFocusControl()) {
+            Display display = getDisplay();
+            if (parent.simple || parent.single) {
+                gc.setBackground(display.getSystemColor(DWT.COLOR_BLACK));
+                gc.setForeground(display.getSystemColor(DWT.COLOR_WHITE));
+                gc.drawFocus(xDraw-1, textY-1, extent.x+2, extent.y+2);
+            } else {
+                gc.setForeground(display.getSystemColor(CTabFolder.BUTTON_BORDER));
+                gc.drawLine(xDraw, textY+extent.y+1, xDraw+extent.x+1, textY+extent.y+1);
             }
-            else {
-                int[] left = parent.simple ? CTabFolder.SIMPLE_TOP_LEFT_CORNER : CTabFolder.TOP_LEFT_CORNER;
-                int[] right = parent.simple ? CTabFolder.SIMPLE_TOP_RIGHT_CORNER : parent.curve;
-                if (parent.borderLeft is 0 && parent.indexOf(this) is parent.firstIndex) {
-                    left = new int[]
-                    {
-                        x , y
-                    };
-                }
-                shape = new int[left.length + right.length + 8];
-                int index = 0;
-                shape[index++] = x; // first point repeated here because below we reuse shape to draw outline
-                shape[index++] = y + height + 1;
-                shape[index++] = x;
-                shape[index++] = y + height + 1;
-                for (int i = 0; i < left.length / 2; i++) {
-                    shape[index++] = x + left[2 * i];
-                    shape[index++] = y + left[2 * i + 1];
-                }
-                for (int i = 0; i < right.length / 2; i++) {
-                    shape[index++] = parent.simple ? rightEdge - 1 + right[2 * i] : rightEdge - parent.curveIndent + right[2 * i];
-                    shape[index++] = y + right[2 * i + 1];
-                }
-                shape[index++] = parent.simple ? rightEdge - 1 : rightEdge + parent.curveWidth - parent.curveIndent;
-                shape[index++] = y + height + 1;
-                shape[index++] = parent.simple ? rightEdge - 1 : rightEdge + parent.curveWidth - parent.curveIndent;
-                shape[index++] = y + height + 1;
-            }
+        }
+    }
+    if (parent.showClose || showClose) drawClose(gc);
+}
+
+/*
+ * Draw a highlight effect along the left, top, and right edges of the tab.
+ * Only for curved tabs, on top.
+ * Do not draw if insufficient colors.
+ */
+void drawHighlight(GC gc, int rightEdge) {
+    //only draw for curvy tabs and only draw for top tabs
+    if(parent.simple || this.parent.onBottom)
+        return;
+
+    if(parent.selectionHighlightGradientBegin is null)
+        return;
+
+    Color[] gradients = parent.selectionHighlightGradientColorsCache;
+    if(gradients is null)
+        return;
+    int gradientsSize = gradients.length;
+    if(gradientsSize is 0)
+        return;     //shouldn't happen but just to be tidy
+
+    gc.setForeground(gradients[0]);
 
-            Rectangle clipping = gc.getClipping();
-            Rectangle bounds = getBounds();
-            bounds.height += 1;
-            if (parent.onBottom)
-                bounds.y -= 1;
-            bool tabInPaint = clipping.intersects(bounds);
+    //draw top horizontal line
+    gc.drawLine(
+            CTabFolder.TOP_LEFT_CORNER_HILITE[0] + x + 1, //rely on fact that first pair is top/right of curve
+            1 + y,
+            rightEdge - parent.curveIndent,
+            1 + y);
+
+    int[] leftHighlightCurve = CTabFolder.TOP_LEFT_CORNER_HILITE;
+
+    int d = parent.tabHeight - parent.topCurveHighlightEnd.length /2;
+
+    int lastX = 0;
+    int lastY = 0;
+    int lastColorIndex = 0;
+
+    //draw upper left curve highlight
+    for (int i = 0; i < leftHighlightCurve.length /2; i++) {
+        int rawX = leftHighlightCurve[i * 2];
+        int rawY = leftHighlightCurve[i * 2 + 1];
+        lastX = rawX + x;
+        lastY = rawY + y;
+        lastColorIndex = rawY - 1;
+        gc.setForeground(gradients[lastColorIndex]);
+        gc.drawPoint(lastX, lastY);
+    }
+    //draw left vertical line highlight
+    for(int i = lastColorIndex; i < gradientsSize; i++) {
+        gc.setForeground(gradients[i]);
+        gc.drawPoint(lastX, 1 + lastY++);
+    }
+
+    int rightEdgeOffset = rightEdge - parent.curveIndent;
 
-            if (tabInPaint) {
-                // fill in tab background
-                if (parent.selectionGradientColors !is null && !parent.selectionGradientVertical) {
-                    parent.drawBackground(gc, shape, true);
-                }
-                else {
-                    Color defaultBackground = parent.selectionBackground;
-                    Image image = parent.selectionBgImage;
-                    Color[] colors = parent.selectionGradientColors;
-                    int[] percents = parent.selectionGradientPercents;
-                    bool vertical = parent.selectionGradientVertical;
-                    xx = x;
-                    yy = parent.onBottom ? y - 1 : y + 1;
-                    ww = width;
-                    hh = height;
-                    if (!parent.single && !parent.simple)
-                        ww += parent.curveWidth - parent.curveIndent;
-                    parent.drawBackground(gc, shape, xx, yy, ww, hh, defaultBackground, image, colors, percents, vertical);
-                }
-            }
+    //draw right swoop highlight up to diagonal portion
+    for (int i = 0; i < parent.topCurveHighlightStart.length /2; i++) {
+        int rawX = parent.topCurveHighlightStart[i * 2];
+        int rawY = parent.topCurveHighlightStart[i * 2 + 1];
+        lastX = rawX + rightEdgeOffset;
+        lastY = rawY + y;
+        lastColorIndex = rawY - 1;
+        if(lastColorIndex >= gradientsSize)
+            break;  //can happen if tabs are unusually short and cut off the curve
+        gc.setForeground(gradients[lastColorIndex]);
+        gc.drawPoint(lastX, lastY);
+    }
+    //draw right diagonal line highlight
+    for(int i = lastColorIndex; i < lastColorIndex + d; i++) {
+        if(i >= gradientsSize)
+            break;  //can happen if tabs are unusually short and cut off the curve
+        gc.setForeground(gradients[i]);
+        gc.drawPoint(1 + lastX++, 1 + lastY++);
+    }
 
-            //Highlight MUST be drawn before the outline so that outline can cover it in the right spots (start of swoop)
-            //otherwise the curve looks jagged
-            drawHighlight(gc, rightEdge);
+    //draw right swoop highlight from diagonal portion to end
+    for (int i = 0; i < parent.topCurveHighlightEnd.length /2; i++) {
+        int rawX = parent.topCurveHighlightEnd[i * 2]; //d is already encoded in this value
+        int rawY = parent.topCurveHighlightEnd[i * 2 + 1]; //d already encoded
+        lastX = rawX + rightEdgeOffset;
+        lastY = rawY + y;
+        lastColorIndex = rawY - 1;
+        if(lastColorIndex >= gradientsSize)
+            break;  //can happen if tabs are unusually short and cut off the curve
+        gc.setForeground(gradients[lastColorIndex]);
+        gc.drawPoint(lastX, lastY);
+    }
+}
 
-            // draw outline
-            shape[0] = Math.max(0, parent.borderLeft - 1);
-            if (parent.borderLeft is 0 && parent.indexOf(this) is parent.firstIndex) {
-                shape[1] = parent.onBottom ? y + height - 1 : y;
-                shape[5] = shape[3] = shape[1];
-            }
-            shape[shape.length - 2] = size.x - parent.borderRight + 1;
-            for (int i = 0; i < shape.length / 2; i++) {
-                if (shape[2 * i + 1] is y + height + 1)
-                    shape[2 * i + 1] -= 1;
-            }
-            RGB inside = parent.selectionBackground.getRGB();
-            if (parent.selectionBgImage !is null || (parent.selectionGradientColors !is null && parent.selectionGradientColors.length > 1)) {
-                inside = null;
-            }
-            RGB outside = parent.getBackground().getRGB();
-            if (parent.bgImage !is null || (parent.gradientColors !is null && parent.gradientColors.length > 1)) {
-                outside = null;
-            }
-            parent.antialias(shape, CTabFolder.borderColor.getRGB(), inside, outside, gc);
-            gc.setForeground(CTabFolder.borderColor);
-            gc.drawPolyline(shape);
+/*
+ * Draw the unselected border for the receiver on the right.
+ *
+ * @param gc
+ */
+void drawRightUnselectedBorder(GC gc) {
+
+    int[] shape = null;
+    int startX = x + width - 1;
+
+    if (this.parent.onBottom) {
+        int[] right = parent.simple
+            ? CTabFolder.SIMPLE_UNSELECTED_INNER_CORNER
+            : CTabFolder.BOTTOM_RIGHT_CORNER;
+
+        shape = new int[right.length + 2];
+        int index = 0;
 
-            if (!tabInPaint)
-                return;
+        for (int i = 0; i < right.length / 2; i++) {
+            shape[index++] = startX + right[2 * i];
+            shape[index++] = y + height + right[2 * i + 1] - 1;
+        }
+        shape[index++] = startX;
+        shape[index++] = y - 1;
+    } else {
+        int[] right = parent.simple
+            ? CTabFolder.SIMPLE_UNSELECTED_INNER_CORNER
+            : CTabFolder.TOP_RIGHT_CORNER;
+
+        shape = new int[right.length + 2];
+        int index = 0;
+
+        for (int i = 0; i < right.length / 2; i++) {
+            shape[index++] = startX + right[2 * i];
+            shape[index++] = y + right[2 * i + 1];
         }
 
-        // draw Image
-        int xDraw = x + LEFT_MARGIN;
-        if (parent.single && (parent.showClose || showClose))
-            xDraw += CTabFolder.BUTTON_SIZE;
-        Image image = getImage();
-        if (image !is null) {
-            Rectangle imageBounds = image.getBounds();
-            // only draw image if it won't overlap with close button
-            int maxImageWidth = rightEdge - xDraw - RIGHT_MARGIN;
-            if (!parent.single && closeRect.width > 0)
-                maxImageWidth -= closeRect.width + INTERNAL_SPACING;
-            if (imageBounds.width < maxImageWidth) {
-                int imageX = xDraw;
-                int imageY = y + (height - imageBounds.height) / 2;
-                imageY += parent.onBottom ? -1 : 1;
-                gc.drawImage(image, imageX, imageY);
-                xDraw += imageBounds.width + INTERNAL_SPACING;
-            }
-        }
-
-        // draw Text
-        int textWidth = rightEdge - xDraw - RIGHT_MARGIN;
-        if (!parent.single && closeRect.width > 0)
-            textWidth -= closeRect.width + INTERNAL_SPACING;
-        if (textWidth > 0) {
-            Font gcFont = gc.getFont();
-            gc.setFont(font is null ? parent.getFont() : font);
-
-            if (shortenedText is null || shortenedTextWidth !is textWidth) {
-                shortenedText = shortenText(gc, getText(), textWidth);
-                shortenedTextWidth = textWidth;
-            }
-            Point extent = gc.textExtent(shortenedText, FLAGS);
-            int textY = y + (height - extent.y) / 2;
-            textY += parent.onBottom ? -1 : 1;
-
-            gc.setForeground(parent.selectionForeground);
-            gc.drawText(shortenedText, xDraw, textY, FLAGS);
-            gc.setFont(gcFont);
-
-            // draw a Focus rectangle
-            if (parent.isFocusControl()) {
-                Display display = getDisplay();
-                if (parent.simple || parent.single) {
-                    gc.setBackground(display.getSystemColor(DWT.COLOR_BLACK));
-                    gc.setForeground(display.getSystemColor(DWT.COLOR_WHITE));
-                    gc.drawFocus(xDraw - 1, textY - 1, extent.x + 2, extent.y + 2);
-                }
-                else {
-                    gc.setForeground(display.getSystemColor(CTabFolder.BUTTON_BORDER));
-                    gc.drawLine(xDraw, textY + extent.y + 1, xDraw + extent.x + 1, textY + extent.y + 1);
-                }
-            }
-        }
-        if (parent.showClose || showClose)
-            drawClose(gc);
-    }
-
-    /*
-     * Draw a highlight effect along the left, top, and right edges of the tab.
-     * Only for curved tabs, on top.
-     * Do not draw if insufficient colors.
-     */
-    void drawHighlight (GC gc, int rightEdge) {
-        //only draw for curvy tabs and only draw for top tabs
-        if (parent.simple || this.parent.onBottom)
-            return;
-
-        if (parent.selectionHighlightGradientBegin is null)
-            return;
-
-        Color[] gradients = parent.selectionHighlightGradientColorsCache;
-        if (gradients is null)
-            return;
-        int gradientsSize = gradients.length;
-        if (gradientsSize is 0)
-            return; //shouldn't happen but just to be tidy
-
-        gc.setForeground(gradients[0]);
-
-        //draw top horizontal line
-        gc.drawLine(CTabFolder.TOP_LEFT_CORNER_HILITE[0] + x + 1, //rely on fact that first pair is top/right of curve
-                1 + y, rightEdge - parent.curveIndent, 1 + y);
-
-        int[] leftHighlightCurve = CTabFolder.TOP_LEFT_CORNER_HILITE;
-
-        int d = parent.tabHeight - parent.topCurveHighlightEnd.length / 2;
-
-        int lastX = 0;
-        int lastY = 0;
-        int lastColorIndex = 0;
-
-        //draw upper left curve highlight
-        for (int i = 0; i < leftHighlightCurve.length / 2; i++) {
-            int rawX = leftHighlightCurve[i * 2];
-            int rawY = leftHighlightCurve[i * 2 + 1];
-            lastX = rawX + x;
-            lastY = rawY + y;
-            lastColorIndex = rawY - 1;
-            gc.setForeground(gradients[lastColorIndex]);
-            gc.drawPoint(lastX, lastY);
-        }
-        //draw left vertical line highlight
-        for (int i = lastColorIndex; i < gradientsSize; i++) {
-            gc.setForeground(gradients[i]);
-            gc.drawPoint(lastX, 1 + lastY++);
-        }
-
-        int rightEdgeOffset = rightEdge - parent.curveIndent;
-
-        //draw right swoop highlight up to diagonal portion
-        for (int i = 0; i < parent.topCurveHighlightStart.length / 2; i++) {
-            int rawX = parent.topCurveHighlightStart[i * 2];
-            int rawY = parent.topCurveHighlightStart[i * 2 + 1];
-            lastX = rawX + rightEdgeOffset;
-            lastY = rawY + y;
-            lastColorIndex = rawY - 1;
-            if (lastColorIndex >= gradientsSize)
-                break; //can happen if tabs are unusually short and cut off the curve
-            gc.setForeground(gradients[lastColorIndex]);
-            gc.drawPoint(lastX, lastY);
-        }
-        //draw right diagonal line highlight
-        for (int i = lastColorIndex; i < lastColorIndex + d; i++) {
-            if (i >= gradientsSize)
-                break; //can happen if tabs are unusually short and cut off the curve
-            gc.setForeground(gradients[i]);
-            gc.drawPoint(1 + lastX++, 1 + lastY++);
-        }
-
-        //draw right swoop highlight from diagonal portion to end
-        for (int i = 0; i < parent.topCurveHighlightEnd.length / 2; i++) {
-            int rawX = parent.topCurveHighlightEnd[i * 2]; //d is already encoded in this value
-            int rawY = parent.topCurveHighlightEnd[i * 2 + 1]; //d already encoded
-            lastX = rawX + rightEdgeOffset;
-            lastY = rawY + y;
-            lastColorIndex = rawY - 1;
-            if (lastColorIndex >= gradientsSize)
-                break; //can happen if tabs are unusually short and cut off the curve
-            gc.setForeground(gradients[lastColorIndex]);
-            gc.drawPoint(lastX, lastY);
-        }
-    }
-
-    /*
-     * Draw the unselected border for the receiver on the right.
-     * 
-     * @param gc
-     */
-    void drawRightUnselectedBorder (GC gc) {
-
-        int[] shape = null;
-        int startX = x + width - 1;
-
-        if (this.parent.onBottom) {
-            int[] right = parent.simple ? CTabFolder.SIMPLE_UNSELECTED_INNER_CORNER : CTabFolder.BOTTOM_RIGHT_CORNER;
-
-            shape = new int[right.length + 2];
-            int index = 0;
-
-            for (int i = 0; i < right.length / 2; i++) {
-                shape[index++] = startX + right[2 * i];
-                shape[index++] = y + height + right[2 * i + 1] - 1;
-            }
-            shape[index++] = startX;
-            shape[index++] = y - 1;
-        }
-        else {
-            int[] right = parent.simple ? CTabFolder.SIMPLE_UNSELECTED_INNER_CORNER : CTabFolder.TOP_RIGHT_CORNER;
-
-            shape = new int[right.length + 2];
-            int index = 0;
-
-            for (int i = 0; i < right.length / 2; i++) {
-                shape[index++] = startX + right[2 * i];
-                shape[index++] = y + right[2 * i + 1];
-            }
-
-            shape[index++] = startX;
-            shape[index++] = y + height;
-
-        }
-
-        drawBorder(gc, shape);
+        shape[index++] = startX;
+        shape[index++] = y + height;
 
     }
 
-    /*
-     * Draw the border of the tab
-     * 
-     * @param gc
-     * @param shape
-     */
-    void drawBorder (GC gc, int[] shape) {
+    drawBorder(gc, shape);
+
+}
 
-        gc.setForeground(CTabFolder.borderColor);
-        gc.drawPolyline(shape);
-    }
+/*
+ * Draw the border of the tab
+ *
+ * @param gc
+ * @param shape
+ */
+void drawBorder(GC gc, int[] shape) {
 
-    /*
-     * Draw the unselected border for the receiver on the left.
-     * 
-     * @param gc
-     */
-    void drawLeftUnselectedBorder (GC gc) {
+    gc.setForeground(CTabFolder.borderColor);
+    gc.drawPolyline(shape);
+}
+
+/*
+ * Draw the unselected border for the receiver on the left.
+ *
+ * @param gc
+ */
+void drawLeftUnselectedBorder(GC gc) {
 
-        int[] shape = null;
-        if (this.parent.onBottom) {
-            int[] left = parent.simple ? CTabFolder.SIMPLE_UNSELECTED_INNER_CORNER : CTabFolder.BOTTOM_LEFT_CORNER;
+    int[] shape = null;
+    if (this.parent.onBottom) {
+        int[] left = parent.simple
+            ? CTabFolder.SIMPLE_UNSELECTED_INNER_CORNER
+            : CTabFolder.BOTTOM_LEFT_CORNER;
 
-            shape = new int[left.length + 2];
-            int index = 0;
-            shape[index++] = x;
-            shape[index++] = y - 1;
-            for (int i = 0; i < left.length / 2; i++) {
-                shape[index++] = x + left[2 * i];
-                shape[index++] = y + height + left[2 * i + 1] - 1;
-            }
+        shape = new int[left.length + 2];
+        int index = 0;
+        shape[index++] = x;
+        shape[index++] = y - 1;
+        for (int i = 0; i < left.length / 2; i++) {
+            shape[index++] = x + left[2 * i];
+            shape[index++] = y + height + left[2 * i + 1] - 1;
         }
-        else {
-            int[] left = parent.simple ? CTabFolder.SIMPLE_UNSELECTED_INNER_CORNER : CTabFolder.TOP_LEFT_CORNER;
+    } else {
+        int[] left = parent.simple
+            ? CTabFolder.SIMPLE_UNSELECTED_INNER_CORNER
+            : CTabFolder.TOP_LEFT_CORNER;
 
-            shape = new int[left.length + 2];
-            int index = 0;
-            shape[index++] = x;
-            shape[index++] = y + height;
-            for (int i = 0; i < left.length / 2; i++) {
-                shape[index++] = x + left[2 * i];
-                shape[index++] = y + left[2 * i + 1];
-            }
-
+        shape = new int[left.length + 2];
+        int index = 0;
+        shape[index++] = x;
+        shape[index++] = y + height;
+        for (int i = 0; i < left.length / 2; i++) {
+            shape[index++] = x + left[2 * i];
+            shape[index++] = y + left[2 * i + 1];
         }
 
-        drawBorder(gc, shape);
-    }
-
-    void drawUnselected (GC gc) {
-        // Do not draw partial items
-        if (!showing)
-            return;
-
-        Rectangle clipping = gc.getClipping();
-        Rectangle bounds = getBounds();
-        if (!clipping.intersects(bounds))
-            return;
-
-        // draw border
-        int index = parent.indexOf(this);
-
-        if (index > 0 && index < parent.selectedIndex)
-            drawLeftUnselectedBorder(gc);
-        // If it is the last one then draw a line
-        if (index > parent.selectedIndex)
-            drawRightUnselectedBorder(gc);
-
-        // draw Image
-        int xDraw = x + LEFT_MARGIN;
-        Image image = getImage();
-        if (image !is null && parent.showUnselectedImage) {
-            Rectangle imageBounds = image.getBounds();
-            // only draw image if it won't overlap with close button
-            int maxImageWidth = x + width - xDraw - RIGHT_MARGIN;
-            if (parent.showUnselectedClose && (parent.showClose || showClose)) {
-                maxImageWidth -= closeRect.width + INTERNAL_SPACING;
-            }
-            if (imageBounds.width < maxImageWidth) {
-                int imageX = xDraw;
-                int imageHeight = imageBounds.height;
-                int imageY = y + (height - imageHeight) / 2;
-                imageY += parent.onBottom ? -1 : 1;
-                int imageWidth = imageBounds.width * imageHeight / imageBounds.height;
-                gc.drawImage(image, imageBounds.x, imageBounds.y, imageBounds.width, imageBounds.height, imageX, imageY, imageWidth, imageHeight);
-                xDraw += imageWidth + INTERNAL_SPACING;
-            }
-        }
-        // draw Text
-        int textWidth = x + width - xDraw - RIGHT_MARGIN;
-        if (parent.showUnselectedClose && (parent.showClose || showClose)) {
-            textWidth -= closeRect.width + INTERNAL_SPACING;
-        }
-        if (textWidth > 0) {
-            Font gcFont = gc.getFont();
-            gc.setFont(font is null ? parent.getFont() : font);
-            if (shortenedText is null || shortenedTextWidth !is textWidth) {
-                shortenedText = shortenText(gc, getText(), textWidth);
-                shortenedTextWidth = textWidth;
-            }
-            Point extent = gc.textExtent(shortenedText, FLAGS);
-            int textY = y + (height - extent.y) / 2;
-            textY += parent.onBottom ? -1 : 1;
-            gc.setForeground(parent.getForeground());
-            gc.drawText(shortenedText, xDraw, textY, FLAGS);
-            gc.setFont(gcFont);
-        }
-        // draw close
-        if (parent.showUnselectedClose && (parent.showClose || showClose))
-            drawClose(gc);
-    }
-
-    /**
-     * Returns a rectangle describing the receiver's size and location
-     * relative to its parent.
-     *
-     * @return the receiver's bounding column rectangle
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public Rectangle getBounds () {
-        //checkWidget();
-        int w = width;
-        if (!parent.simple && !parent.single && parent.indexOf(this) is parent.selectedIndex)
-            w += parent.curveWidth - parent.curveIndent;
-        return new Rectangle(x, y, w, height);
-    }
-
-    /**
-     * Gets the control that is displayed in the content area of the tab item.
-     *
-     * @return the control
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public Control getControl () {
-        checkWidget();
-        return control;
-    }
-
-    /**
-     * Get the image displayed in the tab if the tab is disabled.
-     * 
-     * @return the disabled image or null
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @deprecated the disabled image is not used
-     */
-    public Image getDisabledImage () {
-        checkWidget();
-        return disabledImage;
-    }
-
-    /**
-     * Returns the font that the receiver will use to paint textual information.
-     *
-     * @return the receiver's font
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     *  @since 3.0
-     */
-    public Font getFont () {
-        checkWidget();
-        if (font !is null)
-            return font;
-        return parent.getFont();
-    }
-
-    /**
-     * Returns the receiver's parent, which must be a <code>CTabFolder</code>.
-     *
-     * @return the receiver's parent
-     * 
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public CTabFolder getParent () {
-        //checkWidget();
-        return parent;
-    }
-
-    /**
-     * Returns <code>true</code> to indicate that the receiver's close button should be shown.
-     * Otherwise return <code>false</code>. The initial value is defined by the style (DWT.CLOSE)
-     * that was used to create the receiver.
-     * 
-     * @return <code>true</code> if the close button should be shown
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.4
-     */
-    public bool getShowClose () {
-        checkWidget();
-        return showClose;
-    }
-
-    /**
-     * Returns the receiver's tool tip text, or null if it has
-     * not been set.
-     *
-     * @return the receiver's tool tip text
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public String getToolTipText () {
-        checkWidget();
-        if (toolTipText is null && shortenedText !is null) {
-            String text = getText();
-            if (!shortenedText.opEquals(text))
-                return text;
-        }
-        return toolTipText;
     }
 
-    /**
-     * Returns <code>true</code> if the item will be rendered in the visible area of the CTabFolder. Returns false otherwise.
-     * 
-     *  @return <code>true</code> if the item will be rendered in the visible area of the CTabFolder. Returns false otherwise.
-     * 
-     *  @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public bool isShowing () {
-        checkWidget();
-        return showing;
-    }
+    drawBorder(gc, shape);
+}
+
+void drawUnselected(GC gc) {
+    // Do not draw partial items
+    if (!showing) return;
+
+    Rectangle clipping = gc.getClipping();
+    Rectangle bounds = getBounds();
+    if (!clipping.intersects(bounds)) return;
+
+    // draw border
+    int index = parent.indexOf(this);
+
+    if (index > 0 && index < parent.selectedIndex)
+        drawLeftUnselectedBorder(gc);
+    // If it is the last one then draw a line
+    if (index > parent.selectedIndex)
+        drawRightUnselectedBorder(gc);
 
-    void onPaint (GC gc, bool isSelected) {
-        if (width is 0 || height is 0)
-            return;
-        if (isSelected) {
-            drawSelected(gc);
+    // draw Image
+    int xDraw = x + LEFT_MARGIN;
+    Image image = getImage();
+    if (image !is null && parent.showUnselectedImage) {
+        Rectangle imageBounds = image.getBounds();
+        // only draw image if it won't overlap with close button
+        int maxImageWidth = x + width - xDraw - RIGHT_MARGIN;
+        if (parent.showUnselectedClose && (parent.showClose || showClose)) {
+            maxImageWidth -= closeRect.width + INTERNAL_SPACING;
         }
-        else {
-            drawUnselected(gc);
+        if (imageBounds.width < maxImageWidth) {
+            int imageX = xDraw;
+            int imageHeight = imageBounds.height;
+            int imageY = y + (height - imageHeight) / 2;
+            imageY += parent.onBottom ? -1 : 1;
+            int imageWidth = imageBounds.width * imageHeight / imageBounds.height;
+            gc.drawImage(image,
+                         imageBounds.x, imageBounds.y, imageBounds.width, imageBounds.height,
+                         imageX, imageY, imageWidth, imageHeight);
+            xDraw += imageWidth + INTERNAL_SPACING;
         }
     }
-
-    int preferredHeight (GC gc) {
-        Image image = getImage();
-        int h = (image is null) ? 0 : image.getBounds().height;
+    // draw Text
+    int textWidth = x + width - xDraw - RIGHT_MARGIN;
+    if (parent.showUnselectedClose && (parent.showClose || showClose)) {
+        textWidth -= closeRect.width + INTERNAL_SPACING;
+    }
+    if (textWidth > 0) {
+        Font gcFont = gc.getFont();
+        gc.setFont(font is null ? parent.getFont() : font);
+        if (shortenedText is null || shortenedTextWidth !is textWidth) {
+            shortenedText = shortenText(gc, getText(), textWidth);
+            shortenedTextWidth = textWidth;
+        }
+        Point extent = gc.textExtent(shortenedText, FLAGS);
+        int textY = y + (height - extent.y) / 2;
+        textY += parent.onBottom ? -1 : 1;
+        gc.setForeground(parent.getForeground());
+        gc.drawText(shortenedText, xDraw, textY, FLAGS);
+        gc.setFont(gcFont);
+    }
+    // draw close
+    if (parent.showUnselectedClose && (parent.showClose || showClose)) drawClose(gc);
+}
+/**
+ * Returns a rectangle describing the receiver's size and location
+ * relative to its parent.
+ *
+ * @return the receiver's bounding column rectangle
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public Rectangle getBounds () {
+    //checkWidget();
+    int w = width;
+    if (!parent.simple && !parent.single && parent.indexOf(this) is parent.selectedIndex) w += parent.curveWidth - parent.curveIndent;
+    return new Rectangle(x, y, w, height);
+}
+/**
+* Gets the control that is displayed in the content area of the tab item.
+*
+* @return the control
+*
+* @exception DWTException <ul>
+*    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+*    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+* </ul>
+*/
+public Control getControl () {
+    checkWidget();
+    return control;
+}
+/**
+ * Get the image displayed in the tab if the tab is disabled.
+ *
+ * @return the disabled image or null
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @deprecated the disabled image is not used
+ */
+public Image getDisabledImage(){
+    checkWidget();
+    return disabledImage;
+}
+/**
+ * Returns the font that the receiver will use to paint textual information.
+ *
+ * @return the receiver's font
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ *  @since 3.0
+ */
+public Font getFont() {
+    checkWidget();
+    if (font !is null) return font;
+    return parent.getFont();
+}
+/**
+ * Returns the receiver's parent, which must be a <code>CTabFolder</code>.
+ *
+ * @return the receiver's parent
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public CTabFolder getParent () {
+    //checkWidget();
+    return parent;
+}
+/**
+ * Returns <code>true</code> to indicate that the receiver's close button should be shown.
+ * Otherwise return <code>false</code>. The initial value is defined by the style (DWT.CLOSE)
+ * that was used to create the receiver.
+ *
+ * @return <code>true</code> if the close button should be shown
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.4
+ */
+public bool getShowClose() {
+    checkWidget();
+    return showClose;
+}
+/**
+ * Returns the receiver's tool tip text, or null if it has
+ * not been set.
+ *
+ * @return the receiver's tool tip text
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public String getToolTipText () {
+    checkWidget();
+    if (toolTipText is null && shortenedText !is null) {
         String text = getText();
+        if (shortenedText!=text) return text;
+    }
+    return toolTipText;
+}
+/**
+* Returns <code>true</code> if the item will be rendered in the visible area of the CTabFolder. Returns false otherwise.
+*
+*  @return <code>true</code> if the item will be rendered in the visible area of the CTabFolder. Returns false otherwise.
+*
+*  @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+* @since 3.0
+*/
+public bool isShowing () {
+    checkWidget();
+    return showing;
+}
+void onPaint(GC gc, bool isSelected) {
+    if (width is 0 || height is 0) return;
+    if (isSelected) {
+        drawSelected(gc);
+    } else {
+        drawUnselected(gc);
+    }
+}
+int preferredHeight(GC gc) {
+    Image image = getImage();
+    int h = (image is null) ? 0 : image.getBounds().height;
+    String text = getText();
+    if (font is null) {
+        h = Math.max(h, gc.textExtent(text, FLAGS).y);
+    } else {
+        Font gcFont = gc.getFont();
+        gc.setFont(font);
+        h = Math.max(h, gc.textExtent(text, FLAGS).y);
+        gc.setFont(gcFont);
+    }
+    return h + TOP_MARGIN + BOTTOM_MARGIN;
+}
+int preferredWidth(GC gc, bool isSelected, bool minimum) {
+    // NOTE: preferred width does not include the "dead space" caused
+    // by the curve.
+    if (isDisposed()) return 0;
+    int w = 0;
+    Image image = getImage();
+    if (image !is null && (isSelected || parent.showUnselectedImage)) {
+        w += image.getBounds().width;
+    }
+    String text = null;
+    if (minimum) {
+        int minChars = parent.minChars;
+        text = minChars is 0 ? null : getText();
+        if (text !is null && text.length > minChars) {
+            if (useEllipses()) {
+                int end = minChars < ELLIPSIS.length + 1 ? minChars : minChars - ELLIPSIS.length;
+                text = text[ 0 .. end ];
+                if (minChars > ELLIPSIS.length + 1) text ~= ELLIPSIS;
+            } else {
+                int end = minChars;
+                text = text[ 0 .. end ];
+            }
+        }
+    } else {
+        text = getText();
+    }
+    if (text !is null) {
+        if (w > 0) w += INTERNAL_SPACING;
         if (font is null) {
-            h = Math.max(h, gc.textExtent(text, FLAGS).y);
-        }
-        else {
+            w += gc.textExtent(text, FLAGS).x;
+        } else {
             Font gcFont = gc.getFont();
             gc.setFont(font);
-            h = Math.max(h, gc.textExtent(text, FLAGS).y);
+            w += gc.textExtent(text, FLAGS).x;
             gc.setFont(gcFont);
         }
-        return h + TOP_MARGIN + BOTTOM_MARGIN;
     }
-
-    int preferredWidth (GC gc, bool isSelected, bool minimum) {
-        // NOTE: preferred width does not include the "dead space" caused
-        // by the curve.
-        if (isDisposed())
-            return 0;
-        int w = 0;
-        Image image = getImage();
-        if (image !is null && (isSelected || parent.showUnselectedImage)) {
-            w += image.getBounds().width;
-        }
-        String text = null;
-        if (minimum) {
-            int minChars = parent.minChars;
-            text = minChars is 0 ? null : getText();
-            if (text !is null && text.length() > minChars) {
-                if (useEllipses()) {
-                    int end = minChars < ELLIPSIS.length() + 1 ? minChars : minChars - ELLIPSIS.length();
-                    text = text.substring(0, end);
-                    if (minChars > ELLIPSIS.length() + 1)
-                        text += ELLIPSIS;
-                }
-                else {
-                    int end = minChars;
-                    text = text.substring(0, end);
-                }
-            }
-        }
-        else {
-            text = getText();
+    if (parent.showClose || showClose) {
+        if (isSelected || parent.showUnselectedClose) {
+            if (w > 0) w += INTERNAL_SPACING;
+            w += CTabFolder.BUTTON_SIZE;
         }
-        if (text !is null) {
-            if (w > 0)
-                w += INTERNAL_SPACING;
-            if (font is null) {
-                w += gc.textExtent(text, FLAGS).x;
-            }
-            else {
-                Font gcFont = gc.getFont();
-                gc.setFont(font);
-                w += gc.textExtent(text, FLAGS).x;
-                gc.setFont(gcFont);
-            }
-        }
-        if (parent.showClose || showClose) {
-            if (isSelected || parent.showUnselectedClose) {
-                if (w > 0)
-                    w += INTERNAL_SPACING;
-                w += CTabFolder.BUTTON_SIZE;
-            }
-        }
-        return w + LEFT_MARGIN + RIGHT_MARGIN;
     }
-
-    /**
-     * Sets the control that is used to fill the client area of
-     * the tab folder when the user selects the tab item.
-     *
-     * @param control the new control (or null)
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</li> 
-     *    <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</li>
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setControl (Control control) {
-        checkWidget();
-        if (control !is null) {
-            if (control.isDisposed())
-                DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-            if (control.getParent() !is parent)
-                DWT.error(DWT.ERROR_INVALID_PARENT);
-        }
-        if (this.control !is null && !this.control.isDisposed()) {
+    return w + LEFT_MARGIN + RIGHT_MARGIN;
+}
+/**
+ * Sets the control that is used to fill the client area of
+ * the tab folder when the user selects the tab item.
+ *
+ * @param control the new control (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</li>
+ *    <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setControl (Control control) {
+    checkWidget();
+    if (control !is null) {
+        if (control.isDisposed()) DWT.error (DWT.ERROR_INVALID_ARGUMENT);
+        if (control.getParent() !is parent) DWT.error (DWT.ERROR_INVALID_PARENT);
+    }
+    if (this.control !is null && !this.control.isDisposed()) {
+        this.control.setVisible(false);
+    }
+    this.control = control;
+    if (this.control !is null) {
+        int index = parent.indexOf (this);
+        if (index is parent.getSelectionIndex ()){
+            this.control.setBounds(parent.getClientArea ());
+            this.control.setVisible(true);
+        } else {
             this.control.setVisible(false);
         }
-        this.control = control;
-        if (this.control !is null) {
-            int index = parent.indexOf(this);
-            if (index is parent.getSelectionIndex()) {
-                this.control.setBounds(parent.getClientArea());
-                this.control.setVisible(true);
-            }
-            else {
-                this.control.setVisible(false);
-            }
-        }
     }
-
-    /**
-     * Sets the image that is displayed if the tab item is disabled.
-     * Null will clear the image.
-     * 
-     * @param image the image to be displayed when the item is disabled or null
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @deprecated This image is not used
-     */
-    public void setDisabledImage (Image image) {
-        checkWidget();
-        if (image !is null && image.isDisposed()) {
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }
-        this.disabledImage = image;
-    }
-
-    /**
-     * Sets the font that the receiver will use to paint textual information
-     * for this item to the font specified by the argument, or to the default font
-     * for that kind of control if the argument is null.
-     *
-     * @param font the new font (or null)
-     *
-     * @exception IllegalArgumentException <ul>
-     *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> 
-     * </ul>
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.0
-     */
-    public void setFont (Font font) {
-        checkWidget();
-        if (font !is null && font.isDisposed()) {
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }
-        if (font is null && this.font is null)
-            return;
-        if (font !is null && font.opEquals(this.font))
-            return;
-        this.font = font;
-        if (!parent.updateTabHeight(false)) {
-            parent.updateItems();
-            parent.redrawTabs();
-        }
+}
+/**
+ * Sets the image that is displayed if the tab item is disabled.
+ * Null will clear the image.
+ *
+ * @param image the image to be displayed when the item is disabled or null
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @deprecated This image is not used
+ */
+public void setDisabledImage (Image image) {
+    checkWidget();
+    if (image !is null && image.isDisposed ()) {
+        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     }
-
-    public void setImage (Image image) {
-        checkWidget();
-        if (image !is null && image.isDisposed()) {
-            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }
-        Image oldImage = getImage();
-        if (image is null && oldImage is null)
-            return;
-        if (image !is null && image.opEquals(oldImage))
-            return;
-        super.setImage(image);
-        if (!parent.updateTabHeight(false)) {
-            // If image is the same size as before, 
-            // redraw only the image
-            if (oldImage !is null && image !is null) {
-                Rectangle oldBounds = oldImage.getBounds();
-                Rectangle bounds = image.getBounds();
-                if (bounds.width is oldBounds.width && bounds.height is oldBounds.height) {
-                    if (showing) {
-                        bool selected = parent.indexOf(this) is parent.selectedIndex;
-                        if (selected || parent.showUnselectedImage) {
-                            int imageX = x + LEFT_MARGIN, maxImageWidth;
-                            if (selected) {
-                                if (parent.single && (parent.showClose || showClose))
-                                    imageX += CTabFolder.BUTTON_SIZE;
-                                int rightEdge = Math.min(x + width, parent.getRightItemEdge());
-                                maxImageWidth = rightEdge - imageX - RIGHT_MARGIN;
-                                if (!parent.single && closeRect.width > 0)
-                                    maxImageWidth -= closeRect.width + INTERNAL_SPACING;
-                            }
-                            else {
-                                maxImageWidth = x + width - imageX - RIGHT_MARGIN;
-                                if (parent.showUnselectedClose && (parent.showClose || showClose)) {
-                                    maxImageWidth -= closeRect.width + INTERNAL_SPACING;
-                                }
-                            }
-                            if (bounds.width < maxImageWidth) {
-                                int imageY = y + (height - bounds.height) / 2 + (parent.onBottom ? -1 : 1);
-                                parent.redraw(imageX, imageY, bounds.width, bounds.height, false);
-                            }
-                        }
-                    }
-                    return;
-                }
-            }
-            parent.updateItems();
-            parent.redrawTabs();
-        }
+    this.disabledImage = image;
+}
+/**
+ * Sets the font that the receiver will use to paint textual information
+ * for this item to the font specified by the argument, or to the default font
+ * for that kind of control if the argument is null.
+ *
+ * @param font the new font (or null)
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void setFont (Font font){
+    checkWidget();
+    if (font !is null && font.isDisposed ()) {
+        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     }
-
-    /**
-     * Sets to <code>true</code> to indicate that the receiver's close button should be shown.
-     * If the parent cast(CTabFolder) was created with DWT.CLOSE style, changing this value has
-     * no effect.
-     * 
-     * @param close the new state of the close button
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     * 
-     * @since 3.4
-     */
-    public void setShowClose (bool close) {
-        checkWidget();
-        if (showClose is close)
-            return;
-        showClose = close;
+    if (font is null && this.font is null) return;
+    if (font !is null && font==this.font) return;
+    this.font = font;
+    if (!parent.updateTabHeight(false)) {
         parent.updateItems();
         parent.redrawTabs();
     }
-
-    public void setText (String String) {
-        checkWidget();
-        if (String is null)
-            DWT.error(DWT.ERROR_NULL_ARGUMENT);
-        if (String.opEquals(getText()))
-            return;
-        super.setText(String);
-        shortenedText = null;
-        shortenedTextWidth = 0;
-        if (!parent.updateTabHeight(false)) {
-            parent.updateItems();
-            parent.redrawTabs();
+}
+public override void setImage (Image image) {
+    checkWidget();
+    if (image !is null && image.isDisposed ()) {
+        DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    Image oldImage = getImage();
+    if (image is null && oldImage is null) return;
+    if (image !is null && image==oldImage) return;
+    super.setImage(image);
+    if (!parent.updateTabHeight(false)) {
+        // If image is the same size as before,
+        // redraw only the image
+        if (oldImage !is null && image !is null) {
+            Rectangle oldBounds = oldImage.getBounds();
+            Rectangle bounds = image.getBounds();
+            if (bounds.width is oldBounds.width && bounds.height is oldBounds.height) {
+                if (showing) {
+                    bool selected = parent.indexOf(this) is parent.selectedIndex;
+                    if (selected || parent.showUnselectedImage) {
+                        int imageX = x + LEFT_MARGIN, maxImageWidth;
+                        if (selected) {
+                            if (parent.single && (parent.showClose || showClose)) imageX += CTabFolder.BUTTON_SIZE;
+                            int rightEdge = Math.min (x + width, parent.getRightItemEdge());
+                            maxImageWidth = rightEdge - imageX - RIGHT_MARGIN;
+                            if (!parent.single && closeRect.width > 0) maxImageWidth -= closeRect.width + INTERNAL_SPACING;
+                        } else {
+                            maxImageWidth = x + width - imageX - RIGHT_MARGIN;
+                            if (parent.showUnselectedClose && (parent.showClose || showClose)) {
+                                maxImageWidth -= closeRect.width + INTERNAL_SPACING;
+                            }
+                        }
+                        if (bounds.width < maxImageWidth) {
+                            int imageY = y + (height - bounds.height) / 2 + (parent.onBottom ? -1 : 1);
+                            parent.redraw(imageX, imageY, bounds.width, bounds.height, false);
+                        }
+                    }
+                }
+                return;
+            }
         }
+        parent.updateItems();
+        parent.redrawTabs();
     }
-
-    /**
-     * Sets the receiver's tool tip text to the argument, which
-     * may be null indicating that no tool tip text should be shown.
-     *
-     * @param String the new tool tip text (or null)
-     *
-     * @exception DWTException <ul>
-     *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
-     *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
-     * </ul>
-     */
-    public void setToolTipText (String String) {
-        checkWidget();
-        toolTipText = String;
+}
+/**
+ * Sets to <code>true</code> to indicate that the receiver's close button should be shown.
+ * If the parent (CTabFolder) was created with DWT.CLOSE style, changing this value has
+ * no effect.
+ *
+ * @param close the new state of the close button
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.4
+ */
+public void setShowClose(bool close) {
+    checkWidget();
+    if (showClose is close) return;
+    showClose = close;
+    parent.updateItems();
+    parent.redrawTabs();
+}
+public override void setText (String string) {
+    checkWidget();
+    // DWT extension: allow null for zero length string
+    //if (string is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    if (string.equals (getText())) return;
+    super.setText(string);
+    shortenedText = null;
+    shortenedTextWidth = 0;
+    if (!parent.updateTabHeight(false)) {
+        parent.updateItems();
+        parent.redrawTabs();
     }
+}
+/**
+ * Sets the receiver's tool tip text to the argument, which
+ * may be null indicating that no tool tip text should be shown.
+ *
+ * @param string the new tool tip text (or null)
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public void setToolTipText (String string) {
+    checkWidget();
+    toolTipText = string;
+}
 
 }
--- a/dwt/custom/ControlEditor.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/ControlEditor.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,13 +7,12 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
  * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
 module dwt.custom.ControlEditor;
 
-import Math = tango.math.Math;
+import dwt.dwthelper.utils;
 
 import dwt.DWT;
 import dwt.graphics.Rectangle;
@@ -24,90 +23,92 @@
 import dwt.widgets.ScrollBar;
 
 /**
- *
- * A ControlEditor is a manager for a Control that appears above a composite and tracks with the
- * moving and resizing of that composite.  It can be used to display one control above 
- * another control.  This could be used when editing a control that does not have editing 
- * capabilities by using a text editor or for launching a dialog by placing a button 
- * above a control.
- *
- * <p> Here is an example of using a ControlEditor:
- *
- * <code><pre>
- * Canvas canvas = new Canvas(shell, DWT.BORDER);
- * canvas.setBounds(10, 10, 300, 300);  
- * Color color = new Color(null, 255, 0, 0);
- * canvas.setBackground(color);
- * ControlEditor editor = new ControlEditor (canvas);
- * // The editor will be a button in the bottom right corner of the canvas.
- * // When selected, it will launch a Color dialog that will change the background 
- * // of the canvas.
- * Button button = new Button(canvas, DWT.PUSH);
- * button.setText("Select Color...");
- * button.addSelectionListener (new SelectionAdapter() {
- *  public void widgetSelected(SelectionEvent e) {
- *      ColorDialog dialog = new ColorDialog(shell);
- *      dialog.open();
- *      RGB rgb = dialog.getRGB();
- *      if (rgb !is null) {
- *          if (color !is null) color.dispose();
- *          color = new Color(null, rgb);
- *          canvas.setBackground(color);
- *      }
- *      
- *  }
- * });
- *
- * editor.horizontalAlignment = DWT.RIGHT;
- * editor.verticalAlignment = DWT.BOTTOM;
- * editor.grabHorizontal = false;
- * editor.grabVertical = false;
- * Point size = button.computeSize(DWT.DEFAULT, DWT.DEFAULT);
- * editor.minimumWidth = size.x;
- * editor.minimumHeight = size.y;
- * editor.setEditor (button);
- * </pre></code>
- */
+*
+* A ControlEditor is a manager for a Control that appears above a composite and tracks with the
+* moving and resizing of that composite.  It can be used to display one control above
+* another control.  This could be used when editing a control that does not have editing
+* capabilities by using a text editor or for launching a dialog by placing a button
+* above a control.
+*
+* <p> Here is an example of using a ControlEditor:
+*
+* <code><pre>
+* Canvas canvas = new Canvas(shell, DWT.BORDER);
+* canvas.setBounds(10, 10, 300, 300);
+* Color color = new Color(null, 255, 0, 0);
+* canvas.setBackground(color);
+* ControlEditor editor = new ControlEditor (canvas);
+* // The editor will be a button in the bottom right corner of the canvas.
+* // When selected, it will launch a Color dialog that will change the background
+* // of the canvas.
+* Button button = new Button(canvas, DWT.PUSH);
+* button.setText("Select Color...");
+* button.addSelectionListener (new SelectionAdapter() {
+*   public void widgetSelected(SelectionEvent e) {
+*       ColorDialog dialog = new ColorDialog(shell);
+*       dialog.open();
+*       RGB rgb = dialog.getRGB();
+*       if (rgb !is null) {
+*           if (color !is null) color.dispose();
+*           color = new Color(null, rgb);
+*           canvas.setBackground(color);
+*       }
+*
+*   }
+* });
+*
+* editor.horizontalAlignment = DWT.RIGHT;
+* editor.verticalAlignment = DWT.BOTTOM;
+* editor.grabHorizontal = false;
+* editor.grabVertical = false;
+* Point size = button.computeSize(DWT.DEFAULT, DWT.DEFAULT);
+* editor.minimumWidth = size.x;
+* editor.minimumHeight = size.y;
+* editor.setEditor (button);
+* </pre></code>
+*
+* @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+*/
 public class ControlEditor {
 
     /**
-     * Specifies how the editor should be aligned relative to the control.  Allowed values
-     * are DWT.LEFT, DWT.RIGHT and DWT.CENTER.  The default value is DWT.CENTER.
-     */
+    * Specifies how the editor should be aligned relative to the control.  Allowed values
+    * are DWT.LEFT, DWT.RIGHT and DWT.CENTER.  The default value is DWT.CENTER.
+    */
     public int horizontalAlignment = DWT.CENTER;
 
     /**
-     * Specifies whether the editor should be sized to use the entire width of the control.
-     * True means resize the editor to the same width as the cell.  False means do not adjust 
-     * the width of the editor. The default value is false.
-     */
+    * Specifies whether the editor should be sized to use the entire width of the control.
+    * True means resize the editor to the same width as the cell.  False means do not adjust
+    * the width of the editor.  The default value is false.
+    */
     public bool grabHorizontal = false;
 
     /**
-     * Specifies the minimum width the editor can have.  This is used in association with
-     * a true value of grabHorizontal.  If the cell becomes smaller than the minimumWidth, the 
-     * editor will not made smaller than the minimum width value.  The default value is 0.
-     */
+    * Specifies the minimum width the editor can have.  This is used in association with
+    * a true value of grabHorizontal.  If the cell becomes smaller than the minimumWidth, the
+    * editor will not made smaller than the minimum width value.  The default value is 0.
+    */
     public int minimumWidth = 0;
 
     /**
-     * Specifies how the editor should be aligned relative to the control.  Allowed values
-     * are DWT.TOP, DWT.BOTTOM and DWT.CENTER.  The default value is DWT.CENTER.
-     */
+    * Specifies how the editor should be aligned relative to the control.  Allowed values
+    * are DWT.TOP, DWT.BOTTOM and DWT.CENTER.  The default value is DWT.CENTER.
+    */
     public int verticalAlignment = DWT.CENTER;
 
     /**
-     * Specifies whether the editor should be sized to use the entire height of the control.
-     * True means resize the editor to the same height as the underlying control.  False means do not adjust 
-     * the height of the editor.    The default value is false.
-     */
+    * Specifies whether the editor should be sized to use the entire height of the control.
+    * True means resize the editor to the same height as the underlying control.  False means do not adjust
+    * the height of the editor. The default value is false.
+    */
     public bool grabVertical = false;
 
     /**
-     * Specifies the minimum height the editor can have.  This is used in association with
-     * a true value of grabVertical.  If the control becomes smaller than the minimumHeight, the 
-     * editor will not made smaller than the minimum height value.  The default value is 0.
-     */
+    * Specifies the minimum height the editor can have.  This is used in association with
+    * a true value of grabVertical.  If the control becomes smaller than the minimumHeight, the
+    * editor will not made smaller than the minimum height value.  The default value is 0.
+    */
     public int minimumHeight = 0;
 
     Composite parent;
@@ -116,160 +117,146 @@
     private Listener controlListener;
     private Listener scrollbarListener;
 
-    private const static int[] EVENTS = [DWT.KeyDown, DWT.KeyUp, DWT.MouseDown, DWT.MouseUp, DWT.Resize];
-
-    /**
-     * Creates a ControlEditor for the specified Composite.
-     *
-     * @param parent the Composite above which this editor will be displayed
-     *
-     */
-    public this (Composite parent) {
-        this.parent = parent;
+    private final static int [] EVENTS = [DWT.KeyDown, DWT.KeyUp, DWT.MouseDown, DWT.MouseUp, DWT.Resize];
+/**
+* Creates a ControlEditor for the specified Composite.
+*
+* @param parent the Composite above which this editor will be displayed
+*
+*/
+public this (Composite parent) {
+    this.parent = parent;
 
-        controlListener = new class Listener {
-            public void handleEvent (Event e) {
-                layout();
-            }
-        };
-        for (int i = 0; i < EVENTS.length; i++) {
-            parent.addListener(EVENTS[i], controlListener);
+    controlListener = new class() Listener {
+        public void handleEvent(Event e) {
+            layout ();
         }
-
-        scrollbarListener = new class Listener {
-            public void handleEvent (Event e) {
-                scroll(e);
-            }
-        };
-        ScrollBar hBar = parent.getHorizontalBar();
-        if (hBar !is null)
-            hBar.addListener(DWT.Selection, scrollbarListener);
-        ScrollBar vBar = parent.getVerticalBar();
-        if (vBar !is null)
-            vBar.addListener(DWT.Selection, scrollbarListener);
+    };
+    for (int i=0; i<EVENTS.length; i++) {
+        parent.addListener (EVENTS [i], controlListener);
     }
 
-    Rectangle computeBounds () {
-        Rectangle clientArea = parent.getClientArea();
-        Rectangle editorRect = new Rectangle(clientArea.x, clientArea.y, minimumWidth, minimumHeight);
-
-        if (grabHorizontal)
-            editorRect.width = Math.max(clientArea.width, minimumWidth);
+    scrollbarListener = new class() Listener {
+        public void handleEvent(Event e) {
+            scroll (e);
+        }
+    };
+    ScrollBar hBar = parent.getHorizontalBar ();
+    if (hBar !is null) hBar.addListener (DWT.Selection, scrollbarListener);
+    ScrollBar vBar = parent.getVerticalBar ();
+    if (vBar !is null) vBar.addListener (DWT.Selection, scrollbarListener);
+}
+Rectangle computeBounds () {
+    Rectangle clientArea = parent.getClientArea();
+    Rectangle editorRect = new Rectangle(clientArea.x, clientArea.y, minimumWidth, minimumHeight);
 
-        if (grabVertical)
-            editorRect.height = Math.max(clientArea.height, minimumHeight);
+    if (grabHorizontal)
+        editorRect.width = Math.max(clientArea.width, minimumWidth);
+
+    if (grabVertical)
+        editorRect.height = Math.max(clientArea.height, minimumHeight);
 
-        switch (horizontalAlignment) {
-            case DWT.RIGHT:
-                editorRect.x += clientArea.width - editorRect.width;
+    switch (horizontalAlignment) {
+        case DWT.RIGHT:
+            editorRect.x += clientArea.width - editorRect.width;
             break;
-            case DWT.LEFT:
+        case DWT.LEFT:
             // do nothing - clientArea.x is the right answer
             break;
-            default:
-                // default is CENTER
-                editorRect.x += (clientArea.width - editorRect.width) / 2;
-        }
+        default:
+            // default is CENTER
+            editorRect.x += (clientArea.width - editorRect.width)/2;
+    }
 
-        switch (verticalAlignment) {
-            case DWT.BOTTOM:
-                editorRect.y += clientArea.height - editorRect.height;
+    switch (verticalAlignment) {
+        case DWT.BOTTOM:
+            editorRect.y += clientArea.height - editorRect.height;
             break;
-            case DWT.TOP:
+        case DWT.TOP:
             // do nothing - clientArea.y is the right answer
             break;
-            default:
-                // default is CENTER
-                editorRect.y += (clientArea.height - editorRect.height) / 2;
-        }
-
-        return editorRect;
-
+        default :
+            // default is CENTER
+            editorRect.y += (clientArea.height - editorRect.height)/2;
     }
 
-    /**
-     * Removes all associations between the Editor and the underlying composite.  The
-     * composite and the editor Control are <b>not</b> disposed.
-     */
-    public void dispose () {
-        if (parent !is null && !parent.isDisposed()) {
-            for (int i = 0; i < EVENTS.length; i++) {
-                parent.removeListener(EVENTS[i], controlListener);
-            }
-            ScrollBar hBar = parent.getHorizontalBar();
-            if (hBar !is null)
-                hBar.removeListener(DWT.Selection, scrollbarListener);
-            ScrollBar vBar = parent.getVerticalBar();
-            if (vBar !is null)
-                vBar.removeListener(DWT.Selection, scrollbarListener);
+
+    return editorRect;
+
+}
+/**
+ * Removes all associations between the Editor and the underlying composite.  The
+ * composite and the editor Control are <b>not</b> disposed.
+ */
+public void dispose () {
+    if (parent !is null && !parent.isDisposed()) {
+        for (int i=0; i<EVENTS.length; i++) {
+            parent.removeListener (EVENTS [i], controlListener);
         }
-
-        parent = null;
-        editor = null;
-        hadFocus = false;
-        controlListener = null;
-        scrollbarListener = null;
-    }
-
-    /**
-     * Returns the Control that is displayed above the composite being edited.
-     *
-     * @return the Control that is displayed above the composite being edited
-     */
-    public Control getEditor () {
-        return editor;
+        ScrollBar hBar = parent.getHorizontalBar ();
+        if (hBar !is null) hBar.removeListener (DWT.Selection, scrollbarListener);
+        ScrollBar vBar = parent.getVerticalBar ();
+        if (vBar !is null) vBar.removeListener (DWT.Selection, scrollbarListener);
     }
 
-    /**
-     * Lays out the control within the underlying composite.  This
-     * method should be called after changing one or more fields to
-     * force the Editor to resize.
-     * 
-     * @since 2.1
-     */
-    public void layout () {
-        if (editor is null || editor.isDisposed())
-            return;
-        if (editor.getVisible()) {
-            hadFocus = editor.isFocusControl();
-        } // this doesn't work because
-        // resizing the column takes the focus away
-        // before we get here
-        editor.setBounds(computeBounds());
-        if (hadFocus) {
-            if (editor is null || editor.isDisposed())
-                return;
-            editor.setFocus();
-        }
+    parent = null;
+    editor = null;
+    hadFocus = false;
+    controlListener = null;
+    scrollbarListener = null;
+}
+/**
+* Returns the Control that is displayed above the composite being edited.
+*
+* @return the Control that is displayed above the composite being edited
+*/
+public Control getEditor () {
+    return editor;
+}
+/**
+ * Lays out the control within the underlying composite.  This
+ * method should be called after changing one or more fields to
+ * force the Editor to resize.
+ *
+ * @since 2.1
+ */
+public void layout () {
+    if (editor is null || editor.isDisposed()) return;
+    if (editor.getVisible ()) {
+        hadFocus = editor.isFocusControl();
+    } // this doesn't work because
+      // resizing the column takes the focus away
+      // before we get here
+    editor.setBounds (computeBounds ());
+    if (hadFocus) {
+        if (editor is null || editor.isDisposed()) return;
+        editor.setFocus ();
+    }
+}
+void scroll (Event e) {
+    if (editor is null || editor.isDisposed()) return;
+    layout();
+}
+/**
+* Specify the Control that is to be displayed.
+*
+* <p>Note: The Control provided as the editor <b>must</b> be created with its parent
+* being the Composite specified in the ControlEditor constructor.
+*
+* @param editor the Control that is displayed above the composite being edited
+*/
+public void setEditor (Control editor) {
+
+    if (editor is null) {
+        // this is the case where the caller is setting the editor to be blank
+        // set all the values accordingly
+        this.editor = null;
+        return;
     }
 
-    void scroll (Event e) {
-        if (editor is null || editor.isDisposed())
-            return;
-        layout();
-    }
-
-    /**
-     * Specify the Control that is to be displayed.
-     *
-     * <p>Note: The Control provided as the editor <b>must</b> be created with its parent 
-     * being the Composite specified in the ControlEditor constructor.
-     * 
-     * @param editor the Control that is displayed above the composite being edited
-     */
-    public void setEditor (Control editor) {
-
-        if (editor is null) {
-            // this is the case where the caller is setting the editor to be blank
-            // set all the values accordingly
-            this.editor = null;
-            return;
-        }
-
-        this.editor = editor;
-        layout();
-        if (this.editor is null || this.editor.isDisposed())
-            return;
-        editor.setVisible(true);
-    }
+    this.editor = editor;
+    layout();
+    if (this.editor is null || this.editor.isDisposed()) return;
+    editor.setVisible(true);
 }
+}
--- a/dwt/custom/DefaultContent.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/DefaultContent.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,39 +7,52 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.DefaultContent;
 
-import dwt.*;
+import dwt.DWT;
+import dwt.DWTException;
 import dwt.internal.Compatibility;
-import dwt.widgets.*;
-import java.util.Vector;
+import dwt.widgets.TypedListener;
+import dwt.custom.StyledTextContent;
+import dwt.custom.TextChangeListener;
+import dwt.custom.StyledTextEvent;
+import dwt.custom.StyledTextListener;
+import dwt.custom.StyledText;
+import dwt.dwthelper.utils;
+
+static import tango.io.model.IFile;
+static import tango.text.Text;
+
+alias tango.text.Text.Text!(char) StringBuffer;
 
 class DefaultContent : StyledTextContent {
-    private final static String LineDelimiter = System.getProperty("line.separator");
+    private final static String LineDelimiter = tango.io.model.IFile.FileConst.NewlineString;
 
-    Vector textListeners = new Vector(); // stores text listeners for event sending
-    char[] textStore = new char[0]; // stores the actual text
+    StyledTextListener[] textListeners; // stores text listeners for event sending
+    char[] textStore; // stores the actual text
     int gapStart = -1;  // the character position start of the gap
     int gapEnd = -1;    // the character position after the end of the gap
     int gapLine = -1;   // the line on which the gap exists, the gap will always be associated with one line
-    int highWatermark = 300;    
-    int lowWatermark = 50;      
-    
-    int[][] lines = new int[50][2]; // array of character positions and lengths representing the lines of text
-    int lineCount = 0;  // the number of lines of text  
+    int highWatermark = 300;
+    int lowWatermark = 50;
+
+    int[][] lines; // array of character positions and lengths representing the lines of text
+    int lineCount_ = 0;  // the number of lines of text
     int expandExp = 1;  // the expansion exponent, used to increase the lines array exponentially
     int replaceExpandExp = 1;   // the expansion exponent, used to increase the lines array exponentially
 
-/** 
+/**
  * Creates a new DefaultContent and initializes it.  A <code>StyledTextContent</> will always have
  * at least one empty line.
  */
 this() {
-    super();
+    lines = new int[][]( 50, 2 );
     setText("");
 }
-/** 
+/**
  * Adds a line to the end of the line indexes array.  Increases the size of the array if necessary.
  * <code>lineCount</code> is updated to reflect the new entry.
  * <p>
@@ -49,19 +62,19 @@
  */
 void addLineIndex(int start, int length) {
     int size = lines.length;
-    if (lineCount is size) {
+    if (lineCount_ is size) {
         // expand the lines by powers of 2
-        int[][] newLines = new int[size+Compatibility.pow2(expandExp)][2];
+        int[][] newLines = new int[][]( size+Compatibility.pow2(expandExp), 2 );
         System.arraycopy(lines, 0, newLines, 0, size);
         lines = newLines;
         expandExp++;
     }
-    int[] range = new int[] {start, length};
-    lines[lineCount] = range;
-    lineCount++;
+    int[] range = [start, length];
+    lines[lineCount_] = range;
+    lineCount_++;
 }
-/** 
- * Adds a line index to the end of <code>linesArray</code>.  Increases the 
+/**
+ * Adds a line index to the end of <code>linesArray</code>.  Increases the
  * size of the array if necessary and returns a new array.
  * <p>
  *
@@ -75,19 +88,19 @@
     int size = linesArray.length;
     int[][] newLines = linesArray;
     if (count is size) {
-        newLines = new int[size+Compatibility.pow2(replaceExpandExp)][2];
+        newLines = new int[][]( size+Compatibility.pow2(replaceExpandExp), 2 );
         replaceExpandExp++;
         System.arraycopy(linesArray, 0, newLines, 0, size);
     }
-    int[] range = new int[] {start, length};
+    int[] range = [start, length];
     newLines[count] = range;
     return newLines;
 }
 /**
- * Adds a <code>TextChangeListener</code> listening for 
- * <code>TextChangingEvent</code> and <code>TextChangedEvent</code>. A 
+ * Adds a <code>TextChangeListener</code> listening for
+ * <code>TextChangingEvent</code> and <code>TextChangedEvent</code>. A
  * <code>TextChangingEvent</code> is sent before changes to the text occur.
- * A <code>TextChangedEvent</code> is sent after changes to the text 
+ * A <code>TextChangedEvent</code> is sent after changes to the text
  * occurred.
  * <p>
  *
@@ -99,8 +112,8 @@
 public void addTextChangeListener(TextChangeListener listener) {
     if (listener is null) error(DWT.ERROR_NULL_ARGUMENT);
     StyledTextListener typedListener = new StyledTextListener(listener);
-    textListeners.addElement(typedListener);    
-}   
+    textListeners ~= typedListener;
+}
 /**
  * Adjusts the gap to accommodate a text change that is occurring.
  * <p>
@@ -124,16 +137,16 @@
     moveAndResizeGap(position, sizeHint, line);
 }
 /**
- * Calculates the indexes of each line in the text store.  Assumes no gap exists.  
+ * Calculates the indexes of each line in the text store.  Assumes no gap exists.
  * Optimized to do less checking.
  */
 void indexLines(){
     int start = 0;
-    lineCount = 0;
+    lineCount_ = 0;
     int textLength = textStore.length;
     int i;
     for (i = start; i < textLength; i++) {
-        char ch = textStore[i];                 
+        char ch = textStore[i];
         if (ch is DWT.CR) {
             // see if the next character is a LF
             if (i + 1 < textLength) {
@@ -151,8 +164,8 @@
     }
     addLineIndex(start, i - start);
 }
-/** 
- * Returns whether or not the given character is a line delimiter.  Both CR and LF 
+/**
+ * Returns whether or not the given character is a line delimiter.  Both CR and LF
  * are valid line delimiters.
  * <p>
  *
@@ -163,7 +176,7 @@
     if (ch is DWT.CR) return true;
     if (ch is DWT.LF) return true;
     return false;
-}   
+}
 /**
  * Determine whether or not the replace operation is valid.  DefaultContent will not allow
  * the /r/n line delimiter to be split or partially deleted.
@@ -179,30 +192,30 @@
         // inserting text, see if the \r\n line delimiter is being split
         if (start is 0) return true;
         if (start is getCharCount()) return true;
-        char before = getTextRange(start - 1, 1).charAt(0);
+        char before = getTextRange(start - 1, 1)[0];
         if (before is '\r') {
-            char after = getTextRange(start, 1).charAt(0);
+            char after = getTextRange(start, 1)[0];
             if (after is '\n') return false;
         }
     } else {
         // deleting text, see if part of a \r\n line delimiter is being deleted
-        char startChar = getTextRange(start, 1).charAt(0);
+        char startChar = getTextRange(start, 1)[0];
         if (startChar is '\n') {
             // see if char before delete position is \r
             if (start !is 0) {
-                char before = getTextRange(start - 1, 1).charAt(0);
+                char before = getTextRange(start - 1, 1)[0];
                 if (before is '\r') return false;
             }
         }
-        char endChar = getTextRange(start + replaceLength - 1, 1).charAt(0);
+        char endChar = getTextRange(start + replaceLength - 1, 1)[0];
         if (endChar is '\r') {
             // see if char after delete position is \n
             if (start + replaceLength !is getCharCount()) {
-                char after = getTextRange(start + replaceLength, 1).charAt(0);
+                char after = getTextRange(start + replaceLength, 1)[0];
                 if (after is '\n') return false;
             }
         }
-    } 
+    }
     return true;
 }
 /**
@@ -213,44 +226,44 @@
  * @param length the length of the text to lineate, includes gap
  * @param numLines the number of lines to initially allocate for the line index array,
  *  passed in for efficiency (the exact number of lines may be known)
- * @return a line indexes array where each line is identified by a start offset and 
+ * @return a line indexes array where each line is identified by a start offset and
  *  a length
  */
 int[][] indexLines(int offset, int length, int numLines){
-    int[][] indexedLines = new int[numLines][2];
+    int[][] indexedLines = new int[][]( numLines, 2 );
     int start = 0;
-    int lineCount = 0;
+    int lineCount_ = 0;
     int i;
     replaceExpandExp = 1;
     for (i = start; i < length; i++) {
-        int location = i + offset; 
+        int location = i + offset;
         if ((location >= gapStart) && (location < gapEnd)) {
             // ignore the gap
         } else {
-            char ch = textStore[location];              
+            char ch = textStore[location];
             if (ch is DWT.CR) {
                 // see if the next character is a LF
                 if (location+1 < textStore.length) {
                     ch = textStore[location+1];
                     if (ch is DWT.LF) {
                         i++;
-                    } 
+                    }
                 }
-                indexedLines = addLineIndex(start, i - start + 1, indexedLines, lineCount);
-                lineCount++;
+                indexedLines = addLineIndex(start, i - start + 1, indexedLines, lineCount_);
+                lineCount_++;
                 start = i + 1;
             } else if (ch is DWT.LF) {
-                indexedLines = addLineIndex(start, i - start + 1, indexedLines, lineCount);
-                lineCount++;
+                indexedLines = addLineIndex(start, i - start + 1, indexedLines, lineCount_);
+                lineCount_++;
                 start = i + 1;
             }
         }
     }
-    int[][] newLines = new int[lineCount+1][2];
-    System.arraycopy(indexedLines, 0, newLines, 0, lineCount);
-    int[] range = new int[] {start, i - start};
-    newLines[lineCount] = range;
-    return newLines; 
+    int[][] newLines = new int[][]( lineCount_+1, 2 );
+    System.arraycopy(indexedLines, 0, newLines, 0, lineCount_);
+    int[] range = [start, i - start];
+    newLines[lineCount_] = range;
+    return newLines;
 }
 /**
  * Inserts text.
@@ -259,30 +272,30 @@
  * @param position the position at which to insert the text
  * @param text the text to insert
  */
-void insert(int position, String text) {    
-    if (text.length() is 0) return;
-                
+void insert(int position, String text) {
+    if (text.length is 0) return;
+
     int startLine = getLineAtOffset(position);
-    int change = text.length();
+    int change = text.length;
     bool endInsert = position is getCharCount();
     adjustGap(position, change, startLine);
 
     // during an insert the gap will be adjusted to start at
     // position and it will be associated with startline, the
-    // inserted text will be placed in the gap      
+    // inserted text will be placed in the gap
     int startLineOffset = getOffsetAtLine(startLine);
     // at this point, startLineLength will include the start line
     // and all of the newly inserted text
-    int startLineLength = getPhysicalLine(startLine).length();
-    
+    int startLineLength = getPhysicalLine(startLine).length;
+
     if (change > 0) {
-        // shrink gap 
+        // shrink gap
         gapStart += (change);
-        for (int i = 0; i < text.length(); i++) {
-            textStore[position + i]= text.charAt(i);
+        for (int i = 0; i < text.length; i++) {
+            textStore[position + i]= text[i];
         }
     }
-        
+
     // figure out the number of new lines that have been inserted
     int [][] newLines = indexLines(startLineOffset, startLineLength, 10);
     // only insert an empty line if it is the last line in the text
@@ -292,17 +305,17 @@
         if (endInsert) {
             // insert happening at end of the text, leave numNewLines as
             // is since the last new line will not be concatenated with another
-            // line 
+            // line
             numNewLines += 1;
         } else {
             numNewLines -= 1;
         }
     }
-    
+
     // make room for the new lines
     expandLinesBy(numNewLines);
     // shift down the lines after the replace line
-    for (int i = lineCount - 1; i > startLine; i--) {
+    for (int i = lineCount_ - 1; i > startLine; i--) {
         lines[i + numNewLines]=lines[i];
     }
     // insert the new lines
@@ -315,13 +328,13 @@
         newLines[numNewLines][0] += startLineOffset;
         lines[startLine + numNewLines] = newLines[numNewLines];
     }
-    
-    lineCount += numNewLines;
+
+    lineCount_ += numNewLines;
     gapLine = getLineAtPhysicalOffset(gapStart);
 }
 /**
- * Moves the gap and adjusts its size in anticipation of a text change.  
- * The gap is resized to actual size + the specified size and moved to the given 
+ * Moves the gap and adjusts its size in anticipation of a text change.
+ * The gap is resized to actual size + the specified size and moved to the given
  * position.
  * <p>
  *
@@ -343,11 +356,11 @@
         // adjust the line length
         lines[gapLine][1] = lines[gapLine][1] - oldSize;
         // adjust the offsets of the lines after the gapLine
-        for (int i = gapLine + 1; i < lineCount; i++) {
+        for (int i = gapLine + 1; i < lineCount_; i++) {
             lines[i][0] = lines[i][0] - oldSize;
         }
     }
-    
+
     if (newSize < 0) {
         if (oldSize > 0) {
             // removing the gap
@@ -364,7 +377,7 @@
     int newGapEnd = newGapStart + newSize;
     if (oldSize is 0) {
         System.arraycopy(textStore, 0, content, 0, newGapStart);
-        System.arraycopy(textStore, newGapStart, content, newGapEnd, content.length - newGapEnd);   
+        System.arraycopy(textStore, newGapStart, content, newGapEnd, content.length - newGapEnd);
     } else if (newGapStart < gapStart) {
         int delta = gapStart - newGapStart;
         System.arraycopy(textStore, 0, content, 0, newGapStart);
@@ -379,7 +392,7 @@
     textStore = content;
     gapStart = newGapStart;
     gapEnd = newGapEnd;
-    
+
     // add the new gap to the lines information
     if (gapExists()) {
         gapLine = newGapLine;
@@ -387,12 +400,12 @@
         int gapLength = gapEnd - gapStart;
         lines[gapLine][1] = lines[gapLine][1] + (gapLength);
         // adjust the offsets of the lines after the gapLine
-        for (int i = gapLine + 1; i < lineCount; i++) {
+        for (int i = gapLine + 1; i < lineCount_; i++) {
             lines[i][0] = lines[i][0] + gapLength;
         }
     }
 }
-/** 
+/**
  * Returns the number of lines that are in the specified text.
  * <p>
  *
@@ -404,7 +417,7 @@
     if (length is 0) {
         return 0;
     }
-    int lineCount = 0;
+    int lineCount_ = 0;
     int count = 0;
     int i = startOffset;
     if (i >= gapStart) {
@@ -414,7 +427,7 @@
         if ((i >= gapStart) && (i < gapEnd)) {
             // ignore the gap
         } else {
-            char ch = textStore[i];         
+            char ch = textStore[i];
             if (ch is DWT.CR) {
                 // see if the next character is a LF
                 if (i + 1 < textStore.length) {
@@ -422,19 +435,19 @@
                     if (ch is DWT.LF) {
                         i++;
                         count++;
-                    } 
-                } 
-                lineCount++;
+                    }
+                }
+                lineCount_++;
             } else if (ch is DWT.LF) {
-                lineCount++;
+                lineCount_++;
             }
             count++;
         }
         i++;
     }
-    return lineCount;
+    return lineCount_;
 }
-/** 
+/**
  * Returns the number of lines that are in the specified text.
  * <p>
  *
@@ -442,20 +455,20 @@
  * @return number of lines in the text
  */
 int lineCount(String text){
-    int lineCount = 0;
-    int length = text.length();
+    int lineCount_ = 0;
+    int length = text.length;
     for (int i = 0; i < length; i++) {
-        char ch = text.charAt(i);
+        char ch = text[i];
         if (ch is DWT.CR) {
-            if (i + 1 < length && text.charAt(i + 1) is DWT.LF) {
+            if (i + 1 < length && text[i + 1] is DWT.LF) {
                 i++;
             }
-            lineCount++;
+            lineCount_++;
         } else if (ch is DWT.LF) {
-            lineCount++;
+            lineCount_++;
         }
     }
-    return lineCount;   
+    return lineCount_;
 }
 /**
  * @return the logical length of the text store
@@ -475,31 +488,31 @@
  * </ul>
  */
 public String getLine(int index) {
-    if ((index >= lineCount) || (index < 0)) error(DWT.ERROR_INVALID_ARGUMENT);
+    if ((index >= lineCount_) || (index < 0)) error(DWT.ERROR_INVALID_ARGUMENT);
     int start = lines[index][0];
-    int length = lines[index][1];
-    int end = start + length - 1;
+    int length_ = lines[index][1];
+    int end = start + length_ - 1;
     if (!gapExists() || (end < gapStart) || (start >= gapEnd)) {
         // line is before or after the gap
-        while ((length - 1 >= 0) && isDelimiter(textStore[start+length-1])) {
-            length--;
+        while ((length_ - 1 >= 0) && isDelimiter(textStore[start+length_-1])) {
+            length_--;
         }
-        return new String(textStore, start, length);
+        return textStore[ start .. start + length_].dup;
     } else {
         // gap is in the specified range, strip out the gap
         StringBuffer buf = new StringBuffer();
         int gapLength = gapEnd - gapStart;
-        buf.append(textStore, start, gapStart - start);
-        buf.append(textStore, gapEnd, length - gapLength - (gapStart - start));
-        length = buf.length();
-        while ((length - 1 >=0) && isDelimiter(buf.charAt(length - 1))) {
-            length--;
+        buf.append(textStore[ start .. gapStart ] );
+        buf.append(textStore[ gapEnd .. gapEnd + length_ - gapLength - (gapStart - start) ]);
+        length_ = buf.length;
+        while ((length_ - 1 >=0) && isDelimiter(buf.slice[length_ - 1])) {
+            length_--;
         }
-        return buf.toString().substring(0, length);
+        return buf.toString()[ 0 .. length_ ].dup;
     }
 }
 /**
- * Returns the line delimiter that should be used by the StyledText 
+ * Returns the line delimiter that should be used by the StyledText
  * widget when inserting new lines.  This delimiter may be different than the
  * delimiter that is used by the <code>StyledTextContent</code> interface.
  * <p>
@@ -518,18 +531,18 @@
  */
 String getFullLine(int index) {
     int start = lines[index][0];
-    int length = lines[index][1];
-    int end = start + length - 1;
+    int length_ = lines[index][1];
+    int end = start + length_ - 1;
     if (!gapExists() || (end < gapStart) || (start >= gapEnd)) {
         // line is before or after the gap
-        return new String(textStore, start, length);
+        return textStore[ start .. start + length_ ].dup;
     } else {
         // gap is in the specified range, strip out the gap
         StringBuffer buffer = new StringBuffer();
         int gapLength = gapEnd - gapStart;
-        buffer.append(textStore, start, gapStart - start);
-        buffer.append(textStore, gapEnd, length - gapLength - (gapStart - start));
-        return buffer.toString();
+        buffer.append(textStore[ start .. gapStart ]);
+        buffer.append(textStore[ gapEnd .. gapEnd + length_ - gapLength - (gapStart - start) ]);
+        return buffer.toString().dup;
     }
 }
 /**
@@ -537,18 +550,18 @@
  * <p>
  *
  * @param index the line index
- * @return the physical line 
+ * @return the physical line
  */
 String getPhysicalLine(int index) {
     int start = lines[index][0];
-    int length = lines[index][1];
-    return getPhysicalText(start, length);
+    int length_ = lines[index][1];
+    return getPhysicalText(start, length_);
 }
 /**
  * @return the number of lines in the text store
  */
 public int getLineCount(){
-    return lineCount;
+    return lineCount_;
 }
 /**
  * Returns the line at the given offset.
@@ -571,18 +584,18 @@
         position = charPosition + (gapEnd - gapStart);
     }
 
-    // if last line and the line is not empty you can ask for 
-    // a position that doesn't exist (the one to the right of the 
+    // if last line and the line is not empty you can ask for
+    // a position that doesn't exist (the one to the right of the
     // last character) - for inserting
-    if (lineCount > 0) {
-        int lastLine = lineCount - 1;
-        if (position is lines[lastLine][0] + lines[lastLine][1]) 
+    if (lineCount_ > 0) {
+        int lastLine = lineCount_ - 1;
+        if (position is lines[lastLine][0] + lines[lastLine][1])
             return lastLine;
     }
 
-    int high = lineCount;
+    int high = lineCount_;
     int low = -1;
-    int index = lineCount;
+    int index = lineCount_;
     while (high - low > 1) {
         index = (high + low) / 2;
         int lineStart = lines[index][0];
@@ -606,9 +619,9 @@
  * @return the line index
  */
 int getLineAtPhysicalOffset(int position){
-    int high = lineCount;
+    int high = lineCount_;
     int low = -1;
-    int index = lineCount;
+    int index = lineCount_;
     while (high - low > 1) {
         index = (high + low) / 2;
         int lineStart = lines[index][0];
@@ -628,7 +641,7 @@
  * Returns the logical offset of the given line.
  * <p>
  *
- * @param lineIndex index of line 
+ * @param lineIndex index of line
  * @return the logical starting offset of the line.  When there are not any lines,
  *  getOffsetAtLine(0) is a valid call that should answer 0.
  * @exception IllegalArgumentException <ul>
@@ -637,14 +650,14 @@
  */
 public int getOffsetAtLine(int lineIndex) {
     if (lineIndex is 0) return 0;
-    if ((lineIndex >= lineCount) || (lineIndex < 0)) error(DWT.ERROR_INVALID_ARGUMENT);
+    if ((lineIndex >= lineCount_) || (lineIndex < 0)) error(DWT.ERROR_INVALID_ARGUMENT);
     int start = lines[lineIndex][0];
     if (start > gapEnd) {
         return start - (gapEnd - gapStart);
     } else {
         return start;
     }
-}   
+}
 /**
  * Increases the line indexes array to accommodate more lines.
  * <p>
@@ -653,14 +666,14 @@
  */
 void expandLinesBy(int numLines) {
     int size = lines.length;
-    if (size - lineCount >= numLines) {
+    if (size - lineCount_ >= numLines) {
         return;
     }
-    int[][] newLines = new int[size+Math.max(10, numLines)][2];
+    int[][] newLines = new int[][]( size+Math.max(10, numLines), 2 );
     System.arraycopy(lines, 0, newLines, 0, size);
     lines = newLines;
 }
-/**  
+/**
  * Reports an DWT error.
  * <p>
  *
@@ -669,7 +682,7 @@
 void error (int code) {
     DWT.error(code);
 }
-/** 
+/**
  * Returns whether or not a gap exists in the text store.
  * <p>
  *
@@ -679,7 +692,7 @@
     return gapStart !is gapEnd;
 }
 /**
- * Returns a String representing the continuous content of
+ * Returns a string representing the continuous content of
  * the text store.
  * <p>
  *
@@ -687,11 +700,11 @@
  * @param length the physical length of the text to return
  * @return the text
  */
-String getPhysicalText(int start, int length) {
-    return new String(textStore, start, length);
+String getPhysicalText(int start, int length_) {
+    return textStore[ start .. start + length_ ].dup;
 }
 /**
- * Returns a String representing the logical content of
+ * Returns a string representing the logical content of
  * the text store (i.e., gap stripped out).
  * <p>
  *
@@ -699,72 +712,73 @@
  * @param length the logical length of the text to return
  * @return the text
  */
-public String getTextRange(int start, int length) {
+public String getTextRange(int start, int length_) {
     if (textStore is null)
         return "";
-    if (length is 0)
+    if (length_ is 0)
         return "";
-    int end= start + length;
+    int end= start + length_;
     if (!gapExists() || (end < gapStart))
-        return new String(textStore, start, length);
+        return textStore[ start .. start + length_].dup;
     if (gapStart < start) {
         int gapLength= gapEnd - gapStart;
-        return new String(textStore, start + gapLength , length);
+        return textStore[ start + gapLength .. start + gapLength + length_ ].dup;
     }
     StringBuffer buf = new StringBuffer();
-    buf.append(textStore, start, gapStart - start);
-    buf.append(textStore, gapEnd, end - gapStart);
-    return buf.toString();
+    buf.append(textStore[ start .. start + gapStart - start ] );
+    buf.append(textStore[ gapEnd .. gapEnd + end - gapStart ] );
+    return buf.toString().dup;
 }
 /**
  * Removes the specified <code>TextChangeListener</code>.
  * <p>
  *
- * @param listener the listener
+ * @param listener the listener which should no longer be notified
+ *
  * @exception IllegalArgumentException <ul>
  *    <li>ERROR_NULL_ARGUMENT when listener is null</li>
  * </ul>
  */
 public void removeTextChangeListener(TextChangeListener listener){
     if (listener is null) error(DWT.ERROR_NULL_ARGUMENT);
-    for (int i = 0; i < textListeners.size(); i++) {
-        TypedListener typedListener = cast(TypedListener) textListeners.elementAt(i);
+    for (int i = 0; i < textListeners.length; i++) {
+        TypedListener typedListener = cast(TypedListener) textListeners[i];
         if (typedListener.getEventListener () is listener) {
-            textListeners.removeElementAt(i);
+            textListeners = textListeners[ 0 .. i ] ~ textListeners[ i+1 .. $ ];
             break;
         }
     }
 }
 /**
- * Replaces the text with <code>newText</code> starting at position <code>start</code> 
+ * Replaces the text with <code>newText</code> starting at position <code>start</code>
  * for a length of <code>replaceLength</code>.  Notifies the appropriate listeners.
  * <p>
  *
- * When sending the TextChangingEvent, <code>newLineCount</code> is the number of 
- * lines that are going to be inserted and <code>replaceLineCount</code> is 
- * the number of lines that are going to be deleted, based on the change 
+ * When sending the TextChangingEvent, <code>newLineCount</code> is the number of
+ * lines that are going to be inserted and <code>replaceLineCount</code> is
+ * the number of lines that are going to be deleted, based on the change
  * that occurs visually.  For example:
  * <ul>
- * <li>(replaceText,newText) ==> (replaceLineCount,newLineCount)
- * <li>("","\n") ==> (0,1)
- * <li>("\n\n","a") ==> (2,0)
+ * <li>(replaceText,newText) is> (replaceLineCount,newLineCount)
+ * <li>("","\n") is> (0,1)
+ * <li>("\n\n","a") is> (2,0)
  * </ul>
  * </p>
  *
  * @param start start offset of text to replace
  * @param replaceLength start offset of text to replace
  * @param newText start offset of text to replace
- * 
+ *
  * @exception DWTException <ul>
  *   <li>ERROR_INVALID_ARGUMENT when the text change results in a multi byte
- *      line delimiter being split or partially deleted.  Splitting a line 
- *      delimiter by inserting text between the CR and LF characters of the 
+ *      line delimiter being split or partially deleted.  Splitting a line
+ *      delimiter by inserting text between the CR and LF characters of the
  *      \r\n delimiter or deleting part of this line delimiter is not supported</li>
  * </ul>
  */
 public void replaceTextRange(int start, int replaceLength, String newText){
     // check for invalid replace operations
-    if (!isValidReplace(start, replaceLength, newText)) DWT.error(DWT.ERROR_INVALID_ARGUMENT);      
+    if (!isValidReplace(start, replaceLength, newText)) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
 
     // inform listeners
     StyledTextEvent event = new StyledTextEvent(this);
@@ -774,11 +788,11 @@
     event.text = newText;
     event.newLineCount = lineCount(newText);
     event.replaceCharCount = replaceLength;
-    event.newCharCount = newText.length();
+    event.newCharCount = newText.length;
     sendTextEvent(event);
 
     // first delete the text to be replaced
-    delete(start, replaceLength, event.replaceLineCount + 1);
+    delete_(start, replaceLength, event.replaceLineCount + 1);
     // then insert the new text
     insert(start, newText);
     // inform listeners
@@ -790,19 +804,19 @@
  * Sends the text listeners the TextChanged event.
  */
 void sendTextEvent(StyledTextEvent event) {
-    for (int i = 0; i < textListeners.size(); i++) {
-        (cast(StyledTextListener)textListeners.elementAt(i)).handleEvent(event);
+    for (int i = 0; i < textListeners.length; i++) {
+        (cast(StyledTextListener)textListeners[i]).handleEvent(event);
     }
-}       
+}
 /**
- * Sets the content to text and removes the gap since there are no sensible predictions 
+ * Sets the content to text and removes the gap since there are no sensible predictions
  * about where the next change will occur.
  * <p>
  *
  * @param text the text
  */
 public void setText (String text){
-    textStore = text.toCharArray();
+    textStore = text.dup;
     gapStart = -1;
     gapEnd = -1;
     expandExp = 1;
@@ -819,32 +833,32 @@
  * @param length the length of the text to delete
  * @param numLines the number of lines that are being deleted
  */
-void delete(int position, int length, int numLines) {
-    if (length is 0) return;
-        
+void delete_(int position, int length_, int numLines) {
+    if (length_ is 0) return;
+
     int startLine = getLineAtOffset(position);
     int startLineOffset = getOffsetAtLine(startLine);
-    int endLine = getLineAtOffset(position + length);
+    int endLine = getLineAtOffset(position + length_);
 
     String endText = "";
     bool splittingDelimiter = false;
-    if (position + length < getCharCount()) {
-        endText = getTextRange(position + length - 1, 2);
-        if ((endText.charAt(0) is DWT.CR) && (endText.charAt(1) is DWT.LF)) {
+    if (position + length_ < getCharCount()) {
+        endText = getTextRange(position + length_ - 1, 2);
+        if ((endText[0] is DWT.CR) && (endText[1] is DWT.LF)) {
             splittingDelimiter = true;
         }
     }
 
-    adjustGap(position + length, -length, startLine);
-    int [][] oldLines = indexLines(position, length + (gapEnd - gapStart), numLines);
-    
+    adjustGap(position + length_, -length_, startLine);
+    int [][] oldLines = indexLines(position, length_ + (gapEnd - gapStart), numLines);
+
     // enlarge the gap - the gap can be enlarged either to the
     // right or left
-    if (position + length is gapStart) {
-        gapStart -= length;
+    if (position + length_ is gapStart) {
+        gapStart -= length_;
     } else {
-        gapEnd += length;
-    }       
+        gapEnd += length_;
+    }
 
     // figure out the length of the new concatenated line, do so by
     // finding the first line delimiter after position
@@ -860,7 +874,7 @@
                     }
                 }
                 eol = true;
-            } 
+            }
         }
         j++;
     }
@@ -871,10 +885,39 @@
     if (splittingDelimiter) numOldLines -= 1;
     // shift up the lines after the last deleted line, no need to update
     // the offset or length of the lines
-    for (int i = endLine + 1; i < lineCount; i++) {
+    for (int i = endLine + 1; i < lineCount_; i++) {
         lines[i - numOldLines] = lines[i];
     }
-    lineCount -= numOldLines;
-    gapLine = getLineAtPhysicalOffset(gapStart);        
+    lineCount_ -= numOldLines;
+    gapLine = getLineAtPhysicalOffset(gapStart);
 }
+
+/++
+ + DWT extension
+ +/
+int utf8AdjustOffset( int offset ){
+    if (textStore is null)
+        return offset;
+    if (offset is 0)
+        return offset;
+    if( offset >= textStore.length ){
+        return offset;
+    }
+    if (!gapExists() || (offset < gapStart)){
+        while( textStore[offset] & 0xC0 is 0x80 ){
+            offset--;
+        }
+        return offset;
+    }
+    int gapLength= gapEnd - gapStart;
+    if( offset+gapLength >= textStore.length ){
+        return offset;
+    }
+    while( textStore[offset+gapLength] & 0xC0 is 0x80 ){
+        offset--;
+    }
+    return offset;
 }
+
+
+}
--- a/dwt/custom/ExtendedModifyEvent.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/ExtendedModifyEvent.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,26 +7,39 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.ExtendedModifyEvent;
 
-import dwt.events.*;
+import dwt.dwthelper.utils;
+
+import dwt.events.TypedEvent;
+import dwt.custom.StyledTextEvent;
 
 /**
  * This event is sent after a text change occurs.
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 public final class ExtendedModifyEvent : TypedEvent {
     /** start offset of the new text */
-    public int start;           
+    public int start;
     /** length of the new text */
     public int length;
-    /** replaced text or empty String if no text was replaced */
+    /** replaced text or empty string if no text was replaced */
     public String replacedText;
-    
+
     static final long serialVersionUID = 3258696507027830832L;
-    
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given event.
+ *
+ * @param e the event containing the information
+ */
 public this(StyledTextEvent e) {
-    super(e);
+    super(cast(Object)e);
     start = e.start;
     length = e.end - e.start;
     replacedText = e.text;
--- a/dwt/custom/ExtendedModifyListener.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/ExtendedModifyListener.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,12 +7,24 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.ExtendedModifyListener;
 
 import dwt.internal.DWTEventListener;
+import dwt.custom.ExtendedModifyEvent;
 
+/**
+ * Classes which implement this interface provide a method
+ * that deals with the event that is generated when text
+ * is modified.
+ *
+ * @see ExtendedModifyEvent
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
 public interface ExtendedModifyListener : DWTEventListener {
+
 /**
  * This method is called after a text change occurs.
  * <p>
--- a/dwt/custom/LineBackgroundEvent.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/LineBackgroundEvent.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,36 +7,50 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.LineBackgroundEvent;
 
-import dwt.events.*;
-import dwt.graphics.*;
+import dwt.dwthelper.utils;
+
+
+import dwt.events.TypedEvent;
+import dwt.graphics.Color;
+import dwt.custom.StyledTextEvent;
 
 /**
  * This event is sent when a line is about to be drawn.
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 public class LineBackgroundEvent : TypedEvent {
-    
+
     /**
      * line start offset
      */
     public int lineOffset;
-    
+
     /**
      * line text
      */
     public String lineText;
-    
+
     /**
      * line background color
      */
-    public Color lineBackground; 
-    
+    public Color lineBackground;
+
     static final long serialVersionUID = 3978711687853324342L;
-    
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given event.
+ *
+ * @param e the event containing the information
+ */
 public this(StyledTextEvent e) {
-    super(e);
+    super(cast(Object)e);
     lineOffset = e.detail;
     lineText = e.text;
     lineBackground = e.lineBackground;
--- a/dwt/custom/LineBackgroundListener.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/LineBackgroundListener.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,13 +7,24 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.LineBackgroundListener;
 
 import dwt.internal.DWTEventListener;
+import dwt.custom.LineBackgroundEvent;
 
+/**
+ * Classes which implement this interface provide a method
+ * that can provide the background color for a line that
+ * is to be drawn.
+ *
+ * @see LineBackgroundEvent
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
 public interface LineBackgroundListener : DWTEventListener {
-    
+
 /**
  * This method is called when a line is about to be drawn in order to get its
  * background color.
--- a/dwt/custom/LineStyleEvent.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/LineStyleEvent.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,36 +7,45 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.LineStyleEvent;
+
+import dwt.dwthelper.utils;
 
-import dwt.events.*;
+import dwt.events.TypedEvent;
+import dwt.custom.StyleRange;
+import dwt.custom.Bullet;
+import dwt.custom.StyledTextEvent;
 
 /**
  * This event is sent when a line is about to be drawn.
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 public class LineStyleEvent : TypedEvent {
-    
+
     /**
      * line start offset (input)
      */
     public int lineOffset;
-    
+
     /**
      * line text (input)
      */
     public String lineText;
-    
+
     /**
      * line ranges (output)
-     * 
+     *
      * @since 3.2
      */
     public int[] ranges;
-    
+
     /**
      * line styles (output)
-     * 
+     *
      * Note: Because a StyleRange includes the start and length, the
      * same instance cannot occur multiple times in the array of styles.
      * If the same style attributes, such as font and color, occur in
@@ -45,23 +54,23 @@
      */
     public StyleRange[] styles;
 
-    /** 
+    /**
      * line alignment (input, output)
-     * 
+     *
      * @since 3.2
      */
     public int alignment;
 
     /**
      * line indent (input, output)
-     * 
+     *
      * @since 3.2
      */
     public int indent;
 
-    /** 
+    /**
      * line justification (input, output)
-     * 
+     *
      * @since 3.2
      */
     public bool justify;
@@ -77,11 +86,17 @@
      * @since 3.2
      */
     public int bulletIndex;
-    
+
     static final long serialVersionUID = 3906081274027192884L;
-    
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given event.
+ *
+ * @param e the event containing the information
+ */
 public this(StyledTextEvent e) {
-    super(e);
+    super(cast(Object)e);
     styles = e.styles;
     ranges = e.ranges;
     lineOffset = e.detail;
--- a/dwt/custom/LineStyleListener.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/LineStyleListener.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,12 +7,24 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.LineStyleListener;
 
 import dwt.internal.DWTEventListener;
+import dwt.custom.LineStyleEvent;
 
+/**
+ * Classes which implement this interface provide a method
+ * that can provide the style information for a line that
+ * is to be drawn.
+ *
+ * @see LineStyleEvent
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
 public interface LineStyleListener : DWTEventListener {
+
 /**
  * This method is called when a line is about to be drawn in order to get the
  * line's style information.
--- a/dwt/custom/MovementEvent.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/MovementEvent.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,54 +7,67 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.MovementEvent;
 
-import dwt.events.*;
+import dwt.dwthelper.utils;
+
+import dwt.events.TypedEvent;
+import dwt.custom.StyledTextEvent;
 
 /**
  * This event is sent when a new offset is required based on the current
  * offset and a movement type.
- * 
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
  * @since 3.3
  */
 public class MovementEvent : TypedEvent {
-    
+
     /**
      * line start offset (input)
      */
     public int lineOffset;
-    
+
     /**
      * line text (input)
      */
     public String lineText;
-    
+
     /**
      * the current offset (input)
      */
     public int offset;
-    
+
     /**
      * the new offset  (input, output)
      */
     public int newOffset;
-    
+
     /**
      * the movement type (input)
-     * 
+     *
      * @see dwt.DWT#MOVEMENT_WORD
-     * @see dwt.DWT#MOVEMENT_WORD_END 
+     * @see dwt.DWT#MOVEMENT_WORD_END
      * @see dwt.DWT#MOVEMENT_WORD_START
      * @see dwt.DWT#MOVEMENT_CHAR
      * @see dwt.DWT#MOVEMENT_CLUSTER
      */
     public int movement;
-    
+
     static final long serialVersionUID = 3978765487853324342L;
-    
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given event.
+ *
+ * @param e the event containing the information
+ */
 public this(StyledTextEvent e) {
-    super(e);
+    super(cast(Object)e);
     lineOffset = e.detail;
     lineText = e.text;
     movement = e.count;
--- a/dwt/custom/MovementListener.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/MovementListener.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
  * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -7,28 +7,31 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.MovementListener;
 
 import dwt.internal.DWTEventListener;
+import dwt.custom.MovementEvent;
 
 /**
  * This listener is invoked when a new offset is required based on the current
  * offset and a movement type.
  *
  * @see dwt.DWT#MOVEMENT_WORD
- * @see dwt.DWT#MOVEMENT_WORD_END 
+ * @see dwt.DWT#MOVEMENT_WORD_END
  * @see dwt.DWT#MOVEMENT_WORD_START
  * @see dwt.DWT#MOVEMENT_CHAR
  * @see dwt.DWT#MOVEMENT_CLUSTER
- * 
+ *
  * @since 3.3
  */
 public interface MovementListener : DWTEventListener {
 /**
  * This method is called when a new offset is required based on the current
  * offset and a movement type.
- * 
+ *
  * <p>
  * The following event fields are used:<ul>
  * <li>event.lineOffset line start offset (input)</li>
@@ -39,7 +42,7 @@
  * </ul>
  *
  * @param event the event
- * 
+ *
  * @see MovementEvent
  * @see StyledText#addWordMovementListener(MovementListener)
  */
@@ -47,7 +50,7 @@
 /**
  * This method is called when a new offset is required based on the current
  * offset and a movement type.
- * 
+ *
  * <p>
  * The following event fields are used:<ul>
  * <li>event.lineOffset line start offset (input)</li>
@@ -58,7 +61,7 @@
  * </ul>
  *
  * @param event the event
- * 
+ *
  * @see MovementEvent
  * @see StyledText#addWordMovementListener(MovementListener)
  */
--- a/dwt/custom/PaintObjectEvent.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/PaintObjectEvent.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,63 +7,77 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.PaintObjectEvent;
+
 
-import dwt.events.*;
-import dwt.graphics.*;
+import dwt.events.TypedEvent;
+import dwt.graphics.GC;
+import dwt.custom.StyleRange;
+import dwt.custom.Bullet;
+import dwt.custom.StyledTextEvent;
 
 /**
  * This event is sent when an object needs to be drawn.
- * 
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
  * @since 3.2
  */
 public class PaintObjectEvent : TypedEvent {
-    
+
     /**
      * the GC
      */
     public GC gc;
-    
+
     /**
      * the x location
      */
     public int x;
-    
+
     /**
      * the y location
      */
     public int y;
-    
+
     /**
      * the line ascent
      */
     public int ascent;
-    
+
     /**
      * the line descent
      */
     public int descent;
-    
+
     /**
      * the StyleRange
      */
     public StyleRange style;
-    
+
     /**
      * the Bullet
      */
     public Bullet bullet;
-    
+
     /**
      * the bullet index
      */
     public int bulletIndex;
-    
+
     static final long serialVersionUID = 3906081274027192855L;
-    
+
+/**
+ * Constructs a new instance of this class based on the
+ * information in the given event.
+ *
+ * @param e the event containing the information
+ */
 public this(StyledTextEvent e) {
-    super(e);
+    super(cast(Object)e);
     gc = e.gc;
     x = e.x;
     y = e.y;
--- a/dwt/custom/PaintObjectListener.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/PaintObjectListener.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
  * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -7,11 +7,15 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.PaintObjectListener;
 
 
 import dwt.internal.DWTEventListener;
+import dwt.custom.PaintObjectEvent;
+
 /**
  * This listener is invoked when an object needs to be drawn.
  *
@@ -20,7 +24,7 @@
 public interface PaintObjectListener : DWTEventListener {
 /**
  * This method is called when an object needs to be drawn.
- * 
+ *
  * <p>
  * The following event fields are used:<ul>
  * <li>event.x the x location (input)</li>
@@ -32,7 +36,7 @@
  * </ul>
  *
  * @param event the event
- * 
+ *
  * @see PaintObjectEvent
  * @see StyledText#addPaintObjectListener(PaintObjectListener)
  */
--- a/dwt/custom/PopupList.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/PopupList.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,72 +7,92 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.PopupList;
+
+import dwt.dwthelper.utils;
+
 
-import dwt.*;
-import dwt.events.*;
-import dwt.graphics.*;
-import dwt.widgets.*;
+import dwt.DWT;
+import dwt.DWTException;
+import dwt.events.ControlEvent;
+import dwt.events.ControlListener;
+import dwt.events.KeyEvent;
+import dwt.events.KeyListener;
+import dwt.events.MouseEvent;
+import dwt.events.MouseListener;
+import dwt.graphics.Font;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.List;
+import dwt.widgets.Listener;
+import dwt.widgets.Shell;
+
 /**
 * A PopupList is a list of selectable items that appears in its own shell positioned above
 * its parent shell.  It is used for selecting items when editing a Table cell (similar to the
 * list that appears when you open a Combo box).
 *
 * The list will be positioned so that it does not run off the screen and the largest number of items
-* are visible.  It may appear above the current cursor location or below it depending how close you 
+* are visible.  It may appear above the current cursor location or below it depending how close you
 * are to the edge of the screen.
+*
+* @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
 */
 public class PopupList {
     Shell  shell;
     List   list;
     int    minimumWidth;
-/** 
+/**
 * Creates a PopupList above the specified shell.
-* 
+*
 * @param parent a Shell control which will be the parent of the new instance (cannot be null)
 */
 public this(Shell parent) {
     this (parent, 0);
 }
-/** 
+/**
 * Creates a PopupList above the specified shell.
-* 
+*
 * @param parent a widget which will be the parent of the new instance (cannot be null)
 * @param style the style of widget to construct
-* 
-* @since 3.0 
+*
+* @since 3.0
 */
 public this(Shell parent, int style) {
     shell = new Shell(parent, checkStyle(style));
-    
-    list = new List(shell, DWT.SINGLE | DWT.V_SCROLL);  
+
+    list = new List(shell, DWT.SINGLE | DWT.V_SCROLL);
 
     // close dialog if user selects outside of the shell
-    shell.addListener(DWT.Deactivate, new Listener() {
-        public void handleEvent(Event e){   
+    shell.addListener(DWT.Deactivate, new class() Listener {
+        public void handleEvent(Event e){
             shell.setVisible (false);
         }
     });
-    
+
     // resize shell when list resizes
-    shell.addControlListener(new ControlListener() {
+    shell.addControlListener(new class() ControlListener {
         public void controlMoved(ControlEvent e){}
         public void controlResized(ControlEvent e){
             Rectangle shellSize = shell.getClientArea();
             list.setSize(shellSize.width, shellSize.height);
         }
     });
-    
+
     // return list selection on Mouse Up or Carriage Return
-    list.addMouseListener(new MouseListener() {
+    list.addMouseListener(new class() MouseListener {
         public void mouseDoubleClick(MouseEvent e){}
         public void mouseDown(MouseEvent e){}
         public void mouseUp(MouseEvent e){
             shell.setVisible (false);
         }
     });
-    list.addKeyListener(new KeyListener() {
+    list.addKeyListener(new class() KeyListener {
         public void keyReleased(KeyEvent e){}
         public void keyPressed(KeyEvent e){
             if (e.character is '\r'){
@@ -80,7 +100,7 @@
             }
         }
     });
-    
+
 }
 private static int checkStyle (int style) {
     int mask = DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT;
@@ -149,7 +169,7 @@
             listSize.y += 2;
         }
         y = rect.y - listSize.y;
-        
+
     } else {
         // place popup list below table cell
         if (listSize.y > spaceBelow){
@@ -159,18 +179,18 @@
         }
         y = rect.y + rect.height;
     }
-    
+
     // Make dialog as wide as the cell
     listSize.x = rect.width;
     // dialog width should not be less than minimumWidth
     if (listSize.x < minimumWidth)
         listSize.x = minimumWidth;
-    
+
     // Align right side of dialog with right side of cell
     int x = rect.x + rect.width - listSize.x;
-    
+
     shell.setBounds(x, y, listSize.x, listSize.y);
-    
+
     shell.open();
     list.setFocus();
 
@@ -178,37 +198,37 @@
     while (!shell.isDisposed () && shell.isVisible ()) {
         if (!display.readAndDispatch()) display.sleep();
     }
-    
+
     String result = null;
     if (!shell.isDisposed ()) {
-        String [] Strings = list.getSelection ();
+        String [] strings = list.getSelection ();
         shell.dispose();
-        if (Strings.length !is 0) result = Strings [0];
+        if (strings.length !is 0) result = strings [0];
     }
     return result;
 }
 /**
 * Selects an item with text that starts with specified String.
 * <p>
-* If the item is not currently selected, it is selected.  
-* If the item at an index is selected, it remains selected.  
-* If the String is not matched, it is ignored.
+* If the item is not currently selected, it is selected.
+* If the item at an index is selected, it remains selected.
+* If the string is not matched, it is ignored.
 *
-* @param String the text of the item
+* @param string the text of the item
 *
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 *   </ul>
 */
-public void select(String String) {
+public void select(String string) {
     String[] items = list.getItems();
 
     // find the first entry in the list that starts with the
-    // specified String
-    if (String !is null){
+    // specified string
+    if (string !is null){
         for (int i = 0; i < items.length; i++) {
-            if (items[i].startsWith(String)){
+            if ( tango.text.Util.locatePattern( items[i], string) is 0 ){
                 int index = list.indexOf(items[i]);
                 list.select(index);
                 break;
@@ -223,7 +243,7 @@
 * to the default system font for the widget.
 *
 * @param font the new font (or null)
-* 
+*
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -240,13 +260,12 @@
 * The new items are added.
 * The top index is set to 0.
 *
-* @param Strings the array of items
+* @param strings the array of items
 *
 * This operation will fail when an item is null
 * or could not be added in the OS.
-* 
+*
 * @exception IllegalArgumentException <ul>
-*    <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
 *    <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li>
 * </ul>
 * @exception DWTException <ul>
@@ -254,8 +273,8 @@
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
 *   </ul>
 */
-public void setItems (String[] Strings) {
-    list.setItems(Strings);
+public void setItems (String[] strings) {
+    list.setItems(strings);
 }
 /**
 * Sets the minimum width of the list.
@@ -265,7 +284,7 @@
 public void setMinimumWidth (int width) {
     if (width < 0)
         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        
+
     minimumWidth = width;
 }
 }
--- a/dwt/custom/ST.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/ST.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,123 +7,127 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.ST;
 
 
 /**
  * This class provides access to the public constants provided by <code>StyledText</code>.
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 public class ST {
-     
+
     /*
      *  Navigation Key Actions. Key bindings for the actions are set
      *  by the StyledText widget.
-     */ 
-    public static final int LINE_UP = 16777217;             // binding = DWT.ARROW_UP
-    public static final int LINE_DOWN = 16777218;       // binding = DWT.ARROW_DOWN
-    public static final int LINE_START = 16777223;      // binding = DWT.HOME
-    public static final int LINE_END = 16777224;        // binding = DWT.END
-    public static final int COLUMN_PREVIOUS = 16777219;     // binding = DWT.ARROW_LEFT
-    public static final int COLUMN_NEXT = 16777220;         // binding = DWT.ARROW_RIGHT
-    public static final int PAGE_UP = 16777221;             // binding = DWT.PAGE_UP
-    public static final int PAGE_DOWN = 16777222;       // binding = DWT.PAGE_DOWN
-    public static final int WORD_PREVIOUS = 17039363;   // binding = DWT.MOD1 + DWT.ARROW_LEFT
-    public static final int WORD_NEXT = 17039364;       // binding = DWT.MOD1 + DWT.ARROW_RIGHT
-    public static final int TEXT_START = 17039367;      // binding = DWT.MOD1 + DWT.HOME
-    public static final int TEXT_END = 17039368;        // binding = DWT.MOD1 + DWT.END
-    public static final int WINDOW_START = 17039365;    // binding = DWT.MOD1 + DWT.PAGE_UP
-    public static final int WINDOW_END = 17039366;      // binding = DWT.MOD1 + DWT.PAGE_DOWN
-
-    /* 
-     * Selection Key Actions 
      */
-    public static final int SELECT_ALL = 262209;                // binding = DWT.MOD1 + 'A'
-    public static final int SELECT_LINE_UP = 16908289;          // binding = DWT.MOD2 + DWT.ARROW_UP
-    public static final int SELECT_LINE_DOWN = 16908290;        // binding = DWT.MOD2 + DWT.ARROW_DOWN
-    public static final int SELECT_LINE_START = 16908295;       // binding = DWT.MOD2 + DWT.HOME
-    public static final int SELECT_LINE_END = 16908296;             // binding = DWT.MOD2 + DWT.END
-    public static final int SELECT_COLUMN_PREVIOUS = 16908291;  // binding = DWT.MOD2 + DWT.ARROW_LEFT
-    public static final int SELECT_COLUMN_NEXT = 16908292;      // binding = DWT.MOD2 + DWT.ARROW_RIGHT
-    public static final int SELECT_PAGE_UP = 16908293;          // binding = DWT.MOD2 + DWT.PAGE_UP
-    public static final int SELECT_PAGE_DOWN = 16908294;        // binding = DWT.MOD2 + DWT.PAGE_DOWN
-    public static final int SELECT_WORD_PREVIOUS = 17170435;        // binding = DWT.MOD1 + DWT.MOD2 + DWT.ARROW_LEFT
-    public static final int SELECT_WORD_NEXT = 17170436;        // binding = DWT.MOD1 + DWT.MOD2 + DWT.ARROW_RIGHT
-    public static final int SELECT_TEXT_START = 17170439;       // binding = DWT.MOD1 + DWT.MOD2 + DWT.HOME
-    public static final int SELECT_TEXT_END = 17170440;             // binding = DWT.MOD1 + DWT.MOD2 + DWT.END
-    public static final int SELECT_WINDOW_START = 17170437;         // binding = DWT.MOD1 + DWT.MOD2 + DWT.PAGE_UP
-    public static final int SELECT_WINDOW_END = 17170438;       // binding = DWT.MOD1 + DWT.MOD2 + DWT.PAGE_DOWN
+    public static const int LINE_UP = 16777217;             // binding = DWT.ARROW_UP
+    public static const int LINE_DOWN = 16777218;       // binding = DWT.ARROW_DOWN
+    public static const int LINE_START = 16777223;      // binding = DWT.HOME
+    public static const int LINE_END = 16777224;        // binding = DWT.END
+    public static const int COLUMN_PREVIOUS = 16777219;     // binding = DWT.ARROW_LEFT
+    public static const int COLUMN_NEXT = 16777220;         // binding = DWT.ARROW_RIGHT
+    public static const int PAGE_UP = 16777221;             // binding = DWT.PAGE_UP
+    public static const int PAGE_DOWN = 16777222;       // binding = DWT.PAGE_DOWN
+    public static const int WORD_PREVIOUS = 17039363;   // binding = DWT.MOD1 + DWT.ARROW_LEFT
+    public static const int WORD_NEXT = 17039364;       // binding = DWT.MOD1 + DWT.ARROW_RIGHT
+    public static const int TEXT_START = 17039367;      // binding = DWT.MOD1 + DWT.HOME
+    public static const int TEXT_END = 17039368;        // binding = DWT.MOD1 + DWT.END
+    public static const int WINDOW_START = 17039365;    // binding = DWT.MOD1 + DWT.PAGE_UP
+    public static const int WINDOW_END = 17039366;      // binding = DWT.MOD1 + DWT.PAGE_DOWN
 
     /*
-     *  Modification Key Actions 
+     * Selection Key Actions
      */
-    public static final int CUT = 131199;           // binding = DWT.MOD2 + DWT.DEL
-    public static final int COPY = 17039369;        // binding = DWT.MOD1 + DWT.INSERT;
-    public static final int PASTE = 16908297;       // binding = DWT.MOD2 + DWT.INSERT ;
-    public static final int DELETE_PREVIOUS = '\b';     // binding = DWT.BS;
-    public static final int DELETE_NEXT = 0x7F;         // binding = DWT.DEL;
-    public static final int DELETE_WORD_PREVIOUS = 262152;  // binding = DWT.BS | DWT.MOD1;
-    public static final int DELETE_WORD_NEXT = 262271;  // binding = DWT.DEL | DWT.MOD1;
+    public static const int SELECT_ALL = 262209;                // binding = DWT.MOD1 + 'A'
+    public static const int SELECT_LINE_UP = 16908289;          // binding = DWT.MOD2 + DWT.ARROW_UP
+    public static const int SELECT_LINE_DOWN = 16908290;        // binding = DWT.MOD2 + DWT.ARROW_DOWN
+    public static const int SELECT_LINE_START = 16908295;       // binding = DWT.MOD2 + DWT.HOME
+    public static const int SELECT_LINE_END = 16908296;             // binding = DWT.MOD2 + DWT.END
+    public static const int SELECT_COLUMN_PREVIOUS = 16908291;  // binding = DWT.MOD2 + DWT.ARROW_LEFT
+    public static const int SELECT_COLUMN_NEXT = 16908292;      // binding = DWT.MOD2 + DWT.ARROW_RIGHT
+    public static const int SELECT_PAGE_UP = 16908293;          // binding = DWT.MOD2 + DWT.PAGE_UP
+    public static const int SELECT_PAGE_DOWN = 16908294;        // binding = DWT.MOD2 + DWT.PAGE_DOWN
+    public static const int SELECT_WORD_PREVIOUS = 17170435;        // binding = DWT.MOD1 + DWT.MOD2 + DWT.ARROW_LEFT
+    public static const int SELECT_WORD_NEXT = 17170436;        // binding = DWT.MOD1 + DWT.MOD2 + DWT.ARROW_RIGHT
+    public static const int SELECT_TEXT_START = 17170439;       // binding = DWT.MOD1 + DWT.MOD2 + DWT.HOME
+    public static const int SELECT_TEXT_END = 17170440;             // binding = DWT.MOD1 + DWT.MOD2 + DWT.END
+    public static const int SELECT_WINDOW_START = 17170437;         // binding = DWT.MOD1 + DWT.MOD2 + DWT.PAGE_UP
+    public static const int SELECT_WINDOW_END = 17170438;       // binding = DWT.MOD1 + DWT.MOD2 + DWT.PAGE_DOWN
 
-    /* 
-     * Miscellaneous Key Actions 
+    /*
+     *  Modification Key Actions
      */
-    public static final int TOGGLE_OVERWRITE = 16777225; // binding = DWT.INSERT;
-    
+    public static const int CUT = 131199;           // binding = DWT.MOD2 + DWT.DEL
+    public static const int COPY = 17039369;        // binding = DWT.MOD1 + DWT.INSERT;
+    public static const int PASTE = 16908297;       // binding = DWT.MOD2 + DWT.INSERT ;
+    public static const int DELETE_PREVIOUS = '\b';     // binding = DWT.BS;
+    public static const int DELETE_NEXT = 0x7F;         // binding = DWT.DEL;
+    public static const int DELETE_WORD_PREVIOUS = 262152;  // binding = DWT.BS | DWT.MOD1;
+    public static const int DELETE_WORD_NEXT = 262271;  // binding = DWT.DEL | DWT.MOD1;
+
+    /*
+     * Miscellaneous Key Actions
+     */
+    public static const int TOGGLE_OVERWRITE = 16777225; // binding = DWT.INSERT;
+
     /**
      *  Bullet style dot.
-     * 
+     *
      *  @see Bullet
-     *  
+     *
      *  @since 3.2
      */
-    public static final int BULLET_DOT = 1 << 0;
+    public static const int BULLET_DOT = 1 << 0;
 
     /**
      *  Bullet style number.
-     * 
+     *
      *  @see Bullet
-     *  
+     *
      *  @since 3.2
      */
-    public static final int BULLET_NUMBER = 1 << 1;
+    public static const int BULLET_NUMBER = 1 << 1;
 
     /**
      *  Bullet style lower case letter.
-     * 
+     *
      *  @see Bullet
-     *  
+     *
      *  @since 3.2
      */
-    public static final int BULLET_LETTER_LOWER = 1 << 2;
+    public static const int BULLET_LETTER_LOWER = 1 << 2;
 
     /**
      *  Bullet style upper case letter.
-     * 
+     *
      *  @see Bullet
-     *  
+     *
      *  @since 3.2
      */
-    public static final int BULLET_LETTER_UPPER = 1 << 3;
+    public static const int BULLET_LETTER_UPPER = 1 << 3;
 
     /**
      *  Bullet style text.
-     * 
+     *
      *  @see Bullet
-     *  
+     *
      *  @since 3.2
      */
-    public static final int BULLET_TEXT = 1 << 4;
+    public static const int BULLET_TEXT = 1 << 4;
 
     /**
      *  Bullet style custom draw.
-     *  
+     *
      *  @see StyledText#addPaintObjectListener(PaintObjectListener)
      *  @see StyledText#removePaintObjectListener(PaintObjectListener)
-     *  @see Bullet 
-     *  
+     *  @see Bullet
+     *
      *  @since 3.2
      */
-    public static final int BULLET_CUSTOM = 1 << 5;
+    public static const int BULLET_CUSTOM = 1 << 5;
 
 }
--- a/dwt/custom/SashForm.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/SashForm.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,13 +7,26 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.SashForm;
+
 
 
-import dwt.*;
-import dwt.widgets.*;
-import dwt.graphics.*;
+import dwt.DWT;
+import dwt.DWTException;
+import dwt.graphics.Color;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Event;
+import dwt.widgets.Layout;
+import dwt.widgets.Listener;
+import dwt.widgets.Sash;
+import dwt.custom.SashFormLayout;
+import dwt.custom.SashFormData;
+import dwt.dwthelper.utils;
 
 /**
  * The SashForm is a composite control that lays out its children in a
@@ -27,23 +40,30 @@
  * <dd>HORIZONTAL, VERTICAL, SMOOTH</dd>
  * </dl>
  * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#sashform">SashForm snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: CustomControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 public class SashForm : Composite {
 
+    /**
+    * The width of all sashes in the form.
+    */
     public int SASH_WIDTH = 3;
 
     int sashStyle;
-    Sash[] sashes = new Sash[0];
+    Sash[] sashes;
     // Remember background and foreground
     // colors to determine whether to set
     // sashes to the default color (null) or
     // a specific color
     Color background = null;
     Color foreground = null;
-    Control[] controls = new Control[0];
+    Control[] controls;
     Control maxControl = null;
     Listener sashListener;
-    static final int DRAG_MINIMUM = 20;
+    static const int DRAG_MINIMUM = 20;
 
 /**
  * Constructs a new instance of this class given its parent
@@ -51,7 +71,7 @@
  * <p>
  * The style value is either one of the style constants defined in
  * class <code>DWT</code> which is applicable to instances of this
- * class, or must be built by <em>bitwise OR</em>'ing together 
+ * class, or must be built by <em>bitwise OR</em>'ing together
  * (that is, using the <code>int</code> "|" operator) two or more
  * of those <code>DWT</code> style constants. The class description
  * lists the style constants that are applicable to the class.
@@ -78,7 +98,7 @@
     sashStyle = ((style & DWT.VERTICAL) !is 0) ? DWT.HORIZONTAL : DWT.VERTICAL;
     if ((style & DWT.BORDER) !is 0) sashStyle |= DWT.BORDER;
     if ((style & DWT.SMOOTH) !is 0) sashStyle |= DWT.SMOOTH;
-    sashListener = new Listener() {
+    sashListener = new class() Listener {
         public void handleEvent(Event e) {
             onDragSash(e);
         }
@@ -91,7 +111,7 @@
 /**
  * Returns DWT.HORIZONTAL if the controls in the SashForm are laid out side by side
  * or DWT.VERTICAL   if the controls in the SashForm are laid out top to bottom.
- * 
+ *
  * @return DWT.HORIZONTAL or DWT.VERTICAL
  */
 public int getOrientation() {
@@ -115,16 +135,16 @@
     checkWidget();
     return SASH_WIDTH;
 }
-public int getStyle() {
+public override int getStyle() {
     int style = super.getStyle();
     style |= getOrientation() is DWT.VERTICAL ? DWT.VERTICAL : DWT.HORIZONTAL;
     if ((sashStyle & DWT.SMOOTH) !is 0) style |= DWT.SMOOTH;
     return style;
 }
 /**
- * Answer the control that currently is maximized in the SashForm.  
+ * Answer the control that currently is maximized in the SashForm.
  * This value may be null.
- * 
+ *
  * @return the control that currently is maximized or null
  */
 public Control getMaximizedControl(){
@@ -133,13 +153,13 @@
 }
 /**
  * Answer the relative weight of each child in the SashForm.  The weight represents the
- * percent of the total width (if SashForm has Horizontal orientation) or 
+ * percent of the total width (if SashForm has Horizontal orientation) or
  * total height (if SashForm has Vertical orientation) each control occupies.
  * The weights are returned in order of the creation of the widgets (weight[0]
  * corresponds to the weight of the first child created).
- * 
+ *
  * @return the relative weight of each child
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -152,8 +172,8 @@
     int[] ratios = new int[cArray.length];
     for (int i = 0; i < cArray.length; i++) {
         Object data = cArray[i].getLayoutData();
-        if (data !is null && null !is cast(SashFormData)data ) {
-            ratios[i] = cast(int)((cast(SashFormData)data).weight * 1000 >> 16);
+        if ( auto sfd = cast(SashFormData)data ) {
+            ratios[i] = cast(int)(sfd.weight * 1000 >> 16);
         } else {
             ratios[i] = 200;
         }
@@ -164,7 +184,7 @@
     Control[] children = getChildren();
     Control[] result = new Control[0];
     for (int i = 0; i < children.length; i++) {
-        if (children[i] instanceof Sash) continue;
+        if ( null !is cast(Sash)children[i]) continue;
         if (onlyVisible && !children[i].getVisible()) continue;
 
         Control[] newResult = new Control[result.length + 1];
@@ -189,13 +209,13 @@
     Control c2 = controls[sashIndex + 1];
     Rectangle b1 = c1.getBounds();
     Rectangle b2 = c2.getBounds();
-    
+
     Rectangle sashBounds = sash.getBounds();
     Rectangle area = getClientArea();
     bool correction = false;
     if (getOrientation() is DWT.HORIZONTAL) {
         correction = b1.width < DRAG_MINIMUM || b2.width < DRAG_MINIMUM;
-        int totalWidth = b2.x + b2.width - b1.x; 
+        int totalWidth = b2.x + b2.width - b1.x;
         int shift = event.x - sashBounds.x;
         b1.width += shift;
         b2.x += shift;
@@ -253,7 +273,7 @@
             c1.setLayoutData(data1);
         }
         Object data2 = c2.getLayoutData();
-        if (data2 is null || !( null !is cast(SashFormData)data2 )) {
+        if (data2 is null || !(null !is cast(SashFormData)data2 )) {
             data2 = new SashFormData();
             c2.setLayoutData(data2);
         }
@@ -267,12 +287,12 @@
     }
 }
 /**
- * If orientation is DWT.HORIZONTAL, lay the controls in the SashForm 
- * out side by side.  If orientation is DWT.VERTICAL, lay the 
+ * If orientation is DWT.HORIZONTAL, lay the controls in the SashForm
+ * out side by side.  If orientation is DWT.VERTICAL, lay the
  * controls in the SashForm out top to bottom.
- * 
+ *
  * @param orientation DWT.HORIZONTAL or DWT.VERTICAL
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -296,14 +316,14 @@
     }
     layout(false);
 }
-public void setBackground (Color color) {
+public override void setBackground (Color color) {
     super.setBackground(color);
     background = color;
     for (int i = 0; i < sashes.length; i++) {
         sashes[i].setBackground(background);
     }
 }
-public void setForeground (Color color) {
+public override void setForeground (Color color) {
     super.setForeground(color);
     foreground = color;
     for (int i = 0; i < sashes.length; i++) {
@@ -325,19 +345,19 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  */
-public void setLayout (Layout layout) {
+public override void setLayout (Layout layout) {
     checkWidget();
     return;
 }
 /**
- * Specify the control that should take up the entire client area of the SashForm.  
- * If one control has been maximized, and this method is called with a different control, 
+ * Specify the control that should take up the entire client area of the SashForm.
+ * If one control has been maximized, and this method is called with a different control,
  * the previous control will be minimized and the new control will be maximized.
  * If the value of control is null, the SashForm will minimize all controls and return to
  * the default layout where all controls are laid out separated by sashes.
- * 
+ *
  * @param control the control to be maximized or null
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -355,7 +375,7 @@
         }
         return;
     }
-    
+
     for (int i= 0; i < sashes.length; i++){
         sashes[i].setVisible(false);
     }
@@ -384,13 +404,13 @@
 }
 /**
  * Specify the relative weight of each child in the SashForm.  This will determine
- * what percent of the total width (if SashForm has Horizontal orientation) or 
+ * what percent of the total width (if SashForm has Horizontal orientation) or
  * total height (if SashForm has Vertical orientation) each control will occupy.
  * The weights must be positive values and there must be an entry for each
  * non-sash child of the SashForm.
- * 
+ *
  * @param weights the relative weight of each child
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -403,7 +423,7 @@
     if (weights is null || weights.length !is cArray.length) {
         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     }
-    
+
     int total = 0;
     for (int i = 0; i < weights.length; i++) {
         if (weights[i] < 0) {
--- a/dwt/custom/SashFormData.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/SashFormData.d	Tue Oct 07 16:29:55 2008 +0200
@@ -7,27 +7,34 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.SashFormData;
+
+import dwt.dwthelper.utils;
+
+static import tango.text.Util;
+import tango.util.Convert;
 
 class SashFormData {
 
     long weight;
 
 String getName () {
-    String String = getClass ().getName ();
-    int index = String.lastIndexOf ('.');
-    if (index is -1) return String;
-    return String.substring (index + 1, String.length ());
+    String string = this.classinfo.name;
+    int index = tango.text.Util.locatePrior( string ,'.' );
+    if (index is string.length ) return string;
+    return string[ index + 1 .. $ ];
 }
 
 /**
- * Returns a String containing a concise, human-readable
+ * Returns a string containing a concise, human-readable
  * description of the receiver.
  *
- * @return a String representation of the event
+ * @return a string representation of the event
  */
-public String toString () {
-    return getName()+" {weight="+weight+"}"; //$NON-NLS-2$
+public override String toString () {
+    return getName()~" {weight="~to!(String)(weight)~"}"; //$NON-NLS-2$
 }
 }
--- a/dwt/custom/SashFormLayout.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/SashFormLayout.d	Tue Oct 07 16:29:55 2008 +0200
@@ -7,25 +7,35 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.SashFormLayout;
+
 
-import dwt.*;
-import dwt.graphics.*;
-import dwt.widgets.*;
+import dwt.DWT;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Layout;
+import dwt.widgets.Sash;
+import dwt.custom.SashForm;
+import dwt.custom.SashFormData;
+import dwt.dwthelper.utils;
 
 /**
  * This class provides the layout for SashForm
- * 
+ *
  * @see SashForm
  */
 class SashFormLayout : Layout {
-protected Point computeSize(Composite composite, int wHint, int hHint, bool flushCache) {
+protected override Point computeSize(Composite composite, int wHint, int hHint, bool flushCache) {
     SashForm sashForm = cast(SashForm)composite;
     Control[] cArray = sashForm.getControls(true);
     int width = 0;
     int height = 0;
-    if (cArray.length is 0) {       
+    if (cArray.length is 0) {
         if (wHint !is DWT.DEFAULT) width = wHint;
         if (hHint !is DWT.DEFAULT) height = hHint;
         return new Point(width, height);
@@ -56,13 +66,13 @@
     long total = 0;
     for (int i = 0; i < cArray.length; i++) {
         Object data = cArray[i].getLayoutData();
-        if (data !is null && null !is cast(SashFormData)data ) {
-            ratios[i] = (cast(SashFormData)data).weight;
+        if ( auto sfd = cast(SashFormData)data) {
+            ratios[i] = sfd.weight;
         } else {
             data = new SashFormData();
             cArray[i].setLayoutData(data);
             (cast(SashFormData)data).weight = ratios[i] = ((200 << 16) + 999) / 1000;
-            
+
         }
         total += ratios[i];
     }
@@ -81,21 +91,21 @@
     return new Point(width, height);
 }
 
-protected bool flushCache(Control control) {
+protected override bool flushCache(Control control) {
     return true;
 }
 
-protected void layout(Composite composite, bool flushCache) {
+protected override void layout(Composite composite, bool flushCache) {
     SashForm sashForm = cast(SashForm)composite;
     Rectangle area = sashForm.getClientArea();
     if (area.width <= 1 || area.height <= 1) return;
-    
+
     Control[] newControls = sashForm.getControls(true);
     if (sashForm.controls.length is 0 && newControls.length is 0) return;
     sashForm.controls = newControls;
-    
+
     Control[] controls = sashForm.controls;
-    
+
     if (sashForm.maxControl !is null && !sashForm.maxControl.isDisposed()) {
         for (int i= 0; i < controls.length; i++){
             if (controls[i] !is sashForm.maxControl) {
@@ -106,7 +116,7 @@
         }
         return;
     }
-    
+
     // keep just the right number of sashes
     if (sashForm.sashes.length < controls.length - 1) {
         Sash[] newSashes = new Sash[controls.length - 1];
@@ -141,17 +151,17 @@
     long total = 0;
     for (int i = 0; i < controls.length; i++) {
         Object data = controls[i].getLayoutData();
-        if (data !is null && null !is cast(SashFormData)data ) {
-            ratios[i] = (cast(SashFormData)data).weight;
+        if ( auto sfd = cast(SashFormData)data ) {
+            ratios[i] = sfd.weight;
         } else {
             data = new SashFormData();
             controls[i].setLayoutData(data);
             (cast(SashFormData)data).weight = ratios[i] = ((200 << 16) + 999) / 1000;
-            
+
         }
         total += ratios[i];
     }
-    
+
     int sashwidth = sashes.length > 0 ? sashForm.SASH_WIDTH + sashes [0].getBorderWidth() * 2 : sashForm.SASH_WIDTH;
     if (sashForm.getOrientation() is DWT.HORIZONTAL) {
         int width = cast(int)(ratios[0] * (area.width - sashes.length * sashwidth) / total);
--- a/dwt/custom/ScrolledComposite.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/ScrolledComposite.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,13 +7,29 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.ScrolledComposite;
+
+import dwt.dwthelper.utils;
+
 
-import dwt.*;
-import dwt.events.*;
-import dwt.graphics.*;
-import dwt.widgets.*;
+import dwt.DWT;
+import dwt.DWTException;
+import dwt.events.DisposeEvent;
+import dwt.events.DisposeListener;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Layout;
+import dwt.widgets.Listener;
+import dwt.widgets.ScrollBar;
+import dwt.widgets.Shell;
+import dwt.custom.ScrolledCompositeLayout;
 
 /**
  * A ScrolledComposite provides scrollbars and will scroll its content when the user
@@ -21,17 +37,17 @@
  *
  *
  * <p>There are two ways to use the ScrolledComposite:
- * 
+ *
  * <p>
- * 1) Set the size of the control that is being scrolled and the ScrolledComposite 
+ * 1) Set the size of the control that is being scrolled and the ScrolledComposite
  * will show scrollbars when the contained control can not be fully seen.
- * 
+ *
  * 2) The second way imitates the way a browser would work.  Set the minimum size of
- * the control and the ScrolledComposite will show scroll bars if the visible area is 
- * less than the minimum size of the control and it will expand the size of the control 
- * if the visible area is greater than the minimum size.  This requires invoking 
+ * the control and the ScrolledComposite will show scroll bars if the visible area is
+ * less than the minimum size of the control and it will expand the size of the control
+ * if the visible area is greater than the minimum size.  This requires invoking
  * both setMinWidth(), setMinHeight() and setExpandHorizontal(), setExpandVertical().
- * 
+ *
  * <code><pre>
  * public static void main (String [] args) {
  *      Display display = new Display ();
@@ -39,7 +55,7 @@
  *      Color blue = display.getSystemColor(DWT.COLOR_BLUE);
  *      Shell shell = new Shell (display);
  *      shell.setLayout(new FillLayout());
- *  
+ *
  *      // set the size of the scrolled content - method 1
  *      final ScrolledComposite sc1 = new ScrolledComposite(shell, DWT.H_SCROLL | DWT.V_SCROLL | DWT.BORDER);
  *      final Composite c1 = new Composite(sc1, DWT.NONE);
@@ -51,7 +67,7 @@
  *      Button b1 = new Button (c1, DWT.PUSH);
  *      b1.setText("first button");
  *      c1.setSize(c1.computeSize(DWT.DEFAULT, DWT.DEFAULT));
- *      
+ *
  *      // set the minimum width and height of the scrolled content - method 2
  *      final ScrolledComposite sc2 = new ScrolledComposite(shell, DWT.H_SCROLL | DWT.V_SCROLL | DWT.BORDER);
  *      sc2.setExpandHorizontal(true);
@@ -65,7 +81,7 @@
  *      Button b2 = new Button (c2, DWT.PUSH);
  *      b2.setText("first button");
  *      sc2.setMinSize(c2.computeSize(DWT.DEFAULT, DWT.DEFAULT));
- *      
+ *
  *      Button add = new Button (shell, DWT.PUSH);
  *      add.setText("add children");
  *      final int[] index = new int[]{0};
@@ -77,7 +93,7 @@
  *              // reset size of content so children can be seen - method 1
  *              c1.setSize(c1.computeSize(DWT.DEFAULT, DWT.DEFAULT));
  *              c1.layout();
- *              
+ *
  *              button = new Button(c2, DWT.PUSH);
  *              button.setText("button "+index[0]);
  *              // reset the minimum width and height so children can be seen - method 2
@@ -85,7 +101,7 @@
  *              c2.layout();
  *          }
  *      });
- * 
+ *
  *      shell.open ();
  *      while (!shell.isDisposed ()) {
  *          if (!display.readAndDispatch ()) display.sleep ();
@@ -97,13 +113,16 @@
  * <dl>
  * <dt><b>Styles:</b><dd>H_SCROLL, V_SCROLL
  * </dl>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#scrolledcomposite">ScrolledComposite snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 public class ScrolledComposite : Composite {
 
     Control content;
     Listener contentListener;
     Listener filter;
-    
+
     int minHeight = 0;
     int minWidth = 0;
     bool expandHorizontal = false;
@@ -117,7 +136,7 @@
  * <p>
  * The style value is either one of the style constants defined in
  * class <code>DWT</code> which is applicable to instances of this
- * class, or must be built by <em>bitwise OR</em>'ing together 
+ * class, or must be built by <em>bitwise OR</em>'ing together
  * (that is, using the <code>int</code> "|" operator) two or more
  * of those <code>DWT</code> style constants. The class description
  * lists the style constants that are applicable to the class.
@@ -137,47 +156,46 @@
  * @see DWT#H_SCROLL
  * @see DWT#V_SCROLL
  * @see #getStyle()
- */ 
+ */
 public this(Composite parent, int style) {
     super(parent, checkStyle(style));
     super.setLayout(new ScrolledCompositeLayout());
     ScrollBar hBar = getHorizontalBar ();
     if (hBar !is null) {
         hBar.setVisible(false);
-        hBar.addListener (DWT.Selection, new Listener () {
+        hBar.addListener (DWT.Selection, new class() Listener  {
             public void handleEvent (Event e) {
                 hScroll();
             }
         });
     }
-    
+
     ScrollBar vBar = getVerticalBar ();
     if (vBar !is null) {
         vBar.setVisible(false);
-        vBar.addListener (DWT.Selection, new Listener () {
+        vBar.addListener (DWT.Selection, new class() Listener {
             public void handleEvent (Event e) {
                 vScroll();
             }
         });
     }
-    
-    contentListener = new Listener() {
+
+    contentListener = new class() Listener {
         public void handleEvent(Event e) {
             if (e.type !is DWT.Resize) return;
             layout(false);
         }
     };
-    
-    filter = new Listener() {
+
+    filter = new class() Listener {
         public void handleEvent(Event event) {
-            if ( null !is cast(Control)event.widget ) {
-                Control control = cast(Control) event.widget;
+            if (auto control = cast(Control)event.widget ) {
                 if (contains(control)) showControl(control);
             }
         }
     };
-    
-    addDisposeListener(new DisposeListener() {
+
+    addDisposeListener(new class() DisposeListener {
         public void widgetDisposed(DisposeEvent e) {
             getDisplay().removeFilter(DWT.FocusIn, filter);
         }
@@ -201,12 +219,12 @@
 }
 
 /**
- * Returns the Always Show Scrollbars flag.  True if the scrollbars are 
- * always shown even if they are not required.  False if the scrollbars are only 
+ * Returns the Always Show Scrollbars flag.  True if the scrollbars are
+ * always shown even if they are not required.  False if the scrollbars are only
  * visible when some part of the composite needs to be scrolled to be seen.
- * The H_SCROLL and V_SCROLL style bits are also required to enable scrollbars in the 
+ * The H_SCROLL and V_SCROLL style bits are also required to enable scrollbars in the
  * horizontal and vertical directions.
- * 
+ *
  * @return the Always Show Scrollbars flag value
  */
 public bool getAlwaysShowScrollBars() {
@@ -215,7 +233,7 @@
 }
 
 /**
- * Returns <code>true</code> if the content control 
+ * Returns <code>true</code> if the content control
  * will be expanded to fill available horizontal space.
  *
  * @return the receiver's horizontal expansion state
@@ -224,7 +242,7 @@
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 3.2
  */
 public bool getExpandHorizontal() {
@@ -233,7 +251,7 @@
 }
 
 /**
- * Returns <code>true</code> if the content control 
+ * Returns <code>true</code> if the content control
  * will be expanded to fill available vertical space.
  *
  * @return the receiver's vertical expansion state
@@ -242,7 +260,7 @@
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 3.2
  */
 public bool getExpandVertical() {
@@ -259,7 +277,7 @@
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 3.2
  */
 public int getMinWidth() {
@@ -276,7 +294,7 @@
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 3.2
  */
 public int getMinHeight() {
@@ -286,7 +304,7 @@
 
 /**
  * Get the content that is being scrolled.
- * 
+ *
  * @return the control displayed in the content area
  */
 public Control getContent() {
@@ -295,14 +313,16 @@
 }
 
 /**
- * Returns <code>true</code> if the receiver automatically scrolls to a focused child control 
+ * Returns <code>true</code> if the receiver automatically scrolls to a focused child control
  * to make it visible. Otherwise, returns <code>false</code>.
- * 
+ *
+ * @return a bool indicating whether focused child controls are automatically scrolled into the viewport
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 3.4
  */
 public bool getShowFocusedControl() {
@@ -320,13 +340,13 @@
 bool needHScroll(Rectangle contentRect, bool vVisible) {
     ScrollBar hBar = getHorizontalBar();
     if (hBar is null) return false;
-    
+
     Rectangle hostRect = getBounds();
     int border = getBorderWidth();
     hostRect.width -= 2*border;
     ScrollBar vBar = getVerticalBar();
     if (vVisible && vBar !is null) hostRect.width -= vBar.getSize().x;
-    
+
     if (!expandHorizontal && contentRect.width > hostRect.width) return true;
     if (expandHorizontal && minWidth > hostRect.width) return true;
     return false;
@@ -335,31 +355,31 @@
 bool needVScroll(Rectangle contentRect, bool hVisible) {
     ScrollBar vBar = getVerticalBar();
     if (vBar is null) return false;
-    
+
     Rectangle hostRect = getBounds();
     int border = getBorderWidth();
     hostRect.height -= 2*border;
     ScrollBar hBar = getHorizontalBar();
     if (hVisible && hBar !is null) hostRect.height -= hBar.getSize().y;
-    
+
     if (!expandVertical && contentRect.height > hostRect.height) return true;
     if (expandVertical && minHeight > hostRect.height) return true;
     return false;
 }
 
 /**
- * Return the point in the content that currently appears in the top left 
+ * Return the point in the content that currently appears in the top left
  * corner of the scrolled composite.
- * 
- * @return the point in the content that currently appears in the top left 
+ *
+ * @return the point in the content that currently appears in the top left
  * corner of the scrolled composite.  If no content has been set, this returns
  * (0, 0).
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 2.0
  */
 public Point getOrigin() {
@@ -369,14 +389,14 @@
     return new Point(-location.x, -location.y);
 }
 /**
- * Scrolls the content so that the specified point in the content is in the top 
- * left corner.  If no content has been set, nothing will occur.  
- * 
- * Negative values will be ignored.  Values greater than the maximum scroll 
+ * Scrolls the content so that the specified point in the content is in the top
+ * left corner.  If no content has been set, nothing will occur.
+ *
+ * Negative values will be ignored.  Values greater than the maximum scroll
  * distance will result in scrolling to the end of the scrollbar.
  *
- * @param origin the point on the content to appear in the top left corner 
- * 
+ * @param origin the point on the content to appear in the top left corner
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -388,21 +408,21 @@
     setOrigin(origin.x, origin.y);
 }
 /**
- * Scrolls the content so that the specified point in the content is in the top 
- * left corner.  If no content has been set, nothing will occur.  
- * 
- * Negative values will be ignored.  Values greater than the maximum scroll 
+ * Scrolls the content so that the specified point in the content is in the top
+ * left corner.  If no content has been set, nothing will occur.
+ *
+ * Negative values will be ignored.  Values greater than the maximum scroll
  * distance will result in scrolling to the end of the scrollbar.
  *
- * @param x the x coordinate of the content to appear in the top left corner 
- * 
- * @param y the y coordinate of the content to appear in the top left corner 
- * 
+ * @param x the x coordinate of the content to appear in the top left corner
+ *
+ * @param y the y coordinate of the content to appear in the top left corner
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 2.0
  */
 public void setOrigin(int x, int y) {
@@ -425,14 +445,14 @@
     content.setLocation(x, y);
 }
 /**
- * Set the Always Show Scrollbars flag.  True if the scrollbars are 
- * always shown even if they are not required.  False if the scrollbars are only 
+ * Set the Always Show Scrollbars flag.  True if the scrollbars are
+ * always shown even if they are not required.  False if the scrollbars are only
  * visible when some part of the composite needs to be scrolled to be seen.
- * The H_SCROLL and V_SCROLL style bits are also required to enable scrollbars in the 
+ * The H_SCROLL and V_SCROLL style bits are also required to enable scrollbars in the
  * horizontal and vertical directions.
- * 
+ *
  * @param show true to show the scrollbars even when not required, false to show scrollbars only when required
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -451,9 +471,9 @@
 
 /**
  * Set the content that will be scrolled.
- * 
+ *
  * @param content the control to be displayed in the content area
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -463,9 +483,9 @@
     checkWidget();
     if (this.content !is null && !this.content.isDisposed()) {
         this.content.removeListener(DWT.Resize, contentListener);
-        this.content.setBounds(new Rectangle(-200, -200, 0, 0));    
+        this.content.setBounds(new Rectangle(-200, -200, 0, 0));
     }
-    
+
     this.content = content;
     ScrollBar vBar = getVerticalBar ();
     ScrollBar hBar = getHorizontalBar ();
@@ -489,15 +509,15 @@
     }
 }
 /**
- * Configure the ScrolledComposite to resize the content object to be as wide as the 
+ * Configure the ScrolledComposite to resize the content object to be as wide as the
  * ScrolledComposite when the width of the ScrolledComposite is greater than the
  * minimum width specified in setMinWidth.  If the ScrolledComposite is less than the
  * minimum width, the content will not be resized and instead the horizontal scroll bar will be
  * used to view the entire width.
  * If expand is false, this behaviour is turned off.  By default, this behaviour is turned off.
- * 
+ *
  * @param expand true to expand the content control to fill available horizontal space
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -510,15 +530,15 @@
     layout(false);
 }
 /**
- * Configure the ScrolledComposite to resize the content object to be as tall as the 
+ * Configure the ScrolledComposite to resize the content object to be as tall as the
  * ScrolledComposite when the height of the ScrolledComposite is greater than the
  * minimum height specified in setMinHeight.  If the ScrolledComposite is less than the
  * minimum height, the content will not be resized and instead the vertical scroll bar will be
  * used to view the entire height.
  * If expand is false, this behaviour is turned off.  By default, this behaviour is turned off.
- * 
+ *
  * @param expand true to expand the content control to fill available vertical space
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -545,17 +565,17 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  */
-public void setLayout (Layout layout) {
+public override void setLayout (Layout layout) {
     checkWidget();
     return;
 }
 /**
  * Specify the minimum height at which the ScrolledComposite will begin scrolling the
- * content with the vertical scroll bar.  This value is only relevant if  
+ * content with the vertical scroll bar.  This value is only relevant if
  * setExpandVertical(true) has been set.
- * 
+ *
  * @param height the minimum height or 0 for default height
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -566,11 +586,11 @@
 }
 /**
  * Specify the minimum width and height at which the ScrolledComposite will begin scrolling the
- * content with the horizontal scroll bar.  This value is only relevant if  
+ * content with the horizontal scroll bar.  This value is only relevant if
  * setExpandHorizontal(true) and setExpandVertical(true) have been set.
- * 
+ *
  * @param size the minimum size or null for the default size
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -585,12 +605,12 @@
 }
 /**
  * Specify the minimum width and height at which the ScrolledComposite will begin scrolling the
- * content with the horizontal scroll bar.  This value is only relevant if  
+ * content with the horizontal scroll bar.  This value is only relevant if
  * setExpandHorizontal(true) and setExpandVertical(true) have been set.
- * 
+ *
  * @param width the minimum width or 0 for default width
  * @param height the minimum height or 0 for default height
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -605,11 +625,11 @@
 }
 /**
  * Specify the minimum width at which the ScrolledComposite will begin scrolling the
- * content with the horizontal scroll bar.  This value is only relevant if  
+ * content with the horizontal scroll bar.  This value is only relevant if
  * setExpandHorizontal(true) has been set.
- * 
+ *
  * @param width the minimum width or 0 for default width
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -622,18 +642,18 @@
 /**
  * Configure the receiver to automatically scroll to a focused child control
  * to make it visible.
- * 
- * If show is <code>false</code>, show a focused control is off.  
+ *
+ * If show is <code>false</code>, show a focused control is off.
  * By default, show a focused control is off.
- * 
+ *
  * @param show <code>true</code> to show a focused control.
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
- *  @since 3.4
+ *
+ * @since 3.4
  */
 public void setShowFocusedControl(bool show) {
     checkWidget();
@@ -668,7 +688,7 @@
     if (control is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (control.isDisposed ()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     if (!contains(control)) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-    
+
     Rectangle itemRect = getDisplay().map(control.getParent(), this, control.getBounds());
     Rectangle area = getClientArea();
     Point origin = getOrigin();
--- a/dwt/custom/ScrolledCompositeLayout.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/ScrolledCompositeLayout.d	Tue Oct 07 16:29:55 2008 +0200
@@ -7,25 +7,35 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.ScrolledCompositeLayout;
+
 
-import dwt.*;
-import dwt.graphics.*;
-import dwt.widgets.*;
+import dwt.DWT;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Layout;
+import dwt.widgets.ScrollBar;
+import dwt.custom.ScrolledComposite;
+
+import Math = tango.math.Math;
 
 /**
  * This class provides the layout for ScrolledComposite
- * 
+ *
  * @see ScrolledComposite
  */
 class ScrolledCompositeLayout : Layout {
-    
+
     bool inLayout = false;
     static final int DEFAULT_WIDTH  = 64;
     static final int DEFAULT_HEIGHT = 64;
-    
-protected Point computeSize(Composite composite, int wHint, int hHint, bool flushCache) {
+
+protected override Point computeSize(Composite composite, int wHint, int hHint, bool flushCache) {
     ScrolledComposite sc = cast(ScrolledComposite)composite;
     Point size = new Point(DEFAULT_WIDTH, DEFAULT_HEIGHT);
     if (sc.content !is null) {
@@ -41,11 +51,11 @@
     return size;
 }
 
-protected bool flushCache(Control control) {
+protected override bool flushCache(Control control) {
     return true;
 }
 
-protected void layout(Composite composite, bool flushCache) {
+protected override void layout(Composite composite, bool flushCache) {
     if (inLayout) return;
     ScrolledComposite sc = cast(ScrolledComposite)composite;
     if (sc.content is null) return;
@@ -72,7 +82,7 @@
     }
     Rectangle hostRect = sc.getClientArea();
     if (sc.expandHorizontal) {
-        contentRect.width = Math.max(sc.minWidth, hostRect.width);  
+        contentRect.width = Math.max(sc.minWidth, hostRect.width);
     }
     if (sc.expandVertical) {
         contentRect.height = Math.max(sc.minHeight, hostRect.height);
@@ -105,7 +115,7 @@
             contentRect.y = -vSelection;
         }
     }
-    
+
     sc.content.setBounds (contentRect);
     inLayout = false;
 }
--- a/dwt/custom/StackLayout.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/StackLayout.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,30 +7,41 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.StackLayout;
+
+import dwt.dwthelper.utils;
+
 
 
-import dwt.*;
-import dwt.graphics.*;
-import dwt.widgets.*;
+import dwt.DWT;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Layout;
+
+import tango.util.Convert;
+static import tango.text.Util;
 
 /**
  * This Layout stacks all the controls one on top of the other and resizes all controls
  * to have the same size and location.
  * The control specified in topControl is visible and all other controls are not visible.
- * Users must set the topControl value to flip between the visible items and then call 
+ * Users must set the topControl value to flip between the visible items and then call
  * layout() on the composite which has the StackLayout.
- * 
- * <p> Here is an example which places ten buttons in a stack layout and 
+ *
+ * <p> Here is an example which places ten buttons in a stack layout and
  * flips between them:
- * 
+ *
  * <pre><code>
  *  public static void main(String[] args) {
  *      Display display = new Display();
  *      Shell shell = new Shell(display);
  *      shell.setLayout(new GridLayout());
- *  
+ *
  *      final Composite parent = new Composite(shell, DWT.NONE);
  *      parent.setLayoutData(new GridData(GridData.FILL_BOTH));
  *      final StackLayout layout = new StackLayout();
@@ -41,7 +52,7 @@
  *          bArray[i].setText("Button "+i);
  *      }
  *      layout.topControl = bArray[0];
- *  
+ *
  *      Button b = new Button(shell, DWT.PUSH);
  *      b.setText("Show Next Button");
  *      final int[] index = new int[1];
@@ -52,18 +63,22 @@
  *              parent.layout();
  *          }
  *      });
- *  
+ *
  *      shell.open();
  *      while (shell !is null && !shell.isDisposed()) {
  *          if (!display.readAndDispatch())
- *              display.sleep(); 
- *      }   
+ *              display.sleep();
+ *      }
  *  }
  * </code></pre>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#stacklayout">StackLayout snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: LayoutExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 
 public class StackLayout : Layout {
-    
+
     /**
      * marginWidth specifies the number of pixels of horizontal margin
      * that will be placed along the left and right edges of the layout.
@@ -85,7 +100,7 @@
      */
     public Control topControl;
 
-protected Point computeSize(Composite composite, int wHint, int hHint, bool flushCache) {
+protected override Point computeSize(Composite composite, int wHint, int hHint, bool flushCache) {
     Control children[] = composite.getChildren();
     int maxWidth = 0;
     int maxHeight = 0;
@@ -101,11 +116,11 @@
     return new Point(width, height);
 }
 
-protected bool flushCache(Control control) {
+protected override bool flushCache(Control control) {
     return true;
 }
 
-protected void layout(Composite composite, bool flushCache) {
+protected override void layout(Composite composite, bool flushCache) {
     Control children[] = composite.getChildren();
     Rectangle rect = composite.getClientArea();
     rect.x += marginWidth;
@@ -115,30 +130,30 @@
     for (int i = 0; i < children.length; i++) {
         children[i].setBounds(rect);
         children[i].setVisible(children[i] is topControl);
-            
+
     }
 }
 
 String getName () {
-    String String = getClass ().getName ();
-    int index = String.lastIndexOf ('.');
-    if (index is -1) return String;
-    return String.substring (index + 1, String.length ());
+    String string = this.classinfo.name;
+    int index = tango.text.Util.locatePrior( string ,'.');
+    if (index is string.length ) return string;
+    return string[ index + 1 .. $ ];
 }
 
 /**
- * Returns a String containing a concise, human-readable
+ * Returns a string containing a concise, human-readable
  * description of the receiver.
  *
- * @return a String representation of the layout
+ * @return a string representation of the layout
  */
-public String toString () {
-    String String = getName ()+" {";
-    if (marginWidth !is 0) String += "marginWidth="+marginWidth+" ";
-    if (marginHeight !is 0) String += "marginHeight="+marginHeight+" ";
-    if (topControl !is null) String += "topControl="+topControl+" ";
-    String = String.trim();
-    String += "}";
-    return String;
+public override String toString () {
+    String string = getName ()~" {";
+    if (marginWidth !is 0) string ~= "marginWidth="~to!(String)(marginWidth)~" ";
+    if (marginHeight !is 0) string ~= "marginHeight="~to!(String)(marginHeight)~" ";
+    if (topControl !is null) string ~= "topControl="~to!(String)(topControl)~" ";
+    string = tango.text.Util.trim(string);
+    string ~= "}";
+    return string;
 }
 }
--- a/dwt/custom/StyleRange.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/StyleRange.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,20 +7,44 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.StyleRange;
+
+import dwt.dwthelper.utils;
+
+
+import dwt.DWT;
+import dwt.graphics.Color;
+import dwt.graphics.TextStyle;
+import dwt.internal.CloneableCompatibility;
+import dwt.custom.StyleRange;
+import dwt.custom.TextChangedEvent;
+import dwt.custom.TextChangingEvent;
 
-import dwt.*;
-import dwt.graphics.*;
-import dwt.internal.CloneableCompatibility;
+static import tango.text.Text;
+alias tango.text.Text.Text!(char) StringBuffer;
 
-public class StyleRange : TextStyle : CloneableCompatibility {
-    
+/**
+ * <code>StyleRange</code> defines a set of styles for a specified
+ * range of text.
+ * <p>
+ * The hashCode() method in this class uses the values of the public
+ * fields to compute the hash value. When storing instances of the
+ * class in hashed collections, do not modify these fields after the
+ * object has been inserted.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public class StyleRange : TextStyle, CloneableCompatibility {
+
     /**
      * the start offset of the range, zero-based from the document start
      */
     public int start;
-    
+
     /**
      * the length of the range
      */
@@ -29,37 +53,46 @@
     /**
      * the font style of the range. It may be a combination of
      * DWT.NORMAL, DWT.ITALIC or DWT.BOLD
-     * 
+     *
      * Note: the font style is not used if the <code>font</code> attribute
      * is set
      */
     public int fontStyle = DWT.NORMAL;
-    
+
 /**
  * Create a new style range with no styles
- * 
+ *
  * @since 3.2
  */
 public this() {
 }
+/++
+ + DWT extension for clone implementation
+ +/
+protected this( StyleRange other ){
+    super( other );
+    start = other.start;
+    length = other.length;
+    fontStyle = other.fontStyle;
+}
 
-/** 
+/**
  * Create a new style range from an existing text style.
  *
- *@param style the text style to copy
+ * @param style the text style to copy
  *
- *@since 3.4
+ * @since 3.4
  */
 public this(TextStyle style) {
     super(style);
 }
 
-/** 
+/**
  * Create a new style range.
  *
  * @param start start offset of the style
- * @param length length of the style 
- * @param foreground foreground color of the style, null if none 
+ * @param length length of the style
+ * @param foreground foreground color of the style, null if none
  * @param background background color of the style, null if none
  */
 public this(int start, int length, Color foreground, Color background) {
@@ -68,12 +101,12 @@
     this.length = length;
 }
 
-/** 
+/**
  * Create a new style range.
  *
  * @param start start offset of the style
- * @param length length of the style 
- * @param foreground foreground color of the style, null if none 
+ * @param length length of the style
+ * @param foreground foreground color of the style, null if none
  * @param background background color of the style, null if none
  * @param fontStyle font style of the style, may be DWT.NORMAL, DWT.ITALIC or DWT.BOLD
  */
@@ -90,12 +123,11 @@
  * @param object the object to compare with this object
  * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
  *
- * @see #toHash()
+ * @see #hashCode()
  */
-public bool opEquals(Object object) {
+public override int opEquals(Object object) {
     if (object is this) return true;
-    if ( null !is cast(StyleRange)object ) {
-        StyleRange style = cast(StyleRange)object;
+    if (auto style = cast(StyleRange) object ) {
         if (start !is style.start) return false;
         if (length !is style.length) return false;
         return similarTo(style);
@@ -104,23 +136,23 @@
 }
 
 /**
- * Returns an integer hash code for the receiver. Any two 
- * objects that return <code>true</code> when passed to 
- * <code>opEquals</code> must return the same value for this
+ * Returns an integer hash code for the receiver. Any two
+ * objects that return <code>true</code> when passed to
+ * <code>equals</code> must return the same value for this
  * method.
  *
  * @return the receiver's hash
  *
- * @see #opEquals(Object)
+ * @see #equals(Object)
  */
-public int toHash() {
+public override hash_t toHash() {
     return super.toHash() ^ fontStyle;
 }
 bool isVariableHeight() {
     return font !is null || metrics !is null || rise !is 0;
 }
 /**
- * Returns whether or not the receiver is unstyled (i.e., does not have any 
+ * Returns whether or not the receiver is unstyled (i.e., does not have any
  * style attributes specified).
  *
  * @return true if the receiver is unstyled, false otherwise.
@@ -139,7 +171,7 @@
 }
 
 /**
- * Compares the specified object to this StyleRange and answer if the two 
+ * Compares the specified object to this StyleRange and answer if the two
  * are similar. The object must be an instance of StyleRange and have the
  * same field values for except for start and length.
  *
@@ -156,22 +188,18 @@
  * Returns a new StyleRange with the same values as this StyleRange.
  *
  * @return a shallow copy of this StyleRange
- */ 
-public Object clone() {
-    try {
-        return super.clone();
-    } catch (CloneNotSupportedException e) {
-        return null;
-    }
+ */
+public /+override+/ Object clone() {
+    return new StyleRange( this );
 }
 
 /**
- * Returns a String containing a concise, human-readable
+ * Returns a string containing a concise, human-readable
  * description of the receiver.
  *
- * @return a String representation of the StyleRange
+ * @return a string representation of the StyleRange
  */
-public String toString() {
+public override String toString() {
     StringBuffer buffer = new StringBuffer();
     buffer.append("StyleRange {");
     buffer.append(start);
@@ -192,9 +220,10 @@
             buffer.append("normal");
     }
     String str = super.toString();
-    int index = str.indexOf('{');
-    str = str.substring(index + 1);
-    if (str.length() > 1) buffer.append(", ");
+    int index = tango.text.Util.locate( str, '{');
+    if( index is str.length ) index = -1;
+    str = str[ index + 1 .. $ ];
+    if (str.length > 1) buffer.append(", ");
     buffer.append(str);
     return buffer.toString();
 }
--- a/dwt/custom/StyledText.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/StyledText.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,39 +7,109 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.StyledText;
 
 
-import java.util.*;
+import dwt.DWT;
+import dwt.DWTError;
+import dwt.DWTException;
+import dwt.accessibility.ACC;
+import dwt.accessibility.Accessible;
+import dwt.accessibility.AccessibleAdapter;
+import dwt.accessibility.AccessibleControlAdapter;
+import dwt.accessibility.AccessibleControlEvent;
+import dwt.accessibility.AccessibleEvent;
+import dwt.accessibility.AccessibleTextAdapter;
+import dwt.accessibility.AccessibleTextEvent;
+import dwt.dnd.Clipboard;
+import dwt.dnd.DND;
+import dwt.dnd.RTFTransfer;
+import dwt.dnd.TextTransfer;
+import dwt.dnd.Transfer;
+import dwt.events.ModifyListener;
+import dwt.events.SelectionEvent;
+import dwt.events.SelectionListener;
+import dwt.events.VerifyListener;
+import dwt.graphics.Color;
+import dwt.graphics.Cursor;
+import dwt.graphics.Font;
+import dwt.graphics.FontData;
+import dwt.graphics.FontMetrics;
+import dwt.graphics.GC;
+import dwt.graphics.GlyphMetrics;
+import dwt.graphics.Image;
+import dwt.graphics.Device;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.graphics.Resource;
+import dwt.graphics.TextLayout;
+import dwt.internal.BidiUtil;
+import dwt.internal.Compatibility;
+import dwt.printing.Printer;
+import dwt.printing.PrinterData;
+import dwt.widgets.Canvas;
+import dwt.widgets.Caret;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.IME;
+import dwt.widgets.Label;
+import dwt.widgets.Listener;
+import dwt.widgets.ScrollBar;
+import dwt.widgets.TypedListener;
+import dwt.custom.StyledTextContent;
+import dwt.custom.TextChangeListener;
+import dwt.custom.StyledTextRenderer;
+import dwt.custom.StyledTextPrintOptions;
+import dwt.custom.ExtendedModifyListener;
+import dwt.custom.BidiSegmentListener;
+import dwt.custom.LineBackgroundListener;
+import dwt.custom.LineStyleListener;
+import dwt.custom.PaintObjectListener;
+import dwt.custom.VerifyKeyListener;
+import dwt.custom.MovementListener;
+import dwt.custom.Bullet;
+import dwt.custom.StyledTextEvent;
+import dwt.custom.StyleRange;
+import dwt.custom.TextChangedEvent;
+import dwt.custom.TextChangingEvent;
+import dwt.custom.DefaultContent;
+import dwt.custom.StyledTextDropTargetEffect;
+import dwt.custom.StyledTextListener;
+import dwt.custom.ST;
+import dwt.dwthelper.Runnable;
 
-import dwt.*;
-import dwt.accessibility.*;
-import dwt.dnd.*;
-import dwt.events.*;
-import dwt.graphics.*;
-import dwt.internal.*;
-import dwt.printing.*;
-import dwt.widgets.*;
+static import tango.text.Text;
+static import tango.text.Util;
+static import tango.io.model.IFile;
+static import tango.text.convert.Utf;
+import tango.util.Convert;
+import dwt.dwthelper.utils;
 
-/**
- * A StyledText is an editable user interface object that displays lines 
- * of text.  The following style attributes can be defined for the text: 
+alias tango.text.Text.Text!(char) StringBuffer;
+
+/**
+ * A StyledText is an editable user interface object that displays lines
+ * of text.  The following style attributes can be defined for the text:
  * <ul>
- * <li>foreground color 
+ * <li>foreground color
  * <li>background color
  * <li>font style (bold, italic, bold-italic, regular)
  * <li>underline
  * <li>strikeout
  * </ul>
  * <p>
- * In addition to text style attributes, the background color of a line may 
+ * In addition to text style attributes, the background color of a line may
  * be specified.
  * </p><p>
- * There are two ways to use this widget when specifying text style information.  
- * You may use the API that is defined for StyledText or you may define your own 
- * LineStyleListener.  If you define your own listener, you will be responsible 
- * for maintaining the text style information for the widget.  IMPORTANT: You may 
+ * There are two ways to use this widget when specifying text style information.
+ * You may use the API that is defined for StyledText or you may define your own
+ * LineStyleListener.  If you define your own listener, you will be responsible
+ * for maintaining the text style information for the widget.  IMPORTANT: You may
  * not define your own listener and use the StyledText API.  The following
  * StyledText API is not supported if you have defined a LineStyleListener:
  * <ul>
@@ -51,11 +121,11 @@
  * </ul>
  * </p><p>
  * There are two ways to use this widget when specifying line background colors.
- * You may use the API that is defined for StyledText or you may define your own 
- * LineBackgroundListener.  If you define your own listener, you will be responsible 
- * for maintaining the line background color information for the widget.  
- * IMPORTANT: You may not define your own listener and use the StyledText API.  
- * The following StyledText API is not supported if you have defined a 
+ * You may use the API that is defined for StyledText or you may define your own
+ * LineBackgroundListener.  If you define your own listener, you will be responsible
+ * for maintaining the line background color information for the widget.
+ * IMPORTANT: You may not define your own listener and use the StyledText API.
+ * The following StyledText API is not supported if you have defined a
  * LineBackgroundListener:
  * <ul>
  * <li>getLineBackground(int)
@@ -64,7 +134,7 @@
  * </p><p>
  * The content implementation for this widget may also be user-defined.  To do so,
  * you must implement the StyledTextContent interface and use the StyledText API
- * setContent(StyledTextContent) to initialize the widget. 
+ * setContent(StyledTextContent) to initialize the widget.
  * </p><p>
  * <dl>
  * <dt><b>Styles:</b><dd>FULL_SELECTION, MULTI, READ_ONLY, SINGLE, WRAP
@@ -73,31 +143,37 @@
  * </p><p>
  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
  * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#styledtext">StyledText snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Examples: CustomControlExample, TextEditor</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 public class StyledText : Canvas {
-    static final char TAB = '\t';
-    static final String PlatformLineDelimiter = System.getProperty("line.separator");
-    static final int BIDI_CARET_WIDTH = 3;
-    static final int DEFAULT_WIDTH  = 64;
-    static final int DEFAULT_HEIGHT = 64;
-    static final int V_SCROLL_RATE = 50;
-    static final int H_SCROLL_RATE = 10;
-    
-    static final int ExtendedModify = 3000;
-    static final int LineGetBackground = 3001;
-    static final int LineGetStyle = 3002;
-    static final int TextChanging = 3003;
-    static final int TextSet = 3004;
-    static final int VerifyKey = 3005;
-    static final int TextChanged = 3006;
-    static final int LineGetSegments = 3007;
-    static final int PaintObject = 3008;
-    static final int WordNext = 3009;
-    static final int WordPrevious = 3010;
-    
-    static final int PREVIOUS_OFFSET_TRAILING = 0;
-    static final int OFFSET_LEADING = 1;
-    
+    alias Canvas.computeSize computeSize;
+
+    static const char TAB = '\t';
+    static const String PlatformLineDelimiter = tango.io.model.IFile.FileConst.NewlineString;
+    static const int BIDI_CARET_WIDTH = 3;
+    static const int DEFAULT_WIDTH  = 64;
+    static const int DEFAULT_HEIGHT = 64;
+    static const int V_SCROLL_RATE = 50;
+    static const int H_SCROLL_RATE = 10;
+
+    static const int ExtendedModify = 3000;
+    static const int LineGetBackground = 3001;
+    static const int LineGetStyle = 3002;
+    static const int TextChanging = 3003;
+    static const int TextSet = 3004;
+    static const int VerifyKey = 3005;
+    static const int TextChanged = 3006;
+    static const int LineGetSegments = 3007;
+    static const int PaintObject = 3008;
+    static const int WordNext = 3009;
+    static const int WordPrevious = 3010;
+
+    static const int PREVIOUS_OFFSET_TRAILING = 0;
+    static const int OFFSET_LEADING = 1;
+
     Color selectionBackground;  // selection background color
     Color selectionForeground;  // selection foreground color
     StyledTextContent content;          // native content (default or user specified)
@@ -118,30 +194,30 @@
     int columnX;                        // keep track of the horizontal caret position when changing lines/pages. Fixes bug 5935
     int caretOffset = 0;
     int caretAlignment;
-    Point selection = new Point(0, 0);  // x and y are start and end caret offsets of selection
+    Point selection;                    // x and y are start and end caret offsets of selection
     Point clipboardSelection;           // x and y are start and end caret offsets of previous selection
     int selectionAnchor;                // position of selection anchor. 0 based offset from beginning of text
     Point doubleClickSelection;         // selection after last mouse double click
     bool editable = true;
     bool wordWrap = false;
-    bool doubleClickEnabled = true; // see getDoubleClickEnabled 
-    bool overwrite = false;         // insert/overwrite edit mode
+    bool doubleClickEnabled = true;  // see getDoubleClickEnabled
+    bool overwrite = false;          // insert/overwrite edit mode
     int textLimit = -1;                 // limits the number of characters the user can type in the widget. Unlimited by default.
-    Hashtable keyActionMap = new Hashtable();
+    int[int] keyActionMap;
     Color background = null;            // workaround for bug 4791
     Color foreground = null;            //
     Clipboard clipboard;
     int clickCount;
     int autoScrollDirection = DWT.NULL; // the direction of autoscrolling (up, down, right, left)
     int autoScrollDistance = 0;
-    int lastTextChangeStart;            // cache data of the 
-    int lastTextChangeNewLineCount;     // last text changing 
-    int lastTextChangeNewCharCount;     // event for use in the 
+    int lastTextChangeStart;            // cache data of the
+    int lastTextChangeNewLineCount;     // last text changing
+    int lastTextChangeNewCharCount;     // event for use in the
     int lastTextChangeReplaceLineCount; // text changed handler
     int lastTextChangeReplaceCharCount;
     int lastLineBottom;                 // the bottom pixel of the last line been replaced
-    bool isMirrored;
-    bool bidiColoring = false;      // apply the BIDI algorithm on text segments of the same color
+    bool isMirrored_;
+    bool bidiColoring = false;       // apply the BIDI algorithm on text segments of the same color
     Image leftCaretBitmap = null;
     Image rightCaretBitmap = null;
     int caretDirection = DWT.NULL;
@@ -149,32 +225,32 @@
     Caret defaultCaret = null;
     bool updateCaretDirection = true;
     bool fixedLineHeight;
-    bool dragDetect = true;
+    bool dragDetect_ = true;
     IME ime;
-    
+
     int alignment;
     bool justify;
     int indent;
     int lineSpacing;
 
-    final static bool IS_CARBON, IS_GTK, IS_MOTIF;
-    static {
+    const static bool IS_CARBON, IS_GTK, IS_MOTIF;
+    static this(){
         String platform = DWT.getPlatform();
-        IS_CARBON = "carbon".opEquals(platform);
-        IS_GTK = "gtk".opEquals(platform);
-        IS_MOTIF = "motif".opEquals(platform);
+        IS_CARBON = ("carbon" == platform);
+        IS_GTK    = ("gtk"    == platform);
+        IS_MOTIF  = ("motif"  == platform);
     }
 
     /**
      * The Printing class : printing of a range of text.
-     * An instance of <code>Printing</code> is returned in the 
-     * StyledText#print(Printer) API. The run() method may be 
+     * An instance of <code>Printing</code> is returned in the
+     * StyledText#print(Printer) API. The run() method may be
      * invoked from any thread.
      */
     static class Printing : Runnable {
-        final static int LEFT = 0;                      // left aligned header/footer segment
-        final static int CENTER = 1;                    // centered header/footer segment
-        final static int RIGHT = 2;                     // right aligned header/footer segment
+        const static int LEFT = 0;                      // left aligned header/footer segment
+        const static int CENTER = 1;                    // centered header/footer segment
+        const static int RIGHT = 2;                     // right aligned header/footer segment
 
         Printer printer;
         StyledTextRenderer printerRenderer;
@@ -182,7 +258,7 @@
         Rectangle clientArea;
         FontData fontData;
         Font printerFont;
-        Hashtable resources;
+        Resource[Resource] resources;
         int tabLength;
         GC gc;                                          // printer GC
         int pageWidth;                                  // width of a printer page in pixels
@@ -190,30 +266,30 @@
         int endPage;                                    // last page to print
         int startLine;                                  // first (wrapped) line to print
         int endLine;                                    // last (wrapped) line to print
-        bool singleLine;                                // widget single line mode
+        bool singleLine;                             // widget single line mode
         Point selection = null;                 // selected text
-        bool mirrored;                      // indicates the printing gc should be mirrored
+        bool mirrored;                       // indicates the printing gc should be mirrored
         int lineSpacing;
         int printMargin;
 
     /**
      * Creates an instance of <code>Printing</code>.
-     * Copies the widget content and rendering data that needs 
+     * Copies the widget content and rendering data that needs
      * to be requested from listeners.
      * </p>
      * @param parent StyledText widget to print.
      * @param printer printer device to print on.
      * @param printOptions print options
-     */     
+     */
     this(StyledText styledText, Printer printer, StyledTextPrintOptions printOptions) {
         this.printer = printer;
         this.printOptions = printOptions;
         this.mirrored = (styledText.getStyle() & DWT.MIRRORED) !is 0;
         singleLine = styledText.isSingleLine();
         startPage = 1;
-        endPage = Integer.MAX_VALUE;
+        endPage = int.max;
         PrinterData data = printer.getPrinterData();
-        if (data.scope is PrinterData.PAGE_RANGE) {
+        if (data.scope_ is PrinterData.PAGE_RANGE) {
             startPage = data.startPage;
             endPage = data.endPage;
             if (endPage < startPage) {
@@ -221,7 +297,7 @@
                 endPage = startPage;
                 startPage = temp;
             }
-        } else if (data.scope is PrinterData.SELECTION) {
+        } else if (data.scope_ is PrinterData.SELECTION) {
             selection = styledText.getSelectionRange();
         }
         printerRenderer = new StyledTextRenderer(printer, null);
@@ -231,7 +307,7 @@
     /**
      * Caches all line data that needs to be requested from a listener.
      * </p>
-     * @param printerContent <code>StyledTextContent</code> to request 
+     * @param printerContent <code>StyledTextContent</code> to request
      *  line data for.
      */
     void cacheLineData(StyledText styledText) {
@@ -252,7 +328,7 @@
                 if (styledText.isBidi()) {
                     int[] segments = styledText.getBidiSegments(lineOffset, line);
                     printerRenderer.setLineSegments(i, 1, segments);
-                }           
+                }
                 event = styledText.getLineStyleData(lineOffset, line);
                 if (event !is null) {
                     printerRenderer.setLineIndent(i, 1, event.indent);
@@ -268,15 +344,18 @@
         }
         Point screenDPI = styledText.getDisplay().getDPI();
         Point printerDPI = printer.getDPI();
-        resources = new Hashtable ();
+        resources = null;
         for (int i = 0; i < lineCount; i++) {
             Color color = printerRenderer.getLineBackground(i, null);
             if (color !is null) {
                 if (printOptions.printLineBackground) {
-                    Color printerColor = cast(Color)resources.get(color);
-                    if (printerColor is null) {
+                    Color printerColor;
+                    if ( auto p = color in resources ) {
+                        printerColor = cast(Color)*p;
+                    }
+                    else {
                         printerColor = new Color (printer, color.getRGB());
-                        resources.put(color, printerColor); 
+                        resources[color]=printerColor;
                     }
                     printerRenderer.setLineBackground(i, 1, printerColor);
                 } else {
@@ -293,20 +372,26 @@
             StyleRange style = styles[i];
             Font font = style.font;
             if (style.font !is null) {
-                Font printerFont = cast(Font)resources.get(font);
-                if (printerFont is null) {
+                Font printerFont;
+                if ( auto p = font in resources ) {
+                    printerFont = cast(Font)*p;
+                }
+                else {
                     printerFont = new Font (printer, font.getFontData());
-                    resources.put(font, printerFont);                   
+                    resources[font]= printerFont;
                 }
                 style.font = printerFont;
             }
             Color color = style.foreground;
             if (color !is null) {
-                Color printerColor = cast(Color)resources.get(color);
                 if (printOptions.printTextForeground) {
-                    if (printerColor is null) {
+                    Color printerColor;
+                    if ( auto p = color in resources ) {
+                        printerColor = cast(Color)*p;
+                    }
+                    else {
                         printerColor = new Color (printer, color.getRGB());
-                        resources.put(color, printerColor); 
+                        resources[color]=printerColor;
                     }
                     style.foreground = printerColor;
                 } else {
@@ -315,11 +400,14 @@
             }
             color = style.background;
             if (color !is null) {
-                Color printerColor = cast(Color)resources.get(color);
                 if (printOptions.printTextBackground) {
-                    if (printerColor is null) {
+                    Color printerColor;
+                    if ( auto p = color in resources ) {
+                        printerColor = cast(Color)*p;
+                    }
+                    else {
                         printerColor = new Color (printer, color.getRGB());
-                        resources.put(color, printerColor); 
+                        resources[color]=printerColor;
                     }
                     style.background = printerColor;
                 } else {
@@ -370,14 +458,10 @@
             gc.dispose();
             gc = null;
         }
-        if (resources !is null) {
-            Enumeration enumeration = resources.elements();         
-            while (enumeration.hasMoreElements()) {
-                Resource resource = cast(Resource) enumeration.nextElement();
-                resource.dispose();
-            }
-            resources = null;
-        }
+        foreach( resource; resources.values ){
+            resource.dispose();
+        }
+        resources = null;
         if (printerFont !is null) {
             printerFont.dispose();
             printerFont = null;
@@ -390,15 +474,15 @@
     void init_() {
         Rectangle trim = printer.computeTrim(0, 0, 0, 0);
         Point dpi = printer.getDPI();
-        
-        printerFont = new Font(printer, fontData.getName(), fontData.getHeight(), DWT.NORMAL);
+
+        printerFont = new Font( cast(Device)printer, fontData.getName(), fontData.getHeight(), DWT.NORMAL);
         clientArea = printer.getClientArea();
         pageWidth = clientArea.width;
         // one inch margin around text
-        clientArea.x = dpi.x + trim.x;              
+        clientArea.x = dpi.x + trim.x;
         clientArea.y = dpi.y + trim.y;
         clientArea.width -= (clientArea.x + trim.width);
-        clientArea.height -= (clientArea.y + trim.height); 
+        clientArea.height -= (clientArea.y + trim.height);
 
         int style = mirrored ? DWT.RIGHT_TO_LEFT : DWT.LEFT_TO_RIGHT;
         gc = new GC(printer, style);
@@ -412,16 +496,16 @@
         if (printOptions.footer !is null) {
             clientArea.height -= lineHeight * 2;
         }
-        
+
         // TODO not wrapped
         StyledTextContent content = printerRenderer.content;
         startLine = 0;
         endLine = singleLine ? 0 : content.getLineCount() - 1;
         PrinterData data = printer.getPrinterData();
-        if (data.scope is PrinterData.PAGE_RANGE) {
+        if (data.scope_ is PrinterData.PAGE_RANGE) {
             int pageSize = clientArea.height / lineHeight;//WRONG
             startLine = (startPage - 1) * pageSize;
-        } else if (data.scope is PrinterData.SELECTION) {
+        } else if (data.scope_ is PrinterData.SELECTION) {
             startLine = content.getLineAtOffset(selection.x);
             if (selection.y > 0) {
                 endLine = content.getLineAtOffset(selection.x + selection.y - 1);
@@ -477,7 +561,7 @@
             }
             TextLayout layout = printerRenderer.getTextLayout(i, orientation, width, lineSpacing);
             Color lineBackground = printerRenderer.getLineBackground(i, background);
-            int paragraphBottom = paintY + layout.getBounds().height; 
+            int paragraphBottom = paintY + layout.getBounds().height;
             if (paragraphBottom <= pageBottom) {
                 //normal case, the whole paragraph fits in the current page
                 printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i);
@@ -507,7 +591,7 @@
                     printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i);
                     gc.setClipping(cast(Rectangle)null);
                     printDecoration(page, false, printLayout);
-                    printer.endPage();                  
+                    printer.endPage();
                     page++;
                     if (page <= endPage) {
                         printer.startPage();
@@ -532,7 +616,7 @@
     }
     /**
      * Print header or footer decorations.
-     * 
+     *
      * @param page page number to print, if specified in the StyledTextPrintOptions header or footer.
      * @param header true = print the header, false = print the footer
      */
@@ -541,16 +625,16 @@
         if (text is null) return;
         int lastSegmentIndex = 0;
         for (int i = 0; i < 3; i++) {
-            int segmentIndex = text.indexOf(StyledTextPrintOptions.SEPARATOR, lastSegmentIndex);
+            int segmentIndex = text.indexOf( StyledTextPrintOptions.SEPARATOR, lastSegmentIndex);
             String segment;
-            if (segmentIndex is -1) {
+            if (segmentIndex is -1 ) {
                 segment = text.substring(lastSegmentIndex);
                 printDecorationSegment(segment, i, page, header, layout);
                 break;
             } else {
                 segment = text.substring(lastSegmentIndex, segmentIndex);
                 printDecorationSegment(segment, i, page, header, layout);
-                lastSegmentIndex = segmentIndex + StyledTextPrintOptions.SEPARATOR.length();
+                lastSegmentIndex = segmentIndex + StyledTextPrintOptions.SEPARATOR.length;
             }
         }
     }
@@ -558,22 +642,22 @@
      * Print one segment of a header or footer decoration.
      * Headers and footers have three different segments.
      * One each for left aligned, centered, and right aligned text.
-     * 
+     *
      * @param segment decoration segment to print
-     * @param alignment alignment of the segment. 0=left, 1=center, 2=right 
+     * @param alignment alignment of the segment. 0=left, 1=center, 2=right
      * @param page page number to print, if specified in the decoration segment.
      * @param header true = print the header, false = print the footer
      */
-    void printDecorationSegment(String segment, int alignment, int page, bool header, TextLayout layout) {      
+    void printDecorationSegment(String segment, int alignment, int page, bool header, TextLayout layout) {
         int pageIndex = segment.indexOf(StyledTextPrintOptions.PAGE_TAG);
-        if (pageIndex !is -1) {
-            int pageTagLength = StyledTextPrintOptions.PAGE_TAG.length();
+        if (pageIndex !is -1 ) {
+            int pageTagLength = StyledTextPrintOptions.PAGE_TAG.length;
             StringBuffer buffer = new StringBuffer(segment.substring (0, pageIndex));
             buffer.append (page);
             buffer.append (segment.substring(pageIndex + pageTagLength));
-            segment = buffer.toString();
-        }
-        if (segment.length() > 0) {
+            segment = buffer.toString().dup;
+        }
+        if (segment.length > 0) {
             layout.setText(segment);
             int segmentWidth = layout.getBounds().width;
             int segmentHeight = printerRenderer.getLineHeight();
@@ -598,7 +682,7 @@
             Rectangle rect = layout.getBounds();
             gc.setBackground(background);
             gc.fillRectangle(x, y, rect.width, rect.height);
-            
+
 //          int lineCount = layout.getLineCount();
 //          for (int i = 0; i < lineCount; i++) {
 //              Rectangle rect = layout.getLineBounds(i);
@@ -620,7 +704,7 @@
                     printLayout.setText("");
                 }
             } else {
-                printLayout.setText(String.valueOf(index));
+                printLayout.setText(to!(String)(index));
             }
             int paintX = x - printMargin - printLayout.getBounds().width;
             printLayout.draw(gc, paintX, y);
@@ -639,64 +723,66 @@
             jobName = "Printing";
         }
         if (printer.startJob(jobName)) {
-            init();
+            init_();
             print();
             dispose();
             printer.endJob();
         }
-    }   
+    }
     }
     /**
      * The <code>RTFWriter</code> class is used to write widget content as
-     * rich text. The implementation complies with the RTF specification 
+     * rich text. The implementation complies with the RTF specification
      * version 1.5.
      * <p>
-     * toString() is guaranteed to return a valid RTF String only after 
-     * close() has been called. 
+     * toString() is guaranteed to return a valid RTF string only after
+     * close() has been called.
      * </p><p>
      * Whole and partial lines and line breaks can be written. Lines will be
-     * formatted using the styles queried from the LineStyleListener, if 
+     * formatted using the styles queried from the LineStyleListener, if
      * set, or those set directly in the widget. All styles are applied to
-     * the RTF stream like they are rendered by the widget. In addition, the 
+     * the RTF stream like they are rendered by the widget. In addition, the
      * widget font name and size is used for the whole text.
      * </p>
      */
     class RTFWriter : TextWriter {
-        static final int DEFAULT_FOREGROUND = 0;
-        static final int DEFAULT_BACKGROUND = 1;
-        Vector colorTable, fontTable;
+
+        alias TextWriter.write write;
+
+        static const int DEFAULT_FOREGROUND = 0;
+        static const int DEFAULT_BACKGROUND = 1;
+        Color[] colorTable;
+        Font[] fontTable;
         bool WriteUnicode;
-        
+
     /**
      * Creates a RTF writer that writes content starting at offset "start"
-     * in the document.  <code>start</code> and <code>length</code>can be set to specify partial 
+     * in the document.  <code>start</code> and <code>length</code>can be set to specify partial
      * lines.
      *
-     * @param start start offset of content to write, 0 based from 
+     * @param start start offset of content to write, 0 based from
      *  beginning of document
      * @param length length of content to write
      */
     public this(int start, int length) {
         super(start, length);
-        colorTable = new Vector();
-        fontTable = new Vector();
-        colorTable.addElement(getForeground());
-        colorTable.addElement(getBackground());
-        fontTable.addElement(getFont());
+        colorTable ~= getForeground();
+        colorTable ~= getBackground();
+        fontTable ~= getFont();
         setUnicode();
     }
     /**
      * Closes the RTF writer. Once closed no more content can be written.
-     * <b>NOTE:</b>  <code>toString()</code> does not return a valid RTF String until 
+     * <b>NOTE:</b>  <code>toString()</code> does not return a valid RTF string until
      * <code>close()</code> has been called.
      */
-    public void close() {
+    public override void close() {
         if (!isClosed()) {
             writeHeader();
             write("\n}}\0");
             super.close();
         }
-    }   
+    }
     /**
      * Returns the index of the specified color in the RTF color table.
      *
@@ -707,10 +793,16 @@
      */
     int getColorIndex(Color color, int defaultIndex) {
         if (color is null) return defaultIndex;
-        int index = colorTable.indexOf(color);
+        int index = -1;
+        foreach( i, col; colorTable ){
+            if( col == color ){
+                index = i;
+                break;
+            }
+        }
         if (index is -1) {
-            index = colorTable.size();
-            colorTable.addElement(color);
+            index = colorTable.length;
+            colorTable ~= color;
         }
         return index;
     }
@@ -723,10 +815,16 @@
      *  or "defaultIndex" if "color" is null.
      */
     int getFontIndex(Font font) {
-        int index = fontTable.indexOf(font);
+        int index = -1;
+        foreach( i, f; colorTable ){
+            if( f == font ){
+                index = i;
+                break;
+            }
+        }
         if (index is -1) {
-            index = fontTable.size();
-            fontTable.addElement(font);
+            index = fontTable.length;
+            fontTable ~= font;
         }
         return index;
     }
@@ -735,68 +833,72 @@
      * Don't write Unicode RTF on Windows 95/98/ME or NT.
      */
     void setUnicode() {
-        final String Win95 = "windows 95";
-        final String Win98 = "windows 98";
-        final String WinME = "windows me";      
-        final String WinNT = "windows nt";
-        String osName = System.getProperty("os.name").toLowerCase();
-        String osVersion = System.getProperty("os.version");
-        int majorVersion = 0;
-        
-        if (osName.startsWith(WinNT) && osVersion !is null) {
-            int majorIndex = osVersion.indexOf('.');
-            if (majorIndex !is -1) {
-                osVersion = osVersion.substring(0, majorIndex);
-                try {
-                    majorVersion = Integer.parseInt(osVersion);
-                } catch (NumberFormatException exception) {
-                    // ignore exception. version number remains unknown.
-                    // will write without Unicode
-                }
-            }
-        }
-        WriteUnicode =  !osName.startsWith(Win95) &&
-                        !osName.startsWith(Win98) &&
-                        !osName.startsWith(WinME) &&
-                        (!osName.startsWith(WinNT) || majorVersion > 4);
+//         const String Win95 = "windows 95";
+//         const String Win98 = "windows 98";
+//         const String WinME = "windows me";
+//         const String WinNT = "windows nt";
+//         String osName = System.getProperty("os.name").toLowerCase();
+//         String osVersion = System.getProperty("os.version");
+//         int majorVersion = 0;
+//
+//         if (osName.startsWith(WinNT) && osVersion !is null) {
+//             int majorIndex = osVersion.indexOf('.');
+//             if (majorIndex !is -1) {
+//                 osVersion = osVersion.substring(0, majorIndex);
+//                 try {
+//                     majorVersion = Integer.parseInt(osVersion);
+//                 } catch (NumberFormatException exception) {
+//                     // ignore exception. version number remains unknown.
+//                     // will write without Unicode
+//                 }
+//             }
+//         }
+//         WriteUnicode =  !osName.startsWith(Win95) &&
+//                         !osName.startsWith(Win98) &&
+//                         !osName.startsWith(WinME) &&
+//                         (!osName.startsWith(WinNT) || majorVersion > 4);
+        WriteUnicode = true; // we are on linux-gtk
     }
     /**
-     * Appends the specified segment of "String" to the RTF data.
+     * Appends the specified segment of "string" to the RTF data.
      * Copy from <code>start</code> up to, but excluding, <code>end</code>.
      *
-     * @param String String to copy a segment from. Must not contain
+     * @param string string to copy a segment from. Must not contain
      *  line breaks. Line breaks should be written using writeLineDelimiter()
      * @param start start offset of segment. 0 based.
      * @param end end offset of segment
      */
-    void write(String String, int start, int end) {
-        for (int index = start; index < end; index++) {
-            char ch = String.charAt(index);
+    void write(String string, int start, int end) {
+        start = 0;
+        end = string.length;
+        int incr = 1;
+        for (int index = start; index < end; index+=incr) {
+            dchar ch = firstCodePoint( string[index .. $], incr );
             if (ch > 0xFF && WriteUnicode) {
-                // write the sub String from the last escaped character 
+                // write the sub string from the last escaped character
                 // to the current one. Fixes bug 21698.
                 if (index > start) {
-                    write(String.substring(start, index));
+                    write( string[start .. index ] );
                 }
                 write("\\u");
-                write(Integer.toString(cast(short) ch));
+                write( to!(String)( cast(short)ch ));
                 write(' ');                     // control word delimiter
-                start = index + 1;
+                start = index + incr;
             } else if (ch is '}' || ch is '{' || ch is '\\') {
-                // write the sub String from the last escaped character 
+                // write the sub string from the last escaped character
                 // to the current one. Fixes bug 21698.
                 if (index > start) {
-                    write(String.substring(start, index));
+                    write(string[start .. index]);
                 }
                 write('\\');
-                write(ch);
+                write(cast(char)ch); // ok because one of {}\
                 start = index + 1;
             }
         }
         // write from the last escaped character to the end.
         // Fixes bug 21698.
         if (start < end) {
-            write(String.substring(start, end));
+            write(string[ start .. end]);
         }
     }
     /**
@@ -806,28 +908,31 @@
         StringBuffer header = new StringBuffer();
         FontData fontData = getFont().getFontData()[0];
         header.append("{\\rtf1\\ansi");
-        // specify code page, necessary for copy to work in bidi 
+        // specify code page, necessary for copy to work in bidi
         // systems that don't support Unicode RTF.
-        String cpg = System.getProperty("file.encoding").toLowerCase();
+        // PORTING_TODO: String cpg = System.getProperty("file.encoding").toLowerCase();
+        String cpg = "UTF16";
+        /+
         if (cpg.startsWith("cp") || cpg.startsWith("ms")) {
             cpg = cpg.substring(2, cpg.length());
             header.append("\\ansicpg");
             header.append(cpg);
         }
+        +/
         header.append("\\uc0\\deff0{\\fonttbl{\\f0\\fnil ");
         header.append(fontData.getName());
         header.append(";");
-        for (int i = 1; i < fontTable.size(); i++) {
+        for (int i = 1; i < fontTable.length; i++) {
             header.append("\\f");
             header.append(i);
             header.append(" ");
-            FontData fd = (cast(Font)fontTable.elementAt(i)).getFontData()[0];
+            FontData fd = (cast(Font)fontTable[i]).getFontData()[0];
             header.append(fd.getName());
-            header.append(";");         
+            header.append(";");
         }
         header.append("}}\n{\\colortbl");
-        for (int i = 0; i < colorTable.size(); i++) {
-            Color color = cast(Color) colorTable.elementAt(i);
+        for (int i = 0; i < colorTable.length; i++) {
+            Color color = cast(Color) colorTable[i];
             header.append("\\red");
             header.append(color.getRed());
             header.append("\\green");
@@ -836,7 +941,7 @@
             header.append(color.getBlue());
             header.append(";");
         }
-        // some RTF readers ignore the deff0 font tag. Explicitly 
+        // some RTF readers ignore the deff0 font tag. Explicitly
         // set the font for the whole document to work around this.
         header.append("}\n{\\f0\\fs");
         // font size is specified in half points
@@ -845,20 +950,20 @@
         write(header.toString(), 0);
     }
     /**
-     * Appends the specified line text to the RTF data.  Lines will be formatted 
-     * using the styles queried from the LineStyleListener, if set, or those set 
+     * Appends the specified line text to the RTF data.  Lines will be formatted
+     * using the styles queried from the LineStyleListener, if set, or those set
      * directly in the widget.
      *
      * @param line line text to write as RTF. Must not contain line breaks
      *  Line breaks should be written using writeLineDelimiter()
-     * @param lineOffset offset of the line. 0 based from the start of the 
-     *  widget document. Any text occurring before the start offset or after the 
+     * @param lineOffset offset of the line. 0 based from the start of the
+     *  widget document. Any text occurring before the start offset or after the
      *  end offset specified during object creation is ignored.
      * @exception DWTException <ul>
      *   <li>ERROR_IO when the writer is closed.</li>
      * </ul>
      */
-    public void writeLine(String line, int lineOffset) {
+    public override void writeLine(String line, int lineOffset) {
         if (isClosed()) {
             DWT.error(DWT.ERROR_IO);
         }
@@ -876,12 +981,12 @@
             styles = event.styles;
         } else {
             lineAlignment = renderer.getLineAlignment(lineIndex, alignment);
-            lineIndent =  renderer.getLineIndent(lineIndex, indent);            
+            lineIndent =  renderer.getLineIndent(lineIndex, indent);
             lineJustify = renderer.getLineJustify(lineIndex, justify);
-            ranges = renderer.getRanges(lineOffset, line.length());
-            styles = renderer.getStyleRanges(lineOffset, line.length(), false);
-        }
-        if (styles is null) styles = new StyleRange[0];     
+            ranges = renderer.getRanges(lineOffset, line.length);
+            styles = renderer.getStyleRanges(lineOffset, line.length, false);
+        }
+        if (styles is null) styles = new StyleRange[0];
         Color lineBackground = renderer.getLineBackground(lineIndex, null);
         event = getLineBackgroundData(lineOffset, line);
         if (event !is null && event.lineBackground !is null) lineBackground = event.lineBackground;
@@ -895,11 +1000,11 @@
      *   <li>ERROR_IO when the writer is closed.</li>
      * </ul>
      */
-    public void writeLineDelimiter(String lineDelimiter) {
+    public override void writeLineDelimiter(String lineDelimiter) {
         if (isClosed()) {
             DWT.error(DWT.ERROR_IO);
         }
-        write(lineDelimiter, 0, lineDelimiter.length());
+        write(lineDelimiter, 0, lineDelimiter.length);
         write("\\par ");
     }
     /**
@@ -913,34 +1018,35 @@
      *
      * @param line line text to write as RTF. Must not contain line breaks
      *  Line breaks should be written using writeLineDelimiter()
-     * @param lineOffset offset of the line. 0 based from the start of the 
-     *  widget document. Any text occurring before the start offset or after the 
+     * @param lineOffset offset of the line. 0 based from the start of the
+     *  widget document. Any text occurring before the start offset or after the
      *  end offset specified during object creation is ignored.
      * @param styles styles to use for formatting. Must not be null.
-     * @param lineBackground line background color to use for formatting. 
+     * @param lineBackground line background color to use for formatting.
      *  May be null.
      */
     void writeStyledLine(String line, int lineOffset, int ranges[], StyleRange[] styles, Color lineBackground, int indent, int alignment, bool justify) {
-        int lineLength = line.length();
+        int lineLength = line.length;
         int startOffset = getStart();
         int writeOffset = startOffset - lineOffset;
         if (writeOffset >= lineLength) return;
         int lineIndex = Math.max(0, writeOffset);
-            
+
         write("\\fi");
         write(indent);
         switch (alignment) {
             case DWT.LEFT: write("\\ql"); break;
             case DWT.CENTER: write("\\qc"); break;
             case DWT.RIGHT: write("\\qr"); break;
+            default:
         }
         if (justify) write("\\qj");
         write(" ");
-        
+
         if (lineBackground !is null) {
             write("{\\highlight");
             write(getColorIndex(lineBackground, DEFAULT_BACKGROUND));
-            write(" "); 
+            write(" ");
         }
         int endOffset = startOffset + super.getCharCount();
         int lineEndOffset = Math.min(lineLength, endOffset - lineOffset);
@@ -965,7 +1071,7 @@
             // write any unstyled text
             if (lineIndex < start) {
                 // copy to start of style
-                // style starting beyond end of write range or end of line 
+                // style starting beyond end of write range or end of line
                 // is guarded against above.
                 write(line, lineIndex, start);
                 lineIndex = start;
@@ -988,10 +1094,10 @@
                 write(fontData.getHeight() * 2);
             } else {
                 if ((style.fontStyle & DWT.BOLD) !is 0) {
-                    write("\\b"); 
+                    write("\\b");
                 }
                 if ((style.fontStyle & DWT.ITALIC) !is 0) {
-                    write("\\i"); 
+                    write("\\i");
                 }
             }
             if (style.underline) {
@@ -1000,7 +1106,7 @@
             if (style.strikeout) {
                 write("\\strike");
             }
-            write(" "); 
+            write(" ");
             // copy to end of style or end of write range or end of line
             int copyEnd = Math.min(end, lineEndOffset);
             // guard against invalid styles and let style processing continue
@@ -1008,10 +1114,10 @@
             write(line, lineIndex, copyEnd);
             if (font is null) {
                 if ((style.fontStyle & DWT.BOLD) !is 0) {
-                    write("\\b0"); 
+                    write("\\b0");
                 }
                 if ((style.fontStyle & DWT.ITALIC) !is 0) {
-                    write("\\i0"); 
+                    write("\\i0");
                 }
             }
             if (style.underline) {
@@ -1032,21 +1138,21 @@
     }
     /**
      * The <code>TextWriter</code> class is used to write widget content to
-     * a String.  Whole and partial lines and line breaks can be written. To write 
-     * partial lines, specify the start and length of the desired segment 
+     * a string.  Whole and partial lines and line breaks can be written. To write
+     * partial lines, specify the start and length of the desired segment
      * during object creation.
      * <p>
-     * </b>NOTE:</b> <code>toString()</code> is guaranteed to return a valid String only after close() 
+     * </b>NOTE:</b> <code>toString()</code> is guaranteed to return a valid string only after close()
      * has been called.
      * </p>
      */
     class TextWriter {
         private StringBuffer buffer;
         private int startOffset;    // offset of first character that will be written
-        private int endOffset;      // offset of last character that will be written. 
-                                    // 0 based from the beginning of the widget text. 
-        private bool isClosed = false;
-    
+        private int endOffset;      // offset of last character that will be written.
+                                    // 0 based from the beginning of the widget text.
+        private bool isClosed_ = false;
+
     /**
      * Creates a writer that writes content starting at offset "start"
      * in the document.  <code>start</code> and <code>length</code> can be set to specify partial lines.
@@ -1061,23 +1167,23 @@
     }
     /**
      * Closes the writer. Once closed no more content can be written.
-     * <b>NOTE:</b>  <code>toString()</code> is not guaranteed to return a valid String unless
+     * <b>NOTE:</b>  <code>toString()</code> is not guaranteed to return a valid string unless
      * the writer is closed.
      */
     public void close() {
-        if (!isClosed) {
-            isClosed = true;
-        }
-    }
-    /** 
+        if (!isClosed_) {
+            isClosed_ = true;
+        }
+    }
+    /**
      * Returns the number of characters to write.
      * @return the integer number of characters to write
      */
     public int getCharCount() {
         return endOffset - startOffset;
-    }   
-    /** 
-     * Returns the offset where writing starts. 0 based from the start of 
+    }
+    /**
+     * Returns the offset where writing starts. 0 based from the start of
      * the widget text. Used to write partial lines.
      * @return the integer offset where writing starts
      */
@@ -1089,37 +1195,38 @@
      * @return a bool specifying whether or not the writer is closed
      */
     public bool isClosed() {
-        return isClosed;
+        return isClosed_;
     }
     /**
-     * Returns the String.  <code>close()</code> must be called before <code>toString()</code> 
-     * is guaranteed to return a valid String.
+     * Returns the string.  <code>close()</code> must be called before <code>toString()</code>
+     * is guaranteed to return a valid string.
      *
-     * @return the String
+     * @return the string
      */
-    public String toString() {
+    public override String toString() {
         return buffer.toString();
     }
     /**
-     * Appends the given String to the data.
+     * Appends the given string to the data.
      */
-    void write(String String) {
-        buffer.append(String);
+    void write(String string) {
+        buffer.append(string);
     }
     /**
-     * Inserts the given String to the data at the specified offset.
+     * Inserts the given string to the data at the specified offset.
      * <p>
      * Do nothing if "offset" is < 0 or > getCharCount()
      * </p>
      *
-     * @param String text to insert
-     * @param offset offset in the existing data to insert "String" at.
+     * @param string text to insert
+     * @param offset offset in the existing data to insert "string" at.
      */
-    void write(String String, int offset) {
+    void write(String string, int offset) {
         if (offset < 0 || offset > buffer.length()) {
             return;
         }
-        buffer.insert(offset, String);
+        buffer.select( offset );
+        buffer.prepend( string );
     }
     /**
      * Appends the given int to the data.
@@ -1138,19 +1245,19 @@
      *
      * @param line line text to write. Must not contain line breaks
      *  Line breaks should be written using writeLineDelimiter()
-     * @param lineOffset offset of the line. 0 based from the start of the 
-     *  widget document. Any text occurring before the start offset or after the 
+     * @param lineOffset offset of the line. 0 based from the start of the
+     *  widget document. Any text occurring before the start offset or after the
      *  end offset specified during object creation is ignored.
      * @exception DWTException <ul>
      *   <li>ERROR_IO when the writer is closed.</li>
      * </ul>
      */
-    public void writeLine(String line, int lineOffset) {    
-        if (isClosed) {
+    public void writeLine(String line, int lineOffset) {
+        if (isClosed_) {
             DWT.error(DWT.ERROR_IO);
-        }       
+        }
         int writeOffset = startOffset - lineOffset;
-        int lineLength = line.length();
+        int lineLength = line.length;
         int lineIndex;
         if (writeOffset >= lineLength) {
             return;                         // whole line is outside write range
@@ -1173,7 +1280,7 @@
      * </ul>
      */
     public void writeLineDelimiter(String lineDelimiter) {
-        if (isClosed) {
+        if (isClosed_) {
             DWT.error(DWT.ERROR_IO);
         }
         write(lineDelimiter);
@@ -1186,7 +1293,7 @@
  * <p>
  * The style value is either one of the style constants defined in
  * class <code>DWT</code> which is applicable to instances of this
- * class, or must be built by <em>bitwise OR</em>'ing together 
+ * class, or must be built by <em>bitwise OR</em>'ing together
  * (that is, using the <code>int</code> "|" operator) two or more
  * of those <code>DWT</code> style constants. The class description
  * lists the style constants that are applicable to the class.
@@ -1211,13 +1318,14 @@
  * @see #getStyle
  */
 public this(Composite parent, int style) {
+    selection = new Point(0, 0);
     super(parent, checkStyle(style));
     // set the fg in the OS to ensure that these are the same as StyledText, necessary
     // for ensuring that the bg/fg the IME box uses is the same as what StyledText uses
     super.setForeground(getForeground());
     super.setDragDetect(false);
     Display display = getDisplay();
-    isMirrored = (super.getStyle() & DWT.MIRRORED) !is 0;
+    isMirrored_ = (super.getStyle() & DWT.MIRRORED) !is 0;
     fixedLineHeight = true;
     if ((style & DWT.READ_ONLY) !is 0) {
         setEditable(false);
@@ -1240,7 +1348,7 @@
     }
     if (isBidiCaret()) {
         createCaretBitmaps();
-        Runnable runnable = new Runnable() {
+        Runnable runnable = new class() Runnable {
             public void run() {
                 int direction = BidiUtil.getKeyboardLanguage() is BidiUtil.KEYBOARD_BIDI ? DWT.RIGHT : DWT.LEFT;
                 if (direction is caretDirection) return;
@@ -1251,7 +1359,7 @@
         };
         BidiUtil.addLanguageListener(this, runnable);
     }
-    setCaret(defaultCaret); 
+    setCaret(defaultCaret);
     calculateScrollBars();
     createKeyBindings();
     setCursor(display.getSystemCursor(DWT.CURSOR_IBEAM));
@@ -1259,8 +1367,8 @@
     initializeAccessible();
     setData("DEFAULT_DROP_TARGET_EFFECT", new StyledTextDropTargetEffect(this));
 }
-/**  
- * Adds an extended modify listener. An ExtendedModify event is sent by the 
+/**
+ * Adds an extended modify listener. An ExtendedModify event is sent by the
  * widget when the widget text has changed.
  *
  * @param extendedModifyListener the listener
@@ -1281,15 +1389,15 @@
 /**
  * Adds a bidirectional segment listener.
  * <p>
- * A BidiSegmentEvent is sent 
- * whenever a line of text is measured or rendered. The user can 
- * specify text ranges in the line that should be treated as if they 
+ * A BidiSegmentEvent is sent
+ * whenever a line of text is measured or rendered. The user can
+ * specify text ranges in the line that should be treated as if they
  * had a different direction than the surrounding text.
  * This may be used when adjacent segments of right-to-left text should
- * not be reordered relative to each other. 
- * E.g., Multiple Java String literals in a right-to-left language
+ * not be reordered relative to each other.
+ * E.g., Multiple Java string literals in a right-to-left language
  * should generally remain in logical order to each other, that is, the
- * way they are stored. 
+ * way they are stored.
  * </p>
  *
  * @param listener the listener
@@ -1309,7 +1417,7 @@
     addListener(LineGetSegments, new StyledTextListener(listener));
 }
 /**
- * Adds a line background listener. A LineGetBackground event is sent by the 
+ * Adds a line background listener. A LineGetBackground event is sent by the
  * widget to determine the background color for a line.
  *
  * @param listener the listener
@@ -1330,7 +1438,7 @@
     addListener(LineGetBackground, new StyledTextListener(listener));
 }
 /**
- * Adds a line style listener. A LineGetStyle event is sent by the widget to 
+ * Adds a line style listener. A LineGetStyle event is sent by the widget to
  * determine the styles for a line.
  *
  * @param listener the listener
@@ -1351,8 +1459,8 @@
     }
     addListener(LineGetStyle, new StyledTextListener(listener));
 }
-/**  
- * Adds a modify listener. A Modify event is sent by the widget when the widget text 
+/**
+ * Adds a modify listener. A Modify event is sent by the widget when the widget text
  * has changed.
  *
  * @param modifyListener the listener
@@ -1369,7 +1477,7 @@
     if (modifyListener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     addListener(DWT.Modify, new TypedListener(modifyListener));
 }
-/**  
+/**
  * Adds a paint object listener. A paint object event is sent by the widget when an object
  * needs to be drawn.
  *
@@ -1381,9 +1489,9 @@
  * @exception IllegalArgumentException <ul>
  *    <li>ERROR_NULL_ARGUMENT when listener is null</li>
  * </ul>
- * 
+ *
  * @since 3.2
- * 
+ *
  * @see PaintObjectListener
  * @see PaintObjectEvent
  */
@@ -1392,15 +1500,15 @@
     if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     addListener(PaintObject, new StyledTextListener(listener));
 }
-/**  
- * Adds a selection listener. A Selection event is sent by the widget when the 
+/**
+ * Adds a selection listener. A Selection event is sent by the widget when the
  * user changes the selection.
  * <p>
  * When <code>widgetSelected</code> is called, the event x and y fields contain
  * the start and end caret indices of the selection.
  * <code>widgetDefaultSelected</code> is not called for StyledTexts.
  * </p>
- * 
+ *
  * @param listener the listener which should be notified when the user changes the receiver's selection
 
  * @exception IllegalArgumentException <ul>
@@ -1420,10 +1528,10 @@
     if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     addListener(DWT.Selection, new TypedListener(listener));
 }
-/**  
- * Adds a verify key listener. A VerifyKey event is sent by the widget when a key 
- * is pressed. The widget ignores the key press if the listener sets the doit field 
- * of the event to false. 
+/**
+ * Adds a verify key listener. A VerifyKey event is sent by the widget when a key
+ * is pressed. The widget ignores the key press if the listener sets the doit field
+ * of the event to false.
  *
  * @param listener the listener
  * @exception DWTException <ul>
@@ -1439,10 +1547,10 @@
     if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     addListener(VerifyKey, new StyledTextListener(listener));
 }
-/**  
- * Adds a verify listener. A Verify event is sent by the widget when the widget text 
- * is about to change. The listener can set the event text and the doit field to 
- * change the text that is set in the widget or to force the widget to ignore the 
+/**
+ * Adds a verify listener. A Verify event is sent by the widget when the widget text
+ * is about to change. The listener can set the event text and the doit field to
+ * change the text that is set in the widget or to force the widget to ignore the
  * text change.
  *
  * @param verifyListener the listener
@@ -1459,9 +1567,9 @@
     if (verifyListener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     addListener(DWT.Verify, new TypedListener(verifyListener));
 }
-/**  
- * Adds a word movement listener. A movement event is sent when the boundary 
- * of a word is needed. For example, this occurs during word next and word 
+/**
+ * Adds a word movement listener. A movement event is sent when the boundary
+ * of a word is needed. For example, this occurs during word next and word
  * previous actions.
  *
  * @param movementListener the listener
@@ -1472,12 +1580,12 @@
  * @exception IllegalArgumentException <ul>
  *    <li>ERROR_NULL_ARGUMENT when listener is null</li>
  * </ul>
- * 
+ *
  * @see MovementEvent
  * @see MovementListener
  * @see #removeWordMovementListener
- * 
- * @since 3.3 
+ *
+ * @since 3.3
  */
 public void addWordMovementListener(MovementListener movementListener) {
     checkWidget();
@@ -1485,26 +1593,24 @@
     addListener(WordNext, new StyledTextListener(movementListener));
     addListener(WordPrevious, new StyledTextListener(movementListener));
 }
-/** 
- * Appends a String to the text at the end of the widget.
- *
- * @param String the String to be appended
+/**
+ * Appends a string to the text at the end of the widget.
+ *
+ * @param string the string to be appended
  * @see #replaceTextRange(int,int,String)
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * @exception IllegalArgumentException <ul>
- *    <li>ERROR_NULL_ARGUMENT when listener is null</li>
- * </ul>
- */
-public void append(String String) {
-    checkWidget();
-    if (String is null) {
-        DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    }
+ */
+public void append(String string) {
+    checkWidget();
+    // DWT extension: allow null for zero length string
+//     if (string is null) {
+//         DWT.error(DWT.ERROR_NULL_ARGUMENT);
+//     }
     int lastChar = Math.max(getCharCount(), 0);
-    replaceTextRange(lastChar, 0, String);
+    replaceTextRange(lastChar, 0, string);
 }
 /**
  * Calculates the scroll bars
@@ -1515,7 +1621,7 @@
     setScrollBars(true);
     if (verticalBar !is null) {
         verticalBar.setIncrement(getVerticalIncrement());
-    }   
+    }
     if (horizontalBar !is null) {
         horizontalBar.setIncrement(getHorizontalIncrement());
     }
@@ -1535,7 +1641,7 @@
             return;
         }
         topIndex = Compatibility.ceil(getVerticalScrollOffset(), verticalIncrement);
-        // Set top index to partially visible top line if no line is fully 
+        // Set top index to partially visible top line if no line is fully
         // visible but at least some of the widget client area is visible.
         // Fixes bug 15088.
         if (topIndex > 0) {
@@ -1543,7 +1649,7 @@
                 int bottomPixel = getVerticalScrollOffset() + clientAreaHeight;
                 int fullLineTopPixel = topIndex * verticalIncrement;
                 int fullLineVisibleHeight = bottomPixel - fullLineTopPixel;
-                // set top index to partially visible line if no line fully fits in 
+                // set top index to partially visible line if no line fully fits in
                 // client area or if space is available but not used (the latter should
                 // never happen because we use claimBottomFreeSpace)
                 if (fullLineVisibleHeight < verticalIncrement) {
@@ -1608,7 +1714,7 @@
     return style;
 }
 /**
- * Scrolls down the text to use new space made available by a resize or by 
+ * Scrolls down the text to use new space made available by a resize or by
  * deleted lines.
  */
 void claimBottomFreeSpace() {
@@ -1632,11 +1738,11 @@
  */
 void claimRightFreeSpace() {
     int newHorizontalOffset = Math.max(0, renderer.getWidth() - (clientAreaWidth - leftMargin - rightMargin));
-    if (newHorizontalOffset < horizontalScrollOffset) {         
+    if (newHorizontalOffset < horizontalScrollOffset) {
         // item is no longer drawn past the right border of the client area
-        // align the right end of the item with the right border of the 
+        // align the right end of the item with the right border of the
         // client area (window is scrolled right).
-        scrollHorizontal(newHorizontalOffset - horizontalScrollOffset, true);                   
+        scrollHorizontal(newHorizontalOffset - horizontalScrollOffset, true);
     }
 }
 /**
@@ -1646,7 +1752,7 @@
  */
 void clearSelection(bool sendEvent) {
     int selectionStart = selection.x;
-    int selectionEnd = selection.y; 
+    int selectionEnd = selection.y;
     resetSelection();
     // redraw old selection, if any
     if (selectionEnd - selectionStart > 0) {
@@ -1663,7 +1769,7 @@
         }
     }
 }
-public Point computeSize (int wHint, int hHint, bool changed) {
+public override Point computeSize (int wHint, int hHint, bool changed) {
     checkWidget();
     int lineCount = (getStyle() & DWT.SINGLE) !is 0 ? 1 : content.getLineCount();
     int width = 0;
@@ -1701,7 +1807,7 @@
  * <p>
  * The text will be put on the clipboard in plain text format and RTF format.
  * The <code>DND.CLIPBOARD</code> clipboard is used for data that is
- * transferred by keyboard accelerator (such as Ctrl+C/Ctrl+V) or 
+ * transferred by keyboard accelerator (such as Ctrl+C/Ctrl+V) or
  * by menu action.
  * </p>
  *
@@ -1715,24 +1821,24 @@
     copy(DND.CLIPBOARD);
 }
 /**
- * Copies the selected text to the specified clipboard.  The text will be put in the 
+ * Copies the selected text to the specified clipboard.  The text will be put in the
  * clipboard in plain text format and RTF format.
  * <p>
- * The clipboardType is  one of the clipboard constants defined in class 
- * <code>DND</code>.  The <code>DND.CLIPBOARD</code>  clipboard is 
- * used for data that is transferred by keyboard accelerator (such as Ctrl+C/Ctrl+V) 
- * or by menu action.  The <code>DND.SELECTION_CLIPBOARD</code> 
- * clipboard is used for data that is transferred by selecting text and pasting 
+ * The clipboardType is  one of the clipboard constants defined in class
+ * <code>DND</code>.  The <code>DND.CLIPBOARD</code>  clipboard is
+ * used for data that is transferred by keyboard accelerator (such as Ctrl+C/Ctrl+V)
+ * or by menu action.  The <code>DND.SELECTION_CLIPBOARD</code>
+ * clipboard is used for data that is transferred by selecting text and pasting
  * with the middle mouse button.
  * </p>
- * 
+ *
  * @param clipboardType indicates the type of clipboard
  *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 3.1
  */
 public void copy(int clipboardType) {
@@ -1743,7 +1849,7 @@
         try {
             setClipboardContent(selection.x, length, clipboardType);
         } catch (DWTError error) {
-            // Copy to clipboard failed. This happens when another application 
+            // Copy to clipboard failed. This happens when another application
             // is accessing the clipboard while we copy. Ignore the error.
             // Fixes 1GDQAVN
             // Rethrow all other errors. Fixes bug 17578.
@@ -1755,16 +1861,16 @@
 }
 /**
  * Returns the alignment of the widget.
- * 
+ *
  * @return the alignment
- * 
- * @exception DWTException <ul>
- *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- *  
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
  * @see #getLineAlignment(int)
- * 
+ *
  * @since 3.2
  */
 public int getAlignment() {
@@ -1802,24 +1908,24 @@
     return Math.min(height, availableHeight);
 }
 /**
- * Returns a String that uses only the line delimiter specified by the 
+ * Returns a string that uses only the line delimiter specified by the
  * StyledTextContent implementation.
  * <p>
  * Returns only the first line if the widget has the DWT.SINGLE style.
  * </p>
  *
- * @param text the text that may have line delimiters that don't 
- *  match the model line delimiter. Possible line delimiters 
+ * @param text the text that may have line delimiters that don't
+ *  match the model line delimiter. Possible line delimiters
  *  are CR ('\r'), LF ('\n'), CR/LF ("\r\n")
- * @return the converted text that only uses the line delimiter 
- *  specified by the model. Returns only the first line if the widget 
+ * @return the converted text that only uses the line delimiter
+ *  specified by the model. Returns only the first line if the widget
  *  has the DWT.SINGLE style.
  */
-String getModelDelimitedText(String text) { 
-    int length = text.length();
+String getModelDelimitedText(String text) {
+    int length = text.length;
     if (length is 0) {
         return text;
-    }   
+    }
     int crIndex = 0;
     int lfIndex = 0;
     int i = 0;
@@ -1827,10 +1933,10 @@
     String delimiter = getLineDelimiter();
     while (i < length) {
         if (crIndex !is -1) {
-            crIndex = text.indexOf(DWT.CR, i);
+            crIndex = text.indexOf (DWT.CR, i);
         }
         if (lfIndex !is -1) {
-            lfIndex = text.indexOf(DWT.LF, i);
+            lfIndex = text.indexOf (DWT.LF, i);
         }
         if (lfIndex is -1 && crIndex is -1) {   // no more line breaks?
             break;
@@ -1850,7 +1956,7 @@
         }
         convertedText.append(delimiter);
     }
-    // copy remaining text if any and if not in single line mode or no 
+    // copy remaining text if any and if not in single line mode or no
     // text copied thus far (because there only is one line)
     if (i < length && (!isSingleLine() || convertedText.length() is 0)) {
         convertedText.append(text.substring(i));
@@ -1877,9 +1983,9 @@
 void createKeyBindings() {
     int nextKey = isMirrored() ? DWT.ARROW_LEFT : DWT.ARROW_RIGHT;
     int previousKey = isMirrored() ? DWT.ARROW_RIGHT : DWT.ARROW_LEFT;
-    
+
     // Navigation
-    setKeyBinding(DWT.ARROW_UP, ST.LINE_UP);    
+    setKeyBinding(DWT.ARROW_UP, ST.LINE_UP);
     setKeyBinding(DWT.ARROW_DOWN, ST.LINE_DOWN);
     if (IS_CARBON) {
         setKeyBinding(previousKey | DWT.MOD1, ST.LINE_START);
@@ -1904,23 +2010,23 @@
     setKeyBinding(DWT.PAGE_DOWN | DWT.MOD1, ST.WINDOW_END);
     setKeyBinding(nextKey, ST.COLUMN_NEXT);
     setKeyBinding(previousKey, ST.COLUMN_PREVIOUS);
-    
+
     // Selection
-    setKeyBinding(DWT.ARROW_UP | DWT.MOD2, ST.SELECT_LINE_UP);  
+    setKeyBinding(DWT.ARROW_UP | DWT.MOD2, ST.SELECT_LINE_UP);
     setKeyBinding(DWT.ARROW_DOWN | DWT.MOD2, ST.SELECT_LINE_DOWN);
     if (IS_CARBON) {
         setKeyBinding(previousKey | DWT.MOD1 | DWT.MOD2, ST.SELECT_LINE_START);
         setKeyBinding(nextKey | DWT.MOD1 | DWT.MOD2, ST.SELECT_LINE_END);
-        setKeyBinding(DWT.HOME | DWT.MOD2, ST.SELECT_TEXT_START);   
+        setKeyBinding(DWT.HOME | DWT.MOD2, ST.SELECT_TEXT_START);
         setKeyBinding(DWT.END | DWT.MOD2, ST.SELECT_TEXT_END);
-        setKeyBinding(DWT.ARROW_UP | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_START);    
+        setKeyBinding(DWT.ARROW_UP | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_START);
         setKeyBinding(DWT.ARROW_DOWN | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_END);
         setKeyBinding(nextKey | DWT.MOD2 | DWT.MOD3, ST.SELECT_WORD_NEXT);
         setKeyBinding(previousKey | DWT.MOD2 | DWT.MOD3, ST.SELECT_WORD_PREVIOUS);
     } else  {
         setKeyBinding(DWT.HOME | DWT.MOD2, ST.SELECT_LINE_START);
         setKeyBinding(DWT.END | DWT.MOD2, ST.SELECT_LINE_END);
-        setKeyBinding(DWT.HOME | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_START);    
+        setKeyBinding(DWT.HOME | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_START);
         setKeyBinding(DWT.END | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_END);
         setKeyBinding(nextKey | DWT.MOD1 | DWT.MOD2, ST.SELECT_WORD_NEXT);
         setKeyBinding(previousKey | DWT.MOD1 | DWT.MOD2, ST.SELECT_WORD_PREVIOUS);
@@ -1930,8 +2036,8 @@
     setKeyBinding(DWT.PAGE_UP | DWT.MOD1 | DWT.MOD2, ST.SELECT_WINDOW_START);
     setKeyBinding(DWT.PAGE_DOWN | DWT.MOD1 | DWT.MOD2, ST.SELECT_WINDOW_END);
     setKeyBinding(nextKey | DWT.MOD2, ST.SELECT_COLUMN_NEXT);
-    setKeyBinding(previousKey | DWT.MOD2, ST.SELECT_COLUMN_PREVIOUS);   
-                
+    setKeyBinding(previousKey | DWT.MOD2, ST.SELECT_COLUMN_PREVIOUS);
+
     // Modification
     // Cut, Copy, Paste
     setKeyBinding('X' | DWT.MOD1, ST.CUT);
@@ -1952,7 +2058,7 @@
     setKeyBinding(DWT.DEL, ST.DELETE_NEXT);
     setKeyBinding(DWT.BS | DWT.MOD1, ST.DELETE_WORD_PREVIOUS);
     setKeyBinding(DWT.DEL | DWT.MOD1, ST.DELETE_WORD_NEXT);
-    
+
     // Miscellaneous
     setKeyBinding(DWT.INSERT, ST.TOGGLE_OVERWRITE);
 }
@@ -1965,30 +2071,30 @@
     int caretWidth = BIDI_CARET_WIDTH;
     Display display = getDisplay();
     if (leftCaretBitmap !is null) {
-        if (defaultCaret !is null && leftCaretBitmap.opEquals(defaultCaret.getImage())) {
+        if (defaultCaret !is null && leftCaretBitmap==/*eq*/defaultCaret.getImage()) {
             defaultCaret.setImage(null);
         }
         leftCaretBitmap.dispose();
     }
     int lineHeight = renderer.getLineHeight();
     leftCaretBitmap = new Image(display, caretWidth, lineHeight);
-    GC gc = new GC (leftCaretBitmap); 
+    GC gc = new GC (leftCaretBitmap);
     gc.setBackground(display.getSystemColor(DWT.COLOR_BLACK));
     gc.fillRectangle(0, 0, caretWidth, lineHeight);
     gc.setForeground(display.getSystemColor(DWT.COLOR_WHITE));
     gc.drawLine(0,0,0,lineHeight);
     gc.drawLine(0,0,caretWidth-1,0);
     gc.drawLine(0,1,1,1);
-    gc.dispose();   
-    
+    gc.dispose();
+
     if (rightCaretBitmap !is null) {
-        if (defaultCaret !is null && rightCaretBitmap.opEquals(defaultCaret.getImage())) {
+        if (defaultCaret !is null && rightCaretBitmap==/*eq*/defaultCaret.getImage()) {
             defaultCaret.setImage(null);
         }
         rightCaretBitmap.dispose();
     }
     rightCaretBitmap = new Image(display, caretWidth, lineHeight);
-    gc = new GC (rightCaretBitmap); 
+    gc = new GC (rightCaretBitmap);
     gc.setBackground(display.getSystemColor(DWT.COLOR_BLACK));
     gc.fillRectangle(0, 0, caretWidth, lineHeight);
     gc.setForeground(display.getSystemColor(DWT.COLOR_WHITE));
@@ -1998,7 +2104,7 @@
     gc.dispose();
 }
 /**
- * Moves the selected text to the clipboard.  The text will be put in the 
+ * Moves the selected text to the clipboard.  The text will be put in the
  * clipboard in plain text format and RTF format.
  *
  * @exception DWTException <ul>
@@ -2013,7 +2119,7 @@
         try {
             setClipboardContent(selection.x, length, DND.CLIPBOARD);
         } catch (DWTError error) {
-            // Copy to clipboard failed. This happens when another application 
+            // Copy to clipboard failed. This happens when another application
             // is accessing the clipboard while we copy. Ignore the error.
             // Fixes 1GDQAVN
             // Rethrow all other errors. Fixes bug 17578.
@@ -2027,9 +2133,9 @@
         doDelete();
     }
 }
-/** 
+/**
  * A mouse move event has occurred.  See if we should start autoscrolling.  If
- * the move position is outside of the client area, initiate autoscrolling.  
+ * the move position is outside of the client area, initiate autoscrolling.
  * Otherwise, we've moved back into the widget so end autoscrolling.
  */
 void doAutoScroll(Event event) {
@@ -2045,7 +2151,7 @@
         endAutoScroll();
     }
 }
-/** 
+/**
  * Initiates autoscrolling.
  *
  * @param direction DWT.UP, DWT.DOWN, DWT.COLUMN_NEXT, DWT.COLUMN_PREVIOUS
@@ -2056,13 +2162,15 @@
     if (autoScrollDirection is direction) {
         return;
     }
-    
+
     Runnable timer = null;
-    final Display display = getDisplay();
+    final Display disp = getDisplay();
     // Set a timer that will simulate the user pressing and holding
     // down a cursor key (i.e., arrowUp, arrowDown).
     if (direction is DWT.UP) {
-        timer = new Runnable() {
+        timer = new class(disp) Runnable {
+            Display display;
+            this( Display d ){ this.display = d; }
             public void run() {
                 if (autoScrollDirection is DWT.UP) {
                     doSelectionPageUp(autoScrollDistance);
@@ -2073,7 +2181,9 @@
         autoScrollDirection = direction;
         display.timerExec(V_SCROLL_RATE, timer);
     } else if (direction is DWT.DOWN) {
-        timer = new Runnable() {
+        timer = new class(disp) Runnable {
+            Display display;
+            this( Display d ){ this.display = d; }
             public void run() {
                 if (autoScrollDirection is DWT.DOWN) {
                     doSelectionPageDown(autoScrollDistance);
@@ -2084,7 +2194,9 @@
         autoScrollDirection = direction;
         display.timerExec(V_SCROLL_RATE, timer);
     } else if (direction is ST.COLUMN_NEXT) {
-        timer = new Runnable() {
+        timer = new class(disp) Runnable {
+            Display display;
+            this( Display d ){ this.display = d; }
             public void run() {
                 if (autoScrollDirection is ST.COLUMN_NEXT) {
                     doVisualNext();
@@ -2097,7 +2209,9 @@
         autoScrollDirection = direction;
         display.timerExec(H_SCROLL_RATE, timer);
     } else if (direction is ST.COLUMN_PREVIOUS) {
-        timer = new Runnable() {
+        timer = new class(disp) Runnable {
+            Display display;
+            this( Display d ){ this.display = d; }
             public void run() {
                 if (autoScrollDirection is ST.COLUMN_PREVIOUS) {
                     doVisualPrevious();
@@ -2126,13 +2240,14 @@
         int lineIndex = content.getLineAtOffset(caretOffset);
         int lineOffset = content.getOffsetAtLine(lineIndex);
         if (caretOffset is lineOffset) {
+            // DWT: on line start, delete line break
             lineOffset = content.getOffsetAtLine(lineIndex - 1);
-            event.start = lineOffset + content.getLine(lineIndex - 1).length();
+            event.start = lineOffset + content.getLine(lineIndex - 1).length;
             event.end = caretOffset;
         } else {
             TextLayout layout = renderer.getTextLayout(lineIndex);
-            int start = layout.getPreviousOffset(caretOffset - lineOffset, DWT.MOVEMENT_CHAR);
-            renderer.disposeTextLayout(layout); 
+            int start = layout.getPreviousOffset(caretOffset - lineOffset, DWT.MOVEMENT_CLUSTER);
+            renderer.disposeTextLayout(layout);
             event.start = start + lineOffset;
             event.end = caretOffset;
         }
@@ -2140,16 +2255,16 @@
     }
 }
 /**
- * Replaces the selection with the character or insert the character at the 
+ * Replaces the selection with the character or insert the character at the
  * current caret position if no selection exists.
  * <p>
- * If a carriage return was typed replace it with the line break character 
+ * If a carriage return was typed replace it with the line break character
  * used by the widget on this platform.
  * </p>
  *
  * @param key the character typed by the user
  */
-void doContent(char key) {
+void doContent(dchar key) {
     Event event = new Event();
     event.start = selection.x;
     event.end = selection.y;
@@ -2162,18 +2277,18 @@
         }
     } else if (selection.x is selection.y && overwrite && key !is TAB) {
         // no selection and overwrite mode is on and the typed key is not a
-        // tab character (tabs are always inserted without overwriting)?    
+        // tab character (tabs are always inserted without overwriting)?
         int lineIndex = content.getLineAtOffset(event.end);
         int lineOffset = content.getOffsetAtLine(lineIndex);
         String line = content.getLine(lineIndex);
-        // replace character at caret offset if the caret is not at the 
+        // replace character at caret offset if the caret is not at the
         // end of the line
-        if (event.end < lineOffset + line.length()) {
-            event.end++;
-        }
-        event.text = new String(new char[] {key});
+        if (event.end < lineOffset + line.length) {
+            event.end+=dcharToString( key ).length;
+        }
+        event.text = dcharToString( key );
     } else {
-        event.text = new String(new char[] {key});
+        event.text = dcharToString( key );
     }
     if (event.text !is null) {
         if (textLimit > 0 && content.getCharCount() - (event.end - event.start) >= textLimit) {
@@ -2186,12 +2301,12 @@
  * Moves the caret after the last character of the widget content.
  */
 void doContentEnd() {
-    // place caret at end of first line if receiver is in single 
+    // place caret at end of first line if receiver is in single
     // line mode. fixes 4820.
     if (isSingleLine()) {
         doLineEnd();
     } else {
-        int length = content.getCharCount();        
+        int length = content.getCharCount();
         if (caretOffset < length) {
             caretOffset = length;
             showCaret();
@@ -2209,7 +2324,7 @@
 }
 /**
  * Moves the caret to the start of the selection if a selection exists.
- * Otherwise, if no selection exists move the cursor according to the 
+ * Otherwise, if no selection exists move the cursor according to the
  * cursor selection rules.
  *
  * @see #doSelectionCursorPrevious
@@ -2225,7 +2340,7 @@
 }
 /**
  * Moves the caret to the end of the selection if a selection exists.
- * Otherwise, if no selection exists move the cursor according to the 
+ * Otherwise, if no selection exists move the cursor according to the
  * cursor selection rules.
  *
  * @see #doSelectionCursorNext
@@ -2252,7 +2367,7 @@
     } else if (caretOffset < content.getCharCount()) {
         int line = content.getLineAtOffset(caretOffset);
         int lineOffset = content.getOffsetAtLine(line);
-        int lineLength = content.getLine(line).length();
+        int lineLength = content.getLine(line).length;
         if (caretOffset is lineOffset + lineLength) {
             event.start = caretOffset;
             event.end = content.getOffsetAtLine(line + 1);
@@ -2268,7 +2383,7 @@
  */
 void doDeleteWordNext() {
     if (selection.x !is selection.y) {
-        // if a selection exists, treat the as if 
+        // if a selection exists, treat the as if
         // only the delete key was pressed
         doDelete();
     } else {
@@ -2284,7 +2399,7 @@
  */
 void doDeleteWordPrevious() {
     if (selection.x !is selection.y) {
-        // if a selection exists, treat as if 
+        // if a selection exists, treat as if
         // only the backspace key was pressed
         doBackspace();
     } else {
@@ -2296,8 +2411,8 @@
     }
 }
 /**
- * Moves the caret one line down and to the same character offset relative 
- * to the beginning of the line. Move the caret to the end of the new line 
+ * Moves the caret one line down and to the same character offset relative
+ * to the beginning of the line. Move the caret to the end of the new line
  * if the new line is shorter than the character offset.
  */
 void doLineDown(bool select) {
@@ -2330,8 +2445,8 @@
     int oldColumnX = columnX;
     int oldHScrollOffset = horizontalScrollOffset;
     if (select) {
-        setMouseWordSelectionAnchor();  
-        // select first and then scroll to reduce flash when key 
+        setMouseWordSelectionAnchor();
+        // select first and then scroll to reduce flash when key
         // repeat scrolls lots of lines
         doSelection(ST.COLUMN_NEXT);
     }
@@ -2344,7 +2459,7 @@
  */
 void doLineEnd() {
     int caretLine = getCaretLine();
-    int lineOffset = content.getOffsetAtLine(caretLine);    
+    int lineOffset = content.getOffsetAtLine(caretLine);
     int lineEndOffset;
     if (wordWrap) {
         TextLayout layout = renderer.getTextLayout(caretLine);
@@ -2354,7 +2469,7 @@
         lineEndOffset = lineOffset + offsets[lineIndex + 1];
         renderer.disposeTextLayout(layout);
     } else {
-        int lineLength = content.getLine(caretLine).length();
+        int lineLength = content.getLine(caretLine).length;
         lineEndOffset = lineOffset + lineLength;
     }
     if (caretOffset < lineEndOffset) {
@@ -2384,8 +2499,8 @@
     }
 }
 /**
- * Moves the caret one line up and to the same character offset relative 
- * to the beginning of the line. Move the caret to the end of the new line 
+ * Moves the caret one line up and to the same character offset relative
+ * to the beginning of the line. Move the caret to the end of the new line
  * if the new line is shorter than the character offset.
  */
 void doLineUp(bool select) {
@@ -2435,25 +2550,25 @@
     int line = getLineIndex(y);
 
     updateCaretDirection = true;
-    // allow caret to be placed below first line only if receiver is 
+    // allow caret to be placed below first line only if receiver is
     // not in single line mode. fixes 4820.
     if (line < 0 || (isSingleLine() && line > 0)) {
         return;
     }
     int oldCaretAlignment = caretAlignment;
     int newCaretOffset = getOffsetAtPoint(x, y);
-    
+
     if (doubleClickEnabled && clickCount > 1) {
         newCaretOffset = doMouseWordSelect(x, newCaretOffset, line);
     }
-    
+
     int newCaretLine = content.getLineAtOffset(newCaretOffset);
-    
-    // Is the mouse within the left client area border or on 
-    // a different line? If not the autoscroll selection 
+
+    // Is the mouse within the left client area border or on
+    // a different line? If not the autoscroll selection
     // could be incorrectly reset. Fixes 1GKM3XS
-    if (0 <= y && y < clientAreaHeight && 
-        (0 <= x && x < clientAreaWidth || wordWrap ||   
+    if (0 <= y && y < clientAreaHeight &&
+        (0 <= x && x < clientAreaWidth || wordWrap ||
         newCaretLine !is content.getLineAtOffset(caretOffset))) {
         if (newCaretOffset !is caretOffset || caretAlignment !is oldCaretAlignment) {
             caretOffset = newCaretOffset;
@@ -2470,8 +2585,8 @@
  * Updates the selection based on the caret position
  */
 void doMouseSelection() {
-    if (caretOffset <= selection.x || 
-        (caretOffset > selection.x && 
+    if (caretOffset <= selection.x ||
+        (caretOffset > selection.x &&
          caretOffset < selection.y && selectionAnchor is selection.x)) {
         doSelection(ST.COLUMN_PREVIOUS);
     } else {
@@ -2479,20 +2594,20 @@
     }
 }
 /**
- * Returns the offset of the word at the specified offset. 
- * If the current selection : from high index to low index 
- * (i.e., right to left, or caret is at left border of selection on 
+ * Returns the offset of the word at the specified offset.
+ * If the current selection extends from high index to low index
+ * (i.e., right to left, or caret is at left border of selection on
  * non-bidi platforms) the start offset of the word preceding the
- * selection is returned. If the current selection : from 
- * low index to high index the end offset of the word following 
+ * selection is returned. If the current selection extends from
+ * low index to high index the end offset of the word following
  * the selection is returned.
- * 
+ *
  * @param x mouse x location
  * @param newCaretOffset caret offset of the mouse cursor location
  * @param line line index of the mouse cursor location
  */
 int doMouseWordSelect(int x, int newCaretOffset, int line) {
-    // flip selection anchor based on word selection direction from 
+    // flip selection anchor based on word selection direction from
     // base double click. Always do this here (and don't rely on doAutoScroll)
     // because auto scroll only does not cover all possible mouse selections
     // (e.g., mouse x < 0 && mouse y > caret line y)
@@ -2517,7 +2632,7 @@
                 if (line + 1 < content.getLineCount()) {
                     lineEnd = content.getOffsetAtLine(line + 1);
                 }
-                newCaretOffset = lineEnd; 
+                newCaretOffset = lineEnd;
             }
         }
     }
@@ -2527,9 +2642,9 @@
  * Scrolls one page down so that the last line (truncated or whole)
  * of the current page becomes the fully visible top line.
  * <p>
- * The caret is scrolled the same number of lines so that its location 
- * relative to the top line remains the same. The exception is the end 
- * of the text where a full page scroll is not possible. In this case 
+ * The caret is scrolled the same number of lines so that its location
+ * relative to the top line remains the same. The exception is the end
+ * of the text where a full page scroll is not possible. In this case
  * the caret is moved after the last character.
  * </p>
  *
@@ -2546,7 +2661,7 @@
             int lineHeight = renderer.getLineHeight();
             int lines = (height is -1 ? clientAreaHeight : height) / lineHeight;
             int scrollLines = Math.min(lineCount - caretLine - 1, lines);
-            // ensure that scrollLines never gets negative and at least one 
+            // ensure that scrollLines never gets negative and at least one
             // line is scrolled. fixes bug 5602.
             scrollLines = Math.max(1, scrollLines);
             caretOffset = getOffsetAtPoint(columnX, getLinePixel(caretLine + scrollLines));
@@ -2627,10 +2742,10 @@
         height = getAvailableHeightBellow(height);
         scrollVertical(height, true);
         if (height is 0) setCaretLocation();
-    }   
+    }
     showCaret();
     int hScrollChange = oldHScrollOffset - horizontalScrollOffset;
-    columnX = oldColumnX + hScrollChange;   
+    columnX = oldColumnX + hScrollChange;
 }
 /**
  * Moves the cursor to the end of the last fully visible line.
@@ -2652,14 +2767,14 @@
                 index--;
             }
             if (index is -1 && lineIndex > 0) {
-                bottomOffset = content.getOffsetAtLine(lineIndex - 1) + content.getLine(lineIndex - 1).length();
+                bottomOffset = content.getOffsetAtLine(lineIndex - 1) + content.getLine(lineIndex - 1).length;
             } else {
                 bottomOffset = content.getOffsetAtLine(lineIndex) + Math.max(0, layout.getLineOffsets()[index + 1] - 1);
             }
             renderer.disposeTextLayout(layout);
         } else {
             int lineIndex = getBottomIndex();
-            bottomOffset = content.getOffsetAtLine(lineIndex) + content.getLine(lineIndex).length();
+            bottomOffset = content.getOffsetAtLine(lineIndex) + content.getLine(lineIndex).length;
         }
         if (caretOffset < bottomOffset) {
             caretOffset = bottomOffset;
@@ -2695,7 +2810,7 @@
         } else {
             topOffset = content.getOffsetAtLine(lineIndex) + layout.getLineOffsets()[index];
         }
-        renderer.disposeTextLayout(layout);     
+        renderer.disposeTextLayout(layout);
     } else {
         topOffset = content.getOffsetAtLine(topIndex);
     }
@@ -2708,17 +2823,17 @@
 /**
  * Scrolls one page up so that the first line (truncated or whole)
  * of the current page becomes the fully visible last line.
- * The caret is scrolled the same number of lines so that its location 
- * relative to the top line remains the same. The exception is the beginning 
+ * The caret is scrolled the same number of lines so that its location
+ * relative to the top line remains the same. The exception is the beginning
  * of the text where a full page scroll is not possible. In this case the
  * caret is moved in front of the first character.
  */
 void doPageUp(bool select, int height) {
     if (isSingleLine()) return;
     int oldHScrollOffset = horizontalScrollOffset;
-    int oldColumnX = columnX;   
+    int oldColumnX = columnX;
     if (isFixedLineHeight()) {
-        int caretLine = getCaretLine(); 
+        int caretLine = getCaretLine();
         if (caretLine > 0) {
             int lineHeight = renderer.getLineHeight();
             int lines = (height is -1 ? clientAreaHeight : height) / lineHeight;
@@ -2798,11 +2913,11 @@
             lineHeight = renderer.getLineHeight(--lineIndex);
         }
         lineHeight = renderer.getLineHeight(lineIndex);
-        caretOffset = getOffsetAtPoint(columnX, lineHeight - caretHeight, lineIndex);   
+        caretOffset = getOffsetAtPoint(columnX, lineHeight - caretHeight, lineIndex);
         if (select) doSelection(ST.COLUMN_PREVIOUS);
         height = getAvailableHeightAbove(height);
         scrollVertical(-height, true);
-        if (height is 0) setCaretLocation();    
+        if (height is 0) setCaretLocation();
     }
     showCaret();
     int hScrollChange = oldHScrollOffset - horizontalScrollOffset;
@@ -2813,15 +2928,15 @@
  */
 void doSelection(int direction) {
     int redrawStart = -1;
-    int redrawEnd = -1; 
+    int redrawEnd = -1;
     if (selectionAnchor is -1) {
         selectionAnchor = selection.x;
-    }   
+    }
     if (direction is ST.COLUMN_PREVIOUS) {
         if (caretOffset < selection.x) {
             // grow selection
-            redrawEnd = selection.x; 
-            redrawStart = selection.x = caretOffset;        
+            redrawEnd = selection.x;
+            redrawStart = selection.x = caretOffset;
             // check if selection has reversed direction
             if (selection.y !is selectionAnchor) {
                 redrawEnd = selection.y;
@@ -2829,10 +2944,10 @@
             }
         // test whether selection actually changed. Fixes 1G71EO1
         } else if (selectionAnchor is selection.x && caretOffset < selection.y) {
-            // caret moved towards selection anchor (left side of selection). 
-            // shrink selection         
+            // caret moved towards selection anchor (left side of selection).
+            // shrink selection
             redrawEnd = selection.y;
-            redrawStart = selection.y = caretOffset;        
+            redrawStart = selection.y = caretOffset;
         }
     } else {
         if (caretOffset > selection.y) {
@@ -2841,15 +2956,15 @@
             redrawEnd = selection.y = caretOffset;
             // check if selection has reversed direction
             if (selection.x !is selectionAnchor) {
-                redrawStart = selection.x;              
+                redrawStart = selection.x;
                 selection.x = selectionAnchor;
             }
-        // test whether selection actually changed. Fixes 1G71EO1   
+        // test whether selection actually changed. Fixes 1G71EO1
         } else if (selectionAnchor is selection.y && caretOffset > selection.x) {
-            // caret moved towards selection anchor (right side of selection). 
-            // shrink selection         
+            // caret moved towards selection anchor (right side of selection).
+            // shrink selection
             redrawStart = selection.x;
-            redrawEnd = selection.x = caretOffset;      
+            redrawEnd = selection.x = caretOffset;
         }
     }
     if (redrawStart !is -1 && redrawEnd !is -1) {
@@ -2858,14 +2973,14 @@
     }
 }
 /**
- * Moves the caret to the next character or to the beginning of the 
+ * Moves the caret to the next character or to the beginning of the
  * next line if the cursor is at the end of a line.
  */
 void doSelectionCursorNext() {
     int caretLine = getCaretLine();
     int lineOffset = content.getOffsetAtLine(caretLine);
     int offsetInLine = caretOffset - lineOffset;
-    if (offsetInLine < content.getLine(caretLine).length()) {
+    if (offsetInLine < content.getLine(caretLine).length) {
         TextLayout layout = renderer.getTextLayout(caretLine);
         offsetInLine = layout.getNextOffset(offsetInLine, DWT.MOVEMENT_CLUSTER);
         int lineStart = layout.getLineOffsets()[layout.getLineIndex(offsetInLine)];
@@ -2874,14 +2989,14 @@
         caretAlignment = offsetInLine is lineStart ? OFFSET_LEADING : PREVIOUS_OFFSET_TRAILING;
         showCaret();
     } else if (caretLine < content.getLineCount() - 1 && !isSingleLine()) {
-        caretLine++;        
+        caretLine++;
         caretOffset = content.getOffsetAtLine(caretLine);
         caretAlignment = PREVIOUS_OFFSET_TRAILING;
         showCaret();
     }
 }
 /**
- * Moves the caret to the previous character or to the end of the previous 
+ * Moves the caret to the previous character or to the end of the previous
  * line if the cursor is at the beginning of a line.
  */
 void doSelectionCursorPrevious() {
@@ -2889,21 +3004,22 @@
     int lineOffset = content.getOffsetAtLine(caretLine);
     int offsetInLine = caretOffset - lineOffset;
     caretAlignment = OFFSET_LEADING;
+
     if (offsetInLine > 0) {
         caretOffset = getClusterPrevious(caretOffset, caretLine);
         showCaret();
     } else if (caretLine > 0) {
         caretLine--;
         lineOffset = content.getOffsetAtLine(caretLine);
-        caretOffset = lineOffset + content.getLine(caretLine).length();
+        caretOffset = lineOffset + content.getLine(caretLine).length;
         showCaret();
     }
 }
 /**
- * Moves the caret one line down and to the same character offset relative 
- * to the beginning of the line. Moves the caret to the end of the new line 
+ * Moves the caret one line down and to the same character offset relative
+ * to the beginning of the line. Moves the caret to the end of the new line
  * if the new line is shorter than the character offset.
- * Moves the caret to the end of the text if the caret already is on the 
+ * Moves the caret to the end of the text if the caret already is on the
  * last line.
  * Adjusts the selection according to the caret change. This can either add
  * to or subtract from the old selection, depending on the previous selection
@@ -2915,8 +3031,8 @@
     columnX = oldColumnX;
 }
 /**
- * Moves the caret one line up and to the same character offset relative 
- * to the beginning of the line. Moves the caret to the end of the new line 
+ * Moves the caret one line up and to the same character offset relative
+ * to the beginning of the line. Moves the caret to the end of the new line
  * if the new line is shorter than the character offset.
  * Moves the caret to the beginning of the document if it is already on the
  * first line.
@@ -2925,17 +3041,17 @@
  * direction.
  */
 void doSelectionLineUp() {
-    int oldColumnX = columnX = getPointAtOffset(caretOffset).x; 
-    doLineUp(true); 
+    int oldColumnX = columnX = getPointAtOffset(caretOffset).x;
+    doLineUp(true);
     columnX = oldColumnX;
 }
 /**
  * Scrolls one page down so that the last line (truncated or whole)
  * of the current page becomes the fully visible top line.
  * <p>
- * The caret is scrolled the same number of lines so that its location 
- * relative to the top line remains the same. The exception is the end 
- * of the text where a full page scroll is not possible. In this case 
+ * The caret is scrolled the same number of lines so that its location
+ * relative to the top line remains the same. The exception is the end
+ * of the text where a full page scroll is not possible. In this case
  * the caret is moved after the last character.
  * <p></p>
  * Adjusts the selection according to the caret change. This can either add
@@ -2952,8 +3068,8 @@
  * Scrolls one page up so that the first line (truncated or whole)
  * of the current page becomes the fully visible last line.
  * <p>
- * The caret is scrolled the same number of lines so that its location 
- * relative to the top line remains the same. The exception is the beginning 
+ * The caret is scrolled the same number of lines so that its location
+ * relative to the top line remains the same. The exception is the beginning
  * of the text where a full page scroll is not possible. In this case the
  * caret is moved in front of the first character.
  * </p><p>
@@ -2974,9 +3090,9 @@
     int newCaretOffset = getWordNext(caretOffset, DWT.MOVEMENT_WORD);
     // Force symmetrical movement for word next and previous. Fixes 14536
     caretAlignment = OFFSET_LEADING;
-    // don't change caret position if in single line mode and the cursor 
+    // don't change caret position if in single line mode and the cursor
     // would be on a different line. fixes 5673
-    if (!isSingleLine() || 
+    if (!isSingleLine() ||
         content.getLineAtOffset(caretOffset) is content.getLineAtOffset(newCaretOffset)) {
         caretOffset = newCaretOffset;
         showCaret();
@@ -2999,8 +3115,8 @@
 }
 /**
  * Moves the caret one character to the left.  Do not go to the previous line.
- * When in a bidi locale and at a R2L character the caret is moved to the 
- * beginning of the R2L segment (visually right) and then one character to the 
+ * When in a bidi locale and at a R2L character the caret is moved to the
+ * beginning of the R2L segment (visually right) and then one character to the
  * left (visually left because it's now in a L2R segment).
  */
 void doVisualPrevious() {
@@ -3009,8 +3125,8 @@
 }
 /**
  * Moves the caret one character to the right.  Do not go to the next line.
- * When in a bidi locale and at a R2L character the caret is moved to the 
- * end of the R2L segment (visually left) and then one character to the 
+ * When in a bidi locale and at a R2L character the caret is moved to the
+ * end of the R2L segment (visually left) and then one character to the
  * right (visually right because it's now in a L2R segment).
  */
 void doVisualNext() {
@@ -3043,13 +3159,13 @@
         doSelectionWordPrevious();
     }
 }
-/** 
+/**
  * Ends the autoscroll process.
  */
 void endAutoScroll() {
     autoScrollDirection = DWT.NULL;
 }
-public Color getBackground() {
+public override Color getBackground() {
     checkWidget();
     if (background is null) {
         return getDisplay().getSystemColor(DWT.COLOR_LIST_BACKGROUND);
@@ -3058,9 +3174,9 @@
 }
 /**
  * Returns the baseline, in pixels.
- *  
- * Note: this API should not be used if a StyleRange attribute causes lines to 
- * have different heights (i.e. different fonts, rise, etc). 
+ *
+ * Note: this API should not be used if a StyleRange attribute causes lines to
+ * have different heights (i.e. different fonts, rise, etc).
  *
  * @return baseline the baseline
  * @exception DWTException <ul>
@@ -3068,7 +3184,7 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @since 3.0
- * 
+ *
  * @see #getBaseline(int)
  */
 public int getBaseline() {
@@ -3076,20 +3192,20 @@
     return renderer.getBaseline();
 }
 /**
- * Returns the baseline at the given offset, in pixels. 
+ * Returns the baseline at the given offset, in pixels.
  *
  * @param offset the offset
- * 
+ *
  * @return baseline the baseline
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li> 
- * </ul>
- *  
+ *   <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li>
+ * </ul>
+ *
  * @since 3.2
  */
 public int getBaseline(int offset) {
@@ -3103,7 +3219,7 @@
     int lineIndex = content.getLineAtOffset(offset);
     int lineOffset = content.getOffsetAtLine(lineIndex);
     TextLayout layout = renderer.getTextLayout(lineIndex);
-    int lineInParagraph = layout.getLineIndex(Math.min(offset - lineOffset, layout.getText().length()));
+    int lineInParagraph = layout.getLineIndex(Math.min(offset - lineOffset, layout.getText().length));
     FontMetrics metrics = layout.getLineMetrics(lineInParagraph);
     renderer.disposeTextLayout(layout);
     return metrics.getAscent() + metrics.getLeading();
@@ -3118,14 +3234,14 @@
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @deprecated use BidiSegmentListener instead.
  */
 public bool getBidiColoring() {
     checkWidget();
     return bidiColoring;
 }
-/** 
+/**
  * Returns the index of the last fully visible line.
  *
  * @return index of the last fully visible line.
@@ -3161,7 +3277,7 @@
     int lineOffset = content.getOffsetAtLine(lineIndex);
     String line = content.getLine(lineIndex);
     Rectangle bounds;
-    if (line.length() !is 0) {
+    if (line.length !is 0) {
         int offsetInLine = offset - lineOffset;
         TextLayout layout = renderer.getTextLayout(lineIndex);
         bounds = layout.getBounds(offsetInLine, offsetInLine);
@@ -3170,7 +3286,7 @@
         bounds = new Rectangle (0, 0, 0, renderer.getLineHeight());
     }
     if (offset is caretOffset) {
-        int lineEnd = lineOffset + line.length();
+        int lineEnd = lineOffset + line.length;
         if (offset is lineEnd && caretAlignment is PREVIOUS_OFFSET_TRAILING) {
             bounds.width += getCaretWidth();
         }
@@ -3207,7 +3323,7 @@
     return clipboard.getContents(plainTextTransfer, clipboardType);
 }
 int getClusterNext(int offset, int lineIndex) {
-    int lineOffset = content.getOffsetAtLine(lineIndex);    
+    int lineOffset = content.getOffsetAtLine(lineIndex);
     TextLayout layout = renderer.getTextLayout(lineIndex);
     offset -= lineOffset;
     offset = layout.getNextOffset(offset, DWT.MOVEMENT_CLUSTER);
@@ -3216,7 +3332,7 @@
     return offset;
 }
 int getClusterPrevious(int offset, int lineIndex) {
-    int lineOffset = content.getOffsetAtLine(lineIndex);    
+    int lineOffset = content.getOffsetAtLine(lineIndex);
     TextLayout layout = renderer.getTextLayout(lineIndex);
     offset -= lineOffset;
     offset = layout.getPreviousOffset(offset, DWT.MOVEMENT_CLUSTER);
@@ -3226,9 +3342,9 @@
 }
 /**
  * Returns the content implementation that is used for text storage.
- * 
+ *
  * @return content the user defined content implementation that is used for
- * text storage or the default content implementation if no user defined 
+ * text storage or the default content implementation if no user defined
  * content implementation has been set.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
@@ -3239,12 +3355,12 @@
     checkWidget();
     return content;
 }
-public bool getDragDetect () {
+public override bool getDragDetect () {
     checkWidget ();
-    return dragDetect;
-}
-/** 
- * Returns whether the widget : double click mouse behavior.
+    return dragDetect_;
+}
+/**
+ * Returns whether the widget implements double click mouse behavior.
  *
  * @return true if double clicking a word selects the word, false if double clicks
  * have the same effect as regular mouse clicks
@@ -3270,22 +3386,22 @@
     checkWidget();
     return editable;
 }
-public Color getForeground() {
+public override Color getForeground() {
     checkWidget();
     if (foreground is null) {
         return getDisplay().getSystemColor(DWT.COLOR_LIST_FOREGROUND);
     }
     return foreground;
 }
-/** 
+/**
  * Returns the horizontal scroll increment.
  *
  * @return horizontal scroll increment.
  */
-int getHorizontalIncrement() {  
+int getHorizontalIncrement() {
     return renderer.averageCharWidth;
 }
-/** 
+/**
  * Returns the horizontal scroll offset relative to the start of the line.
  *
  * @return horizontal scroll offset relative to the start of the line,
@@ -3299,7 +3415,7 @@
     checkWidget();
     return horizontalScrollOffset / getHorizontalIncrement();
 }
-/** 
+/**
  * Returns the horizontal scroll offset relative to the start of the line.
  *
  * @return the horizontal scroll offset relative to the start of the line,
@@ -3315,16 +3431,16 @@
 }
 /**
  * Returns the line indentation of the widget.
- * 
+ *
  * @return the line indentation
- * 
- * @exception DWTException <ul>
- *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- *  
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
  * @see #getLineIndent(int)
- * 
+ *
  * @since 3.2
  */
 public int getIndent() {
@@ -3333,32 +3449,32 @@
 }
 /**
  * Returns whether the widget justifies lines.
- * 
+ *
  * @return whether lines are justified
- * 
- * @exception DWTException <ul>
- *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- *  
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
  * @see #getLineJustify(int)
- * 
+ *
  * @since 3.2
  */
 public bool getJustify() {
     checkWidget();
     return justify;
 }
-/** 
+/**
  * Returns the action assigned to the key.
  * Returns DWT.NULL if there is no action associated with the key.
  *
- * @param key a key code defined in DWT.java or a character. 
+ * @param key a key code defined in DWT.java or a character.
  *  Optionally ORd with a state mask.  Preferred state masks are one or more of
- *  DWT.MOD1, DWT.MOD2, DWT.MOD3, since these masks account for modifier platform 
+ *  DWT.MOD1, DWT.MOD2, DWT.MOD3, since these masks account for modifier platform
  *  differences.  However, there may be cases where using the specific state masks
  *  (i.e., DWT.CTRL, DWT.SHIFT, DWT.ALT, DWT.COMMAND) makes sense.
- * @return one of the predefined actions defined in ST.java or DWT.NULL 
+ * @return one of the predefined actions defined in ST.java or DWT.NULL
  *  if there is no action associated with the key.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
@@ -3367,8 +3483,10 @@
  */
 public int getKeyBinding(int key) {
     checkWidget();
-    Integer action = cast(Integer) keyActionMap.get(new Integer(key));  
-    return action is null ? DWT.NULL : action.intValue();
+    if( auto p = key in keyActionMap ){
+        return *p;
+    }
+    return DWT.NULL;
 }
 /**
  * Gets the number of characters.
@@ -3386,36 +3504,36 @@
 /**
  * Returns the line at the given line index without delimiters.
  * Index 0 is the first line of the content. When there are not
- * any lines, getLine(0) is a valid call that answers an empty String.
+ * any lines, getLine(0) is a valid call that answers an empty string.
  * <p>
  *
  * @param lineIndex index of the line to return.
  * @return the line text without delimiters
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when the line index is outside the valid range (< 0 or >= getLineCount())</li> 
+ *   <li>ERROR_INVALID_RANGE when the line index is outside the valid range (< 0 or >= getLineCount())</li>
  * </ul>
  * @since 3.4
  */
 public String getLine(int lineIndex) {
     checkWidget();
-    if (lineIndex < 0 || 
+    if (lineIndex < 0 ||
         (lineIndex > 0 && lineIndex >= content.getLineCount())) {
-        DWT.error(DWT.ERROR_INVALID_RANGE);     
+        DWT.error(DWT.ERROR_INVALID_RANGE);
     }
     return content.getLine(lineIndex);
 }
 /**
  * Returns the alignment of the line at the given index.
- * 
+ *
  * @param index the index of the line
- * 
+ *
  * @return the line alignment
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -3423,9 +3541,9 @@
  * @exception IllegalArgumentException <ul>
  *    <li>ERROR_INVALID_ARGUMENT when the index is invalid</li>
  * </ul>
- * 
+ *
  * @see #getAlignment()
- * 
+ *
  * @since 3.2
  */
 public int getLineAlignment(int index) {
@@ -3440,7 +3558,7 @@
  * where 0 &lt; offset &lt; getCharCount() so that getLineAtOffset(getCharCount())
  * returns the line of the insert location.
  *
- * @param offset offset relative to the start of the content. 
+ * @param offset offset relative to the start of the content.
  *  0 <= offset <= getCharCount()
  * @return line at the specified offset in the text
  * @exception DWTException <ul>
@@ -3448,26 +3566,26 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li> 
+ *   <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li>
  * </ul>
  */
 public int getLineAtOffset(int offset) {
-    checkWidget();  
+    checkWidget();
     if (offset < 0 || offset > getCharCount()) {
-        DWT.error(DWT.ERROR_INVALID_RANGE);     
+        DWT.error(DWT.ERROR_INVALID_RANGE);
     }
     return content.getLineAtOffset(offset);
 }
 /**
  * Returns the background color of the line at the given index.
- * Returns null if a LineBackgroundListener has been set or if no background 
+ * Returns null if a LineBackgroundListener has been set or if no background
  * color has been specified for the line. Should not be called if a
  * LineBackgroundListener has been set since the listener maintains the
  * line background colors.
- * 
+ *
  * @param index the index of the line
  * @return the background color of the line at the given index.
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -3485,11 +3603,11 @@
 }
 /**
  * Returns the bullet of the line at the given index.
- * 
+ *
  * @param index the index of the line
- * 
+ *
  * @return the line bullet
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -3497,7 +3615,7 @@
  * @exception IllegalArgumentException <ul>
  *    <li>ERROR_INVALID_ARGUMENT when the index is invalid</li>
  * </ul>
- * 
+ *
  * @since 3.2
  */
 public Bullet getLineBullet(int index) {
@@ -3508,9 +3626,9 @@
     return isListening(LineGetStyle) ? null : renderer.getLineBullet(index, null);
 }
 /**
- * Returns the line background data for the given line or null if 
+ * Returns the line background data for the given line or null if
  * there is none.
- * 
+ *
  * @param lineOffset offset of the line start relative to the start
  *  of the content.
  * @param line line to get line background data for
@@ -3519,7 +3637,7 @@
 StyledTextEvent getLineBackgroundData(int lineOffset, String line) {
     return sendLineEvent(LineGetBackground, lineOffset, line);
 }
-/** 
+/**
  * Gets the number of text lines.
  *
  * @return the number of lines in the widget
@@ -3533,10 +3651,10 @@
     return content.getLineCount();
 }
 /**
- * Returns the number of lines that can be completely displayed in the 
+ * Returns the number of lines that can be completely displayed in the
  * widget client area.
  *
- * @return number of lines that can be completely displayed in the widget 
+ * @return number of lines that can be completely displayed in the widget
  *  client area.
  */
 int getLineCountWhole() {
@@ -3564,7 +3682,7 @@
 /**
  * Returns the line height.
  * <p>
- * Note: this API should not be used if a StyleRange attribute causes lines to 
+ * Note: this API should not be used if a StyleRange attribute causes lines to
  * have different heights (i.e. different fonts, rise, etc).
  * </p>
  *
@@ -3583,17 +3701,17 @@
  * Returns the line height at the given offset.
  *
  * @param offset the offset
- *  
+ *
  * @return line height in pixels
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li> 
- * </ul> 
- * 
+ *   <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li>
+ * </ul>
+ *
  * @since 3.2
  */
 public int getLineHeight(int offset) {
@@ -3607,18 +3725,18 @@
     int lineIndex = content.getLineAtOffset(offset);
     int lineOffset = content.getOffsetAtLine(lineIndex);
     TextLayout layout = renderer.getTextLayout(lineIndex);
-    int lineInParagraph = layout.getLineIndex(Math.min(offset - lineOffset, layout.getText().length()));
+    int lineInParagraph = layout.getLineIndex(Math.min(offset - lineOffset, layout.getText().length));
     int height = layout.getLineBounds(lineInParagraph).height;
     renderer.disposeTextLayout(layout);
     return height;
 }
 /**
  * Returns the indentation of the line at the given index.
- * 
+ *
  * @param index the index of the line
- * 
+ *
  * @return the line indentation
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -3626,9 +3744,9 @@
  * @exception IllegalArgumentException <ul>
  *    <li>ERROR_INVALID_ARGUMENT when the index is invalid</li>
  * </ul>
- * 
+ *
  * @see #getIndent()
- * 
+ *
  * @since 3.2
  */
 public int getLineIndent(int index) {
@@ -3640,11 +3758,11 @@
 }
 /**
  * Returns whether the line at the given index is justified.
- * 
+ *
  * @param index the index of the line
- * 
- * @return whether the line is justified 
- * 
+ *
+ * @return whether the line is justified
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -3652,9 +3770,9 @@
  * @exception IllegalArgumentException <ul>
  *    <li>ERROR_INVALID_ARGUMENT when the index is invalid</li>
  * </ul>
- * 
+ *
  * @see #getJustify()
- * 
+ *
  * @since 3.2
  */
 public bool getLineJustify(int index) {
@@ -3662,18 +3780,18 @@
     if (index < 0 || index > content.getLineCount()) {
         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     }
-    return isListening(LineGetStyle) ? false : renderer.getLineJustify(index, justify); 
+    return isListening(LineGetStyle) ? false : renderer.getLineJustify(index, justify);
 }
 /**
  * Returns the line spacing of the widget.
- * 
+ *
  * @return the line spacing
- *  
- * @exception DWTException <ul>
- *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- * 
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
  * @since 3.2
  */
 public int getLineSpacing() {
@@ -3681,18 +3799,18 @@
     return lineSpacing;
 }
 /**
- * Returns the line style data for the given line or null if there is 
+ * Returns the line style data for the given line or null if there is
  * none.
  * <p>
- * If there is a LineStyleListener but it does not set any styles, 
- * the StyledTextEvent.styles field will be initialized to an empty 
+ * If there is a LineStyleListener but it does not set any styles,
+ * the StyledTextEvent.styles field will be initialized to an empty
  * array.
  * </p>
- * 
- * @param lineOffset offset of the line start relative to the start of 
+ *
+ * @param lineOffset offset of the line start relative to the start of
  *  the content.
  * @param line line to get line styles for
- * @return line style data for the given line. Styles may start before 
+ * @return line style data for the given line. Styles may start before
  *  line start and end after line end
  */
 StyledTextEvent getLineStyleData(int lineOffset, String line) {
@@ -3701,11 +3819,13 @@
 /**
  * Returns the top pixel, relative to the client area, of a given line.
  * Clamps out of ranges index.
- *  
+ *
  * @param lineIndex the line index, the max value is lineCount. If
  * lineIndex is lineCount it returns the bottom pixel of the last line.
- * It means this function can be used to retrieve the bottom pixel of any line. 
- * 
+ * It means this function can be used to retrieve the bottom pixel of any line.
+ *
+ * @return the top pixel of a given line index
+ *
  * @since 3.2
  */
 public int getLinePixel(int lineIndex) {
@@ -3733,6 +3853,10 @@
  * Returns the line index for a y, relative to the client area.
  * The line index returned is always in the range 0..lineCount - 1.
  *
+ * @param y the y-coordinate pixel
+ *
+ * @return the line index for a given y-coordinate pixel
+ *
  * @since 3.2
  */
 public int getLineIndex(int y) {
@@ -3762,59 +3886,59 @@
     return line;
 }
 /**
- * Returns the x, y location of the upper left corner of the character 
- * bounding box at the specified offset in the text. The point is 
+ * Returns the x, y location of the upper left corner of the character
+ * bounding box at the specified offset in the text. The point is
  * relative to the upper left corner of the widget client area.
  *
- * @param offset offset relative to the start of the content. 
+ * @param offset offset relative to the start of the content.
  *  0 <= offset <= getCharCount()
- * @return x, y location of the upper left corner of the character 
+ * @return x, y location of the upper left corner of the character
  *  bounding box at the specified offset in the text.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li> 
+ *   <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li>
  * </ul>
  */
 public Point getLocationAtOffset(int offset) {
     checkWidget();
     if (offset < 0 || offset > getCharCount()) {
-        DWT.error(DWT.ERROR_INVALID_RANGE);     
+        DWT.error(DWT.ERROR_INVALID_RANGE);
     }
     return getPointAtOffset(offset);
 }
 /**
  * Returns the character offset of the first character of the given line.
  *
- * @param lineIndex index of the line, 0 based relative to the first 
+ * @param lineIndex index of the line, 0 based relative to the first
  *  line in the content. 0 <= lineIndex < getLineCount(), except
  *  lineIndex may always be 0
  * @return offset offset of the first character of the line, relative to
  *  the beginning of the document. The first character of the document is
- *  at offset 0.  
- *  When there are not any lines, getOffsetAtLine(0) is a valid call that 
+ *  at offset 0.
+ *  When there are not any lines, getOffsetAtLine(0) is a valid call that
  *  answers 0.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when the line index is outside the valid range (< 0 or >= getLineCount())</li> 
+ *   <li>ERROR_INVALID_RANGE when the line index is outside the valid range (< 0 or >= getLineCount())</li>
  * </ul>
  * @since 2.0
  */
 public int getOffsetAtLine(int lineIndex) {
     checkWidget();
-    if (lineIndex < 0 || 
+    if (lineIndex < 0 ||
         (lineIndex > 0 && lineIndex >= content.getLineCount())) {
-        DWT.error(DWT.ERROR_INVALID_RANGE);     
+        DWT.error(DWT.ERROR_INVALID_RANGE);
     }
     return content.getOffsetAtLine(lineIndex);
 }
 /**
- * Returns the offset of the character at the given location relative 
+ * Returns the offset of the character at the given location relative
  * to the first character in the document.
  * <p>
  * The return value reflects the character offset that the caret will
@@ -3823,9 +3947,9 @@
  * the returned offset will be behind the character.
  * </p>
  *
- * @param point the origin of character bounding box relative to 
+ * @param point the origin of character bounding box relative to
  *  the origin of the widget client area.
- * @return offset of the character at the given location relative 
+ * @return offset of the character at the given location relative
  *  to the first character in the document.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
@@ -3864,7 +3988,7 @@
 int getOffsetAtPoint(int x, int y, int lineIndex) {
     TextLayout layout = renderer.getTextLayout(lineIndex);
     x += horizontalScrollOffset - leftMargin;
-    int[] trailing = new int[1];    
+    int[1] trailing;
     int offsetInLine = layout.getOffset(x, y, trailing);
     caretAlignment = OFFSET_LEADING;
     if (trailing[0] !is 0) {
@@ -3874,11 +3998,11 @@
             offsetInLine += trailing[0];
             caretAlignment = PREVIOUS_OFFSET_TRAILING;
         } else {
-            String line = content.getLine(lineIndex);           
+            String line = content.getLine(lineIndex);
             int level;
             int offset = offsetInLine;
-            while (offset > 0 && Character.isDigit(line.charAt(offset))) offset--;
-            if (offset is 0 && Character.isDigit(line.charAt(offset))) {
+            while (offset > 0 && tango.text.Unicode.isDigit(line[offset])) offset--;
+            if (offset is 0 && tango.text.Unicode.isDigit(line[offset])) {
                 level = isMirrored() ? 1 : 0;
             } else {
                 level = layout.getLevel(offset) & 0x1;
@@ -3906,7 +4030,7 @@
     }
     int lineIndex = getLineIndex(y);
     int lineOffset = content.getOffsetAtLine(lineIndex);
-    TextLayout layout = renderer.getTextLayout(lineIndex);  
+    TextLayout layout = renderer.getTextLayout(lineIndex);
     x += horizontalScrollOffset - leftMargin ;
     y -= getLinePixel(lineIndex);
     int offset = layout.getOffset(x, y, trailing);
@@ -3921,19 +4045,19 @@
  * Returns the orientation of the receiver.
  *
  * @return the orientation style
- * 
- * @exception DWTException <ul>
- *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- * 
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
  * @since 2.1.2
  */
 public int getOrientation () {
     checkWidget();
     return isMirrored() ? DWT.RIGHT_TO_LEFT : DWT.LEFT_TO_RIGHT;
 }
-/** 
+/**
  * Returns the index of the last partially visible line.
  *
  * @return index of the last partially visible line.
@@ -3946,7 +4070,7 @@
     }
     return getLineIndex(clientAreaHeight - bottomMargin);
 }
-/** 
+/**
  * Returns the index of the first partially visible line.
  *
  * @return index of the first partially visible line.
@@ -3959,11 +4083,11 @@
     return topIndexY <= 0 ? topIndex : topIndex - 1;
 }
 /**
- * Returns the content in the specified range using the platform line 
+ * Returns the content in the specified range using the platform line
  * delimiter to separate lines.
  *
  * @param writer the TextWriter to write line text into
- * @return the content in the specified range using the platform line 
+ * @return the content in the specified range using the platform line
  *  delimiter to separate lines as written by the specified TextWriter.
  */
 String getPlatformDelimitedText(TextWriter writer) {
@@ -3972,14 +4096,14 @@
     int endLine = content.getLineAtOffset(end);
     String endLineText = content.getLine(endLine);
     int endLineOffset = content.getOffsetAtLine(endLine);
-    
+
     for (int i = startLine; i <= endLine; i++) {
         writer.writeLine(content.getLine(i), content.getOffsetAtLine(i));
         if (i < endLine) {
             writer.writeLineDelimiter(PlatformLineDelimiter);
         }
     }
-    if (end > endLineOffset + endLineText.length()) {
+    if (end > endLineOffset + endLineText.length) {
         writer.writeLineDelimiter(PlatformLineDelimiter);
     }
     writer.close();
@@ -3987,8 +4111,8 @@
 }
 /**
  * Returns all the ranges of text that have an associated StyleRange.
- * Returns an empty array if a LineStyleListener has been set. 
- * Should not be called if a LineStyleListener has been set since the 
+ * Returns an empty array if a LineStyleListener has been set.
+ * Should not be called if a LineStyleListener has been set since the
  * listener maintains the styles.
  * <p>
  * The ranges array contains start and length pairs.  Each pair refers to
@@ -3996,16 +4120,16 @@
  * that starts at ranges[n] with length ranges[n+1] uses the style
  * at styles[n/2] returned by <code>getStyleRanges(int, int, bool)</code>.
  * </p>
- * 
+ *
  * @return the ranges or an empty array if a LineStyleListener has been set.
- * 
- * @exception DWTException <ul>
- *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- * 
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
  * @since 3.2
- * 
+ *
  * @see #getStyleRanges(bool)
  */
 public int[] getRanges() {
@@ -4018,8 +4142,8 @@
 }
 /**
  * Returns the ranges of text that have an associated StyleRange.
- * Returns an empty array if a LineStyleListener has been set. 
- * Should not be called if a LineStyleListener has been set since the 
+ * Returns an empty array if a LineStyleListener has been set.
+ * Should not be called if a LineStyleListener has been set since the
  * listener maintains the styles.
  * <p>
  * The ranges array contains start and length pairs.  Each pair refers to
@@ -4030,19 +4154,19 @@
  *
  * @param start the start offset of the style ranges to return
  * @param length the number of style ranges to return
- * 
+ *
  * @return the ranges or an empty array if a LineStyleListener has been set.
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE if start or length are outside the widget content</li> 
- * </ul> 
- * 
+ *   <li>ERROR_INVALID_RANGE if start or length are outside the widget content</li>
+ * </ul>
+ *
  * @since 3.2
- * 
+ *
  * @see #getStyleRanges(int, int, bool)
  */
 public int[] getRanges(int start, int length) {
@@ -4062,15 +4186,15 @@
  * Returns the selection.
  * <p>
  * Text selections are specified in terms of caret positions.  In a text
- * widget that contains N characters, there are N+1 caret positions, 
+ * widget that contains N characters, there are N+1 caret positions,
  * ranging from 0..N
  * </p>
  *
- * @return start and end of the selection, x is the offset of the first 
+ * @return start and end of the selection, x is the offset of the first
  *  selected character, y is the offset after the last selected character.
- *  The selection values returned are visual (i.e., x will always always be   
- *  <= y).  To determine if a selection is right-to-left cast(RtoL) vs. left-to-right 
- *  cast(LtoR), compare the caretOffset to the start and end of the selection 
+ *  The selection values returned are visual (i.e., x will always always be
+ *  <= y).  To determine if a selection is right-to-left (RtoL) vs. left-to-right
+ *  (LtoR), compare the caretOffset to the start and end of the selection
  *  (e.g., caretOffset is start of selection implies that the selection is RtoL).
  * @see #getSelectionRange
  * @exception DWTException <ul>
@@ -4085,12 +4209,12 @@
 /**
  * Returns the selection.
  *
- * @return start and length of the selection, x is the offset of the 
- *  first selected character, relative to the first character of the 
- *  widget content. y is the length of the selection. 
- *  The selection values returned are visual (i.e., length will always always be   
- *  positive).  To determine if a selection is right-to-left cast(RtoL) vs. left-to-right 
- *  cast(LtoR), compare the caretOffset to the start and end of the selection 
+ * @return start and length of the selection, x is the offset of the
+ *  first selected character, relative to the first character of the
+ *  widget content. y is the length of the selection.
+ *  The selection values returned are visual (i.e., length will always always be
+ *  positive).  To determine if a selection is right-to-left (RtoL) vs. left-to-right
+ *  (LtoR), compare the caretOffset to the start and end of the selection
  *  (e.g., caretOffset is start of selection implies that the selection is RtoL).
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
@@ -4163,7 +4287,7 @@
     checkWidget();
     return content.getTextRange(selection.x, selection.y - selection.x);
 }
-public int getStyle() {
+public override int getStyle() {
     int style = super.getStyle();
     style &= ~(DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT | DWT.MIRRORED);
     if (isMirrored()) {
@@ -4175,18 +4299,18 @@
 }
 
 /**
- * Returns the text segments that should be treated as if they 
+ * Returns the text segments that should be treated as if they
  * had a different direction than the surrounding text.
  *
- * @param lineOffset offset of the first character in the line. 
+ * @param lineOffset offset of the first character in the line.
  *  0 based from the beginning of the document.
  * @param line text of the line to specify bidi segments for
  * @return text segments that should be treated as if they had a
- *  different direction than the surrounding text. Only the start 
- *  index of a segment is specified, relative to the start of the 
- *  line. Always starts with 0 and ends with the line length. 
+ *  different direction than the surrounding text. Only the start
+ *  index of a segment is specified, relative to the start of the
+ *  line. Always starts with 0 and ends with the line length.
  * @exception IllegalArgumentException <ul>
- *    <li>ERROR_INVALID_ARGUMENT - if the segment indices returned 
+ *    <li>ERROR_INVALID_ARGUMENT - if the segment indices returned
  *      by the listener do not start with 0, are not in ascending order,
  *      exceed the line length or have duplicates</li>
  * </ul>
@@ -4197,21 +4321,21 @@
         return getBidiSegmentsCompatibility(line, lineOffset);
     }
     StyledTextEvent event = sendLineEvent(LineGetSegments, lineOffset, line);
-    int lineLength = line.length();
+    int lineLength = line.length;
     int[] segments;
     if (event is null || event.segments is null || event.segments.length is 0) {
-        segments = new int[] {0, lineLength};
+        segments = [0, lineLength];
     } else {
         int segmentCount = event.segments.length;
-        
+
         // test segment index consistency
         if (event.segments[0] !is 0) {
             DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        }   
+        }
         for (int i = 1; i < segmentCount; i++) {
             if (event.segments[i] <= event.segments[i - 1] || event.segments[i] > lineLength) {
                 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-            }   
+            }
         }
         // ensure that last segment index is line end offset
         if (event.segments[segmentCount - 1] !is lineLength) {
@@ -4229,9 +4353,9 @@
  * Supports deprecated setBidiColoring API. Remove when API is removed.
  */
 int [] getBidiSegmentsCompatibility(String line, int lineOffset) {
-    int lineLength = line.length();
+    int lineLength = line.length;
     if (!bidiColoring) {
-        return new int[] {0, lineLength};
+        return [0, lineLength];
     }
     StyleRange [] styles = null;
     StyledTextEvent event = getLineStyleData(lineOffset, line);
@@ -4241,7 +4365,7 @@
         styles = renderer.getStyleRanges(lineOffset, lineLength, true);
     }
     if (styles is null || styles.length is 0) {
-        return new int[] {0, lineLength};
+        return [0, lineLength];
     }
     int k=0, count = 1;
     while (k < styles.length && styles[k].start is 0 && styles[k].length is lineLength) {
@@ -4252,7 +4376,7 @@
         StyleRange style = styles[i];
         int styleLineStart = Math.max(style.start - lineOffset, 0);
         int styleLineEnd = Math.max(style.start + style.length - lineOffset, styleLineStart);
-        styleLineEnd = Math.min (styleLineEnd, line.length ());
+        styleLineEnd = Math.min (styleLineEnd, line.length );
         if (i > 0 && count > 1 &&
             ((styleLineStart >= offsets[count-2] && styleLineStart <= offsets[count-1]) ||
              (styleLineEnd >= offsets[count-2] && styleLineEnd <= offsets[count-1])) &&
@@ -4284,15 +4408,15 @@
  * Returns the style range at the given offset.
  * <p>
  * Returns null if a LineStyleListener has been set or if a style is not set
- * for the offset. 
- * Should not be called if a LineStyleListener has been set since the 
+ * for the offset.
+ * Should not be called if a LineStyleListener has been set since the
  * listener maintains the styles.
  * </p>
  *
- * @param offset the offset to return the style for. 
+ * @param offset the offset to return the style for.
  *  0 <= offset < getCharCount() must be true.
  * @return a StyleRange with start is offset and length is 1, indicating
- *  the style at the given offset. null if a LineStyleListener has been set 
+ *  the style at the given offset. null if a LineStyleListener has been set
  *  or if a style is not set for the given offset.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
@@ -4316,8 +4440,8 @@
 /**
  * Returns the styles.
  * <p>
- * Returns an empty array if a LineStyleListener has been set. 
- * Should not be called if a LineStyleListener has been set since the 
+ * Returns an empty array if a LineStyleListener has been set.
+ * Should not be called if a LineStyleListener has been set since the
  * listener maintains the styles.
  * <p></p>
  * Note: Because a StyleRange includes the start and length, the
@@ -4333,7 +4457,7 @@
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @see #getStyleRanges(bool)
  */
 public StyleRange[] getStyleRanges() {
@@ -4343,8 +4467,8 @@
 /**
  * Returns the styles.
  * <p>
- * Returns an empty array if a LineStyleListener has been set. 
- * Should not be called if a LineStyleListener has been set since the 
+ * Returns an empty array if a LineStyleListener has been set.
+ * Should not be called if a LineStyleListener has been set since the
  * listener maintains the styles.
  * </p><p>
  * Note: When <code>includeRanges</code> is true, the start and length
@@ -4353,18 +4477,18 @@
  * false, <code>getRanges(int, int)</code> can be used to get the
  * associated ranges.
  * </p>
- * 
+ *
  * @param includeRanges whether the start and length field of the StyleRanges should be set.
- * 
+ *
  * @return the styles or an empty array if a LineStyleListener has been set.
- * 
- * @exception DWTException <ul>
- *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- * 
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
  * @since 3.2
- * 
+ *
  * @see #getRanges(int, int)
  * @see #setStyleRanges(int[], StyleRange[])
  */
@@ -4375,8 +4499,8 @@
 /**
  * Returns the styles for the given text range.
  * <p>
- * Returns an empty array if a LineStyleListener has been set. 
- * Should not be called if a LineStyleListener has been set since the 
+ * Returns an empty array if a LineStyleListener has been set.
+ * Should not be called if a LineStyleListener has been set since the
  * listener maintains the styles.
  * </p><p>
  * Note: Because the StyleRange includes the start and length, the
@@ -4388,10 +4512,10 @@
  * @param start the start offset of the style ranges to return
  * @param length the number of style ranges to return
  *
- * @return the styles or an empty array if a LineStyleListener has 
- *  been set.  The returned styles will reflect the given range.  The first 
- *  returned <code>StyleRange</code> will have a starting offset >= start 
- *  and the last returned <code>StyleRange</code> will have an ending 
+ * @return the styles or an empty array if a LineStyleListener has
+ *  been set.  The returned styles will reflect the given range.  The first
+ *  returned <code>StyleRange</code> will have a starting offset >= start
+ *  and the last returned <code>StyleRange</code> will have an ending
  *  offset <= start + length - 1
  *
  * @exception DWTException <ul>
@@ -4399,11 +4523,11 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li> 
- * </ul>
- * 
+ *   <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li>
+ * </ul>
+ *
  * @see #getStyleRanges(int, int, bool)
- * 
+ *
  * @since 3.0
  */
 public StyleRange[] getStyleRanges(int start, int length) {
@@ -4413,8 +4537,8 @@
 /**
  * Returns the styles for the given text range.
  * <p>
- * Returns an empty array if a LineStyleListener has been set. 
- * Should not be called if a LineStyleListener has been set since the 
+ * Returns an empty array if a LineStyleListener has been set.
+ * Should not be called if a LineStyleListener has been set since the
  * listener maintains the styles.
  * </p><p>
  * Note: When <code>includeRanges</code> is true, the start and length
@@ -4423,15 +4547,15 @@
  * false, <code>getRanges(int, int)</code> can be used to get the
  * associated ranges.
  * </p>
- * 
+ *
  * @param start the start offset of the style ranges to return
  * @param length the number of style ranges to return
  * @param includeRanges whether the start and length field of the StyleRanges should be set.
  *
- * @return the styles or an empty array if a LineStyleListener has 
- *  been set.  The returned styles will reflect the given range.  The first 
- *  returned <code>StyleRange</code> will have a starting offset >= start 
- *  and the last returned <code>StyleRange</code> will have an ending 
+ * @return the styles or an empty array if a LineStyleListener has
+ *  been set.  The returned styles will reflect the given range.  The first
+ *  returned <code>StyleRange</code> will have a starting offset >= start
+ *  and the last returned <code>StyleRange</code> will have an ending
  *  offset <= start + length - 1
  *
  * @exception DWTException <ul>
@@ -4439,11 +4563,11 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li> 
- * </ul>
- * 
+ *   <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li>
+ * </ul>
+ *
  * @since 3.2
- * 
+ *
  * @see #getRanges(int, int)
  * @see #setStyleRanges(int[], StyleRange[])
  */
@@ -4490,7 +4614,7 @@
  * Returns the widget content between the two offsets.
  *
  * @param start offset of the first character in the returned String
- * @param end offset of the last character in the returned String 
+ * @param end offset of the last character in the returned String
  * @return widget content starting at start and ending at end
  * @see #getTextRange(int,int)
  * @exception DWTException <ul>
@@ -4498,7 +4622,7 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li> 
+ *   <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li>
  * </ul>
  */
 public String getText(int start, int end) {
@@ -4513,20 +4637,20 @@
  * Returns the smallest bounding rectangle that includes the characters between two offsets.
  *
  * @param start offset of the first character included in the bounding box
- * @param end offset of the last character included in the bounding box 
+ * @param end offset of the last character included in the bounding box
  * @return bounding box of the text between start and end
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li> 
+ *   <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li>
  * </ul>
  * @since 3.1
  */
 public Rectangle getTextBounds(int start, int end) {
-    checkWidget();  
-    int contentLength = getCharCount(); 
+    checkWidget();
+    int contentLength = getCharCount();
     if (start < 0 || start >= contentLength || end < 0 || end >= contentLength || start > end) {
         DWT.error(DWT.ERROR_INVALID_RANGE);
     }
@@ -4537,9 +4661,9 @@
     int height = 0;
     int left = 0x7fffffff, right = 0;
     for (int i = lineStart; i <= lineEnd; i++) {
-        int lineOffset = content.getOffsetAtLine(i);        
+        int lineOffset = content.getOffsetAtLine(i);
         TextLayout layout = renderer.getTextLayout(i);
-        int length = layout.getText().length();
+        int length = layout.getText().length;
         if (length > 0) {
             if (i is lineStart) {
                 if (i is lineEnd) {
@@ -4569,14 +4693,14 @@
  * Returns the widget content starting at start for length characters.
  *
  * @param start offset of the first character in the returned String
- * @param length number of characters to return 
+ * @param length number of characters to return
  * @return widget content starting at start and extending length characters.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when start and/or length are outside the widget content</li> 
+ *   <li>ERROR_INVALID_RANGE when start and/or length are outside the widget content</li>
  * </ul>
  */
 public String getTextRange(int start, int length) {
@@ -4585,12 +4709,12 @@
     int end = start + length;
     if (start > end || start < 0 || end > contentLength) {
         DWT.error(DWT.ERROR_INVALID_RANGE);
-    }   
+    }
     return content.getTextRange(start, length);
 }
 /**
  * Returns the maximum number of characters that the receiver is capable of holding.
- * 
+ *
  * @return the text limit
  *
  * @exception DWTException <ul>
@@ -4605,8 +4729,8 @@
 /**
  * Gets the top index.
  * <p>
- * The top index is the index of the fully visible line that is currently 
- * at the top of the widget or the topmost partially visible line if no line is fully visible. 
+ * The top index is the index of the fully visible line that is currently
+ * at the top of the widget or the topmost partially visible line if no line is fully visible.
  * The top index changes when the widget is scrolled. Indexing is zero based.
  * </p>
  *
@@ -4623,10 +4747,10 @@
 /**
  * Gets the top pixel.
  * <p>
- * The top pixel is the pixel position of the line that is 
- * currently at the top of the widget. The text widget can be scrolled by pixels 
- * by dragging the scroll thumb so that a partial line may be displayed at the top 
- * the widget.  The top pixel changes when the widget is scrolled.  The top pixel 
+ * The top pixel is the pixel position of the line that is
+ * currently at the top of the widget. The text widget can be scrolled by pixels
+ * by dragging the scroll thumb so that a partial line may be displayed at the top
+ * the widget.  The top pixel changes when the widget is scrolled.  The top pixel
  * does not include the widget trimming.
  * </p>
  *
@@ -4640,7 +4764,7 @@
     checkWidget();
     return getVerticalScrollOffset();
 }
-/** 
+/**
  * Returns the vertical scroll increment.
  *
  * @return vertical scroll increment.
@@ -4679,12 +4803,12 @@
     int lineOffset = content.getOffsetAtLine(caretLine);
     String line = content.getLine(caretLine);
     int offset = caretOffset - lineOffset;
-    int lineLength = line.length();
+    int lineLength = line.length;
     if (lineLength is 0) return isMirrored() ? DWT.RIGHT : DWT.LEFT;
     if (caretAlignment is PREVIOUS_OFFSET_TRAILING && offset > 0) offset--;
     if (offset is lineLength && offset > 0) offset--;
-    while (offset > 0 && Character.isDigit(line.charAt(offset))) offset--;
-    if (offset is 0 && Character.isDigit(line.charAt(offset))) {
+    while (offset > 0 && tango.text.Unicode.isDigit(line[offset])) offset--;
+    if (offset is 0 && tango.text.Unicode.isDigit(line[offset])) {
         return isMirrored() ? DWT.RIGHT : DWT.LEFT;
     }
     TextLayout layout = renderer.getTextLayout(caretLine);
@@ -4717,7 +4841,7 @@
         int lineIndex = content.getLineAtOffset(offset);
         lineOffset = content.getOffsetAtLine(lineIndex);
         lineText = content.getLine(lineIndex);
-        int lineLength = lineText.length();
+        int lineLength = lineText.length;
         if (offset is lineOffset + lineLength) {
             newOffset = content.getOffsetAtLine(lineIndex + 1);
         } else {
@@ -4742,12 +4866,12 @@
         lineText = content.getLine(lineIndex);
         if (offset is lineOffset) {
             String nextLineText = content.getLine(lineIndex - 1);
-            int nextLineOffset = content.getOffsetAtLine(lineIndex - 1); 
-            newOffset = nextLineOffset + nextLineText.length();
+            int nextLineOffset = content.getOffsetAtLine(lineIndex - 1);
+            newOffset = nextLineOffset + nextLineText.length;
         } else {
             TextLayout layout = renderer.getTextLayout(lineIndex);
             newOffset = lineOffset + layout.getPreviousOffset(offset - lineOffset, movement);
-            renderer.disposeTextLayout(layout); 
+            renderer.disposeTextLayout(layout);
         }
     }
     return sendWordBoundaryEvent(WordPrevious, movement, offset, newOffset, lineText, lineOffset);
@@ -4762,7 +4886,7 @@
     checkWidget();
     return wordWrap;
 }
-/** 
+/**
  * Returns the location of the given offset.
  * <p>
  * <b>NOTE:</b> Does not return correct values for true italic fonts (vs. slanted fonts).
@@ -4775,7 +4899,7 @@
     String line = content.getLine(lineIndex);
     int lineOffset = content.getOffsetAtLine(lineIndex);
     int offsetInLine = offset - lineOffset;
-    int lineLength = line.length();
+    int lineLength = line.length;
     if (lineIndex < content.getLineCount() - 1) {
         int endLineOffset = content.getOffsetAtLine(lineIndex + 1) - 1;
         if (lineLength < offsetInLine && offsetInLine <= endLineOffset) {
@@ -4786,7 +4910,9 @@
     TextLayout layout = renderer.getTextLayout(lineIndex);
     if (lineLength !is 0  && offsetInLine <= lineLength) {
         if (offsetInLine is lineLength) {
-            point = layout.getLocation(offsetInLine - 1, true);
+            // DWT: Instead of go back one byte, go back one codepoint
+            int offsetInLine_m1 = layout.getPreviousOffset(offsetInLine, DWT.MOVEMENT_CLUSTER);
+            point = layout.getLocation(offsetInLine_m1, true);
         } else {
             switch (caretAlignment) {
                 case OFFSET_LEADING:
@@ -4797,7 +4923,9 @@
                     if (offsetInLine is 0) {
                         point = layout.getLocation(offsetInLine, false);
                     } else {
-                        point = layout.getLocation(offsetInLine - 1, true);
+                        // DWT: Instead of go back one byte, go back one codepoint
+                        int offsetInLine_m1 = layout.getPreviousOffset(offsetInLine, DWT.MOVEMENT_CLUSTER);
+                        point = layout.getLocation(offsetInLine_m1, true);
                     }
                     break;
             }
@@ -4810,32 +4938,30 @@
     point.y += getLinePixel(lineIndex);
     return point;
 }
-/** 
- * Inserts a String.  The old selection is replaced with the new text.  
- *
- * @param String the String
+/**
+ * Inserts a string.  The old selection is replaced with the new text.
+ *
+ * @param string the string
  * @see #replaceTextRange(int,int,String)
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * @exception IllegalArgumentException <ul>
- *    <li>ERROR_NULL_ARGUMENT when String is null</li>
- * </ul>
- */
-public void insert(String String) {
-    checkWidget();
-    if (String is null) {
-        DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    }
+ */
+public void insert(String string) {
+    checkWidget();
+    // DWT extension: allow null for zero length string
+//     if (string is null) {
+//         DWT.error(DWT.ERROR_NULL_ARGUMENT);
+//     }
     Point sel = getSelectionRange();
-    replaceTextRange(sel.x, sel.y, String);
+    replaceTextRange(sel.x, sel.y, string);
 }
 /**
  * Creates content change listeners and set the default content model.
  */
 void installDefaultContent() {
-    textChangeListener = new TextChangeListener() {
+    textChangeListener = new class() TextChangeListener {
         public void textChanging(TextChangingEvent event) {
             handleTextChanging(event);
         }
@@ -4849,14 +4975,14 @@
     content = new DefaultContent();
     content.addTextChangeListener(textChangeListener);
 }
-/** 
+/**
  * Adds event listeners
  */
 void installListeners() {
     ScrollBar verticalBar = getVerticalBar();
     ScrollBar horizontalBar = getHorizontalBar();
-    
-    listener = new Listener() {
+
+    listener = new class() Listener {
         public void handleEvent(Event event) {
             switch (event.type) {
                 case DWT.Dispose: handleDispose(event); break;
@@ -4868,8 +4994,9 @@
                 case DWT.Paint: handlePaint(event); break;
                 case DWT.Resize: handleResize(event); break;
                 case DWT.Traverse: handleTraverse(event); break;
+                default:
             }
-        }       
+        }
     };
     addListener(DWT.Dispose, listener);
     addListener(DWT.KeyDown, listener);
@@ -4880,24 +5007,25 @@
     addListener(DWT.Paint, listener);
     addListener(DWT.Resize, listener);
     addListener(DWT.Traverse, listener);
-    ime.addListener(DWT.ImeComposition, new Listener() {
+    ime.addListener(DWT.ImeComposition, new class() Listener {
         public void handleEvent(Event event) {
             switch (event.detail) {
                 case DWT.COMPOSITION_SELECTION: handleCompositionSelection(event); break;
                 case DWT.COMPOSITION_CHANGED: handleCompositionChanged(event); break;
                 case DWT.COMPOSITION_OFFSET: handleCompositionOffset(event); break;
+                default:
             }
         }
     });
     if (verticalBar !is null) {
-        verticalBar.addListener(DWT.Selection, new Listener() {
+        verticalBar.addListener(DWT.Selection, new class() Listener {
             public void handleEvent(Event event) {
                 handleVerticalScroll(event);
             }
         });
     }
     if (horizontalBar !is null) {
-        horizontalBar.addListener(DWT.Selection, new Listener() {
+        horizontalBar.addListener(DWT.Selection, new class() Listener {
             public void handleEvent(Event event) {
                 handleHorizontalScroll(event);
             }
@@ -4930,8 +5058,8 @@
     TextLayout layout = renderer.getTextLayout(startLine);
     int lineX = leftMargin - horizontalScrollOffset, startLineY = getLinePixel(startLine);
     int[] offsets = layout.getLineOffsets();
-    int startIndex = layout.getLineIndex(Math.min(start, layout.getText().length()));
-    
+    int startIndex = layout.getLineIndex(Math.min(start, layout.getText().length));
+
     /* Redraw end of line before start line if wrapped and start offset is first char */
     if (wordWrap && startIndex > 0 && offsets[startIndex] is start) {
         Rectangle rect = layout.getLineBounds(startIndex - 1);
@@ -4941,9 +5069,9 @@
         rect.y += startLineY;
         super.redraw(rect.x, rect.y, rect.width, rect.height, false);
     }
-    
+
     if (startLine is endLine) {
-        int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length()));
+        int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length));
         if (startIndex is endIndex) {
             /* Redraw rect between start and end offset if start and end offsets are in same wrapped line */
             Rectangle rect = layout.getBounds(start, end - 1);
@@ -4974,7 +5102,7 @@
         layout = renderer.getTextLayout(endLine);
         offsets = layout.getLineOffsets();
     }
-    int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length()));
+    int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length));
     Rectangle endRect = layout.getBounds(offsets[endIndex], end - 1);
     if (endRect.height is 0) {
         Rectangle bounds = layout.getLineBounds(endIndex);
@@ -5006,26 +5134,27 @@
     String text = event.text;
     int start = event.start;
     int end = event.end;
-    int length = text.length();
+    int length = text.length;
     if (length is ime.getCommitCount()) {
         content.replaceTextRange(start, end - start, "");
-        caretOffset = start;
+        caretOffset = ime.getCompositionOffset();
         caretWidth = 0;
         caretDirection = DWT.NULL;
     } else {
         content.replaceTextRange(start, end - start, text);
         caretOffset = ime.getCaretOffset();
         if (ime.getWideCaret()) {
+            start = ime.getCompositionOffset();
             int lineIndex = getCaretLine();
             int lineOffset = content.getOffsetAtLine(lineIndex);
-            TextLayout layout = renderer.getTextLayout(lineIndex);  
+            TextLayout layout = renderer.getTextLayout(lineIndex);
             caretWidth = layout.getBounds(start - lineOffset, start + length - 1 - lineOffset).width;
             renderer.disposeTextLayout(layout);
         }
     }
     showCaret();
 }
-/** 
+/**
  * Frees resources.
  */
 void handleDispose(Event event) {
@@ -5067,7 +5196,7 @@
     foreground = null;
     clipboard = null;
 }
-/** 
+/**
  * Scrolls the widget horizontally.
  */
 void handleHorizontalScroll(Event event) {
@@ -5101,35 +5230,35 @@
     }
     if (action is DWT.NULL) {
         bool ignore = false;
-        
+
         if (IS_CARBON) {
-            // Ignore accelerator key combinations (we do not want to 
-            // insert a character in the text in this instance). Do not  
+            // Ignore accelerator key combinations (we do not want to
+            // insert a character in the text in this instance). Do not
             // ignore COMMAND+ALT combinations since that key sequence
             // produces characters on the mac.
             ignore = (event.stateMask ^ DWT.COMMAND) is 0 ||
                     (event.stateMask ^ (DWT.COMMAND | DWT.SHIFT)) is 0;
         } else if (IS_MOTIF) {
-            // Ignore accelerator key combinations (we do not want to 
-            // insert a character in the text in this instance). Do not  
+            // Ignore accelerator key combinations (we do not want to
+            // insert a character in the text in this instance). Do not
             // ignore ALT combinations since this key sequence
             // produces characters on motif.
             ignore = (event.stateMask ^ DWT.CTRL) is 0 ||
                     (event.stateMask ^ (DWT.CTRL | DWT.SHIFT)) is 0;
         } else {
-            // Ignore accelerator key combinations (we do not want to 
-            // insert a character in the text in this instance). Don't  
-            // ignore CTRL+ALT combinations since that is the Alt Gr 
-            // key on some keyboards.  See bug 20953. 
-            ignore = (event.stateMask ^ DWT.ALT) is 0 || 
+            // Ignore accelerator key combinations (we do not want to
+            // insert a character in the text in this instance). Don't
+            // ignore CTRL+ALT combinations since that is the Alt Gr
+            // key on some keyboards.  See bug 20953.
+            ignore = (event.stateMask ^ DWT.ALT) is 0 ||
                     (event.stateMask ^ DWT.CTRL) is 0 ||
                     (event.stateMask ^ (DWT.ALT | DWT.SHIFT)) is 0 ||
                     (event.stateMask ^ (DWT.CTRL | DWT.SHIFT)) is 0;
         }
         // -ignore anything below SPACE except for line delimiter keys and tab.
-        // -ignore DEL 
-        if (!ignore && event.character > 31 && event.character !is DWT.DEL || 
-            event.character is DWT.CR || event.character is DWT.LF || 
+        // -ignore DEL
+        if (!ignore && event.character > 31 && event.character !is DWT.DEL ||
+            event.character is DWT.CR || event.character is DWT.LF ||
             event.character is TAB) {
             doContent(event.character);
             update();
@@ -5148,7 +5277,7 @@
     if (clipboardSelection is null) {
         clipboardSelection = new Point(selection.x, selection.y);
     }
-    
+
     Event verifyEvent = new Event();
     verifyEvent.character = event.character;
     verifyEvent.keyCode = event.keyCode;
@@ -5172,7 +5301,7 @@
                     setClipboardContent(selection.x, selection.y - selection.x, DND.SELECTION_CLIPBOARD);
                 }
             } catch (DWTError error) {
-                // Copy to clipboard failed. This happens when another application 
+                // Copy to clipboard failed. This happens when another application
                 // is accessing the clipboard while we copy. Ignore the error.
                 // Fixes 1GDQAVN
                 // Rethrow all other errors. Fixes bug 17578.
@@ -5184,21 +5313,22 @@
     }
     clipboardSelection = null;
 }
-/** 
- * Updates the caret location and selection if mouse button 1 has been 
+/**
+ * Updates the caret location and selection if mouse button 1 has been
  * pressed.
  */
 void handleMouseDown(Event event) {
     //force focus (object support)
     forceFocus();
-        
+
     //drag detect
-    if (dragDetect && checkDragDetect(event)) return;
-        
+    if (dragDetect_ && checkDragDetect(event)) return;
+
     //paste clipboard selection
     if (event.button is 2) {
-        String text = cast(String)getClipboardContent(DND.SELECTION_CLIPBOARD);
-        if (text !is null && text.length() > 0) {
+        auto o = cast(ArrayWrapperString)getClipboardContent(DND.SELECTION_CLIPBOARD);
+        String text = o.array;
+        if (text !is null && text.length > 0) {
             // position cursor
             doMouseLocationChange(event.x, event.y, false);
             // insert text
@@ -5209,10 +5339,10 @@
             sendKeyEvent(e);
         }
     }
-    
+
     //set selection
     if ((event.button !is 1) || (IS_CARBON && (event.stateMask & DWT.MOD4) !is 0)) {
-        return; 
+        return;
     }
     clickCount = event.count;
     if (clickCount is 1) {
@@ -5245,8 +5375,8 @@
         }
     }
 }
-/** 
- * Updates the caret location and selection if mouse button 1 is pressed 
+/**
+ * Updates the caret location and selection if mouse button 1 is pressed
  * during the mouse move.
  */
 void handleMouseMove(Event event) {
@@ -5255,7 +5385,7 @@
     update();
     doAutoScroll(event);
 }
-/** 
+/**
  * Autoscrolling ends when the mouse button is released.
  */
 void handleMouseUp(Event event) {
@@ -5267,7 +5397,7 @@
                 setClipboardContent(selection.x, selection.y - selection.x, DND.SELECTION_CLIPBOARD);
             }
         } catch (DWTError error) {
-            // Copy to clipboard failed. This happens when another application 
+            // Copy to clipboard failed. This happens when another application
             // is accessing the clipboard while we copy. Ignore the error.
             // Fixes 1GDQAVN
             // Rethrow all other errors. Fixes bug 17578.
@@ -5319,7 +5449,7 @@
     }
 }
 /**
- * Recalculates the scroll bars. Rewraps all lines when in word 
+ * Recalculates the scroll bars. Rewraps all lines when in word
  * wrap mode.
  *
  * @param event resize event
@@ -5333,13 +5463,13 @@
     /* Redraw the old or new right/bottom margin if needed */
     if (oldWidth !is clientAreaWidth) {
         if (rightMargin > 0) {
-            int x = (oldWidth < clientAreaWidth ? oldWidth : clientAreaWidth) - rightMargin; 
+            int x = (oldWidth < clientAreaWidth ? oldWidth : clientAreaWidth) - rightMargin;
             super.redraw(x, 0, rightMargin, oldHeight, false);
         }
     }
     if (oldHeight !is clientAreaHeight) {
         if (bottomMargin > 0) {
-            int y = (oldHeight < clientAreaHeight ? oldHeight : clientAreaHeight) - bottomMargin; 
+            int y = (oldHeight < clientAreaHeight ? oldHeight : clientAreaHeight) - bottomMargin;
             super.redraw(0, y, oldWidth, bottomMargin, false);
         }
     }
@@ -5378,10 +5508,14 @@
 //  }
 }
 /**
- * Updates the caret position and selection and the scroll bars to reflect 
+ * Updates the caret position and selection and the scroll bars to reflect
  * the content change.
  */
 void handleTextChanged(TextChangedEvent event) {
+    int offset = ime.getCompositionOffset();
+    if (offset !is -1 && lastTextChangeStart < offset) {
+        ime.setCompositionOffset(offset + lastTextChangeNewCharCount - lastTextChangeReplaceCharCount);
+    }
     int firstLine = content.getLineAtOffset(lastTextChangeStart);
     resetCache(firstLine, 0);
     if (!isFixedLineHeight() && topIndex > firstLine) {
@@ -5394,7 +5528,6 @@
         int newLastLineBottom = getLinePixel(lastLine + 1);
         if (lastLineBottom !is newLastLineBottom) {
             super.redraw();
-            if (wordWrap) setCaretLocation();
         } else {
             super.redraw(0, firstLineTop, clientAreaWidth, newLastLineBottom - firstLineTop, false);
             redrawLinesBullet(renderer.redrawLines);
@@ -5403,10 +5536,10 @@
     renderer.redrawLines = null;
     // update selection/caret location after styles have been changed.
     // otherwise any text measuring could be incorrect
-    // 
-    // also, this needs to be done after all scrolling. Otherwise, 
+    //
+    // also, this needs to be done after all scrolling. Otherwise,
     // selection redraw would be flushed during scroll which is wrong.
-    // in some cases new text would be drawn in scroll source area even 
+    // in some cases new text would be drawn in scroll source area even
     // though the intent is to scroll it.
     updateSelection(lastTextChangeStart, lastTextChangeReplaceCharCount, lastTextChangeNewCharCount);
     if (lastTextChangeReplaceLineCount > 0 || wordWrap) {
@@ -5420,7 +5553,7 @@
  * Updates the screen to reflect a pending content change.
  *
  * @param event .start the start offset of the change
- * @param event .newText text that is going to be inserted or empty String 
+ * @param event .newText text that is going to be inserted or empty String
  *  if no text will be inserted
  * @param event .replaceCharCount length of text that is going to be replaced
  * @param event .newCharCount length of text that is going to be inserted
@@ -5436,7 +5569,7 @@
     lastTextChangeNewLineCount = event.newLineCount;
     lastTextChangeNewCharCount = event.newCharCount;
     lastTextChangeReplaceLineCount = event.replaceLineCount;
-    lastTextChangeReplaceCharCount = event.replaceCharCount;    
+    lastTextChangeReplaceCharCount = event.replaceCharCount;
     int lineIndex = content.getLineAtOffset(event.start);
     int srcY = getLinePixel(lineIndex + event.replaceLineCount + 1);
     int destY = getLinePixel(lineIndex + 1) + event.newLineCount * renderer.getLineHeight();
@@ -5451,7 +5584,7 @@
     }
 
     renderer.textChanging(event);
-    
+
     // Update the caret offset if it is greater than the length of the content.
     // This is necessary since style range API may be called between the
     // handleTextChanging and handleTextChanged events and this API sets the
@@ -5460,20 +5593,20 @@
     if (caretOffset > newEndOfText) caretOffset = newEndOfText;
 }
 /**
- * Called when the widget content is set programmatically, overwriting 
- * the old content. Resets the caret position, selection and scroll offsets. 
+ * Called when the widget content is set programmatically, overwriting
+ * the old content. Resets the caret position, selection and scroll offsets.
  * Recalculates the content width and scroll bars. Redraws the widget.
  *
- * @param event text change event. 
+ * @param event text change event.
  */
 void handleTextSet(TextChangedEvent event) {
     reset();
 }
 /**
  * Called when a traversal key is pressed.
- * Allow tab next traversal to occur when the widget is in single 
- * line mode or in multi line and non-editable mode . 
- * When in editable multi line mode we want to prevent the tab 
+ * Allow tab next traversal to occur when the widget is in single
+ * line mode or in multi line and non-editable mode .
+ * When in editable multi line mode we want to prevent the tab
  * traversal and receive the tab key event instead.
  *
  * @param event the event
@@ -5496,9 +5629,10 @@
                 }
             }
             break;
-    }
-}
-/** 
+        default:
+    }
+}
+/**
  * Scrolls the widget vertically.
  */
 void handleVerticalScroll(Event event) {
@@ -5510,7 +5644,7 @@
  */
 void initializeAccessible() {
     final Accessible accessible = getAccessible();
-    accessible.addAccessibleListener(new AccessibleAdapter() {
+    accessible.addAccessibleListener(new class() AccessibleAdapter {
         public void getName (AccessibleEvent e) {
             String name = null;
             Label label = getAssociatedLabel ();
@@ -5528,26 +5662,26 @@
             if (label !is null) {
                 String text = label.getText ();
                 if (text !is null) {
-                    char mnemonic = _findMnemonic (text);
+                    dchar mnemonic = _findMnemonic (text);
                     if (mnemonic !is '\0') {
-                        shortcut = "Alt+"+mnemonic; //$NON-NLS-1$
+                        shortcut = "Alt+"~tango.text.convert.Utf.toString( [mnemonic] ); //$NON-NLS-1$
                     }
                 }
             }
             e.result = shortcut;
         }
     });
-    accessible.addAccessibleTextListener(new AccessibleTextAdapter() {
+    accessible.addAccessibleTextListener(new class() AccessibleTextAdapter {
         public void getCaretOffset(AccessibleTextEvent e) {
-            e.offset = StyledText.this.getCaretOffset();
+            e.offset = this.outer.getCaretOffset();
         }
         public void getSelectionRange(AccessibleTextEvent e) {
-            Point selection = StyledText.this.getSelectionRange();
+            Point selection = this.outer.getSelectionRange();
             e.offset = selection.x;
             e.length = selection.y;
         }
     });
-    accessible.addAccessibleControlListener(new AccessibleControlAdapter() {
+    accessible.addAccessibleControlListener(new class() AccessibleControlAdapter {
         public void getRole(AccessibleControlEvent e) {
             e.detail = ACC.ROLE_TEXT;
         }
@@ -5560,58 +5694,60 @@
             e.detail = state;
         }
         public void getValue(AccessibleControlEvent e) {
-            e.result = StyledText.this.getText();
-        }
-    }); 
-    addListener(DWT.FocusIn, new Listener() {
+            e.result = this.outer.getText();
+        }
+    });
+    addListener(DWT.FocusIn, new class(accessible) Listener {
+        Accessible acc;
+        this( Accessible acc ){ this.acc = acc; }
         public void handleEvent(Event event) {
-            accessible.setFocus(ACC.CHILDID_SELF);
-        }
-    }); 
-}
-/* 
- * Return the Label immediately preceding the receiver in the z-order, 
- * or null if none. 
+            acc.setFocus(ACC.CHILDID_SELF);
+        }
+    });
+}
+/*
+ * Return the Label immediately preceding the receiver in the z-order,
+ * or null if none.
  */
 Label getAssociatedLabel () {
     Control[] siblings = getParent ().getChildren ();
     for (int i = 0; i < siblings.length; i++) {
-        if (siblings [i] is StyledText.this) {
-            if (i > 0 && siblings [i-1] instanceof Label) {
+        if (siblings [i] is this) {
+            if (i > 0 && ( null !is cast(Label)siblings [i-1])) {
                 return cast(Label) siblings [i-1];
             }
         }
     }
     return null;
 }
-String stripMnemonic (String String) {
+String stripMnemonic (String string) {
     int index = 0;
-    int length = String.length ();
+    int length_ = string.length;
     do {
-        while ((index < length) && (String.charAt (index) !is '&')) index++;
-        if (++index >= length) return String;
-        if (String.charAt (index) !is '&') {
-            return String.substring(0, index-1) + String.substring(index, length);
+        while ((index < length_) && (string[index] !is '&')) index++;
+        if (++index >= length_) return string;
+        if (string[index] !is '&') {
+            return string.substring(0, index-1) ~ string.substring(index, length_);
         }
         index++;
-    } while (index < length);
-    return String;
+    } while (index < length_);
+    return string;
 }
 /*
  * Return the lowercase of the first non-'&' character following
- * an '&' character in the given String. If there are no '&'
- * characters in the given String, return '\0'.
- */
-char _findMnemonic (String String) {
-    if (String is null) return '\0';
+ * an '&' character in the given string. If there are no '&'
+ * characters in the given string, return '\0'.
+ */
+dchar _findMnemonic (String string) {
+    if (string is null) return '\0';
     int index = 0;
-    int length = String.length ();
+    int length_ = string.length;
     do {
-        while (index < length && String.charAt (index) !is '&') index++;
-        if (++index >= length) return '\0';
-        if (String.charAt (index) !is '&') return Character.toLowerCase (String.charAt (index));
+        while (index < length_ && string[index] !is '&') index++;
+        if (++index >= length_) return '\0';
+        if (string[index] !is '&') return CharacterFirstToLower(string[index .. $ ] );
         index++;
-    } while (index < length);
+    } while (index < length_);
     return '\0';
 }
 /**
@@ -5680,7 +5816,7 @@
             doPageEnd();
             clearSelection(true);
             break;
-        // Selection    
+        // Selection
         case ST.SELECT_LINE_UP:
             doSelectionLineUp();
             break;
@@ -5736,7 +5872,7 @@
             doPageEnd();
             doSelection(ST.COLUMN_NEXT);
             break;
-        // Modification         
+        // Modification
         case ST.CUT:
             cut();
             break;
@@ -5762,13 +5898,14 @@
         case ST.TOGGLE_OVERWRITE:
             overwrite = !overwrite;     // toggle insert/overwrite mode
             break;
+        default:
     }
 }
 /**
  * Temporary until DWT provides this
  */
 bool isBidi() {
-    return IS_GTK || IS_CARBON || BidiUtil.isBidiPlatform() || isMirrored;
+    return IS_GTK || IS_CARBON || BidiUtil.isBidiPlatform() || isMirrored_;
 }
 bool isBidiCaret() {
     return BidiUtil.isBidiPlatform();
@@ -5778,45 +5915,45 @@
 }
 /**
  * Returns whether the given offset is inside a multi byte line delimiter.
- * Example: 
+ * Example:
  * "Line1\r\n" isLineDelimiter(5) is false but isLineDelimiter(6) is true
- * 
+ *
  * @return true if the given offset is inside a multi byte line delimiter.
  * false if the given offset is before or after a line delimiter.
  */
 bool isLineDelimiter(int offset) {
     int line = content.getLineAtOffset(offset);
-    int lineOffset = content.getOffsetAtLine(line); 
+    int lineOffset = content.getOffsetAtLine(line);
     int offsetInLine = offset - lineOffset;
-    // offsetInLine will be greater than line length if the line 
+    // offsetInLine will be greater than line length if the line
     // delimiter is longer than one character and the offset is set
     // in between parts of the line delimiter.
-    return offsetInLine > content.getLine(line).length();
-}
-/**
- * Returns whether the widget is mirrored (right oriented/right to left 
- * writing order). 
- * 
- * @return isMirrored true=the widget is right oriented, false=the widget 
+    return offsetInLine > content.getLine(line).length;
+}
+/**
+ * Returns whether the widget is mirrored (right oriented/right to left
+ * writing order).
+ *
+ * @return isMirrored true=the widget is right oriented, false=the widget
  *  is left oriented
  */
 bool isMirrored() {
-    return isMirrored;
+    return isMirrored_;
 }
 /**
  * Returns whether the widget can have only one line.
  *
- * @return true if widget can have only one line, false if widget can have 
+ * @return true if widget can have only one line, false if widget can have
  *  multiple lines
  */
 bool isSingleLine() {
     return (getStyle() & DWT.SINGLE) !is 0;
 }
 /**
- * Sends the specified verify event, replace/insert text as defined by 
+ * Sends the specified verify event, replace/insert text as defined by
  * the event and send a modify event.
  *
- * @param event the text change event. 
+ * @param event the text change event.
  *  <ul>
  *  <li>event.start - the replace start offset</li>
  *  <li>event.end - the replace end offset</li>
@@ -5834,12 +5971,12 @@
         if (isListening(ExtendedModify)) {
             styledTextEvent = new StyledTextEvent(content);
             styledTextEvent.start = event.start;
-            styledTextEvent.end = event.start + event.text.length();
+            styledTextEvent.end = event.start + event.text.length;
             styledTextEvent.text = content.getTextRange(event.start, replacedLength);
         }
         if (updateCaret) {
             //Fix advancing flag for delete/backspace key on direction boundary
-            if (event.text.length() is 0) {
+            if (event.text.length is 0) {
                 int lineIndex = content.getLineAtOffset(event.start);
                 int lineOffset = content.getOffsetAtLine(lineIndex);
                 TextLayout layout = renderer.getTextLayout(lineIndex);
@@ -5864,7 +6001,7 @@
         // fixes 1GBB8NJ
         if (updateCaret) {
             // always update the caret location. fixes 1G8FODP
-            setSelection(event.start + event.text.length(), 0, true);
+            setSelection(event.start + event.text.length, 0, true);
             showCaret();
         }
         sendModifyEvent(event);
@@ -5887,10 +6024,10 @@
         notifyListeners(PaintObject, event);
     }
 }
-/** 
- * Replaces the selection with the text on the <code>DND.CLIPBOARD</code>  
- * clipboard  or, if there is no selection,  inserts the text at the current 
- * caret offset.   If the widget has the DWT.SINGLE style and the 
+/**
+ * Replaces the selection with the text on the <code>DND.CLIPBOARD</code>
+ * clipboard  or, if there is no selection,  inserts the text at the current
+ * caret offset.   If the widget has the DWT.SINGLE style and the
  * clipboard text contains more than one line, only the first line without
  * line delimiters is  inserted in the widget.
  *
@@ -5900,9 +6037,12 @@
  * </ul>
  */
 public void paste(){
-    checkWidget();  
-    String text = cast(String) getClipboardContent(DND.CLIPBOARD);
-    if (text !is null && text.length() > 0) {
+    checkWidget();
+    String text = null;
+    if( auto o = cast(ArrayWrapperString) getClipboardContent(DND.CLIPBOARD)){
+        text = o.array;
+    }
+    if (text !is null && text.length > 0) {
         Event event = new Event();
         event.start = selection.x;
         event.end = selection.y;
@@ -5910,7 +6050,7 @@
         sendKeyEvent(event);
     }
 }
-/** 
+/**
  * Prints the widget's text to the default printer.
  *
  * @exception DWTException <ul>
@@ -5925,18 +6065,21 @@
     options.printTextForeground = true;
     options.printTextBackground = true;
     options.printTextFontStyle = true;
-    options.printLineBackground = true; 
-    new Printing(this, printer, options).run();
+    options.printLineBackground = true;
+    (new Printing(this, printer, options)).run();
     printer.dispose();
 }
-/** 
+/**
  * Returns a runnable that will print the widget's text
  * to the specified printer.
  * <p>
  * The runnable may be run in a non-UI thread.
  * </p>
- * 
+ *
  * @param printer the printer to print to
+ *
+ * @return a <code>Runnable</code> for printing the receiver's text
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -5946,7 +6089,7 @@
  * </ul>
  */
 public Runnable print(Printer printer) {
-    checkWidget();  
+    checkWidget();
     if (printer is null) {
         DWT.error(DWT.ERROR_NULL_ARGUMENT);
     }
@@ -5957,15 +6100,18 @@
     options.printLineBackground = true;
     return print(printer, options);
 }
-/** 
+/**
  * Returns a runnable that will print the widget's text
  * to the specified printer.
  * <p>
  * The runnable may be run in a non-UI thread.
  * </p>
- * 
+ *
  * @param printer the printer to print to
  * @param options print options to use during printing
+ *
+ * @return a <code>Runnable</code> for printing the receiver's text
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -5988,8 +6134,8 @@
  * is processed, the control will be completely painted.
  * <p>
  * Recalculates the content width for all lines in the bounds.
- * When a <code>LineStyleListener</code> is used a redraw call 
- * is the only notification to the widget that styles have changed 
+ * When a <code>LineStyleListener</code> is used a redraw call
+ * is the only notification to the widget that styles have changed
  * and that the content width may have changed.
  * </p>
  *
@@ -6000,7 +6146,7 @@
  *
  * @see Control#update()
  */
-public void redraw() {
+public override void redraw() {
     super.redraw();
     int itemCount = getPartialBottomIndex() - topIndex + 1;
     renderer.reset(topIndex, itemCount);
@@ -6009,18 +6155,18 @@
 }
 /**
  * Causes the rectangular area of the receiver specified by
- * the arguments to be marked as needing to be redrawn. 
+ * the arguments to be marked as needing to be redrawn.
  * The next time a paint request is processed, that area of
  * the receiver will be painted. If the <code>all</code> flag
  * is <code>true</code>, any children of the receiver which
  * intersect with the specified area will also paint their
- * intersecting areas. If the <code>all</code> flag is 
+ * intersecting areas. If the <code>all</code> flag is
  * <code>false</code>, the children will not be painted.
  * <p>
  * Marks the content width of all lines in the specified rectangle
  * as unknown. Recalculates the content width of all visible lines.
- * When a <code>LineStyleListener</code> is used a redraw call 
- * is the only notification to the widget that styles have changed 
+ * When a <code>LineStyleListener</code> is used a redraw call
+ * is the only notification to the widget that styles have changed
  * and that the content width may have changed.
  * </p>
  *
@@ -6037,7 +6183,7 @@
  *
  * @see Control#update()
  */
-public void redraw(int x, int y, int width, int height, bool all) {
+public override void redraw(int x, int y, int width, int height, bool all) {
     super.redraw(x, y, width, height, all);
     if (height > 0) {
         int firstLine = getLineIndex(y);
@@ -6046,7 +6192,7 @@
     }
 }
 void redrawLines(int startLine, int lineCount) {
-    // do nothing if redraw range is completely invisible   
+    // do nothing if redraw range is completely invisible
     int partialBottomIndex = getPartialBottomIndex();
     if (startLine > partialBottomIndex || startLine + lineCount - 1 < topIndex) {
         return;
@@ -6062,7 +6208,7 @@
     startLine -= topIndex;
     int redrawTop = getLinePixel(startLine);
     int redrawBottom = getLinePixel(startLine + lineCount);
-    int redrawWidth = clientAreaWidth - leftMargin - rightMargin; 
+    int redrawWidth = clientAreaWidth - leftMargin - rightMargin;
     super.redraw(leftMargin, redrawTop, redrawWidth, redrawBottom - redrawTop, true);
 }
 void redrawLinesBullet (int[] redrawLines) {
@@ -6085,7 +6231,7 @@
         super.redraw(0, y, width, height, false);
     }
 }
-/** 
+/**
  * Redraws the specified text range.
  *
  * @param start offset of the first character to redraw
@@ -6093,20 +6239,20 @@
  * @param clearBackground true if the background should be cleared as
  *  part of the redraw operation.  If true, the entire redraw range will
  *  be cleared before anything is redrawn.  If the redraw range includes
- *  the last character of a line (i.e., the entire line is redrawn) the 
+ *  the last character of a line (i.e., the entire line is redrawn) the
  *  line is cleared all the way to the right border of the widget.
- *  The redraw operation will be faster and smoother if clearBackground 
- *  is set to false.  Whether or not the flag can be set to false depends 
- *  on the type of change that has taken place.  If font styles or 
- *  background colors for the redraw range have changed, clearBackground 
- *  should be set to true.  If only foreground colors have changed for 
- *  the redraw range, clearBackground can be set to false. 
+ *  The redraw operation will be faster and smoother if clearBackground
+ *  is set to false.  Whether or not the flag can be set to false depends
+ *  on the type of change that has taken place.  If font styles or
+ *  background colors for the redraw range have changed, clearBackground
+ *  should be set to true.  If only foreground colors have changed for
+ *  the redraw range, clearBackground can be set to false.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li> 
+ *   <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li>
  * </ul>
  */
 public void redrawRange(int start, int length, bool clearBackground) {
@@ -6124,7 +6270,8 @@
 /**
  * Removes the specified bidirectional segment listener.
  *
- * @param listener the listener
+ * @param listener the listener which should no longer be notified
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -6132,17 +6279,19 @@
  * @exception IllegalArgumentException <ul>
  *    <li>ERROR_NULL_ARGUMENT when listener is null</li>
  * </ul>
+ *
  * @since 2.0
  */
 public void removeBidiSegmentListener(BidiSegmentListener listener) {
     checkWidget();
     if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    removeListener(LineGetSegments, listener);  
+    removeListener(LineGetSegments, listener);
 }
 /**
  * Removes the specified extended modify listener.
  *
- * @param extendedModifyListener the listener
+ * @param extendedModifyListener the listener which should no longer be notified
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -6154,12 +6303,13 @@
 public void removeExtendedModifyListener(ExtendedModifyListener extendedModifyListener) {
     checkWidget();
     if (extendedModifyListener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    removeListener(ExtendedModify, extendedModifyListener); 
+    removeListener(ExtendedModify, extendedModifyListener);
 }
 /**
  * Removes the specified line background listener.
  *
- * @param listener the listener
+ * @param listener the listener which should no longer be notified
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -6176,7 +6326,8 @@
 /**
  * Removes the specified line style listener.
  *
- * @param listener the listener
+ * @param listener the listener which should no longer be notified
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -6193,7 +6344,8 @@
 /**
  * Removes the specified modify listener.
  *
- * @param modifyListener the listener
+ * @param modifyListener the listener which should no longer be notified
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -6210,7 +6362,8 @@
 /**
  * Removes the specified listener.
  *
- * @param listener the listener
+ * @param listener the listener which should no longer be notified
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -6250,7 +6403,8 @@
 /**
  * Removes the specified verify listener.
  *
- * @param verifyListener the listener
+ * @param verifyListener the listener which should no longer be notified
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -6267,7 +6421,8 @@
 /**
  * Removes the specified key verify listener.
  *
- * @param listener the listener
+ * @param listener the listener which should no longer be notified
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -6283,7 +6438,8 @@
 /**
  * Removes the specified word movement listener.
  *
- * @param listener the listener
+ * @param listener the listener which should no longer be notified
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -6291,24 +6447,24 @@
  * @exception IllegalArgumentException <ul>
  *    <li>ERROR_NULL_ARGUMENT when listener is null</li>
  * </ul>
- * 
+ *
  * @see MovementEvent
  * @see MovementListener
  * @see #addWordMovementListener
- * 
+ *
  * @since 3.3
  */
 
 public void removeWordMovementListener(MovementListener listener) {
     checkWidget();
     if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    removeListener(WordNext, listener); 
+    removeListener(WordNext, listener);
     removeListener(WordPrevious, listener);
 }
-/** 
+/**
  * Replaces the styles in the given range with new styles.  This method
  * effectively deletes the styles in the given range and then adds the
- * the new styles. 
+ * the new styles.
  * <p>
  * Note: Because a StyleRange includes the start and length, the
  * same instance cannot occur multiple times in the array of styles.
@@ -6316,14 +6472,14 @@
  * multiple StyleRanges, <code>setStyleRanges(int, int, int[], StyleRange[])</code>
  * can be used to share styles and reduce memory usage.
  * </p><p>
- * Should not be called if a LineStyleListener has been set since the 
+ * Should not be called if a LineStyleListener has been set since the
  * listener maintains the styles.
  * </p>
  *
  * @param start offset of first character where styles will be deleted
  * @param length length of the range to delete styles in
  * @param ranges StyleRange objects containing the new style information.
- * The ranges should not overlap and should be within the specified start 
+ * The ranges should not overlap and should be within the specified start
  * and length. The style rendering is undefined if the ranges do overlap
  * or are ill-defined. Must not be null.
  * @exception DWTException <ul>
@@ -6331,33 +6487,33 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when either start or end is outside the valid range (0 <= offset <= getCharCount())</li> 
- *   <li>ERROR_NULL_ARGUMENT when ranges is null</li>
- * </ul>
- * 
+ *   <li>ERROR_INVALID_RANGE when either start or end is outside the valid range (0 <= offset <= getCharCount())</li>
+ * </ul>
+ *
  * @since 2.0
- * 
+ *
  * @see #setStyleRanges(int, int, int[], StyleRange[])
  */
 public void replaceStyleRanges(int start, int length, StyleRange[] ranges) {
     checkWidget();
     if (isListening(LineGetStyle)) return;
-    if (ranges is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    // DWT extension: allow null for zero length string
+    //if (ranges is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     setStyleRanges(start, length, null, ranges, false);
 }
 /**
  * Replaces the given text range with new text.
- * If the widget has the DWT.SINGLE style and "text" contains more than 
- * one line, only the first line is rendered but the text is stored 
- * unchanged. A subsequent call to getText will return the same text 
- * that was set. Note that only a single line of text should be set when 
+ * If the widget has the DWT.SINGLE style and "text" contains more than
+ * one line, only the first line is rendered but the text is stored
+ * unchanged. A subsequent call to getText will return the same text
+ * that was set. Note that only a single line of text should be set when
  * the DWT.SINGLE style is used.
  * <p>
  * <b>NOTE:</b> During the replace operation the current selection is
  * changed as follows:
- * <ul> 
+ * <ul>
  * <li>selection before replaced text: selection unchanged
- * <li>selection after replaced text: adjust the selection so that same text 
+ * <li>selection after replaced text: adjust the selection so that same text
  * remains selected
  * <li>selection intersects replaced text: selection is cleared and caret
  * is placed after inserted text
@@ -6372,17 +6528,17 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when either start or end is outside the valid range (0 <= offset <= getCharCount())</li> 
- *   <li>ERROR_INVALID_ARGUMENT when either start or end is inside a multi byte line delimiter. 
- *      Splitting a line delimiter for example by inserting text in between the CR and LF and deleting part of a line delimiter is not supported</li>  
- *   <li>ERROR_NULL_ARGUMENT when String is null</li>
+ *   <li>ERROR_INVALID_RANGE when either start or end is outside the valid range (0 <= offset <= getCharCount())</li>
+ *   <li>ERROR_INVALID_ARGUMENT when either start or end is inside a multi byte line delimiter.
+ *      Splitting a line delimiter for example by inserting text in between the CR and LF and deleting part of a line delimiter is not supported</li>
  * </ul>
  */
 public void replaceTextRange(int start, int length, String text) {
     checkWidget();
-    if (text is null) {
-        DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    }
+    // DWT extension: allow null for zero length string
+//     if (text is null) {
+//         DWT.error(DWT.ERROR_NULL_ARGUMENT);
+//     }
     int contentLength = getCharCount();
     int end = start + length;
     if (start > end || start < 0 || end > contentLength) {
@@ -6405,14 +6561,14 @@
     topIndex = 0;
     topIndexY = 0;
     verticalScrollOffset = 0;
-    horizontalScrollOffset = 0; 
+    horizontalScrollOffset = 0;
     resetSelection();
     renderer.setContent(content);
     if (verticalBar !is null) {
         verticalBar.setSelection(0);
     }
     if (horizontalBar !is null) {
-        horizontalBar.setSelection(0);  
+        horizontalBar.setSelection(0);
     }
     resetCache(0, 0);
     setCaretLocation();
@@ -6441,7 +6597,7 @@
     selectionAnchor = -1;
 }
 
-public void scroll(int destX, int destY, int x, int y, int width, int height, bool all) {
+public override void scroll(int destX, int destY, int x, int y, int width, int height, bool all) {
     super.scroll(destX, destY, x, y, width, height, false);
     if (all) {
         int deltaX = destX - x, deltaY = destY - y;
@@ -6459,11 +6615,11 @@
  *
  * @param pixels number of pixels to scroll, > 0 = scroll left,
  *  < 0 scroll right
- * @param adjustScrollBar 
+ * @param adjustScrollBar
  *  true= the scroll thumb will be moved to reflect the new scroll offset.
  *  false = the scroll thumb will not be moved
- * @return 
- *  true=the widget was scrolled 
+ * @return
+ *  true=the widget was scrolled
  *  false=the widget was not scrolled, the given offset is not valid.
  */
 bool scrollHorizontal(int pixels, bool adjustScrollBar) {
@@ -6502,11 +6658,11 @@
  * Scrolls the widget vertically.
  *
  * @param pixel the new vertical scroll offset
- * @param adjustScrollBar 
+ * @param adjustScrollBar
  *  true= the scroll thumb will be moved to reflect the new scroll offset.
  *  false = the scroll thumb will not be moved
- * @return 
- *  true=the widget was scrolled 
+ * @return
+ *  true=the widget was scrolled
  *  false=the widget was not scrolled
  */
 bool scrollVertical(int pixels, bool adjustScrollBar) {
@@ -6574,7 +6730,7 @@
         super.redraw(leftMargin, clientAreaHeight - bottomMargin, scrollWidth, bottomMargin, false);
     }
 }
-/** 
+/**
  * Selects all the text.
  *
  * @exception DWTException <ul>
@@ -6589,7 +6745,7 @@
 /**
  * Replaces/inserts text as defined by the event.
  *
- * @param event the text change event. 
+ * @param event the text change event.
  *  <ul>
  *  <li>event.start - the replace start offset</li>
  *  <li>event.end - the replace end offset</li>
@@ -6602,19 +6758,19 @@
     }
 }
 /**
- * Returns a StyledTextEvent that can be used to request data such 
+ * Returns a StyledTextEvent that can be used to request data such
  * as styles and background color for a line.
  * <p>
- * The specified line may be a visual (wrapped) line if in word 
- * wrap mode. The returned object will always be for a logical 
+ * The specified line may be a visual (wrapped) line if in word
+ * wrap mode. The returned object will always be for a logical
  * (unwrapped) line.
  * </p>
  *
  * @param lineOffset offset of the line. This may be the offset of
  *  a visual line if the widget is in word wrap mode.
- * @param line line text. This may be the text of a visual line if 
+ * @param line line text. This may be the text of a visual line if
  *  the widget is in word wrap mode.
- * @return StyledTextEvent that can be used to request line data 
+ * @return StyledTextEvent that can be used to request line data
  *  for the given line.
  */
 StyledTextEvent sendLineEvent(int eventType, int lineOffset, String line) {
@@ -6632,14 +6788,14 @@
 }
 void sendModifyEvent(Event event) {
     Accessible accessible = getAccessible();
-    if (event.text.length() is 0) {
+    if (event.text.length is 0) {
         accessible.textChanged(ACC.TEXT_DELETE, event.start, event.end - event.start);
     } else {
         if (event.start is event.end) {
-            accessible.textChanged(ACC.TEXT_INSERT, event.start, event.text.length());
+            accessible.textChanged(ACC.TEXT_INSERT, event.start, event.text.length);
         } else {
             accessible.textChanged(ACC.TEXT_DELETE, event.start, event.end - event.start);
-            accessible.textChanged(ACC.TEXT_INSERT, event.start, event.text.length());  
+            accessible.textChanged(ACC.TEXT_INSERT, event.start, event.text.length);
         }
     }
     notifyListeners(DWT.Modify, event);
@@ -6681,22 +6837,22 @@
     return newOffset;
 }
 /**
- * Sets the alignment of the widget. The argument should be one of <code>DWT.LEFT</code>, 
+ * Sets the alignment of the widget. The argument should be one of <code>DWT.LEFT</code>,
  * <code>DWT.CENTER</code> or <code>DWT.RIGHT</code>. The alignment applies for all lines.
  * </p><p>
  * Note that if <code>DWT.MULTI</code> is set, then <code>DWT.WRAP</code> must also be set
  * in order to stabilize the right edge before setting alignment.
  * </p>
- * 
+ *
  * @param alignment the new alignment
- *  
- * @exception DWTException <ul>
- *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- * 
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
  * @see #setLineAlignment(int, int, int)
- *  
+ *
  * @since 3.2
  */
 public void setAlignment(int alignment) {
@@ -6711,7 +6867,7 @@
 /**
  * @see Control#setBackground(Color)
  */
-public void setBackground(Color color) {
+public override void setBackground(Color color) {
     checkWidget();
     background = color;
     super.setBackground(color);
@@ -6719,7 +6875,7 @@
 }
 /**
  * Sets the receiver's caret.  Set the caret's height and location.
- * 
+ *
  * </p>
  * @param caret the new caret for the receiver
  *
@@ -6728,7 +6884,7 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  */
-public void setCaret(Caret caret) {
+public override void setCaret(Caret caret) {
     checkWidget ();
     super.setCaret(caret);
     caretDirection = DWT.NULL;
@@ -6746,7 +6902,7 @@
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @deprecated use BidiSegmentListener instead.
  */
 public void setBidiColoring(bool mode) {
@@ -6818,7 +6974,7 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a 
+ *   <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a
  * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter)
  * </ul>
  */
@@ -6832,7 +6988,7 @@
             caretOffset = length;
         } else {
             if (isLineDelimiter(offset)) {
-                // offset is inside a multi byte line delimiter. This is an 
+                // offset is inside a multi byte line delimiter. This is an
                 // illegal operation and an exception is thrown. Fixes 1GDKK3R
                 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
             }
@@ -6844,14 +7000,14 @@
         clearSelection(false);
     }
     setCaretLocation();
-}   
+}
 /**
  * Copies the specified text range to the clipboard.  The text will be placed
  * in the clipboard in plain text format and RTF format.
  *
  * @param start start index of the text
  * @param length length of text to place in clipboard
- * 
+ *
  * @exception DWTError, see Clipboard.setContents
  * @see dwt.dnd.Clipboard#setContents
  */
@@ -6863,14 +7019,14 @@
     Object[] data;
     Transfer[] types;
     if (clipboardType is DND.SELECTION_CLIPBOARD) {
-        data = new Object[]{plainText};
-        types = new Transfer[]{plainTextTransfer};
+        data = [ cast(Object) new ArrayWrapperString(plainText) ];
+        types = [plainTextTransfer];
     } else {
         RTFTransfer rtfTransfer = RTFTransfer.getInstance();
         RTFWriter rtfWriter = new RTFWriter(start, length);
         String rtfText = getPlatformDelimitedText(rtfWriter);
-        data = new Object[]{rtfText, plainText};
-        types = new Transfer[]{rtfTransfer, plainTextTransfer};
+        data = [ cast(Object) new ArrayWrapperString(rtfText), new ArrayWrapperString(plainText) ];
+        types = [ cast(Transfer)rtfTransfer, plainTextTransfer];
     }
     clipboard.setContents(data, types, clipboardType);
 }
@@ -6887,7 +7043,7 @@
  * </ul>
  */
 public void setContent(StyledTextContent newContent) {
-    checkWidget();  
+    checkWidget();
     if (newContent is null) {
         DWT.error(DWT.ERROR_NULL_ARGUMENT);
     }
@@ -6900,12 +7056,12 @@
 }
 /**
  * Sets the receiver's cursor to the cursor specified by the
- * argument.  Overridden to handle the null case since the 
+ * argument.  Overridden to handle the null case since the
  * StyledText widget uses an ibeam as its default cursor.
  *
  * @see Control#setCursor(Cursor)
  */
-public void setCursor (Cursor cursor) {
+public override void setCursor (Cursor cursor) {
     if (cursor is null) {
         Display display = getDisplay();
         super.setCursor(display.getSystemCursor(DWT.CURSOR_IBEAM));
@@ -6913,7 +7069,7 @@
         super.setCursor(cursor);
     }
 }
-/** 
+/**
  * Sets whether the widget : double click mouse behavior.
  * </p>
  *
@@ -6928,15 +7084,15 @@
     checkWidget();
     doubleClickEnabled = enable;
 }
-public void setDragDetect (bool dragDetect) {
+public override void setDragDetect (bool dragDetect_) {
     checkWidget ();
-    this.dragDetect = dragDetect;
+    this.dragDetect_ = dragDetect_;
 }
 /**
  * Sets whether the widget content can be edited.
  * </p>
  *
- * @param editable if true content can be edited, if false content can not be 
+ * @param editable if true content can be edited, if false content can not be
  *  edited
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
@@ -6960,10 +7116,10 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  */
-public void setFont(Font font) {
+public override void setFont(Font font) {
     checkWidget();
     int oldLineHeight = renderer.getLineHeight();
-    super.setFont(font);    
+    super.setFont(font);
     renderer.setFont(getFont(), tabLength);
     // keep the same top line visible. fixes 5815
     if (isFixedLineHeight()) {
@@ -6974,32 +7130,29 @@
         }
     }
     resetCache(0, content.getLineCount());
-    claimBottomFreeSpace(); 
+    claimBottomFreeSpace();
     calculateScrollBars();
     if (isBidiCaret()) createCaretBitmaps();
     caretDirection = DWT.NULL;
     setCaretLocation();
     super.redraw();
 }
-/**
- * @see dwt.widgets.Control#setForeground
- */
-public void setForeground(Color color) {
+public override void setForeground(Color color) {
     checkWidget();
     foreground = color;
     super.setForeground(getForeground());
     super.redraw();
 }
-/** 
+/**
  * Sets the horizontal scroll offset relative to the start of the line.
  * Do nothing if there is no text set.
  * <p>
- * <b>NOTE:</b> The horizontal index is reset to 0 when new text is set in the 
+ * <b>NOTE:</b> The horizontal index is reset to 0 when new text is set in the
  * widget.
  * </p>
  *
- * @param offset horizontal scroll offset relative to the start 
- *  of the line, measured in character increments starting at 0, if 
+ * @param offset horizontal scroll offset relative to the start
+ *  of the line, measured in character increments starting at 0, if
  *  equal to 0 the content is not scrolled, if > 0 = the content is scrolled.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
@@ -7010,14 +7163,14 @@
     checkWidget();
     if (getCharCount() is 0) {
         return;
-    }   
+    }
     if (offset < 0) {
         offset = 0;
     }
     offset *= getHorizontalIncrement();
-    // allow any value if client area width is unknown or 0. 
+    // allow any value if client area width is unknown or 0.
     // offset will be checked in resize handler.
-    // don't use isVisible since width is known even if widget 
+    // don't use isVisible since width is known even if widget
     // is temporarily invisible
     if (clientAreaWidth > 0) {
         int width = renderer.getWidth();
@@ -7030,15 +7183,15 @@
     }
     scrollHorizontal(offset - horizontalScrollOffset, true);
 }
-/** 
+/**
  * Sets the horizontal pixel offset relative to the start of the line.
  * Do nothing if there is no text set.
  * <p>
- * <b>NOTE:</b> The horizontal pixel offset is reset to 0 when new text 
+ * <b>NOTE:</b> The horizontal pixel offset is reset to 0 when new text
  * is set in the widget.
  * </p>
  *
- * @param pixel horizontal pixel offset relative to the start 
+ * @param pixel horizontal pixel offset relative to the start
  *  of the line.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
@@ -7050,13 +7203,13 @@
     checkWidget();
     if (getCharCount() is 0) {
         return;
-    }   
+    }
     if (pixel < 0) {
         pixel = 0;
     }
-    // allow any value if client area width is unknown or 0. 
+    // allow any value if client area width is unknown or 0.
     // offset will be checked in resize handler.
-    // don't use isVisible since width is known even if widget 
+    // don't use isVisible since width is known even if widget
     // is temporarily invisible
     if (clientAreaWidth > 0) {
         int width = renderer.getWidth();
@@ -7072,19 +7225,19 @@
 /**
  * Sets the line indentation of the widget.
  * <p>
- * It is the amount of blank space, in pixels, at the beginning of each line. 
- * When a line wraps in several lines only the first one is indented. 
+ * It is the amount of blank space, in pixels, at the beginning of each line.
+ * When a line wraps in several lines only the first one is indented.
  * </p>
- * 
+ *
  * @param indent the new indent
- *  
- * @exception DWTException <ul>
- *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- * 
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
  * @see #setLineIndent(int, int, int)
- *  
+ *
  * @since 3.2
  */
 public void setIndent(int indent) {
@@ -7093,20 +7246,20 @@
     this.indent = indent;
     resetCache(0, content.getLineCount());
     setCaretLocation();
-    super.redraw(); 
-}
-/**
- * Sets whether the widget should justify lines.  
- * 
+    super.redraw();
+}
+/**
+ * Sets whether the widget should justify lines.
+ *
  * @param justify whether lines should be justified
- *  
- * @exception DWTException <ul>
- *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- * 
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
  * @see #setLineJustify(int, int, bool)
- *  
+ *
  * @since 3.2
  */
 public void setJustify(bool justify) {
@@ -7115,21 +7268,21 @@
     this.justify = justify;
     resetCache(0, content.getLineCount());
     setCaretLocation();
-    super.redraw(); 
-}
-/** 
+    super.redraw();
+}
+/**
  * Maps a key to an action.
  * <p>
- * One action can be associated with N keys. However, each key can only 
+ * One action can be associated with N keys. However, each key can only
  * have one action (key:action is N:1 relation).
  * </p>
  *
- * @param key a key code defined in DWT.java or a character. 
+ * @param key a key code defined in DWT.java or a character.
  *  Optionally ORd with a state mask.  Preferred state masks are one or more of
- *  DWT.MOD1, DWT.MOD2, DWT.MOD3, since these masks account for modifier platform 
+ *  DWT.MOD1, DWT.MOD2, DWT.MOD3, since these masks account for modifier platform
  *  differences.  However, there may be cases where using the specific state masks
  *  (i.e., DWT.CTRL, DWT.SHIFT, DWT.ALT, DWT.COMMAND) makes sense.
- * @param action one of the predefined actions defined in ST.java. 
+ * @param action one of the predefined actions defined in ST.java.
  *  Use DWT.NULL to remove a key binding.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
@@ -7139,58 +7292,58 @@
 public void setKeyBinding(int key, int action) {
     checkWidget();
     int modifierValue = key & DWT.MODIFIER_MASK;
-    char keyChar = cast(wchar)(key & DWT.KEY_MASK);
+    char keyChar = cast(char)(key & DWT.KEY_MASK);
     if (Compatibility.isLetter(keyChar)) {
         // make the keybinding case insensitive by adding it
         // in its upper and lower case form
-        char ch = Character.toUpperCase(keyChar);
+        char ch = CharacterToUpper(keyChar);
         int newKey = ch | modifierValue;
         if (action is DWT.NULL) {
-            keyActionMap.remove(new Integer(newKey));
+            keyActionMap.remove(newKey);
         } else {
-            keyActionMap.put(new Integer(newKey), new Integer(action));
-        }
-        ch = Character.toLowerCase(keyChar);
+            keyActionMap[newKey] = action;
+        }
+        ch = CharacterToLower(keyChar);
         newKey = ch | modifierValue;
         if (action is DWT.NULL) {
-            keyActionMap.remove(new Integer(newKey));
+            keyActionMap.remove(newKey);
         } else {
-            keyActionMap.put(new Integer(newKey), new Integer(action));
+            keyActionMap[newKey] = action;
         }
     } else {
         if (action is DWT.NULL) {
-            keyActionMap.remove(new Integer(key));
+            keyActionMap.remove(key);
         } else {
-            keyActionMap.put(new Integer(key), new Integer(action));
-        }
-    }       
-}
-/**
- * Sets the alignment of the specified lines. The argument should be one of <code>DWT.LEFT</code>, 
+            keyActionMap[key]=action;
+        }
+    }
+}
+/**
+ * Sets the alignment of the specified lines. The argument should be one of <code>DWT.LEFT</code>,
  * <code>DWT.CENTER</code> or <code>DWT.RIGHT</code>.
  * <p><p>
  * Note that if <code>DWT.MULTI</code> is set, then <code>DWT.WRAP</code> must also be set
  * in order to stabilize the right edge before setting alignment.
  * </p>
- * Should not be called if a LineStyleListener has been set since the listener 
+ * Should not be called if a LineStyleListener has been set since the listener
  * maintains the line attributes.
  * </p><p>
- * All line attributes are maintained relative to the line text, not the 
+ * All line attributes are maintained relative to the line text, not the
  * line index that is specified in this method call.
- * During text changes, when entire lines are inserted or removed, the line 
- * attributes that are associated with the lines after the change 
- * will "move" with their respective text. An entire line is defined as 
- * extending from the first character on a line to the last and including the 
- * line delimiter. 
+ * During text changes, when entire lines are inserted or removed, the line
+ * attributes that are associated with the lines after the change
+ * will "move" with their respective text. An entire line is defined as
+ * extending from the first character on a line to the last and including the
+ * line delimiter.
  * </p><p>
- * When two lines are joined by deleting a line delimiter, the top line 
- * attributes take precedence and the attributes of the bottom line are deleted. 
- * For all other text changes line attributes will remain unchanged. 
- *   
+ * When two lines are joined by deleting a line delimiter, the top line
+ * attributes take precedence and the attributes of the bottom line are deleted.
+ * For all other text changes line attributes will remain unchanged.
+ *
  * @param startLine first line the alignment is applied to, 0 based
  * @param lineCount number of lines the alignment applies to.
  * @param alignment line alignment
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -7216,30 +7369,30 @@
         setCaretLocation();
     }
 }
-/** 
+/**
  * Sets the background color of the specified lines.
  * <p>
  * The background color is drawn for the width of the widget. All
  * line background colors are discarded when setText is called.
- * The text background color if defined in a StyleRange overlays the 
- * line background color. 
+ * The text background color if defined in a StyleRange overlays the
+ * line background color.
  * </p><p>
- * Should not be called if a LineBackgroundListener has been set since the 
+ * Should not be called if a LineBackgroundListener has been set since the
  * listener maintains the line backgrounds.
  * </p><p>
- * All line attributes are maintained relative to the line text, not the 
+ * All line attributes are maintained relative to the line text, not the
  * line index that is specified in this method call.
- * During text changes, when entire lines are inserted or removed, the line 
- * attributes that are associated with the lines after the change 
- * will "move" with their respective text. An entire line is defined as 
- * extending from the first character on a line to the last and including the 
- * line delimiter. 
+ * During text changes, when entire lines are inserted or removed, the line
+ * attributes that are associated with the lines after the change
+ * will "move" with their respective text. An entire line is defined as
+ * extending from the first character on a line to the last and including the
+ * line delimiter.
  * </p><p>
- * When two lines are joined by deleting a line delimiter, the top line 
- * attributes take precedence and the attributes of the bottom line are deleted. 
- * For all other text changes line attributes will remain unchanged. 
+ * When two lines are joined by deleting a line delimiter, the top line
+ * attributes take precedence and the attributes of the bottom line are deleted.
+ * For all other text changes line attributes will remain unchanged.
  * </p>
- * 
+ *
  * @param startLine first line the color is applied to, 0 based
  * @param lineCount number of lines the color applies to.
  * @param background line background color
@@ -7252,7 +7405,7 @@
  * </ul>
  */
 public void setLineBackground(int startLine, int lineCount, Color background) {
-    checkWidget();  
+    checkWidget();
     if (isListening(LineGetBackground)) return;
     if (startLine < 0 || startLine + lineCount > content.getLineCount()) {
         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
@@ -7267,26 +7420,26 @@
 /**
  * Sets the bullet of the specified lines.
  * <p>
- * Should not be called if a LineStyleListener has been set since the listener 
+ * Should not be called if a LineStyleListener has been set since the listener
  * maintains the line attributes.
  * </p><p>
- * All line attributes are maintained relative to the line text, not the 
+ * All line attributes are maintained relative to the line text, not the
  * line index that is specified in this method call.
- * During text changes, when entire lines are inserted or removed, the line 
- * attributes that are associated with the lines after the change 
- * will "move" with their respective text. An entire line is defined as 
- * extending from the first character on a line to the last and including the 
- * line delimiter. 
+ * During text changes, when entire lines are inserted or removed, the line
+ * attributes that are associated with the lines after the change
+ * will "move" with their respective text. An entire line is defined as
+ * extending from the first character on a line to the last and including the
+ * line delimiter.
  * </p><p>
- * When two lines are joined by deleting a line delimiter, the top line 
- * attributes take precedence and the attributes of the bottom line are deleted. 
+ * When two lines are joined by deleting a line delimiter, the top line
+ * attributes take precedence and the attributes of the bottom line are deleted.
  * For all other text changes line attributes will remain unchanged.
  * </p>
  *
  * @param startLine first line the bullet is applied to, 0 based
  * @param lineCount number of lines the bullet applies to.
  * @param bullet line bullet
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -7298,7 +7451,7 @@
  */
 public void setLineBullet(int startLine, int lineCount, Bullet bullet) {
     checkWidget();
-    if (isListening(LineGetStyle)) return;  
+    if (isListening(LineGetStyle)) return;
     if (startLine < 0 || startLine + lineCount > content.getLineCount()) {
         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     }
@@ -7319,26 +7472,26 @@
 /**
  * Sets the indent of the specified lines.
  * <p>
- * Should not be called if a LineStyleListener has been set since the listener 
+ * Should not be called if a LineStyleListener has been set since the listener
  * maintains the line attributes.
  * </p><p>
- * All line attributes are maintained relative to the line text, not the 
+ * All line attributes are maintained relative to the line text, not the
  * line index that is specified in this method call.
- * During text changes, when entire lines are inserted or removed, the line 
- * attributes that are associated with the lines after the change 
- * will "move" with their respective text. An entire line is defined as 
- * extending from the first character on a line to the last and including the 
- * line delimiter. 
+ * During text changes, when entire lines are inserted or removed, the line
+ * attributes that are associated with the lines after the change
+ * will "move" with their respective text. An entire line is defined as
+ * extending from the first character on a line to the last and including the
+ * line delimiter.
  * </p><p>
- * When two lines are joined by deleting a line delimiter, the top line 
- * attributes take precedence and the attributes of the bottom line are deleted. 
+ * When two lines are joined by deleting a line delimiter, the top line
+ * attributes take precedence and the attributes of the bottom line are deleted.
  * For all other text changes line attributes will remain unchanged.
  * </p>
  *
  * @param startLine first line the indent is applied to, 0 based
  * @param lineCount number of lines the indent applies to.
  * @param indent line indent
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -7367,26 +7520,26 @@
 /**
  * Sets the justify of the specified lines.
  * <p>
- * Should not be called if a LineStyleListener has been set since the listener 
+ * Should not be called if a LineStyleListener has been set since the listener
  * maintains the line attributes.
  * </p><p>
- * All line attributes are maintained relative to the line text, not the 
+ * All line attributes are maintained relative to the line text, not the
  * line index that is specified in this method call.
- * During text changes, when entire lines are inserted or removed, the line 
- * attributes that are associated with the lines after the change 
- * will "move" with their respective text. An entire line is defined as 
- * extending from the first character on a line to the last and including the 
- * line delimiter. 
+ * During text changes, when entire lines are inserted or removed, the line
+ * attributes that are associated with the lines after the change
+ * will "move" with their respective text. An entire line is defined as
+ * extending from the first character on a line to the last and including the
+ * line delimiter.
  * </p><p>
- * When two lines are joined by deleting a line delimiter, the top line 
- * attributes take precedence and the attributes of the bottom line are deleted. 
+ * When two lines are joined by deleting a line delimiter, the top line
+ * attributes take precedence and the attributes of the bottom line are deleted.
  * For all other text changes line attributes will remain unchanged.
  * </p>
- *  
+ *
  * @param startLine first line the justify is applied to, 0 based
  * @param lineCount number of lines the justify applies to.
  * @param justify true if lines should be justified
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -7414,7 +7567,7 @@
 }
 /**
  * Sets the line spacing of the widget. The line spacing applies for all lines.
- * 
+ *
  * @param lineSpacing the line spacing
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
@@ -7425,7 +7578,7 @@
 public void setLineSpacing(int lineSpacing) {
     checkWidget();
     if (this.lineSpacing is lineSpacing || lineSpacing < 0) return;
-    this.lineSpacing = lineSpacing; 
+    this.lineSpacing = lineSpacing;
     setVariableLineHeight();
     resetCache(0, content.getLineCount());
     setCaretLocation();
@@ -7456,43 +7609,43 @@
  * of the constants <code>DWT.LEFT_TO_RIGHT</code> or <code>DWT.RIGHT_TO_LEFT</code>.
  *
  * @param orientation new orientation style
- * 
- * @exception DWTException <ul>
- *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
- *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
- * </ul>
- * 
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
  * @since 2.1.2
  */
 public void setOrientation(int orientation) {
-    if ((orientation & (DWT.RIGHT_TO_LEFT | DWT.LEFT_TO_RIGHT)) is 0) { 
+    if ((orientation & (DWT.RIGHT_TO_LEFT | DWT.LEFT_TO_RIGHT)) is 0) {
         return;
     }
     if ((orientation & DWT.RIGHT_TO_LEFT) !is 0 && (orientation & DWT.LEFT_TO_RIGHT) !is 0) {
-        return; 
+        return;
     }
     if ((orientation & DWT.RIGHT_TO_LEFT) !is 0 && isMirrored()) {
-        return; 
-    } 
+        return;
+    }
     if ((orientation & DWT.LEFT_TO_RIGHT) !is 0 && !isMirrored()) {
         return;
     }
     if (!BidiUtil.setOrientation(this, orientation)) {
         return;
     }
-    isMirrored = (orientation & DWT.RIGHT_TO_LEFT) !is 0;
+    isMirrored_ = (orientation & DWT.RIGHT_TO_LEFT) !is 0;
     caretDirection = DWT.NULL;
     resetCache(0, content.getLineCount());
     setCaretLocation();
-    keyActionMap.clear();
+    keyActionMap = null;
     createKeyBindings();
     super.redraw();
 }
 /**
- * Adjusts the maximum and the page size of the scroll bars to 
+ * Adjusts the maximum and the page size of the scroll bars to
  * reflect content width/length changes.
- * 
- * @param vertical indicates if the vertical scrollbar also needs to be set 
+ *
+ * @param vertical indicates if the vertical scrollbar also needs to be set
  */
 void setScrollBars(bool vertical) {
     int inactive = 1;
@@ -7500,7 +7653,7 @@
         ScrollBar verticalBar = getVerticalBar();
         if (verticalBar !is null) {
             int maximum = renderer.getHeight();
-            // only set the real values if the scroll bar can be used 
+            // only set the real values if the scroll bar can be used
             // (ie. because the thumb size is less than the scroll maximum)
             // avoids flashing on Motif, fixes 1G7RE1J and 1G5SE92
             if (clientAreaHeight < maximum) {
@@ -7521,7 +7674,7 @@
     ScrollBar horizontalBar = getHorizontalBar();
     if (horizontalBar !is null && horizontalBar.getVisible()) {
         int maximum = renderer.getWidth();
-        // only set the real values if the scroll bar can be used 
+        // only set the real values if the scroll bar can be used
         // (ie. because the thumb size is less than the scroll maximum)
         // avoids flashing on Motif, fixes 1G7RE1J and 1G5SE92
         if (clientAreaWidth < maximum) {
@@ -7539,7 +7692,7 @@
         }
     }
 }
-/** 
+/**
  * Sets the selection to the given position and scrolls it into view.  Equivalent to setSelection(start,start).
  *
  * @param start new caret position
@@ -7549,19 +7702,19 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a 
+ *   <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a
  * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter)
- * </ul> 
+ * </ul>
  */
 public void setSelection(int start) {
-    // checkWidget test done in setSelectionRange   
+    // checkWidget test done in setSelectionRange
     setSelection(start, start);
 }
-/** 
+/**
  * Sets the selection and scrolls it into view.
  * <p>
  * Indexing is zero based.  Text selections are specified in terms of
- * caret positions.  In a text widget that contains N characters, there are 
+ * caret positions.  In a text widget that contains N characters, there are
  * N+1 caret positions, ranging from 0..N
  * </p>
  *
@@ -7574,13 +7727,13 @@
  * </ul>
  * @exception IllegalArgumentException <ul>
  *   <li>ERROR_NULL_ARGUMENT when point is null</li>
- *   <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a 
+ *   <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a
  * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter)
- * </ul> 
+ * </ul>
  */
 public void setSelection(Point point) {
     checkWidget();
-    if (point is null) DWT.error (DWT.ERROR_NULL_ARGUMENT); 
+    if (point is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
     setSelection(point.x, point.y);
 }
 /**
@@ -7591,7 +7744,7 @@
  * @param color the new color (or null)
  *
  * @exception IllegalArgumentException <ul>
- *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> 
+ *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
  * </ul>
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
@@ -7610,7 +7763,7 @@
 /**
  * Sets the receiver's selection foreground color to the color specified
  * by the argument, or to the default system color for the control
- * if the argument is null. 
+ * if the argument is null.
  * <p>
  * Note that this is a <em>HINT</em>. Some platforms do not allow the application
  * to change the selection foreground color.
@@ -7618,7 +7771,7 @@
  * @param color the new color (or null)
  *
  * @exception IllegalArgumentException <ul>
- *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> 
+ *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
  * </ul>
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
@@ -7634,15 +7787,15 @@
     selectionForeground = color;
     super.redraw();
 }
-/** 
+/**
  * Sets the selection and scrolls it into view.
  * <p>
  * Indexing is zero based.  Text selections are specified in terms of
- * caret positions.  In a text widget that contains N characters, there are 
+ * caret positions.  In a text widget that contains N characters, there are
  * N+1 caret positions, ranging from 0..N
  * </p>
  *
- * @param start selection start offset. The caret will be placed at the 
+ * @param start selection start offset. The caret will be placed at the
  *  selection start when start > end.
  * @param end selection end offset
  * @see #setSelectionRange(int,int)
@@ -7651,7 +7804,7 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a 
+ *   <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a
  * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter)
  * </ul>
  */
@@ -7659,31 +7812,33 @@
     setSelectionRange(start, end - start);
     showSelection();
 }
-/** 
+/**
  * Sets the selection.
  * <p>
- * The new selection may not be visible. Call showSelection to scroll 
+ * The new selection may not be visible. Call showSelection to scroll
  * the selection into view.
  * </p>
  *
  * @param start offset of the first selected character, start >= 0 must be true.
- * @param length number of characters to select, 0 <= start + length 
- *  <= getCharCount() must be true. 
+ * @param length number of characters to select, 0 <= start + length
+ *  <= getCharCount() must be true.
  *  A negative length places the caret at the selection start.
- * @param sendEvent a Selection event is sent when set to true and when 
+ * @param sendEvent a Selection event is sent when set to true and when
  *  the selection is reset.
  */
 void setSelection(int start, int length, bool sendEvent) {
     int end = start + length;
+    start = content.utf8AdjustOffset(start);
+    end = content.utf8AdjustOffset(end);
     if (start > end) {
         int temp = end;
         end = start;
         start = temp;
     }
-    // is the selection range different or is the selection direction 
+    // is the selection range different or is the selection direction
     // different?
-    if (selection.x !is start || selection.y !is end || 
-        (length > 0 && selectionAnchor !is selection.x) || 
+    if (selection.x !is start || selection.y !is end ||
+        (length > 0 && selectionAnchor !is selection.x) ||
         (length < 0 && selectionAnchor !is selection.y)) {
         clearSelection(sendEvent);
         if (length < 0) {
@@ -7697,7 +7852,7 @@
         internalRedrawRange(selection.x, selection.y - selection.x);
     }
 }
-/** 
+/**
  * Sets the selection.
  * <p>
  * The new selection may not be visible. Call showSelection to scroll the selection
@@ -7706,13 +7861,13 @@
  *
  * @param start offset of the first selected character
  * @param length number of characters to select
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a 
+ *   <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a
  * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter)
  * </ul>
  */
@@ -7727,23 +7882,23 @@
         if (end > contentLength) length = contentLength - start;
     }
     if (isLineDelimiter(start) || isLineDelimiter(start + length)) {
-        // the start offset or end offset of the selection range is inside a 
-        // multi byte line delimiter. This is an illegal operation and an exception 
+        // the start offset or end offset of the selection range is inside a
+        // multi byte line delimiter. This is an illegal operation and an exception
         // is thrown. Fixes 1GDKK3R
         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
     }
     setSelection(start, length, false);
     setCaretLocation();
 }
-/** 
+/**
  * Adds the specified style.
  * <p>
  * The new style overwrites existing styles for the specified range.
- * Existing style ranges are adjusted if they partially overlap with 
- * the new style. To clear an individual style, call setStyleRange 
- * with a StyleRange that has null attributes. 
+ * Existing style ranges are adjusted if they partially overlap with
+ * the new style. To clear an individual style, call setStyleRange
+ * with a StyleRange that has null attributes.
  * </p><p>
- * Should not be called if a LineStyleListener has been set since the 
+ * Should not be called if a LineStyleListener has been set since the
  * listener maintains the styles.
  * </p>
  *
@@ -7755,7 +7910,7 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *   <li>ERROR_INVALID_RANGE when the style range is outside the valid range (> getCharCount())</li> 
+ *   <li>ERROR_INVALID_RANGE when the style range is outside the valid range (> getCharCount())</li>
  * </ul>
  */
 public void setStyleRange(StyleRange range) {
@@ -7765,14 +7920,14 @@
         if (range.isUnstyled()) {
             setStyleRanges(range.start, range.length, null, null, false);
         } else {
-            setStyleRanges(range.start, 0, null, new StyleRange[]{range}, false);
+            setStyleRanges(range.start, 0, null, [range], false);
         }
     } else {
         setStyleRanges(0, 0, null, null, true);
     }
 }
-/** 
- * Clears the styles in the range specified by <code>start</code> and 
+/**
+ * Clears the styles in the range specified by <code>start</code> and
  * <code>length</code> and adds the new styles.
  * <p>
  * The ranges array contains start and length pairs.  Each pair refers to
@@ -7784,7 +7939,7 @@
  * Note: It is expected that the same instance of a StyleRange will occur
  * multiple times within the styles array, reducing memory usage.
  * </p><p>
- * Should not be called if a LineStyleListener has been set since the 
+ * Should not be called if a LineStyleListener has been set since the
  * listener maintains the styles.
  * </p>
  *
@@ -7792,19 +7947,19 @@
  * @param length length of the range to delete styles in
  * @param ranges the array of ranges.  The ranges must not overlap and must be in order.
  * @param styles the array of StyleRanges.  The range fields within the StyleRange are unused.
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
  *    <li>ERROR_NULL_ARGUMENT when an element in the styles array is null</li>
- *    <li>ERROR_INVALID_RANGE when the number of ranges and style do not match (ranges.length * 2 is styles.length)</li> 
- *    <li>ERROR_INVALID_RANGE when a range is outside the valid range (> getCharCount() or less than zero)</li> 
- *    <li>ERROR_INVALID_RANGE when a range overlaps</li> 
- * </ul>
- * 
- * @since 3.2 
+ *    <li>ERROR_INVALID_RANGE when the number of ranges and style do not match (ranges.length * 2 is styles.length)</li>
+ *    <li>ERROR_INVALID_RANGE when a range is outside the valid range (> getCharCount() or less than zero)</li>
+ *    <li>ERROR_INVALID_RANGE when a range overlaps</li>
+ * </ul>
+ *
+ * @since 3.2
  */
 public void setStyleRanges(int start, int length, int[] ranges, StyleRange[] styles) {
     checkWidget();
@@ -7815,7 +7970,7 @@
         setStyleRanges(start, length, ranges, styles, false);
     }
 }
-/** 
+/**
  * Sets styles to be used for rendering the widget content.
  * <p>
  * All styles in the widget will be replaced with the given set of ranges and styles.
@@ -7828,25 +7983,25 @@
  * Note: It is expected that the same instance of a StyleRange will occur
  * multiple times within the styles array, reducing memory usage.
  * </p><p>
- * Should not be called if a LineStyleListener has been set since the 
+ * Should not be called if a LineStyleListener has been set since the
  * listener maintains the styles.
  * </p>
  *
  * @param ranges the array of ranges.  The ranges must not overlap and must be in order.
  * @param styles the array of StyleRanges.  The range fields within the StyleRange are unused.
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
  *    <li>ERROR_NULL_ARGUMENT when an element in the styles array is null</li>
- *    <li>ERROR_INVALID_RANGE when the number of ranges and style do not match (ranges.length * 2 is styles.length)</li> 
- *    <li>ERROR_INVALID_RANGE when a range is outside the valid range (> getCharCount() or less than zero)</li> 
- *    <li>ERROR_INVALID_RANGE when a range overlaps</li> 
- * </ul>
- * 
- * @since 3.2 
+ *    <li>ERROR_INVALID_RANGE when the number of ranges and style do not match (ranges.length * 2 is styles.length)</li>
+ *    <li>ERROR_INVALID_RANGE when a range is outside the valid range (> getCharCount() or less than zero)</li>
+ *    <li>ERROR_INVALID_RANGE when a range overlaps</li>
+ * </ul>
+ *
+ * @since 3.2
  */
 public void setStyleRanges(int[] ranges, StyleRange[] styles) {
     checkWidget();
@@ -7871,7 +8026,7 @@
             if (ranges.length !is styles.length << 1) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
         }
         int lastOffset = 0;
-        bool variableHeight = false; 
+        bool variableHeight = false;
         for (int i = 0; i < styles.length; i ++) {
             if (styles[i] is null) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
             int rangeStart, rangeLength;
@@ -7882,7 +8037,7 @@
                 rangeStart = styles[i].start;
                 rangeLength = styles[i].length;
             }
-            if (rangeLength < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 
+            if (rangeLength < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
             if (!(0 <= rangeStart && rangeStart + rangeLength <= charCount)) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
             if (lastOffset > rangeStart) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
             variableHeight |= styles[i].isVariableHeight();
@@ -7941,13 +8096,13 @@
                 }
                 height = newLastLineBottom - y;
             }
-            super.redraw(0, y, clientAreaWidth, height, false);     
+            super.redraw(0, y, clientAreaWidth, height, false);
         }
     }
     setCaretLocation();
 }
-/** 
- * Sets styles to be used for rendering the widget content. All styles 
+/**
+ * Sets styles to be used for rendering the widget content. All styles
  * in the widget will be replaced with the given set of styles.
  * <p>
  * Note: Because a StyleRange includes the start and length, the
@@ -7956,32 +8111,32 @@
  * multiple StyleRanges, <code>setStyleRanges(int[], StyleRange[])</code>
  * can be used to share styles and reduce memory usage.
  * </p><p>
- * Should not be called if a LineStyleListener has been set since the 
+ * Should not be called if a LineStyleListener has been set since the
  * listener maintains the styles.
  * </p>
  *
  * @param ranges StyleRange objects containing the style information.
- * The ranges should not overlap. The style rendering is undefined if 
+ * The ranges should not overlap. The style rendering is undefined if
  * the ranges do overlap. Must not be null. The styles need to be in order.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  * @exception IllegalArgumentException <ul>
- *    <li>ERROR_NULL_ARGUMENT when the list of ranges is null</li>
- *    <li>ERROR_INVALID_RANGE when the last of the style ranges is outside the valid range (> getCharCount())</li> 
- * </ul>
- * 
+ *    <li>ERROR_INVALID_RANGE when the last of the style ranges is outside the valid range (> getCharCount())</li>
+ * </ul>
+ *
  * @see #setStyleRanges(int[], StyleRange[])
  */
 public void setStyleRanges(StyleRange[] ranges) {
     checkWidget();
     if (isListening(LineGetStyle)) return;
-    if (ranges is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    // DWT extension: allow null for zero length string
+    //if (ranges is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     setStyleRanges(0, 0, null, ranges, true);
 }
-/** 
- * Sets the tab width. 
+/**
+ * Sets the tab width.
  *
  * @param tabs tab width measured in characters.
  * @exception DWTException <ul>
@@ -7990,56 +8145,54 @@
  * </ul>
  */
 public void setTabs(int tabs) {
-    checkWidget();  
+    checkWidget();
     tabLength = tabs;
     renderer.setFont(null, tabs);
     resetCache(0, content.getLineCount());
     setCaretLocation();
     super.redraw();
 }
-/** 
- * Sets the widget content. 
- * If the widget has the DWT.SINGLE style and "text" contains more than 
- * one line, only the first line is rendered but the text is stored 
- * unchanged. A subsequent call to getText will return the same text 
+/**
+ * Sets the widget content.
+ * If the widget has the DWT.SINGLE style and "text" contains more than
+ * one line, only the first line is rendered but the text is stored
+ * unchanged. A subsequent call to getText will return the same text
  * that was set.
  * <p>
- * <b>Note:</b> Only a single line of text should be set when the DWT.SINGLE 
+ * <b>Note:</b> Only a single line of text should be set when the DWT.SINGLE
  * style is used.
  * </p>
  *
- * @param text new widget content. Replaces existing content. Line styles 
+ * @param text new widget content. Replaces existing content. Line styles
  *  that were set using StyledText API are discarded.  The
  *  current selection is also discarded.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * @exception IllegalArgumentException <ul>
- *    <li>ERROR_NULL_ARGUMENT when String is null</li>
- * </ul>
  */
 public void setText(String text) {
     checkWidget();
-    if (text is null) {
-        DWT.error(DWT.ERROR_NULL_ARGUMENT);
-    }
+    // DWT extension: allow null for zero length string
+//     if (text is null) {
+//         DWT.error(DWT.ERROR_NULL_ARGUMENT);
+//     }
     Event event = new Event();
     event.start = 0;
     event.end = getCharCount();
     event.text = text;
-    event.doit = true;  
+    event.doit = true;
     notifyListeners(DWT.Verify, event);
     if (event.doit) {
         StyledTextEvent styledTextEvent = null;
         if (isListening(ExtendedModify)) {
             styledTextEvent = new StyledTextEvent(content);
             styledTextEvent.start = event.start;
-            styledTextEvent.end = event.start + event.text.length();
+            styledTextEvent.end = event.start + event.text.length;
             styledTextEvent.text = content.getTextRange(event.start, event.end - event.start);
         }
         content.setText(event.text);
-        sendModifyEvent(event); 
+        sendModifyEvent(event);
         if (styledTextEvent !is null) {
             notifyListeners(ExtendedModify, styledTextEvent);
         }
@@ -8071,15 +8224,15 @@
 /**
  * Sets the top index. Do nothing if there is no text set.
  * <p>
- * The top index is the index of the line that is currently at the top 
+ * The top index is the index of the line that is currently at the top
  * of the widget. The top index changes when the widget is scrolled.
  * Indexing starts from zero.
  * Note: The top index is reset to 0 when new text is set in the widget.
  * </p>
  *
- * @param topIndex new top index. Must be between 0 and 
- *  getLineCount() - fully visible lines per page. If no lines are fully 
- *  visible the maximum value is getLineCount() - 1. An out of range 
+ * @param topIndex new top index. Must be between 0 and
+ *  getLineCount() - fully visible lines per page. If no lines are fully
+ *  visible the maximum value is getLineCount() - 1. An out of range
  *  index will be adjusted accordingly.
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
@@ -8108,7 +8261,7 @@
         } else {
             pixel = getAvailableHeightAbove(pixel);
         }
-    } 
+    }
     scrollVertical(pixel, true);
 }
 /**
@@ -8120,7 +8273,7 @@
  * Note: The top pixel is reset to 0 when new text is set in the widget.
  * </p>
  *
- * @param pixel new top pixel offset. Must be between 0 and 
+ * @param pixel new top pixel offset. Must be between 0 and
  *  (getLineCount() - visible lines per page) / getLineHeight()). An out
  *  of range offset will be adjusted accordingly.
  * @exception DWTException <ul>
@@ -8133,7 +8286,7 @@
     checkWidget();
     if (getCharCount() is 0) {
         return;
-    }   
+    }
     if (pixel < 0) pixel = 0;
     int lineCount = content.getLineCount();
     int height = clientAreaHeight - topMargin - bottomMargin;
@@ -8141,7 +8294,7 @@
     if (isFixedLineHeight()) {
         int maxTopPixel = Math.max(0, lineCount * getVerticalIncrement() - height);
         if (pixel > maxTopPixel) pixel = maxTopPixel;
-        pixel -= verticalOffset; 
+        pixel -= verticalOffset;
     } else {
         pixel -= verticalOffset;
         if (pixel > 0) {
@@ -8175,6 +8328,7 @@
     setCaretLocation();
     super.redraw();
 }
+// DWT: If necessary, scroll to show the location
 bool showLocation(Rectangle rect, bool scrollPage) {
     int clientAreaWidth = this.clientAreaWidth - leftMargin - rightMargin;
     int clientAreaHeight = this.clientAreaHeight - topMargin - bottomMargin;
@@ -8236,10 +8390,10 @@
         startOffset = selection.x;
         endOffset = selection.y;
     }
-    
+
     Rectangle startBounds = getBoundsAtOffset(startOffset);
     Rectangle endBounds = getBoundsAtOffset(endOffset);
-    
+
     // can the selection be fully displayed within the widget's visible width?
     int w = clientAreaWidth - leftMargin - rightMargin;
     bool selectionFits = rightToLeft ? startBounds.x - endBounds.x <= w : endBounds.x - startBounds.x <= w;
@@ -8254,7 +8408,7 @@
         endBounds.width = 0;
         showLocation(endBounds, false);
     } else {
-        // just show the end of the selection since the selection start 
+        // just show the end of the selection since the selection start
         // will not be visible
         showLocation(endBounds, true);
     }
@@ -8262,10 +8416,10 @@
 /**
  * Updates the selection and caret position depending on the text change.
  * <p>
- * If the selection intersects with the replaced text, the selection is 
+ * If the selection intersects with the replaced text, the selection is
  * reset and the caret moved to the end of the new text.
  * If the selection is behind the replaced text it is moved so that the
- * same text remains selected.  If the selection is before the replaced text 
+ * same text remains selected.  If the selection is before the replaced text
  * it is left unchanged.
  * </p>
  *
@@ -8276,6 +8430,7 @@
 void updateSelection(int startOffset, int replacedLength, int newLength) {
     if (selection.y <= startOffset) {
         // selection ends before text change
+        if (wordWrap) setCaretLocation();
         return;
     }
     if (selection.x < startOffset) {
@@ -8284,7 +8439,7 @@
     }
     if (selection.y > startOffset + replacedLength && selection.x < startOffset + replacedLength) {
         // clear selection fragment after text change.
-        // do this only when the selection is actually affected by the 
+        // do this only when the selection is actually affected by the
         // change. Selection is only affected if it intersects the change (1GDY217).
         int netNewLength = newLength - replacedLength;
         int redrawStart = startOffset + newLength;
--- a/dwt/custom/StyledTextContent.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/StyledTextContent.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,15 +7,19 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.StyledTextContent;
 
+import dwt.dwthelper.utils;
 
+import dwt.custom.TextChangeListener;
 /**
- * Clients may implement the StyledTextContent interface to provide a 
- * custom store for the StyledText widget content. The StyledText widget 
- * interacts with its StyledTextContent in order to access and update 
- * the text that is being displayed and edited in the widget. 
+ * Clients may implement the StyledTextContent interface to provide a
+ * custom store for the StyledText widget content. The StyledText widget
+ * interacts with its StyledTextContent in order to access and update
+ * the text that is being displayed and edited in the widget.
  * A custom content implementation can be set in the widget using the
  * StyledText.setContent API.
  */
@@ -46,8 +50,8 @@
  * Return the line at the given line index without delimiters.
  * <p>
  *
- * @param lineIndex index of the line to return. Does not include 
- *  delimiters of preceding lines. Index 0 is the first line of the 
+ * @param lineIndex index of the line to return. Does not include
+ *  delimiters of preceding lines. Index 0 is the first line of the
  *  content.
  * @return the line text without delimiters
  */
@@ -57,12 +61,12 @@
  * Return the line index at the given character offset.
  * <p>
  *
- * @param offset offset of the line to return. The first character of the 
- *  document is at offset 0.  An offset of getLength() is valid and should 
- *  answer the number of lines. 
- * @return the line index. The first line is at index 0.  If the character 
- *  at offset is a delimiter character, answer the line index of the line 
- *  that is delimited. 
+ * @param offset offset of the line to return. The first character of the
+ *  document is at offset 0.  An offset of getLength() is valid and should
+ *  answer the number of lines.
+ * @return the line index. The first line is at index 0.  If the character
+ *  at offset is a delimiter character, answer the line index of the line
+ *  that is delimited.
  *  For example, if text = "\r\n\r\n", and delimiter = "\r\n", then:
  * <ul>
  * <li>getLineAtOffset(0) is 0
@@ -81,18 +85,18 @@
  *
  * @return the number of lines.  For example:
  * <ul>
- * <li> text value ==> getLineCount     
- * <li> null ==> 1      
- * <li> "" ==> 1        
- * <li> "a\n" ==> 2         
- * <li> "\n\n" ==> 3            
+ * <li> text value is> getLineCount
+ * <li> null is> 1
+ * <li> "" is> 1
+ * <li> "a\n" is> 2
+ * <li> "\n\n" is> 3
  * </ul>
  */
 public int getLineCount();
 
 /**
- * Return the line delimiter that should be used by the StyledText 
- * widget when inserting new lines. New lines entered using key strokes 
+ * Return the line delimiter that should be used by the StyledText
+ * widget when inserting new lines. New lines entered using key strokes
  * and paste operations use this line delimiter.
  * Implementors may use System.getProperty("line.separator") to return
  * the platform line delimiter.
@@ -106,14 +110,14 @@
 /**
  * Return the character offset of the first character of the given line.
  * <p>
- * <b>NOTE:</b> When there is no text (i.e., no lines), getOffsetAtLine(0) 
+ * <b>NOTE:</b> When there is no text (i.e., no lines), getOffsetAtLine(0)
  * is a valid call that should return 0.
  * </p>
  *
  * @param lineIndex index of the line. The first line is at index 0.
- * @return offset offset of the first character of the line. The first 
- *  character of the document is at offset 0.  The return value should 
- *  include line delimiters.  
+ * @return offset offset of the first character of the line. The first
+ *  character of the document is at offset 0.  The return value should
+ *  include line delimiters.
  *  For example, if text = "\r\ntest\r\n" and delimiter = "\r\n", then:
  * <ul>
  * <li>getOffsetAtLine(0) is 0
@@ -124,10 +128,10 @@
 public int getOffsetAtLine(int lineIndex);
 
 /**
- * Returns a String representing the content at the given range.
+ * Returns a string representing the content at the given range.
  * <p>
  *
- * @param start the start offset of the text to return. Offset 0 is the 
+ * @param start the start offset of the text to return. Offset 0 is the
  *  first character of the document.
  * @param length the length of the text to return
  * @return the text at the given range
@@ -138,7 +142,8 @@
  * Remove the specified text changed listener.
  * <p>
  *
- * @param listener the listener
+ * @param listener the listener which should no longer be notified
+ *
  * @exception IllegalArgumentException <ul>
  *    <li>ERROR_NULL_ARGUMENT when listener is null</li>
  * </ul>
@@ -146,46 +151,46 @@
 public void removeTextChangeListener(TextChangeListener listener);
 
 /**
- * Replace the text with "newText" starting at position "start" 
+ * Replace the text with "newText" starting at position "start"
  * for a length of "replaceLength".
  * <p>
- * Implementors have to notify the TextChangeListeners that were added 
- * using <code>addTextChangeListener</code> before and after the content 
- * is changed. A <code>TextChangingEvent</code> has to be sent to the 
- * textChanging method before the content is changed and a 
+ * Implementors have to notify the TextChangeListeners that were added
+ * using <code>addTextChangeListener</code> before and after the content
+ * is changed. A <code>TextChangingEvent</code> has to be sent to the
+ * textChanging method before the content is changed and a
  * <code>TextChangedEvent</code> has to be sent to the textChanged method
  * after the content has changed.
- * The text change that occurs after the <code>TextChangingEvent</code> 
- * has been sent has to be consistent with the data provided in the 
+ * The text change that occurs after the <code>TextChangingEvent</code>
+ * has been sent has to be consistent with the data provided in the
  * <code>TextChangingEvent</code>.
- * This data will be cached by the widget and will be used when the 
+ * This data will be cached by the widget and will be used when the
  * <code>TextChangedEvent</code> is received.
  * <p>
  * The <code>TextChangingEvent</code> should be set as follows:
  * <ul>
  * <li>event.start = start of the replaced text
- * <li>event.newText = text that is going to be inserted or empty String 
+ * <li>event.newText = text that is going to be inserted or empty String
  *  if no text will be inserted
  * <li>event.replaceCharCount = length of text that is going to be replaced
  * <li>event.newCharCount = length of text that is going to be inserted
  * <li>event.replaceLineCount = number of lines that are going to be replaced
  * <li>event.newLineCount = number of new lines that are going to be inserted
  * </ul>
- * <b>NOTE:</b> newLineCount is the number of inserted lines and replaceLineCount 
- * is the number of deleted lines based on the change that occurs visually.  
+ * <b>NOTE:</b> newLineCount is the number of inserted lines and replaceLineCount
+ * is the number of deleted lines based on the change that occurs visually.
  * For example:
  * <ul>
- * <li>(replaceText, newText) ==> (replaceLineCount, newLineCount)
- * <li>("", "\n") ==> (0, 1)
- * <li>("\n\n", "a") ==> (2, 0)
- * <li>("a", "\n\n") ==> (0, 2)
- * <li>("\n", "") ==> (1, 0)
+ * <li>(replaceText, newText) is> (replaceLineCount, newLineCount)
+ * <li>("", "\n") is> (0, 1)
+ * <li>("\n\n", "a") is> (2, 0)
+ * <li>("a", "\n\n") is> (0, 2)
+ * <li>("\n", "") is> (1, 0)
  * </ul>
  * </p>
  *
- * @param start start offset of text to replace, none of the offsets include 
- *  delimiters of preceding lines, offset 0 is the first character of the 
- *  document 
+ * @param start start offset of text to replace, none of the offsets include
+ *  delimiters of preceding lines, offset 0 is the first character of the
+ *  document
  * @param replaceLength length of text to replace
  * @param text text to replace
  * @see TextChangeListener
@@ -194,8 +199,8 @@
 
 /**
  * Set text to "text".
- * Implementors have to send a <code>TextChangedEvent</code> to the 
- * textSet method of the TextChangeListeners that were added using 
+ * Implementors have to send a <code>TextChangedEvent</code> to the
+ * textSet method of the TextChangeListeners that were added using
  * <code>addTextChangeListener</code>.
  * <p>
  *
@@ -203,4 +208,10 @@
  * @see TextChangeListener
  */
 public void setText(String text);
+
+/++
+ + DWT Extension
+ +/
+int utf8AdjustOffset( int offset );
+
 }
--- a/dwt/custom/StyledTextDropTargetEffect.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/StyledTextDropTargetEffect.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,31 +7,46 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.StyledTextDropTargetEffect;
+
 
-import dwt.*;
-import dwt.dnd.*;
-import dwt.graphics.*;
-import dwt.widgets.*;
+import dwt.DWT;
+import dwt.dnd.DND;
+import dwt.dnd.DropTargetAdapter;
+import dwt.dnd.DropTargetEffect;
+import dwt.dnd.DropTargetEvent;
+import dwt.graphics.FontMetrics;
+import dwt.graphics.GC;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.custom.StyledText;
+import dwt.custom.StyledTextContent;
+
+static import tango.core.Exception;
+import dwt.dwthelper.utils;
 
 /**
- * This adapter class provides a default drag under effect (eg. select and scroll) 
+ * This adapter class provides a default drag under effect (eg. select and scroll)
  * when a drag occurs over a <code>StyledText</code>.
- * 
+ *
  * <p>Classes that wish to provide their own drag under effect for a <code>StyledText</code>
  * can extend this class, override the <code>StyledTextDropTargetEffect.dragOver</code>
- * method and override any other applicable methods in <code>StyledTextDropTargetEffect</code> to 
+ * method and override any other applicable methods in <code>StyledTextDropTargetEffect</code> to
  * display their own drag under effect.</p>
  *
  * Subclasses that override any methods of this class should call the corresponding
  * <code>super</code> method to get the default drag under effect implementation.
  *
- * <p>The feedback value is either one of the FEEDBACK constants defined in 
- * class <code>DND</code> which is applicable to instances of this class, 
- * or it must be built by <em>bitwise OR</em>'ing together 
+ * <p>The feedback value is either one of the FEEDBACK constants defined in
+ * class <code>DND</code> which is applicable to instances of this class,
+ * or it must be built by <em>bitwise OR</em>'ing together
  * (that is, using the <code>int</code> "|" operator) two or more
- * of those <code>DND</code> effect constants. 
+ * of those <code>DND</code> effect constants.
  * </p>
  * <p>
  * <dl>
@@ -39,31 +54,32 @@
  * <dd>FEEDBACK_SELECT, FEEDBACK_SCROLL</dd>
  * </dl>
  * </p>
- * 
+ *
  * @see DropTargetAdapter
  * @see DropTargetEvent
- * 
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
  * @since 3.3
  */
 public class StyledTextDropTargetEffect : DropTargetEffect {
     static final int CARET_WIDTH = 2;
     static final int SCROLL_HYSTERESIS = 100; // milli seconds
     static final int SCROLL_TOLERANCE = 20; // pixels
-    
+
     int currentOffset = -1;
     long scrollBeginTime;
     int scrollX = -1, scrollY = -1;
     Listener paintListener;
-    
+
     /**
-     * Creates a new <code>StyledTextDropTargetEffect</code> to handle the drag under effect on the specified 
+     * Creates a new <code>StyledTextDropTargetEffect</code> to handle the drag under effect on the specified
      * <code>StyledText</code>.
-     * 
+     *
      * @param styledText the <code>StyledText</code> over which the user positions the cursor to drop the data
      */
     public this(StyledText styledText) {
         super(styledText);
-        paintListener = new Listener () {
+        paintListener = new class() Listener {
             public void handleEvent (Event event) {
                 if (currentOffset !is -1) {
                     StyledText text = cast(StyledText) getControl();
@@ -75,22 +91,22 @@
             }
         };
     }
-    
+
     /**
      * This implementation of <code>dragEnter</code> provides a default drag under effect
      * for the feedback specified in <code>event.feedback</code>.
-     * 
+     *
      * For additional information see <code>DropTargetAdapter.dragEnter</code>.
-     * 
+     *
      * Subclasses that override this method should call <code>super.dragEnter(event)</code>
      * to get the default drag under effect implementation.
      *
      * @param event  the information associated with the drag start event
-     * 
+     *
      * @see DropTargetAdapter
      * @see DropTargetEvent
      */
-    public void dragEnter(DropTargetEvent event) {
+    public override void dragEnter(DropTargetEvent event) {
         currentOffset = -1;
         scrollBeginTime = 0;
         scrollX = -1;
@@ -98,22 +114,22 @@
         getControl().removeListener(DWT.Paint, paintListener);
         getControl().addListener (DWT.Paint, paintListener);
     }
-    
+
     /**
      * This implementation of <code>dragLeave</code> provides a default drag under effect
      * for the feedback specified in <code>event.feedback</code>.
-     * 
+     *
      * For additional information see <code>DropTargetAdapter.dragLeave</code>.
-     * 
+     *
      * Subclasses that override this method should call <code>super.dragLeave(event)</code>
      * to get the default drag under effect implementation.
      *
      * @param event  the information associated with the drag leave event
-     * 
+     *
      * @see DropTargetAdapter
      * @see DropTargetEvent
      */
-    public void dragLeave(DropTargetEvent event) {
+    public override void dragLeave(DropTargetEvent event) {
         StyledText text = cast(StyledText) getControl();
         if (currentOffset !is -1) {
             refreshCaret(text, currentOffset, -1);
@@ -127,23 +143,23 @@
     /**
      * This implementation of <code>dragOver</code> provides a default drag under effect
      * for the feedback specified in <code>event.feedback</code>.
-     * 
+     *
      * For additional information see <code>DropTargetAdapter.dragOver</code>.
-     * 
+     *
      * Subclasses that override this method should call <code>super.dragOver(event)</code>
      * to get the default drag under effect implementation.
      *
      * @param event  the information associated with the drag over event
-     * 
+     *
      * @see DropTargetAdapter
      * @see DropTargetEvent
      * @see DND#FEEDBACK_SELECT
      * @see DND#FEEDBACK_SCROLL
      */
-    public void dragOver(DropTargetEvent event) {
+    public override void dragOver(DropTargetEvent event) {
         int effect = event.feedback;
         StyledText text = cast(StyledText) getControl();
-        
+
         Point pt = text.getDisplay().map(null, text, event.x, event.y);
         if ((effect & DND.FEEDBACK_SCROLL) is 0) {
             scrollBeginTime = 0;
@@ -190,7 +206,7 @@
                 }
             }
         }
-            
+
         if ((effect & DND.FEEDBACK_SELECT) !is 0) {
             int[] trailing = new int [1];
             int newOffset = text.getOffsetAtPoint(pt.x, pt.y, trailing, false);
@@ -220,18 +236,18 @@
     /**
      * This implementation of <code>dropAccept</code> provides a default drag under effect
      * for the feedback specified in <code>event.feedback</code>.
-     * 
+     *
      * For additional information see <code>DropTargetAdapter.dropAccept</code>.
-     * 
+     *
      * Subclasses that override this method should call <code>super.dropAccept(event)</code>
      * to get the default drag under effect implementation.
      *
      * @param event  the information associated with the drop accept event
-     * 
+     *
      * @see DropTargetAdapter
      * @see DropTargetEvent
      */
-    public void dropAccept(DropTargetEvent event) {
+    public override void dropAccept(DropTargetEvent event) {
         if (currentOffset !is -1) {
             StyledText text = cast(StyledText) getControl();
             text.setSelection(currentOffset);
--- a/dwt/custom/StyledTextEvent.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/StyledTextEvent.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
  * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -7,15 +7,21 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.StyledTextEvent;
+
 
-import dwt.graphics.*;
-import dwt.widgets.*;
+import dwt.graphics.Color;
+import dwt.widgets.Event;
+import dwt.custom.StyleRange;
+import dwt.custom.Bullet;
+import dwt.custom.StyledTextContent;
 
 /**
  *
- */ 
+ */
 class StyledTextEvent : Event {
     // used by LineStyleEvent
     int[] ranges;
@@ -28,10 +34,10 @@
     // used by LineBackgroundEvent
     Color lineBackground;
     // used by BidiSegmentEvent
-    int[] segments; 
+    int[] segments;
     // used by TextChangedEvent
-    int replaceCharCount;   
-    int newCharCount; 
+    int replaceCharCount;
+    int newCharCount;
     int replaceLineCount;
     int newLineCount;
     // used by PaintObjectEvent
@@ -42,8 +48,7 @@
     StyleRange style;
 
 this (StyledTextContent content) {
-    super();
-    data = content; 
+    data = cast(Object)content;
 }
 }
 
--- a/dwt/custom/StyledTextListener.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/StyledTextListener.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,12 +7,36 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.StyledTextListener;
+
 
-import dwt.events.*;
-import dwt.widgets.*;
+import dwt.events.VerifyEvent;
 import dwt.internal.DWTEventListener;
+import dwt.widgets.Event;
+import dwt.widgets.TypedListener;
+import dwt.custom.StyledText;
+import dwt.custom.ExtendedModifyEvent;
+import dwt.custom.ExtendedModifyListener;
+import dwt.custom.StyledTextEvent;
+import dwt.custom.LineBackgroundEvent;
+import dwt.custom.BidiSegmentEvent;
+import dwt.custom.LineStyleEvent;
+import dwt.custom.PaintObjectEvent;
+import dwt.custom.MovementEvent;
+import dwt.custom.TextChangedEvent;
+import dwt.custom.TextChangingEvent;
+import dwt.custom.LineBackgroundListener;
+import dwt.custom.BidiSegmentListener;
+import dwt.custom.LineStyleListener;
+import dwt.custom.PaintObjectListener;
+import dwt.custom.VerifyKeyListener;
+import dwt.custom.StyledTextContent;
+import dwt.custom.TextChangeListener;
+import dwt.custom.MovementListener;
+
 
 class StyledTextListener : TypedListener {
 /**
@@ -22,24 +46,26 @@
 }
 /**
  * Process StyledText events by invoking the event's handler.
+ *
+ * @param e the event to handle
  */
-public void handleEvent(Event e) {
-    
+public override void handleEvent(Event e) {
+
     switch (e.type) {
         case StyledText.ExtendedModify:
             ExtendedModifyEvent extendedModifyEvent = new ExtendedModifyEvent(cast(StyledTextEvent) e);
             (cast(ExtendedModifyListener) eventListener).modifyText(extendedModifyEvent);
-            break;      
+            break;
         case StyledText.LineGetBackground:
             LineBackgroundEvent lineBgEvent = new LineBackgroundEvent(cast(StyledTextEvent) e);
             (cast(LineBackgroundListener) eventListener).lineGetBackground(lineBgEvent);
             (cast(StyledTextEvent) e).lineBackground = lineBgEvent.lineBackground;
-            break;      
+            break;
         case StyledText.LineGetSegments:
             BidiSegmentEvent segmentEvent = new BidiSegmentEvent(cast(StyledTextEvent) e);
             (cast(BidiSegmentListener) eventListener).lineGetSegments(segmentEvent);
             (cast(StyledTextEvent) e).segments = segmentEvent.segments;
-            break;      
+            break;
         case StyledText.LineGetStyle:
             LineStyleEvent lineStyleEvent = new LineStyleEvent(cast(StyledTextEvent) e);
             (cast(LineStyleListener) eventListener).lineGetStyle(lineStyleEvent);
@@ -54,7 +80,7 @@
         case StyledText.PaintObject:
             PaintObjectEvent paintObjectEvent = new PaintObjectEvent(cast(StyledTextEvent) e);
             (cast(PaintObjectListener) eventListener).paintObject(paintObjectEvent);
-            break;          
+            break;
         case StyledText.VerifyKey:
             VerifyEvent verifyEvent = new VerifyEvent(e);
             (cast(VerifyKeyListener) eventListener).verifyKey(verifyEvent);
@@ -86,6 +112,7 @@
             (cast(StyledTextEvent) e).end = wordBoundaryEvent.newOffset;
             break;
         }
+        default:
     }
 }
 }
--- a/dwt/custom/StyledTextPrintOptions.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/StyledTextPrintOptions.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2006 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,8 +7,12 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.StyledTextPrintOptions;
+
+import dwt.dwthelper.utils;
 
 /**
  * Use StyledTextPrintOptions to specify printing options for the
@@ -20,13 +24,16 @@
  * </p>
  * <pre>
  * StyledTextPrintOptions options = new StyledTextPrintOptions();
- * options.footer = "\t\t&lt;page&gt;"; 
+ * options.footer = "\t\t&lt;page&gt;";
  * options.jobName = "Example";
  * options.printLineBackground = true;
- * 
- * Runnable runnable = styledText.print(new Printer(), options); 
+ *
+ * Runnable runnable = styledText.print(new Printer(), options);
  * runnable.run();
  * </pre>
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
  * @since 2.1
  */
 public class StyledTextPrintOptions {
@@ -46,7 +53,7 @@
      * <p>left, center, right = &lt;page&gt; | #CDATA</p>
      * <p>Header and footer are defined as three separate regions for arbitrary
      * text or the page number placeholder &lt;page&gt;
-     * (<code>StyledTextPrintOptions.PAGE_TAG</code>). The three regions are 
+     * (<code>StyledTextPrintOptions.PAGE_TAG</code>). The three regions are
      * left aligned, centered and right aligned. They are separated by a tab
      * character (<code>StyledTextPrintOptions.SEPARATOR</code>).
      */
@@ -57,7 +64,7 @@
      * <p>left, center, right = &lt;page&gt; | #CDATA</p>
      * <p>Header and footer are defined as three separate regions for arbitrary
      * text or the page number placeholder &lt;page&gt;
-     * (<code>StyledTextPrintOptions.PAGE_TAG</code>). The three regions are 
+     * (<code>StyledTextPrintOptions.PAGE_TAG</code>). The three regions are
      * left aligned, centered and right aligned. They are separated by a tab
      * character (<code>StyledTextPrintOptions.SEPARATOR</code>).
      */
@@ -66,7 +73,7 @@
      * Name of the print job.
      */
     public String jobName = null;
-    
+
     /**
      * Print the text foreground color. Default value is <code>false</code>.
      */
@@ -83,19 +90,19 @@
      * Print the line background color. Default value is <code>false</code>.
      */
     public bool printLineBackground = false;
-    
+
     /**
      * Print line numbers. Default value is <code>false</code>.
-     * 
+     *
      * @since 3.3
      */
     public bool printLineNumbers = false;
-    
+
     /**
      * Labels used for printing line numbers.
      * 
      * @since 3.4
      */
     public String[] lineLabels = null;
-    
+
 }
--- a/dwt/custom/StyledTextRenderer.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/StyledTextRenderer.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,13 +7,44 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.StyledTextRenderer;
+
 
 
 import dwt.DWT;
-import dwt.graphics.*;
-import dwt.widgets.*;
+import dwt.graphics.Color;
+import dwt.graphics.Device;
+import dwt.graphics.Font;
+import dwt.graphics.FontData;
+import dwt.graphics.FontMetrics;
+import dwt.graphics.GC;
+import dwt.graphics.GlyphMetrics;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.graphics.TextLayout;
+import dwt.graphics.TextStyle;
+import dwt.widgets.Display;
+import dwt.widgets.IME;
+import dwt.widgets.ScrollBar;
+import dwt.custom.StyledText;
+import dwt.custom.Bullet;
+import dwt.custom.StyleRange;
+import dwt.custom.StyledText;
+import dwt.custom.StyledTextContent;
+import dwt.custom.TextChangingEvent;
+import dwt.custom.ST;
+import dwt.custom.StyledTextEvent;
+
+import dwt.dwthelper.Runnable;
+import dwt.dwthelper.utils;
+
+static import tango.text.Text;
+static import tango.text.Util;
+static import tango.text.convert.Utf;
+import tango.util.Convert;
 
 /**
  * A StyledTextRenderer renders the content of a StyledText widget.
@@ -29,7 +60,7 @@
     int tabWidth;
     int ascent, descent;
     int averageCharWidth;
-    
+
     /* Line data */
     int topIndex = -1;
     TextLayout[] layouts;
@@ -40,33 +71,33 @@
     int maxWidth;
     int maxWidthLineIndex;
     bool idleRunning;
-    
+
     /* Bullet */
     Bullet[] bullets;
     int[] bulletsIndices;
     int[] redrawLines;
-    
+
     /* Style data */
     int[] ranges;
-    int styleCount; 
+    int styleCount;
     StyleRange[] styles;
     StyleRange[] stylesSet;
     int stylesSetCount = 0;
     final static int BULLET_MARGIN = 8;
-    
+
     final static bool COMPACT_STYLES = true;
     final static bool MERGE_STYLES = true;
-    
+
     final static int GROW = 32;
     final static int IDLE_TIME = 50;
     final static int CACHE_SIZE = 128;
-    
+
     final static int BACKGROUND = 1 << 0;
     final static int ALIGNMENT = 1 << 1;
     final static int INDENT = 1 << 2;
     final static int JUSTIFY = 1 << 3;
     final static int SEGMENTS = 1 << 5;
-    
+
     static class LineInfo {
         int flags;
         Color background;
@@ -88,7 +119,7 @@
             }
         }
     }
-    
+
 this(Device device, StyledText styledText) {
     this.device = device;
     this.styledText = styledText;
@@ -121,7 +152,7 @@
         }
     }
     if (MERGE_STYLES) {
-        int j = modifyStart;    
+        int j = modifyStart;
         for (int i = 0; i < mergeCount; i += 2) {
             if (j > 0 && ranges[j - 2] + ranges[j - 1] is mergeRanges[i] && mergeStyles[i >> 1].similarTo(styles[(j - 2) >> 1])) {
                 ranges[j - 1] += mergeRanges[i + 1];
@@ -222,7 +253,7 @@
 }
 void calculateIdle () {
     if (idleRunning) return;
-    Runnable runnable = new Runnable() {
+    Runnable runnable = new class() Runnable {
         public void run() {
             if (styledText is null) return;
             int i;
@@ -234,7 +265,7 @@
                 }
             }
             if (i < lineCount) {
-                Display display = styledText.getDisplay();              
+                Display display = styledText.getDisplay();
                 display.asyncExec(this);
             } else {
                 idleRunning = false;
@@ -242,10 +273,10 @@
                 ScrollBar bar = styledText.getVerticalBar();
                 if (bar !is null) {
                     bar.setSelection(styledText.getVerticalScrollOffset());
-                }                   
+                }
             }
         }
-    };      
+    };
     Display display = styledText.getDisplay();
     display.asyncExec(runnable);
     idleRunning = true;
@@ -286,7 +317,7 @@
     if (lines !is null) {
         LineInfo[] newLines = renderer.lines = new LineInfo[lineCount];
         for (int i = 0; i < newLines.length; i++) {
-            newLines[i] = new LineInfo(lines[i]);               
+            newLines[i] = new LineInfo(lines[i]);
         }
         renderer.lineCount = lineCount;
     }
@@ -328,24 +359,25 @@
     }
     Font font = style.font;
     if (font !is null) gc.setFont(font);
-    String String = "";
+    String string = "";
     int type = bullet.type & (ST.BULLET_DOT|ST.BULLET_NUMBER|ST.BULLET_LETTER_LOWER|ST.BULLET_LETTER_UPPER);
     switch (type) {
-        case ST.BULLET_DOT: String = "\u2022"; break;
-        case ST.BULLET_NUMBER: String = String.valueOf(index); break;
-        case ST.BULLET_LETTER_LOWER: String = String.valueOf(cast(wchar) (index % 26 + 97)); break;
-        case ST.BULLET_LETTER_UPPER: String = String.valueOf(cast(wchar) (index % 26 + 65)); break;
+        case ST.BULLET_DOT: string = "\u2022"; break;
+        case ST.BULLET_NUMBER: string = to!(String)(index); break;
+        case ST.BULLET_LETTER_LOWER: string = [cast(char) (index % 26 + 97)]; break;
+        case ST.BULLET_LETTER_UPPER: string = [cast(char) (index % 26 + 65)]; break;
+        default:
     }
-    if ((bullet.type & ST.BULLET_TEXT) !is 0) String += bullet.text;
+    if ((bullet.type & ST.BULLET_TEXT) !is 0) string ~= bullet.text;
     Display display = styledText.getDisplay();
     TextLayout layout = new TextLayout(display);
-    layout.setText(String);
+    layout.setText(string);
     layout.setAscent(lineAscent);
     layout.setDescent(lineDescent);
     style = cast(StyleRange)style.clone();
     style.metrics = null;
     if (style.font is null) style.font = getFont(style.fontStyle);
-    layout.setStyle(style, 0, String.length()); 
+    layout.setStyle(style, 0, string.length);
     int x = paintX + Math.max(0, metrics.width - layout.getBounds().width - BULLET_MARGIN);
     layout.draw(gc, x, paintY);
     layout.dispose();
@@ -354,14 +386,15 @@
     TextLayout layout = getTextLayout(lineIndex);
     String line = content.getLine(lineIndex);
     int lineOffset = content.getOffsetAtLine(lineIndex);
-    int lineLength = line.length();
+    int lineLength = line.length;
     Point selection = styledText.getSelection();
     int selectionStart = selection.x - lineOffset;
     int selectionEnd = selection.y - lineOffset;
-    Rectangle client = styledText.getClientArea();  
+    Rectangle client = styledText.getClientArea();
     Color lineBackground = getLineBackground(lineIndex, null);
     StyledTextEvent event = styledText.getLineBackgroundData(lineOffset, line);
     if (event !is null && event.lineBackground !is null) lineBackground = event.lineBackground;
+
     int height = layout.getBounds().height;
     if (lineBackground !is null) {
         gc.setBackground(lineBackground);
@@ -389,7 +422,7 @@
         }
         layout.draw(gc, paintX, paintY, start, end - 1, selectionFg, selectionBg, flags);
     }
-    
+
     // draw objects
     Bullet bullet = null;
     int bulletIndex = -1;
@@ -473,7 +506,7 @@
         int height = lineHeight[i];
         if (height is -1) {
             if (width > 0) {
-                int length = content.getLine(i).length();
+                int length = content.getLine(i).length;
                 height = ((length * averageCharWidth / width) + 1) * defaultLineHeight;
             } else {
                 height = defaultLineHeight;
@@ -587,7 +620,7 @@
             StyleRange style = styles[i];
             newRanges[j] = style.start;
             newRanges[j + 1] = style.length;
-        }       
+        }
     }
     if (start > newRanges[0]) {
         newRanges[1] = newRanges[0] + newRanges[1] - start;
@@ -658,7 +691,7 @@
 TextLayout getTextLayout(int lineIndex, int orientation, int width, int lineSpacing) {
     TextLayout layout = null;
     if (styledText !is null) {
-        int topIndex = styledText.topIndex > 0 ? styledText.topIndex - 1 : 0;   
+        int topIndex = styledText.topIndex > 0 ? styledText.topIndex - 1 : 0;
         if (layouts is null || topIndex !is this.topIndex) {
             TextLayout[] newLayouts = new TextLayout[CACHE_SIZE];
             if (layouts !is null) {
@@ -798,13 +831,13 @@
     layout.setSegments(segments);
     layout.setWidth(width);
     layout.setSpacing(lineSpacing);
-    layout.setTabs(new int[]{tabWidth});
+    layout.setTabs([tabWidth]);
     layout.setIndent(indent);
     layout.setAlignment(alignment);
     layout.setJustify(justify);
-    
+
     int lastOffset = 0;
-    int length = line.length();
+    int length = line.length;
     if (styles !is null) {
         if (ranges !is null) {
             int rangeCount = styleCount << 1;
@@ -849,7 +882,7 @@
         int compositionOffset = ime.getCompositionOffset();
         if (compositionOffset !is -1) {
             int commitCount = ime.getCommitCount();
-            int compositionLength = ime.getText().length();
+            int compositionLength = ime.getText().length;
             if (compositionLength !is commitCount) {
                 int compositionLine = content.getLineAtOffset(compositionOffset);
                 if (compositionLine is lineIndex) {
@@ -895,7 +928,7 @@
             }
         }
     }
-    
+
     if (styledText !is null && styledText.isFixedLineHeight()) {
         int index = -1;
         int lineCount = layout.getLineCount();
@@ -1116,7 +1149,7 @@
         return;
     }
     if (newRanges is null && COMPACT_STYLES) {
-        newRanges = new int[newStyles.length << 1];     
+        newRanges = new int[newStyles.length << 1];
         StyleRange[] tmpStyles = new StyleRange[newStyles.length];
         if (stylesSet is null) stylesSet = new StyleRange[4];
         for (int i = 0, j = 0; i < newStyles.length; i++) {
@@ -1140,7 +1173,7 @@
         }
         newStyles = tmpStyles;
     }
-    
+
     if (styleCount is 0) {
         if (newRanges !is null) {
             ranges = new int[newRanges.length];
@@ -1195,7 +1228,7 @@
             if (ranges[modifyStart] < newStart && newStart < ranges[modifyStart] + ranges[modifyStart + 1]) {
                 mergeStyles[mergeCount >> 1] = styles[modifyStart >> 1];
                 mergeRanges[mergeCount] = ranges[modifyStart];
-                mergeRanges[mergeCount + 1] = newStart - ranges[modifyStart];               
+                mergeRanges[mergeCount + 1] = newStart - ranges[modifyStart];
                 mergeCount += 2;
             }
             mergeStyles[mergeCount >> 1] = newStyles[i >> 1];
@@ -1229,7 +1262,7 @@
         modifyEnd = modifyStart;
         StyleRange[] mergeStyles = new StyleRange[3];
         for (int i = 0; i < newStyles.length; i++) {
-            StyleRange newStyle = newStyles[i], style; 
+            StyleRange newStyle = newStyles[i], style;
             int newStart = newStyle.start;
             int newEnd = newStart + newStyle.length;
             if (newStart is newEnd) continue;
@@ -1263,9 +1296,9 @@
     int start = event.start;
     int newCharCount = event.newCharCount, replaceCharCount = event.replaceCharCount;
     int newLineCount = event.newLineCount, replaceLineCount = event.replaceLineCount;
-    
-    updateRanges(start, replaceCharCount, newCharCount);    
-    
+
+    updateRanges(start, replaceCharCount, newCharCount);
+
     int startLine = content.getLineAtOffset(start);
     if (replaceCharCount is content.getCharCount()) lines = null;
     if (replaceLineCount is lineCount) {
@@ -1278,7 +1311,7 @@
         if (lineCount + delta > lineWidth.length) {
             int[] newWidths = new int[lineCount + delta + GROW];
             System.arraycopy(lineWidth, 0, newWidths, 0, lineCount);
-            lineWidth = newWidths;          
+            lineWidth = newWidths;
             int[] newHeights = new int[lineCount + delta + GROW];
             System.arraycopy(lineHeight, 0, newHeights, 0, lineCount);
             lineHeight = newHeights;
@@ -1440,7 +1473,7 @@
                 ranges[modifyStart + 3] = ranges[modifyStart] + ranges[modifyStart + 1] - end;
                 ranges[modifyStart + 2] = start + newCharCount;
                 ranges[modifyStart + 1] = start - ranges[modifyStart];
-                styles[(modifyStart >> 1) + 1] = styles[modifyStart >> 1]; 
+                styles[(modifyStart >> 1) + 1] = styles[modifyStart >> 1];
                 rangeCount += 2;
                 styleCount++;
                 modifyEnd += 4;
--- a/dwt/custom/TableCursor.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/TableCursor.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,27 +7,47 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.TableCursor;
+
+import dwt.dwthelper.utils;
+
 
-import dwt.*;
-import dwt.graphics.*;
-import dwt.widgets.*;
-import dwt.events.*;
+import dwt.DWT;
+import dwt.DWTException;
+import dwt.events.SelectionEvent;
+import dwt.events.SelectionListener;
+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.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.widgets.ScrollBar;
+import dwt.widgets.Table;
+import dwt.widgets.TableColumn;
+import dwt.widgets.TableItem;
+import dwt.widgets.TypedListener;
+import dwt.widgets.Widget;
 
 /**
  * A TableCursor provides a way for the user to navigate around a Table
  * using the keyboard.  It also provides a mechanism for selecting an
  * individual cell in a table.
- * 
+ *
  * <p> Here is an example of using a TableCursor to navigate to a cell and then edit it.
- * 
+ *
  * <code><pre>
  *  public static void main(String[] args) {
  *      Display display = new Display();
  *      Shell shell = new Shell(display);
  *      shell.setLayout(new GridLayout());
- *  
+ *
  *      // create a a table with 3 columns and fill with data
  *      final Table table = new Table(shell, DWT.BORDER | DWT.MULTI | DWT.FULL_SELECTION);
  *      table.setLayoutData(new GridData(GridData.FILL_BOTH));
@@ -41,22 +61,22 @@
  *      column1.pack();
  *      column2.pack();
  *      column3.pack();
- *  
+ *
  *      // create a TableCursor to navigate around the table
  *      final TableCursor cursor = new TableCursor(table, DWT.NONE);
- *      // create an editor to edit the cell when the user hits "ENTER" 
+ *      // create an editor to edit the cell when the user hits "ENTER"
  *      // while over a cell in the table
  *      final ControlEditor editor = new ControlEditor(cursor);
  *      editor.grabHorizontal = true;
  *      editor.grabVertical = true;
- *  
+ *
  *      cursor.addSelectionListener(new SelectionAdapter() {
- *          // when the TableEditor is over a cell, select the corresponding row in 
+ *          // when the TableEditor is over a cell, select the corresponding row in
  *          // the table
  *          public void widgetSelected(SelectionEvent e) {
  *              table.setSelection(new TableItem[] {cursor.getRow()});
  *          }
- *          // when the user hits "ENTER" in the TableCursor, pop up a text editor so that 
+ *          // when the user hits "ENTER" in the TableCursor, pop up a text editor so that
  *          // they can change the text of the cell
  *          public void widgetDefaultSelected(SelectionEvent e){
  *              final Text text = new Text(cursor, DWT.NONE);
@@ -65,7 +85,7 @@
  *              text.setText(row.getText(column));
  *              text.addKeyListener(new KeyAdapter() {
  *                  public void keyPressed(KeyEvent e) {
- *                      // close the text editor and copy the data over 
+ *                      // close the text editor and copy the data over
  *                      // when the user hits "ENTER"
  *                      if (e.character is DWT.CR) {
  *                          TableItem row = cursor.getRow();
@@ -87,9 +107,9 @@
  *      // This allows the user to select multiple items in the table.
  *      cursor.addKeyListener(new KeyAdapter() {
  *          public void keyPressed(KeyEvent e) {
- *              if (e.keyCode is DWT.MOD1 || 
- *                  e.keyCode is DWT.MOD2 || 
- *                  (e.stateMask & DWT.MOD1) !is 0 || 
+ *              if (e.keyCode is DWT.MOD1 ||
+ *                  e.keyCode is DWT.MOD2 ||
+ *                  (e.stateMask & DWT.MOD1) !is 0 ||
  *                  (e.stateMask & DWT.MOD2) !is 0) {
  *                  cursor.setVisible(false);
  *              }
@@ -103,7 +123,7 @@
  *              if (e.keyCode is DWT.MOD2 && (e.stateMask & DWT.MOD1) !is 0) return;
  *              if (e.keyCode !is DWT.MOD1 && (e.stateMask & DWT.MOD1) !is 0) return;
  *              if (e.keyCode !is DWT.MOD2 && (e.stateMask & DWT.MOD2) !is 0) return;
- *          
+ *
  *              TableItem[] selection = table.getSelection();
  *              TableItem row = (selection.length is 0) ? table.getItem(table.getTopIndex()) : selection[0];
  *              table.showItem(row);
@@ -112,7 +132,7 @@
  *              cursor.setFocus();
  *          }
  *      });
- *  
+ *
  *      shell.open();
  *      while (!shell.isDisposed()) {
  *          if (!display.readAndDispatch())
@@ -121,18 +141,23 @@
  *      display.dispose();
  *  }
  * </pre></code>
- * 
+ *
  * <dl>
  * <dt><b>Styles:</b></dt>
  * <dd>BORDER</dd>
  * <dt><b>Events:</b></dt>
  * <dd>Selection, DefaultSelection</dd>
  * </dl>
- * 
+ *
  * @since 2.0
- * 
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#tablecursor">TableCursor snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> 
  */
 public class TableCursor : Canvas {
+
+    alias Canvas.dispose dispose;
+
     Table table;
     TableItem row = null;
     TableColumn column = null;
@@ -151,7 +176,7 @@
  * <p>
  * The style value is either one of the style constants defined in
  * class <code>DWT</code> which is applicable to instances of this
- * class, or must be built by <em>bitwise OR</em>'ing together 
+ * class, or must be built by <em>bitwise OR</em>'ing together
  * (that is, using the <code>int</code> "|" operator) two or more
  * of those <code>DWT</code> style constants. The class description
  * lists the style constants that are applicable to the class.
@@ -178,8 +203,8 @@
     table = parent;
     setBackground(null);
     setForeground(null);
-    
-    Listener listener = new Listener() {
+
+    Listener listener = new class() Listener {
         public void handleEvent(Event event) {
             switch (event.type) {
                 case DWT.Dispose :
@@ -203,18 +228,20 @@
                         case DWT.TRAVERSE_RETURN :
                             event.doit = false;
                             break;
+                        default:
                     }
                     break;
                 }
+                default:
             }
         }
     };
-    int[] events = new int[] {DWT.Dispose, DWT.FocusIn, DWT.FocusOut, DWT.KeyDown, DWT.Paint, DWT.Traverse};
+    int[] events = [DWT.Dispose, DWT.FocusIn, DWT.FocusOut, DWT.KeyDown, DWT.Paint, DWT.Traverse];
     for (int i = 0; i < events.length; i++) {
         addListener(events[i], listener);
     }
 
-    tableListener = new Listener() {
+    tableListener = new class() Listener {
         public void handleEvent(Event event) {
             switch (event.type) {
                 case DWT.MouseDown :
@@ -223,13 +250,14 @@
                 case DWT.FocusIn :
                     tableFocusIn(event);
                     break;
+                default:
             }
         }
     };
     table.addListener(DWT.FocusIn, tableListener);
     table.addListener(DWT.MouseDown, tableListener);
 
-    disposeItemListener = new Listener() {
+    disposeItemListener = new class() Listener {
         public void handleEvent(Event event) {
             unhookRowColumnListeners();
             row = null;
@@ -237,7 +265,7 @@
             _resize();
         }
     };
-    disposeColumnListener = new Listener() {
+    disposeColumnListener = new class() Listener {
         public void handleEvent(Event event) {
             unhookRowColumnListeners();
             row = null;
@@ -245,7 +273,7 @@
             _resize();
         }
     };
-    resizeListener = new Listener() {
+    resizeListener = new class() Listener {
         public void handleEvent(Event event) {
             _resize();
         }
@@ -285,7 +313,7 @@
  * @see SelectionListener
  * @see SelectionEvent
  * @see #removeSelectionListener(SelectionListener)
- * 
+ *
  */
 public void addSelectionListener(SelectionListener listener) {
     checkWidget();
@@ -316,6 +344,7 @@
         case DWT.CR :
             notifyListeners(DWT.DefaultSelection, new Event());
             return;
+        default:
     }
     int rowIndex = table.indexOf(row);
     int columnIndex = column is null ? 0 : table.indexOf(column);
@@ -328,7 +357,7 @@
             break;
         case DWT.ARROW_LEFT :
         case DWT.ARROW_RIGHT :
-            {   
+            {
                 int columnCount = table.getColumnCount();
                 if (columnCount is 0) break;
                 int[] order = table.getColumnOrder();
@@ -387,6 +416,7 @@
                 setRowColumn(index, columnIndex, true);
                 break;
             }
+        default:
     }
 }
 
@@ -408,14 +438,14 @@
         x += imageSize.width;
     }
     String text = row.getText(columnIndex);
-    if (text.length() > 0) {
+    if (text.length > 0) {
         Rectangle bounds = row.getBounds(columnIndex);
-        Point extent = gc.StringExtent(text);
+        Point extent = gc.stringExtent(text);
         // Temporary code - need a better way to determine table trim
         String platform = DWT.getPlatform();
-        if ("win32".opEquals(platform)) { //$NON-NLS-1$
+        if ("win32"==platform) { //$NON-NLS-1$
             if (table.getColumnCount() is 0 || columnIndex is 0) {
-                x += 2; 
+                x += 2;
             } else {
                 int alignmnent = column.getAlignment();
                 switch (alignmnent) {
@@ -428,11 +458,12 @@
                     case DWT.CENTER:
                         x += (bounds.width - x - extent.x) / 2;
                         break;
+                    default:
                 }
             }
         }  else {
             if (table.getColumnCount() is 0) {
-                x += 5; 
+                x += 5;
             } else {
                 int alignmnent = column.getAlignment();
                 switch (alignmnent) {
@@ -445,6 +476,7 @@
                     case DWT.CENTER:
                         x += (bounds.width - x - extent.x) / 2 + 2;
                         break;
+                    default:
                 }
             }
         }
@@ -557,7 +589,7 @@
     }
 }
 
-public void setVisible(bool visible) {
+public override void setVisible(bool visible) {
     checkWidget();
     if (visible) _resize();
     super.setVisible(visible);
@@ -579,7 +611,7 @@
  *
  * @see SelectionListener
  * @see #addSelectionListener(SelectionListener)
- * 
+ *
  * @since 3.0
  */
 public void removeSelectionListener(SelectionListener listener) {
@@ -588,7 +620,7 @@
         DWT.error(DWT.ERROR_NULL_ARGUMENT);
     }
     removeListener(DWT.Selection, listener);
-    removeListener(DWT.DefaultSelection, listener); 
+    removeListener(DWT.DefaultSelection, listener);
 }
 
 void _resize() {
@@ -669,7 +701,7 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  */
-public void setBackground (Color color) {
+public override void setBackground (Color color) {
     background = color;
     super.setBackground(getBackground());
     redraw();
@@ -691,13 +723,13 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  */
-public void setForeground (Color color) {
+public override void setForeground (Color color) {
     foreground = color;
     super.setForeground(getForeground());
     redraw();
 }
 /**
- * Positions the TableCursor over the cell at the given row and column in the parent table. 
+ * Positions the TableCursor over the cell at the given row and column in the parent table.
  *
  * @param row the index of the row for the cell to select
  * @param column the index of column for the cell to select
@@ -720,7 +752,7 @@
     setRowColumn(row, column, false);
 }
 /**
- * Positions the TableCursor over the cell at the given row and column in the parent table. 
+ * Positions the TableCursor over the cell at the given row and column in the parent table.
  *
  * @param row the TableItem of the row for the cell to select
  * @param column the index of column for the cell to select
--- a/dwt/custom/TableEditor.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/TableEditor.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,14 +7,26 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.TableEditor;
+
+import dwt.dwthelper.utils;
+
 
 
-import dwt.*;
-import dwt.events.*;
-import dwt.graphics.*;
-import dwt.widgets.*;
+import dwt.DWT;
+import dwt.events.ControlEvent;
+import dwt.events.ControlListener;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Table;
+import dwt.widgets.TableColumn;
+import dwt.widgets.TableItem;
+import dwt.custom.ControlEditor;
+import dwt.dwthelper.Runnable;
 
 /**
 *
@@ -34,7 +46,7 @@
 *   }
 *   column1.pack();
 *   column2.pack();
-*   
+*
 *   final TableEditor editor = new TableEditor(table);
 *   //The editor must have the same size as the cell and must
 *   //not be any smaller than 50 pixels.
@@ -43,23 +55,23 @@
 *   editor.minimumWidth = 50;
 *   // editing the second column
 *   final int EDITABLECOLUMN = 1;
-*   
+*
 *   table.addSelectionListener(new SelectionAdapter() {
 *       public void widgetSelected(SelectionEvent e) {
 *           // Clean up any previous editor control
 *           Control oldEditor = editor.getEditor();
 *           if (oldEditor !is null) oldEditor.dispose();
-*   
+*
 *           // Identify the selected row
-*           TableItem item = cast(TableItem)e.item;
+*           TableItem item = (TableItem)e.item;
 *           if (item is null) return;
-*   
+*
 *           // The control that will be the editor must be a child of the Table
 *           Text newEditor = new Text(table, DWT.NONE);
 *           newEditor.setText(item.getText(EDITABLECOLUMN));
 *           newEditor.addModifyListener(new ModifyListener() {
 *               public void modifyText(ModifyEvent e) {
-*                   Text text = cast(Text)editor.getEditor();
+*                   Text text = (Text)editor.getEditor();
 *                   editor.getItem().setText(EDITABLECOLUMN, text.getText());
 *               }
 *           });
@@ -69,6 +81,9 @@
 *       }
 *   });
 * </pre></code>
+*
+* @see <a href="http://www.eclipse.org/swt/snippets/#tableeditor">TableEditor snippets</a>
+* @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
 */
 public class TableEditor : ControlEditor {
     Table table;
@@ -86,8 +101,8 @@
 public this (Table table) {
     super(table);
     this.table = table;
-    
-    columnListener = new ControlListener() {
+
+    columnListener = new class() ControlListener {
         public void controlMoved(ControlEvent e){
             layout ();
         }
@@ -95,16 +110,16 @@
             layout ();
         }
     };
-    timer = new Runnable () {
+    timer = new class() Runnable {
         public void run() {
             layout ();
         }
     };
-    
+
     // To be consistent with older versions of DWT, grabVertical defaults to true
     grabVertical = true;
 }
-Rectangle computeBounds () {
+override Rectangle computeBounds () {
     if (item is null || column is -1 || item.isDisposed()) return new Rectangle(0, 0, 0, 0);
     Rectangle cell = item.getBounds(column);
     Rectangle rect = item.getImageBounds(column);
@@ -121,11 +136,11 @@
     if (grabHorizontal) {
         editorRect.width = Math.max(cell.width, minimumWidth);
     }
-    
+
     if (grabVertical) {
         editorRect.height = Math.max(cell.height, minimumHeight);
     }
-    
+
     if (horizontalAlignment is DWT.RIGHT) {
         editorRect.x += cell.width - editorRect.width;
     } else if (horizontalAlignment is DWT.LEFT) {
@@ -133,7 +148,7 @@
     } else { // default is CENTER
         editorRect.x += (cell.width - editorRect.width)/2;
     }
-    
+
     if (verticalAlignment is DWT.BOTTOM) {
         editorRect.y += cell.height - editorRect.height;
     } else if (verticalAlignment is DWT.TOP) {
@@ -147,7 +162,7 @@
  * Removes all associations between the TableEditor and the cell in the table.  The
  * Table and the editor Control are <b>not</b> disposed.
  */
-public void dispose () {
+public override void dispose () {
     if (table !is null && !table.isDisposed()) {
         if (this.column > -1 && this.column < table.getColumnCount()){
             TableColumn tableColumn = table.getColumn(this.column);
@@ -193,8 +208,8 @@
 }
 /**
 * Sets the zero based index of the column of the cell being tracked by this editor.
-* 
-* @param column the zero based index of the column of the cell being tracked by this editor 
+*
+* @param column the zero based index of the column of the cell being tracked by this editor
 */
 public void setColumn(int column) {
     int columnCount = table.getColumnCount();
@@ -211,18 +226,23 @@
         this.column = -1;
     }
 
-    if (column < 0  || column >= table.getColumnCount()) return;    
-        
+    if (column < 0  || column >= table.getColumnCount()) return;
+
     this.column = column;
     TableColumn tableColumn = table.getColumn(this.column);
     tableColumn.addControlListener(columnListener);
     resize();
 }
-public void setItem (TableItem item) {  
+/**
+* Specifies the <code>TableItem</code> that is to be edited.
+*
+* @param item the item to be edited
+*/
+public void setItem (TableItem item) {
     this.item = item;
     resize();
 }
-public void setEditor (Control editor) {
+public override void setEditor (Control editor) {
     super.setEditor(editor);
     resize();
 }
@@ -231,7 +251,7 @@
 *
 * <p>Note: The Control provided as the editor <b>must</b> be created with its parent being the Table control
 * specified in the TableEditor constructor.
-* 
+*
 * @param editor the Control that is displayed above the cell being edited
 * @param item the TableItem for the row of the cell being tracked by this editor
 * @param column the zero based index of the column of the cell being tracked by this editor
@@ -241,7 +261,7 @@
     setColumn(column);
     setEditor(editor);
 }
-public void layout () {
+public override void layout () {
     if (table is null || table.isDisposed()) return;
     if (item is null || item.isDisposed()) return;
     int columnCount = table.getColumnCount();
--- a/dwt/custom/TableTree.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/TableTree.d	Tue Oct 07 16:29:55 2008 +0200
@@ -7,16 +7,38 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.TableTree;
+
 
 
-import dwt.*;
-import dwt.events.*;
-import dwt.graphics.*;
-import dwt.widgets.*;
+import dwt.DWT;
+import dwt.DWTException;
+import dwt.events.SelectionEvent;
+import dwt.events.SelectionListener;
+import dwt.events.TreeListener;
+import dwt.graphics.Color;
+import dwt.graphics.Font;
+import dwt.graphics.GC;
+import dwt.graphics.Image;
+import dwt.graphics.ImageData;
+import dwt.graphics.PaletteData;
+import dwt.graphics.Point;
+import dwt.graphics.RGB;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Composite;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.widgets.Menu;
+import dwt.widgets.Table;
+import dwt.widgets.TableItem;
+import dwt.widgets.TypedListener;
+import dwt.custom.TableTreeItem;
+import dwt.dwthelper.utils;
 
-/** 
+/**
  * A TableTree is a selectable user interface object
  * that displays a hierarchy of items, and issues
  * notification when an item is selected.
@@ -36,31 +58,34 @@
  * <p>
  * Note: Only one of the styles SINGLE, and MULTI may be specified.
  * </p>
- * 
+ *
  * @deprecated As of 3.1 use Tree, TreeItem and TreeColumn
  */
 public class TableTree : Composite {
+
+    alias Composite.computeSize computeSize;
+
     Table table;
-    TableTreeItem[] items = EMPTY_ITEMS;
+    TableTreeItem[] items;
     Image plusImage, minusImage, sizeImage;
 
     /*
     * TableTreeItems are not treated as children but rather as items.
-    * When the TableTree is disposed, all children are disposed because 
+    * When the TableTree is disposed, all children are disposed because
     * TableTree inherits this behaviour from Composite.  The items
     * must be disposed separately.  Because TableTree is not part of
-    * the dwt.widgets module, the method releaseWidget can 
+    * the org.eclipse.swt.widgets module, the method releaseWidget can
     * not be overridden (this is how items are disposed of in Table and Tree).
     * Instead, the items are disposed of in response to the dispose event on the
     * TableTree.  The "inDispose" flag is used to distinguish between disposing
-    * one TableTreeItem (e.g. when removing an entry from the TableTree) and 
+    * one TableTreeItem (e.g. when removing an entry from the TableTree) and
     * disposing the entire TableTree.
     */
     bool inDispose = false;
-    
-    static final TableTreeItem[] EMPTY_ITEMS = new TableTreeItem [0];   
-    static final String[] EMPTY_TEXTS = new String [0]; 
-    static final Image[] EMPTY_IMAGES = new Image [0];
+
+    static final TableTreeItem[] EMPTY_ITEMS;
+    static final String[] EMPTY_TEXTS;
+    static final Image[] EMPTY_IMAGES;
     static final String ITEMID = "TableTreeItemID"; //$NON-NLS-1$
 
 /**
@@ -69,7 +94,7 @@
  * <p>
  * The style value is either one of the style constants defined in
  * class <code>DWT</code> which is applicable to instances of this
- * class, or must be built by <em>bitwise OR</em>'ing together 
+ * class, or must be built by <em>bitwise OR</em>'ing together
  * (that is, using the <code>int</code> "|" operator) two or more
  * of those <code>DWT</code> style constants. The class description
  * lists the style constants that are applicable to the class.
@@ -94,40 +119,43 @@
  */
 public this(Composite parent, int style) {
     super(parent, checkStyle (style));
+    items = EMPTY_ITEMS;
     table = new Table(this, style);
-    Listener tableListener = new Listener() {
+    Listener tableListener = new class() Listener {
         public void handleEvent(Event e) {
             switch (e.type) {
             case DWT.MouseDown: onMouseDown(e); break;
             case DWT.Selection: onSelection(e); break;
             case DWT.DefaultSelection: onSelection(e); break;
             case DWT.KeyDown: onKeyDown(e); break;
+            default:
             }
         }
     };
-    int[] tableEvents = new int[]{DWT.MouseDown, 
-                                   DWT.Selection, 
-                                   DWT.DefaultSelection, 
-                                   DWT.KeyDown};
+    int[] tableEvents = [DWT.MouseDown,
+                                   DWT.Selection,
+                                   DWT.DefaultSelection,
+                                   DWT.KeyDown];
     for (int i = 0; i < tableEvents.length; i++) {
         table.addListener(tableEvents[i], tableListener);
     }
-    
-    Listener listener = new Listener() {
+
+    Listener listener = new class() Listener {
         public void handleEvent(Event e) {
             switch (e.type) {
             case DWT.Dispose: onDispose(e); break;
             case DWT.Resize:  onResize(e); break;
             case DWT.FocusIn: onFocusIn(e); break;
+            default:
             }
         }
     };
-    int[] events = new int[]{DWT.Dispose, 
-                              DWT.Resize, 
-                              DWT.FocusIn};
+    int[] events = [DWT.Dispose,
+                              DWT.Resize,
+                              DWT.FocusIn];
     for (int i = 0; i < events.length; i++) {
         addListener(events[i], listener);
-    }                         
+    }
 }
 
 int addItem(TableTreeItem item, int index) {
@@ -135,13 +163,13 @@
     TableTreeItem[] newItems = new TableTreeItem[items.length + 1];
     System.arraycopy(items, 0, newItems, 0, index);
     newItems[index] = item;
-    System.arraycopy(items, index, newItems, index + 1, items.length - index); 
+    System.arraycopy(items, index, newItems, index + 1, items.length - index);
     items = newItems;
 
     /* Return the index in the table where this table should be inserted */
-    if (index is items.length - 1 ) 
+    if (index is items.length - 1 )
         return table.getItemCount();
-    else 
+    else
         return table.indexOf(items[index+1].tableItem);
 }
 
@@ -207,15 +235,15 @@
     addListener (DWT.Collapse, typedListener);
 }
 private static int checkStyle (int style) {
-    int mask = DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT; 
+    int mask = DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT;
     style = style & mask;
     return style;
-} 
-public Point computeSize (int wHint, int hHint, bool changed) {
+}
+public override Point computeSize (int wHint, int hHint, bool changed) {
     checkWidget();
     return table.computeSize (wHint, hHint, changed);
 }
-public Rectangle computeTrim (int x, int y, int width, int height) {
+public override Rectangle computeTrim (int x, int y, int width, int height) {
     checkWidget();
     return table.computeTrim(x, y, width, height);
 }
@@ -248,22 +276,22 @@
         notifyListeners(DWT.Expand, event);
     }
 }
-public Color getBackground () {
+public override Color getBackground () {
     // This method must be overridden otherwise, in a TableTree in which the first
     // item has no sub items, a grey (Widget background colour) square will appear in
     // the first column of the first item.
     // It is not possible in the constructor to set the background of the TableTree
-    // to be the same as the background of the Table because this interferes with 
+    // to be the same as the background of the Table because this interferes with
     // the TableTree adapting to changes in the System color settings.
     return table.getBackground();
 }
-public Rectangle getClientArea () {
+public override Rectangle getClientArea () {
     return table.getClientArea();
 }
-public Color getForeground () {
+public override Color getForeground () {
     return table.getForeground();
 }
-public Font getFont () {
+public override Font getFont () {
     return table.getFont();
 }
 /**
@@ -347,7 +375,7 @@
     return table.getSelectionCount();
 }
 
-public int getStyle () {
+public override int getStyle () {
     checkWidget();
     return table.getStyle();
 }
@@ -363,23 +391,23 @@
 }
 
 void createImages () {
-    
+
     int itemHeight = sizeImage.getBounds().height;
-    // Calculate border around image. 
+    // Calculate border around image.
     // At least 9 pixels are needed to draw the image
     // Leave at least a 6 pixel border.
     int indent = Math.min(6, (itemHeight - 9) / 2);
     indent = Math.max(0, indent);
-    int size = Math.max (10, itemHeight - 2 * indent); 
+    int size = Math.max (10, itemHeight - 2 * indent);
     size = ((size + 1) / 2) * 2; // size must be an even number
     int midpoint = indent + size / 2;
-    
+
     Color foreground = getForeground();
     Color plusMinus = getDisplay().getSystemColor(DWT.COLOR_WIDGET_NORMAL_SHADOW);
     Color background = getBackground();
-    
+
     /* Plus image */
-    PaletteData palette = new PaletteData(new RGB[]{foreground.getRGB(), background.getRGB(), plusMinus.getRGB()});
+    PaletteData palette = new PaletteData( [ foreground.getRGB(), background.getRGB(), plusMinus.getRGB()]);
     ImageData imageData = new ImageData(itemHeight, itemHeight, 4, palette);
     imageData.transparentPixel = 1;
     plusImage = new Image(getDisplay(), imageData);
@@ -392,9 +420,9 @@
     gc.drawLine(midpoint, indent + 2, midpoint, indent + size - 2);
     gc.drawLine(indent + 2, midpoint, indent + size - 2, midpoint);
     gc.dispose();
-    
+
     /* Minus image */
-    palette = new PaletteData(new RGB[]{foreground.getRGB(), background.getRGB(), plusMinus.getRGB()});
+    palette = new PaletteData([foreground.getRGB(), background.getRGB(), plusMinus.getRGB()]);
     imageData = new ImageData(itemHeight, itemHeight, 4, palette);
     imageData.transparentPixel = 1;
     minusImage = new Image(getDisplay(), imageData);
@@ -420,7 +448,7 @@
 
 /**
  * Gets the index of an item.
- * 
+ *
  * <p>The widget is searched starting at 0 until an
  * item is found that is equal to the search item.
  * If no item is found, -1 is returned.  Indexing
@@ -486,7 +514,7 @@
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 3.1
  */
 public TableTreeItem getItem (int index) {
@@ -517,7 +545,7 @@
     TableItem item = table.getItem(point);
     if (item is null) return null;
     return getItem(item);
-    
+
 }
 TableTreeItem getItem(TableItem tableItem) {
     if (tableItem is null) return null;
@@ -542,7 +570,7 @@
             if (item.getItemCount() is 0) return;
             if (item.getExpanded()) {
                 TableTreeItem newSelection = item.getItems()[0];
-                table.setSelection(new TableItem[]{newSelection.tableItem});
+                table.setSelection([newSelection.tableItem]);
                 showItem(newSelection);
                 type = DWT.Selection;
             } else {
@@ -558,7 +586,7 @@
                 if (parent !is null) {
                     int index = parent.indexOf(item);
                     if (index !is 0) return;
-                    table.setSelection(new TableItem[]{parent.tableItem});
+                    table.setSelection([parent.tableItem]);
                     type = DWT.Selection;
                 }
             }
@@ -578,7 +606,7 @@
             item.setExpanded(true);
             type = DWT.Expand;
         }
-    } 
+    }
     if (type is 0) return;
     Event event = new Event();
     event.item = item;
@@ -697,7 +725,7 @@
     checkWidget();
     table.selectAll();
 }
-public void setBackground (Color color) {
+public override void setBackground (Color color) {
     super.setBackground(color);
     table.setBackground(color);
     if (sizeImage !is null) {
@@ -708,19 +736,19 @@
         gc.dispose();
     }
 }
-public void setEnabled (bool enabled) {
+public override void setEnabled (bool enabled) {
     super.setEnabled(enabled);
     table.setEnabled(enabled);
 }
-public void setFont (Font font) {
+public override void setFont (Font font) {
     super.setFont(font);
     table.setFont(font);
 }
-public void setForeground (Color color) {
+public override void setForeground (Color color) {
     super.setForeground(color);
     table.setForeground(color);
 }
-public void setMenu (Menu menu) {
+public override void setMenu (Menu menu) {
     super.setMenu(menu);
     table.setMenu(menu);
 }
@@ -736,7 +764,6 @@
  * @param items the array of items
  *
  * @exception IllegalArgumentException <ul>
- *    <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
  *    <li>ERROR_INVALID_ARGUMENT - if one of the item has been disposed</li>
  * </ul>
  * @exception DWTException <ul>
@@ -748,7 +775,8 @@
  */
 public void setSelection (TableTreeItem[] items) {
     checkWidget ();
-    if (items is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    // DWT extension: allow null for zero length string
+    //if (items is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
     int length = items.length;
     if (length is 0 || ((table.getStyle() & DWT.SINGLE) !is 0 && length > 1)) {
         deselectAll();
@@ -762,9 +790,9 @@
     }
     table.setSelection(tableItems);
 }
-public void setToolTipText (String String) {
-    super.setToolTipText(String);
-    table.setToolTipText(String);
+public override void setToolTipText (String string) {
+    super.setToolTipText(string);
+    table.setToolTipText(string);
 }
 
 /**
--- a/dwt/custom/TableTreeEditor.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/TableTreeEditor.d	Tue Oct 07 16:29:55 2008 +0200
@@ -7,20 +7,35 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.TableTreeEditor;
+
+import dwt.dwthelper.utils;
 
 
-import dwt.*;
-import dwt.graphics.*;
-import dwt.widgets.*;
-import dwt.events.*;
+import dwt.DWT;
+import dwt.events.ControlEvent;
+import dwt.events.ControlListener;
+import dwt.events.TreeEvent;
+import dwt.events.TreeListener;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Control;
+import dwt.widgets.Table;
+import dwt.widgets.TableColumn;
+import dwt.custom.ControlEditor;
+import dwt.custom.TableTree;
+import dwt.custom.TableTreeItem;
+
+import dwt.dwthelper.Runnable;
+
 /**
 *
 * A TableTreeEditor is a manager for a Control that appears above a cell in a TableTree
 * and tracks with the moving and resizing of that cell.  It can be used to display a
-* text widget above a cell in a TableTree so that the user can edit the contents of 
-* that cell.  It can also be used to display a button that can launch a dialog for 
+* text widget above a cell in a TableTree so that the user can edit the contents of
+* that cell.  It can also be used to display a button that can launch a dialog for
 * modifying the contents of the associated cell.
 *
 * <p> Here is an example of using a TableTreeEditor:
@@ -41,7 +56,7 @@
 *   }
 *   column1.setWidth(100);
 *   column2.pack();
-*   
+*
 *   final TableTreeEditor editor = new TableTreeEditor(tableTree);
 *   //The editor must have the same size as the cell and must
 *   //not be any smaller than 50 pixels.
@@ -50,23 +65,23 @@
 *   editor.minimumWidth = 50;
 *   // editing the second column
 *   final int EDITABLECOLUMN = 1;
-*   
+*
 *   tableTree.addSelectionListener(new SelectionAdapter() {
 *       public void widgetSelected(SelectionEvent e) {
 *           // Clean up any previous editor control
 *           Control oldEditor = editor.getEditor();
 *           if (oldEditor !is null) oldEditor.dispose();
-*   
+*
 *           // Identify the selected row
-*           TableTreeItem item = cast(TableTreeItem)e.item;
+*           TableTreeItem item = (TableTreeItem)e.item;
 *           if (item is null) return;
-*   
+*
 *           // The control that will be the editor must be a child of the Table
 *           Text newEditor = new Text(table, DWT.NONE);
 *           newEditor.setText(item.getText(EDITABLECOLUMN));
 *           newEditor.addModifyListener(new ModifyListener() {
 *               public void modifyText(ModifyEvent e) {
-*                   Text text = cast(Text)editor.getEditor();
+*                   Text text = (Text)editor.getEditor();
 *                   editor.getItem().setText(EDITABLECOLUMN, text.getText());
 *               }
 *           });
@@ -76,11 +91,13 @@
 *       }
 *   });
 * </pre></code>
-* 
+*
 * @deprecated As of 3.1 use TreeEditor with Tree, TreeItem and TreeColumn
 */
 public class TableTreeEditor : ControlEditor {
 
+    alias ControlEditor.setEditor setEditor;
+
     TableTree tableTree;
     TableTreeItem item;
     int column = -1;
@@ -96,15 +113,18 @@
     super(tableTree.getTable());
     this.tableTree = tableTree;
 
-    treeListener = new TreeListener () {
-        final Runnable runnable = new Runnable() {
-            public void run() {
-                if (editor is null || editor.isDisposed()) return;
-                if (TableTreeEditor.this.tableTree.isDisposed()) return;
-                layout();
-                editor.setVisible(true);
-            }
-        };
+    treeListener = new class() TreeListener  {
+        Runnable runnable;
+        this() {
+            runnable = new class() Runnable {
+                public void run() {
+                    if (editor is null || editor.isDisposed()) return;
+                    if (this.outer.outer.tableTree.isDisposed()) return;
+                    layout();
+                    editor.setVisible(true);
+                }
+            };
+        }
         public void treeCollapsed(TreeEvent e) {
             if (editor is null || editor.isDisposed ()) return;
             editor.setVisible(false);
@@ -117,8 +137,8 @@
         }
     };
     tableTree.addTreeListener(treeListener);
-    
-    columnListener = new ControlListener() {
+
+    columnListener = new class() ControlListener {
         public void controlMoved(ControlEvent e){
             layout ();
         }
@@ -126,11 +146,12 @@
             layout ();
         }
     };
-    
+
     // To be consistent with older versions of DWT, grabVertical defaults to true
     grabVertical = true;
 }
-Rectangle computeBounds () {
+
+override Rectangle computeBounds () {
     if (item is null || column is -1 || item.isDisposed() || item.tableItem is null) return new Rectangle(0, 0, 0, 0);
     Rectangle cell = item.getBounds(column);
     Rectangle area = tableTree.getClientArea();
@@ -144,11 +165,11 @@
     if (grabHorizontal) {
         editorRect.width = Math.max(cell.width, minimumWidth);
     }
-    
+
     if (grabVertical) {
         editorRect.height = Math.max(cell.height, minimumHeight);
     }
-    
+
     if (horizontalAlignment is DWT.RIGHT) {
         editorRect.x += cell.width - editorRect.width;
     } else if (horizontalAlignment is DWT.LEFT) {
@@ -156,7 +177,7 @@
     } else { // default is CENTER
         editorRect.x += (cell.width - editorRect.width)/2;
     }
-    
+
     if (verticalAlignment is DWT.BOTTOM) {
         editorRect.y += cell.height - editorRect.height;
     } else if (verticalAlignment is DWT.TOP) {
@@ -170,7 +191,7 @@
  * Removes all associations between the TableTreeEditor and the cell in the table tree.  The
  * TableTree and the editor Control are <b>not</b> disposed.
  */
-public void dispose () {
+public override void dispose () {
     if (tableTree !is null && !tableTree.isDisposed()) {
         Table table = tableTree.getTable();
         if (table !is null && !table.isDisposed()) {
@@ -220,14 +241,14 @@
         this.column = -1;
     }
 
-    if (column < 0  || column >= table.getColumnCount()) return;    
-        
+    if (column < 0  || column >= table.getColumnCount()) return;
+
     this.column = column;
     TableColumn tableColumn = table.getColumn(this.column);
     tableColumn.addControlListener(columnListener);
     layout();
 }
-public void setItem (TableTreeItem item) {  
+public void setItem (TableTreeItem item) {
     this.item = item;
     layout();
 }
@@ -237,17 +258,18 @@
 *
 * <p>Note: The Control provided as the editor <b>must</b> be created with its parent being the Table control
 * specified in the TableEditor constructor.
-* 
+*
 * @param editor the Control that is displayed above the cell being edited
 * @param item the TableItem for the row of the cell being tracked by this editor
 * @param column the zero based index of the column of the cell being tracked by this editor
 */
+alias ControlEditor.setEditor setEditor;
 public void setEditor (Control editor, TableTreeItem item, int column) {
     setItem(item);
     setColumn(column);
     setEditor(editor);
 }
-public void layout () {
+public override void layout () {
     if (tableTree is null || tableTree.isDisposed()) return;
     if (item is null || item.isDisposed()) return;
     Table table = tableTree.getTable();
@@ -256,4 +278,5 @@
     if (columnCount > 0 && (column < 0 || column >= columnCount)) return;
     super.layout();
 }
+
 }
--- a/dwt/custom/TableTreeItem.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/TableTreeItem.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,28 +7,43 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.TableTreeItem;
+
 
 
-import dwt.*;
-import dwt.graphics.*;
-import dwt.widgets.*;
+import dwt.DWT;
+import dwt.DWTException;
+import dwt.graphics.Color;
+import dwt.graphics.Font;
+import dwt.graphics.GC;
+import dwt.graphics.Image;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Event;
+import dwt.widgets.Item;
+import dwt.widgets.Table;
+import dwt.widgets.TableItem;
+import dwt.widgets.Widget;
+import dwt.custom.TableTree;
+import dwt.dwthelper.utils;
+
 
 /**
  * A TableTreeItem is a selectable user interface object
  * that represents an item in a hierarchy of items in a
  * TableTree.
- * 
+ *
  * @deprecated As of 3.1 use Tree, TreeItem and TreeColumn
  */
 public class TableTreeItem : Item {
     TableItem tableItem;
     TableTree parent;
     TableTreeItem parentItem;
-    TableTreeItem [] items = TableTree.EMPTY_ITEMS;
-    String[] texts = TableTree.EMPTY_TEXTS;
-    Image[] images = TableTree.EMPTY_IMAGES;
+    TableTreeItem [] items;
+    String[] texts;
+    Image[] images;
     Color background;
     Color foreground;
     Font font;
@@ -44,7 +59,7 @@
  * <p>
  * The style value is either one of the style constants defined in
  * class <code>DWT</code> which is applicable to instances of this
- * class, or must be built by <em>bitwise OR</em>'ing together 
+ * class, or must be built by <em>bitwise OR</em>'ing together
  * (that is, using the <code>int</code> "|" operator) two or more
  * of those <code>DWT</code> style constants. The class description
  * lists the style constants that are applicable to the class.
@@ -76,7 +91,7 @@
  * <p>
  * The style value is either one of the style constants defined in
  * class <code>DWT</code> which is applicable to instances of this
- * class, or must be built by <em>bitwise OR</em>'ing together 
+ * class, or must be built by <em>bitwise OR</em>'ing together
  * (that is, using the <code>int</code> "|" operator) two or more
  * of those <code>DWT</code> style constants. The class description
  * lists the style constants that are applicable to the class.
@@ -109,7 +124,7 @@
  * <p>
  * The style value is either one of the style constants defined in
  * class <code>DWT</code> which is applicable to instances of this
- * class, or must be built by <em>bitwise OR</em>'ing together 
+ * class, or must be built by <em>bitwise OR</em>'ing together
  * (that is, using the <code>int</code> "|" operator) two or more
  * of those <code>DWT</code> style constants. The class description
  * lists the style constants that are applicable to the class.
@@ -141,7 +156,7 @@
  * <p>
  * The style value is either one of the style constants defined in
  * class <code>DWT</code> which is applicable to instances of this
- * class, or must be built by <em>bitwise OR</em>'ing together 
+ * class, or must be built by <em>bitwise OR</em>'ing together
  * (that is, using the <code>int</code> "|" operator) two or more
  * of those <code>DWT</code> style constants. The class description
  * lists the style constants that are applicable to the class.
@@ -167,11 +182,16 @@
 }
 
 this(TableTree parent, TableTreeItem parentItem, int style, int index) {
+
+    items = TableTree.EMPTY_ITEMS;
+    texts = TableTree.EMPTY_TEXTS;
+    images = TableTree.EMPTY_IMAGES;
+
     super(parent, style);
     this.parent = parent;
     this.parentItem = parentItem;
     if (parentItem is null) {
-        
+
         /* Root items are visible immediately */
         int tableIndex = parent.addItem(this, index);
         tableItem = new TableItem(parent.getTable(), style, tableIndex);
@@ -206,7 +226,7 @@
 void addItem(TableTreeItem item, int index) {
     if (item is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
     if (index < 0 || index > items.length) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
-        
+
     /* Now that item has a sub-node it must indicate that it can be expanded */
     if (items.length is 0 && index is 0) {
         if (tableItem !is null) {
@@ -214,7 +234,7 @@
             tableItem.setImage(0, image);
         }
     }
-    
+
     /* Put the item in the items list */
     TableTreeItem[] newItems = new TableTreeItem[items.length + 1];
     System.arraycopy(items, 0, newItems, 0, index);
@@ -228,14 +248,14 @@
  * Returns the receiver's background color.
  *
  * @return the background color
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 2.0
- * 
+ *
  */
 public Color getBackground () {
     checkWidget ();
@@ -290,7 +310,7 @@
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 2.1
  */
 public bool getGrayed () {
@@ -336,9 +356,9 @@
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 2.0
- * 
+ *
  */
 public Color getForeground () {
     checkWidget ();
@@ -351,13 +371,13 @@
  * images of the tree, therefore getImage(0) will return null.
  *
  * @return the image at index 0
- * 
+ *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  */
-public Image getImage () {
+public override Image getImage () {
     checkWidget();
     return getImage(0);
 }
@@ -398,7 +418,7 @@
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 3.1
  */
 public TableTreeItem getItem (int index) {
@@ -425,7 +445,7 @@
  * <p>
  * Note: This is not the actual structure used by the receiver
  * to maintain its list of items, so modifying the array will
- * not affect the receiver. 
+ * not affect the receiver.
  * </p>
  *
  * @return the receiver's items
@@ -468,7 +488,7 @@
     //checkWidget();
     return parentItem;
 }
-public String getText () {
+public override String getText () {
     checkWidget();
     return getText(0);
 }
@@ -497,7 +517,7 @@
 
 /**
  * Gets the index of the specified item.
- * 
+ *
  * <p>The widget is searched starting at 0 until an
  * item is found that is equal to the search item.
  * If no item is found, -1 is returned.  Indexing
@@ -508,7 +528,7 @@
  *
  */
 public int indexOf (TableTreeItem item) {
-    //checkWidget();    
+    //checkWidget();
     for (int i = 0; i < items.length; i++) {
         if (items[i] is item) return i;
     }
@@ -529,7 +549,7 @@
         items[i].expandAll(notify);
     }
 }
-int expandedIndexOf (TableTreeItem item) {  
+int expandedIndexOf (TableTreeItem item) {
     int index = 0;
     for (int i = 0; i < items.length; i++) {
         if (items[i] is item) return index;
@@ -549,7 +569,7 @@
     return count;
 }
 
-public void dispose () {
+public override void dispose () {
     if (isDisposed()) return;
     for (int i = items.length - 1; i >= 0; i--) {
         items[i].dispose();
@@ -593,17 +613,17 @@
  * if the argument is null.
  *
  * @param color the new color (or null)
- * 
+ *
  * @exception IllegalArgumentException <ul>
- *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> 
+ *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
  * </ul>
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 2.0
- * 
+ *
  */
 public void setBackground (Color color) {
     checkWidget ();
@@ -617,7 +637,7 @@
 }
 
 /**
- * Sets the checked state of the checkbox for this item.  This state change 
+ * Sets the checked state of the checkbox for this item.  This state change
  * only applies if the Table was created with the DWT.CHECK style.
  *
  * @param checked the new checked state of the checkbox
@@ -638,16 +658,16 @@
 }
 
 /**
- * Sets the grayed state of the checkbox for this item.  This state change 
+ * Sets the grayed state of the checkbox for this item.  This state change
  * only applies if the Table was created with the DWT.CHECK style.
  *
- * @param grayed the new grayed state of the checkbox; 
+ * @param grayed the new grayed state of the checkbox;
  *
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 2.1
  */
 public void setGrayed (bool grayed) {
@@ -693,13 +713,13 @@
  * @param font the new font (or null)
  *
  * @exception IllegalArgumentException <ul>
- *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> 
+ *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
  * </ul>
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 3.0
  */
 public void setFont (Font font){
@@ -720,17 +740,17 @@
  * @param color the new color (or null)
  *
  * @since 2.0
- * 
+ *
  * @exception IllegalArgumentException <ul>
- *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> 
+ *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
  * </ul>
  * @exception DWTException <ul>
  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
- * 
+ *
  * @since 2.0
- * 
+ *
  */
 public void setForeground (Color color) {
     checkWidget ();
@@ -778,13 +798,13 @@
  * images of the tree, therefore do nothing.
  *
  * @param image the new image or null
- * 
+ *
  * @exception DWTException <ul>
  *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
  *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
  *  </ul>
  */
-public void setImage (Image image) {
+public override void setImage (Image image) {
     setImage(0, image);
 }
 
@@ -799,9 +819,6 @@
  * @param index the column number
  * @param text the new text
  *
- * @exception IllegalArgumentException <ul>
- *    <li>ERROR_NULL_ARGUMENT - if the text is null</li>
- * </ul>
  * @exception DWTException <ul>
  *      <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
  *      <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
@@ -809,7 +826,8 @@
  */
 public void setText(int index, String text) {
     checkWidget();
-    if (text is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
+    // DWT extension: allow null for zero length string
+    //if (text is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
     int columnCount = Math.max(parent.getTable().getColumnCount(), 1);
     if (index < 0 || index >= columnCount) return;
     if (texts.length < columnCount) {
@@ -820,8 +838,8 @@
     texts[index] = text;
     if (tableItem !is null) tableItem.setText(index, text);
 }
-public void setText (String String) {
-    setText(0, String);
+public override void setText (String string) {
+    setText(0, string);
 }
 
 void setVisible (bool show) {
@@ -862,7 +880,7 @@
                 tableItem.setImage(0, parent.getPlusImage());
             }
         }
-        
+
     } else {
 
         for (int i = 0, length = items.length; i < length; i++) {
--- a/dwt/custom/TextChangeListener.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/TextChangeListener.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
  * Copyright (c) 2000, 2003 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -7,33 +7,37 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.TextChangeListener;
 
 
 import dwt.internal.DWTEventListener;
+import dwt.custom.TextChangingEvent;
+import dwt.custom.TextChangedEvent;
 
 /**
- * The StyledText widget : this listener to receive
+ * The StyledText widget implements this listener to receive
  * notifications when changes to the model occur.
- * It is not intended to be implemented by clients or by 
- * implementors of StyledTextContent. 
- * Clients should listen to the ModifyEvent or ExtendedModifyEvent 
- * that is sent by the StyledText widget to receive text change 
+ * It is not intended to be implemented by clients or by
+ * implementors of StyledTextContent.
+ * Clients should listen to the ModifyEvent or ExtendedModifyEvent
+ * that is sent by the StyledText widget to receive text change
  * notifications.
  * Implementors of StyledTextContent should call the textChanging
- * and textChanged methods when text changes occur as described 
- * below. If the entire text is replaced the textSet method 
+ * and textChanged methods when text changes occur as described
+ * below. If the entire text is replaced the textSet method
  * should be called instead.
  */
 public interface TextChangeListener : DWTEventListener {
 
 /**
  * This method is called when the content is about to be changed.
- * Callers also need to call the textChanged method after the 
- * content change has been applied. The widget only updates the 
- * screen properly when it receives both events. 
- * 
+ * Callers also need to call the textChanged method after the
+ * content change has been applied. The widget only updates the
+ * screen properly when it receives both events.
+ *
  * @param event the text changing event. All event fields need
  *  to be set by the sender.
  * @see TextChangingEvent
@@ -41,18 +45,18 @@
 public void textChanging(TextChangingEvent event);
 /**
  * This method is called when the content has changed.
- * Callers need to have called the textChanging method prior to 
- * applying the content change and calling this method. The widget 
+ * Callers need to have called the textChanging method prior to
+ * applying the content change and calling this method. The widget
  * only updates the screen properly when it receives both events.
- * 
+ *
  * @param event the text changed event
  */
 public void textChanged(TextChangedEvent event);
 /**
- * This method is called instead of the textChanging/textChanged 
- * combination when the entire old content has been replaced 
+ * This method is called instead of the textChanging/textChanged
+ * combination when the entire old content has been replaced
  * (e.g., by a call to StyledTextContent.setText()).
- * 
+ *
  * @param event the text changed event
  */
 public void textSet(TextChangedEvent event);
--- a/dwt/custom/TextChangedEvent.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/TextChangedEvent.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,27 +7,29 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.TextChangedEvent;
 
-import dwt.events.*;
-
+import dwt.events.TypedEvent;
+import dwt.custom.StyledTextContent;
 /**
- * This event is sent by the StyledTextContent implementor when a change to 
+ * This event is sent by the StyledTextContent implementor when a change to
  * the text occurs.
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 public class TextChangedEvent : TypedEvent {
 
-    static final long serialVersionUID = 3258696524257835065L;
-
 /**
  * Create the TextChangedEvent to be used by the StyledTextContent implementor.
  * <p>
  *
- * @param source the object that will be sending the TextChangedEvent, 
- *  cannot be null  
+ * @param source the object that will be sending the TextChangedEvent,
+ *  cannot be null
  */
 public this(StyledTextContent source) {
-    super(source);
+    super(cast(Object)source);
 }
 }
--- a/dwt/custom/TextChangingEvent.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/TextChangingEvent.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,15 +7,23 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.TextChangingEvent;
+
+import dwt.dwthelper.utils;
 
 
-import dwt.events.*;
+import dwt.events.TypedEvent;
+import dwt.custom.StyledTextContent;
+import dwt.custom.StyledTextEvent;
 
 /**
  * This event is sent by the StyledTextContent implementor when a change
  * to the text is about to occur.
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 public class TextChangingEvent : TypedEvent {
     /**
@@ -23,7 +31,7 @@
      */
     public int start;
     /**
-     * Text that is going to be inserted or empty String
+     * Text that is going to be inserted or empty string
      * if no text will be inserted
      */
     public String newText;
@@ -45,19 +53,19 @@
     public int newLineCount;
 
     static final long serialVersionUID = 3257290210114352439L;
-    
+
 /**
  * Create the TextChangedEvent to be used by the StyledTextContent implementor.
  * <p>
  *
- * @param source the object that will be sending the new TextChangingEvent, 
- *  cannot be null  
+ * @param source the object that will be sending the new TextChangingEvent,
+ *  cannot be null
  */
 public this(StyledTextContent source) {
-    super(source);
+    super( cast(Object)source);
 }
 this(StyledTextContent source, StyledTextEvent e) {
-    super(source);
+    super( cast(Object)source);
     start = e.start;
     replaceCharCount = e.replaceCharCount;
     newCharCount = e.newCharCount;
--- a/dwt/custom/TreeEditor.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/TreeEditor.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,14 +7,27 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.TreeEditor;
+
+import dwt.dwthelper.utils;
 
 
-import dwt.*;
-import dwt.events.*;
-import dwt.graphics.*;
-import dwt.widgets.*;
+import dwt.DWT;
+import dwt.events.ControlEvent;
+import dwt.events.ControlListener;
+import dwt.events.TreeEvent;
+import dwt.events.TreeListener;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Tree;
+import dwt.widgets.TreeColumn;
+import dwt.widgets.TreeItem;
+import dwt.custom.ControlEditor;
+import dwt.dwthelper.Runnable;
 
 /**
 *
@@ -34,30 +47,30 @@
 *           subItem.setText("item " + i + " " + j);
 *       }
 *   }
-*   
+*
 *   final TreeEditor editor = new TreeEditor(tree);
 *   //The editor must have the same size as the cell and must
 *   //not be any smaller than 50 pixels.
 *   editor.horizontalAlignment = DWT.LEFT;
 *   editor.grabHorizontal = true;
 *   editor.minimumWidth = 50;
-*   
+*
 *   tree.addSelectionListener(new SelectionAdapter() {
 *       public void widgetSelected(SelectionEvent e) {
 *           // Clean up any previous editor control
 *           Control oldEditor = editor.getEditor();
 *           if (oldEditor !is null) oldEditor.dispose();
-*   
+*
 *           // Identify the selected row
-*           TreeItem item = cast(TreeItem)e.item;
+*           TreeItem item = (TreeItem)e.item;
 *           if (item is null) return;
-*   
+*
 *           // The control that will be the editor must be a child of the Tree
 *           Text newEditor = new Text(tree, DWT.NONE);
 *           newEditor.setText(item.getText());
 *           newEditor.addModifyListener(new ModifyListener() {
 *               public void modifyText(ModifyEvent e) {
-*                   Text text = cast(Text)editor.getEditor();
+*                   Text text = (Text)editor.getEditor();
 *                   editor.getItem().setText(text.getText());
 *               }
 *           });
@@ -67,16 +80,20 @@
 *       }
 *   });
 * </pre></code>
+*
+* @see <a href="http://www.eclipse.org/swt/snippets/#treeeditor">TreeEditor snippets</a>
+* @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
 */
-public class TreeEditor : ControlEditor {   
+
+public class TreeEditor : ControlEditor {
     Tree tree;
     TreeItem item;
     int column = 0;
     ControlListener columnListener;
     TreeListener treeListener;
     Runnable timer;
-    static final int TIMEOUT = 1500;
-    
+    static const int TIMEOUT = 1500;
+
 /**
 * Creates a TreeEditor for the specified Tree.
 *
@@ -87,7 +104,7 @@
     super(tree);
     this.tree = tree;
 
-    columnListener = new ControlListener() {
+    columnListener = new class() ControlListener {
         public void controlMoved(ControlEvent e){
             layout();
         }
@@ -95,38 +112,41 @@
             layout();
         }
     };
-    timer = new Runnable () {
+    timer = new class() Runnable {
         public void run() {
             layout ();
         }
     };
-    treeListener = new TreeListener () {
-        final Runnable runnable = new Runnable() {
-            public void run() {
-                if (editor is null || editor.isDisposed()) return;
-                if (TreeEditor.this.tree.isDisposed()) return;
-                layout();
-                editor.setVisible(true);
-            }
-        };
+    treeListener = new class() TreeListener {
+        Runnable runnable;
+        this(){
+            runnable = new class() Runnable {
+                public void run() {
+                    if (this.outer.outer.editor is null || this.outer.outer.editor.isDisposed()) return;
+                    if (this.outer.outer.tree.isDisposed()) return;
+                    layout();
+                    this.outer.outer.editor.setVisible(true);
+                }
+            };
+        }
         public void treeCollapsed(TreeEvent e) {
-            if (editor is null || editor.isDisposed ()) return;
-            editor.setVisible(false);
+            if (this.outer.editor is null || this.outer.editor.isDisposed ()) return;
+            this.outer.editor.setVisible(false);
             e.display.asyncExec(runnable);
         }
         public void treeExpanded(TreeEvent e) {
-            if (editor is null || editor.isDisposed ()) return;
-            editor.setVisible(false);
+            if (this.outer.editor is null || this.outer.editor.isDisposed ()) return;
+            this.outer.editor.setVisible(false);
             e.display.asyncExec(runnable);
         }
     };
     tree.addTreeListener(treeListener);
-    
+
     // To be consistent with older versions of DWT, grabVertical defaults to true
     grabVertical = true;
 }
 
-Rectangle computeBounds () {
+override Rectangle computeBounds () {
     if (item is null || column is -1 || item.isDisposed()) return new Rectangle(0, 0, 0, 0);
     Rectangle cell = item.getBounds(column);
     Rectangle rect = item.getImageBounds(column);
@@ -142,17 +162,17 @@
 
     if (grabHorizontal) {
         if (tree.getColumnCount() is 0) {
-            // Bounds of tree item only include the text area - stretch out to include 
+            // Bounds of tree item only include the text area - stretch out to include
             // entire client area
             cell.width = area.x + area.width - cell.x;
         }
         editorRect.width = Math.max(cell.width, minimumWidth);
     }
-    
+
     if (grabVertical) {
         editorRect.height = Math.max(cell.height, minimumHeight);
     }
-    
+
     if (horizontalAlignment is DWT.RIGHT) {
         editorRect.x += cell.width - editorRect.width;
     } else if (horizontalAlignment is DWT.LEFT) {
@@ -160,9 +180,9 @@
     } else { // default is CENTER
         editorRect.x += (cell.width - editorRect.width)/2;
     }
-    // don't let the editor overlap with the +/- of the tree
+    // don't let the editor overlap with the + / - of the tree
     editorRect.x = Math.max(cell.x, editorRect.x);
-    
+
     if (verticalAlignment is DWT.BOTTOM) {
         editorRect.y += cell.height - editorRect.height;
     } else if (verticalAlignment is DWT.TOP) {
@@ -177,7 +197,7 @@
  * Removes all associations between the TreeEditor and the row in the tree.  The
  * tree and the editor Control are <b>not</b> disposed.
  */
-public void dispose () {
+public override void dispose () {
     if (tree !is null && !tree.isDisposed()) {
         if (this.column > -1 && this.column < tree.getColumnCount()){
             TreeColumn treeColumn = tree.getColumn(this.column);
@@ -231,7 +251,7 @@
 
 /**
 * Sets the zero based index of the column of the cell being tracked by this editor.
-* 
+*
 * @param column the zero based index of the column of the cell being tracked by this editor
 *
 * @since 3.1
@@ -251,14 +271,19 @@
         this.column = -1;
     }
 
-    if (column < 0  || column >= tree.getColumnCount()) return; 
-        
+    if (column < 0  || column >= tree.getColumnCount()) return;
+
     this.column = column;
     TreeColumn treeColumn = tree.getColumn(this.column);
     treeColumn.addControlListener(columnListener);
     resize();
 }
 
+/**
+* Specifies the <code>TreeItem</code> that is to be edited.
+*
+* @param item the item to be edited
+*/
 public void setItem (TreeItem item) {
     this.item = item;
     resize();
@@ -269,7 +294,7 @@
 *
 * <p>Note: The Control provided as the editor <b>must</b> be created with its parent being the Tree control
 * specified in the TreeEditor constructor.
-* 
+*
 * @param editor the Control that is displayed above the cell being edited
 * @param item the TreeItem for the row of the cell being tracked by this editor
 * @param column the zero based index of the column of the cell being tracked by this editor
@@ -281,7 +306,7 @@
     setColumn(column);
     setEditor(editor);
 }
-public void setEditor (Control editor) {
+public override void setEditor (Control editor) {
     super.setEditor(editor);
     resize();
 }
@@ -291,7 +316,7 @@
 *
 * <p>Note: The Control provided as the editor <b>must</b> be created with its parent being the Tree control
 * specified in the TreeEditor constructor.
-* 
+*
 * @param editor the Control that is displayed above the cell being edited
 * @param item the TreeItem for the row of the cell being tracked by this editor
 */
@@ -300,12 +325,13 @@
     setEditor(editor);
 }
 
-public void layout () {
+public override void layout () {
     if (tree is null || tree.isDisposed()) return;
-    if (item is null || item.isDisposed()) return;  
+    if (item is null || item.isDisposed()) return;
     int columnCount = tree.getColumnCount();
     if (columnCount is 0 && column !is 0) return;
     if (columnCount > 0 && (column < 0 || column >= columnCount)) return;
     super.layout();
 }
+
 }
--- a/dwt/custom/VerifyKeyListener.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/VerifyKeyListener.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,12 +7,23 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.VerifyKeyListener;
 
-import dwt.events.*;
+
+import dwt.events.VerifyEvent;
 import dwt.internal.DWTEventListener;
 
+/**
+ * Classes which implement this interface provide a method
+ * that deals with the event that is generated when a
+ * key is pressed.
+ *
+ * @see VerifyEvent
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
 public interface VerifyKeyListener : DWTEventListener {
 /**
  * The following event fields are used:<ul>
--- a/dwt/custom/ViewForm.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/ViewForm.d	Tue Oct 07 16:29:55 2008 +0200
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * Copyright (c) 2000, 2008 IBM Corporation 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
@@ -7,17 +7,32 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.ViewForm;
+
+import dwt.dwthelper.utils;
+
 
 
-import dwt.graphics.*;
-import dwt.widgets.*;
-import dwt.*;
+import dwt.DWT;
+import dwt.DWTException;
+import dwt.graphics.Color;
+import dwt.graphics.GC;
+import dwt.graphics.Point;
+import dwt.graphics.RGB;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Event;
+import dwt.widgets.Layout;
+import dwt.widgets.Listener;
+import dwt.custom.ViewFormLayout;
 
 /**
  * Instances of this class implement a Composite that positions and sizes
- * children and allows programmatic control of layout and border parameters. 
+ * children and allows programmatic control of layout and border parameters.
  * ViewForm is used in the workbench to lay out a view's label/menu/toolbar
  * local bar.
  * <p>
@@ -28,11 +43,13 @@
  * <dt><b>Styles:</b></dt>
  * <dd>BORDER, FLAT</dd>
  * <dt><b>Events:</b></dt>
- * <dd>cast(None)</dd>
+ * <dd>(None)</dd>
  * </dl>
  * <p>
  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
  * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
  */
 
 public class ViewForm : Composite {
@@ -66,45 +83,45 @@
      * The default value is 1.
      */
     public int verticalSpacing = 1;
-    
+
     /**
      * Color of innermost line of drop shadow border.
-     * 
+     *
      * NOTE This field is badly named and can not be fixed for backwards compatibility.
      * It should be capitalized.
-     * 
+     *
      * @deprecated
      */
-    public static RGB borderInsideRGB  = new RGB (132, 130, 132);
+    public static RGB borderInsideRGB;
     /**
      * Color of middle line of drop shadow border.
-     * 
+     *
      * NOTE This field is badly named and can not be fixed for backwards compatibility.
      * It should be capitalized.
-     * 
+     *
      * @deprecated
      */
-    public static RGB borderMiddleRGB  = new RGB (143, 141, 138);
+    public static RGB borderMiddleRGB;
     /**
      * Color of outermost line of drop shadow border.
-     * 
+     *
      * NOTE This field is badly named and can not be fixed for backwards compatibility.
      * It should be capitalized.
-     * 
+     *
      * @deprecated
      */
-    public static RGB borderOutsideRGB = new RGB (171, 168, 165);
-    
+    public static RGB borderOutsideRGB;
+
     // DWT widgets
     Control topLeft;
     Control topCenter;
     Control topRight;
     Control content;
-    
+
     // Configuration and state info
     bool separateTopCenter = false;
     bool showBorder = false;
-    
+
     int separator = -1;
     int borderTop = 0;
     int borderBottom = 0;
@@ -112,19 +129,26 @@
     int borderRight = 0;
     int highlight = 0;
     Point oldSize;
-    
+
     Color selectionBackground;
-    
+
     static final int OFFSCREEN = -200;
     static final int BORDER1_COLOR = DWT.COLOR_WIDGET_NORMAL_SHADOW;
     static final int SELECTION_BACKGROUND = DWT.COLOR_LIST_BACKGROUND;
+
+
+    static this(){
+        borderInsideRGB  = new RGB (132, 130, 132);
+        borderMiddleRGB  = new RGB (143, 141, 138);
+        borderOutsideRGB = new RGB (171, 168, 165);
+    }
 /**
  * Constructs a new instance of this class given its parent
  * and a style value describing its behavior and appearance.
  * <p>
  * The style value is either one of the style constants defined in
  * class <code>DWT</code> which is applicable to instances of this
- * class, or must be built by <em>bitwise OR</em>'ing together 
+ * class, or must be built by <em>bitwise OR</em>'ing together
  * (that is, using the <code>int</code> "|" operator) two or more
  * of those <code>DWT</code> style constants. The class description
  * lists the style constants that are applicable to the class.
@@ -144,25 +168,26 @@
  * @see DWT#BORDER
  * @see DWT#FLAT
  * @see #getStyle()
- */     
+ */
 public this(Composite parent, int style) {
     super(parent, checkStyle(style));
     super.setLayout(new ViewFormLayout());
-    
+
     setBorderVisible((style & DWT.BORDER) !is 0);
-    
-    Listener listener = new Listener() {
+
+    Listener listener = new class() Listener {
         public void handleEvent(Event e) {
             switch (e.type) {
                 case DWT.Dispose: onDispose(); break;
                 case DWT.Paint: onPaint(e.gc); break;
                 case DWT.Resize: onResize(); break;
+                default:
             }
         }
     };
-    
-    int[] events = new int[] {DWT.Dispose, DWT.Paint, DWT.Resize};
-    
+
+    int[] events = [DWT.Dispose, DWT.Paint, DWT.Resize];
+
     for (int i = 0; i < events.length; i++) {
         addListener(events[i], listener);
     }
@@ -176,12 +201,12 @@
 //protected void checkSubclass () {
 //  String name = getClass().getName ();
 //  String validName = ViewForm.class.getName();
-//  if (!validName.opEquals(name)) {
+//  if (!validName.equals(name)) {
 //      DWT.error (DWT.ERROR_INVALID_SUBCLASS);
 //  }
 //}
 
-public Rectangle computeTrim (int x, int y, int width, int height) {
+public override Rectangle computeTrim (int x, int y, int width, int height) {
     checkWidget ();
     int trimX = x - borderLeft - highlight;
     int trimY = y - borderTop - highlight;
@@ -189,7 +214,7 @@
     int trimHeight = height + borderTop + borderBottom + 2*highlight;
     return new Rectangle(trimX, trimY, trimWidth, trimHeight);
 }
-public Rectangle getClientArea() {
+public override Rectangle getClientArea() {
     checkWidget();
     Rectangle clientArea = super.getClientArea();
     clientArea.x += borderLeft;
@@ -200,7 +225,7 @@
 }
 /**
 * Returns the content area.
-* 
+*
 * @return the control in the content area of the pane or null
 */
 public Control getContent() {
@@ -210,7 +235,7 @@
 /**
 * Returns Control that appears in the top center of the pane.
 * Typically this is a toolbar.
-* 
+*
 * @return the control in the top center of the pane or null
 */
 public Control getTopCenter() {
@@ -220,7 +245,7 @@
 /**
 * Returns the Control that appears in the top left corner of the pane.
 * Typically this is a label such as CLabel.
-* 
+*
 * @return the control in the top left corner of the pane or null
 */
 public Control getTopLeft() {
@@ -230,7 +255,7 @@
 /**
 * Returns the control in the top right corner of the pane.
 * Typically this is a Close button or a composite with a Menu and Close button.
-* 
+*
 * @return the control in the top right corner of the pane or null
 */
 public Control getTopRight() {
@@ -257,9 +282,9 @@
             int y1 = 1;
             int x2 = size.x - 1;
             int y2 = size.y - 1;
-            int[] shape = new int[] {x1,y1, x2,y1, x2,y2, x1,y2, x1,y1+highlight,
-                               x1+highlight,y1+highlight, x1+highlight,y2-highlight, 
-                               x2-highlight,y2-highlight, x2-highlight,y1+highlight, x1,y1+highlight};
+            int[] shape = [x1,y1, x2,y1, x2,y2, x1,y2, x1,y1+highlight,
+                               x1+highlight,y1+highlight, x1+highlight,y2-highlight,
+                               x2-highlight,y2-highlight, x2-highlight,y1+highlight, x1,y1+highlight];
             Color highlightColor = getDisplay().getSystemColor(DWT.COLOR_LIST_SELECTION);
             gc.setBackground(highlightColor);
             gc.fillPolygon(shape);
@@ -280,16 +305,16 @@
         if (oldSize.x < size.x) {
             width = size.x - oldSize.x + borderRight + highlight;
         } else if (oldSize.x > size.x) {
-            width = borderRight + highlight;            
+            width = borderRight + highlight;
         }
         redraw(size.x - width, 0, width, size.y, false);
-        
+
         int height = 0;
         if (oldSize.y < size.y) {
-            height = size.y - oldSize.y + borderBottom + highlight;     
+            height = size.y - oldSize.y + borderBottom + highlight;
         }
         if (oldSize.y > size.y) {
-            height = borderBottom + highlight;      
+            height = borderBottom + highlight;
         }
         redraw(0, size.y - height, size.x, height, false);
     }
@@ -297,11 +322,11 @@
 }
 /**
 * Sets the content.
-* Setting the content to null will remove it from 
+* Setting the content to null will remove it from
 * the pane - however, the creator of the content must dispose of the content.
-* 
+*
 * @param content the control to be displayed in the content area or null
-* 
+*
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -334,7 +359,7 @@
  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
  * </ul>
  */
-public void setLayout (Layout layout) {
+public override void setLayout (Layout layout) {
     checkWidget();
     return;
 }
@@ -348,11 +373,11 @@
 /**
 * Set the control that appears in the top center of the pane.
 * Typically this is a toolbar.
-* The topCenter is optional.  Setting the topCenter to null will remove it from 
+* The topCenter is optional.  Setting the topCenter to null will remove it from
 * the pane - however, the creator of the topCenter must dispose of the topCenter.
-* 
+*
 * @param topCenter the control to be displayed in the top center or null
-* 
+*
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -374,11 +399,11 @@
 /**
 * Set the control that appears in the top left corner of the pane.
 * Typically this is a label such as CLabel.
-* The topLeft is optional.  Setting the top left control to null will remove it from 
+* The topLeft is optional.  Setting the top left control to null will remove it from
 * the pane - however, the creator of the control must dispose of the control.
-* 
+*
 * @param c the control to be displayed in the top left corner or null
-* 
+*
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -400,11 +425,11 @@
 /**
 * Set the control that appears in the top right corner of the pane.
 * Typically this is a Close button or a composite with a Menu and Close button.
-* The topRight is optional.  Setting the top right control to null will remove it from 
+* The topRight is optional.  Setting the top right control to null will remove it from
 * the pane - however, the creator of the control must dispose of the control.
-* 
+*
 * @param c the control to be displayed in the top right corner or null
-* 
+*
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -425,9 +450,9 @@
 }
 /**
 * Specify whether the border should be displayed or not.
-* 
+*
 * @param show true if the border should be displayed
-* 
+*
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
@@ -436,11 +461,11 @@
 public void setBorderVisible(bool show) {
     checkWidget();
     if (showBorder is show) return;
-    
+
     showBorder = show;
     if (showBorder) {
         borderLeft = borderTop = borderRight = borderBottom = 1;
-        if ((getStyle() & DWT.FLAT)== 0) highlight = 2;
+        if ((getStyle() & DWT.FLAT)is 0) highlight = 2;
     } else {
         borderBottom = borderTop = borderLeft = borderRight = 0;
         highlight = 0;
@@ -449,12 +474,12 @@
     redraw();
 }
 /**
-* If true, the topCenter will always appear on a separate line by itself, otherwise the 
+* If true, the topCenter will always appear on a separate line by itself, otherwise the
 * topCenter will appear in the top row if there is room and will be moved to the second row if
 * required.
-* 
+*
 * @param show true if the topCenter will always appear on a separate line by itself
-* 
+*
 * @exception DWTException <ul>
 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
--- a/dwt/custom/ViewFormLayout.d	Tue Oct 07 14:41:31 2008 +0200
+++ b/dwt/custom/ViewFormLayout.d	Tue Oct 07 16:29:55 2008 +0200
@@ -7,27 +7,37 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
-module dwt.custom;
+module dwt.custom.ViewFormLayout;
+
+import dwt.dwthelper.utils;
 
-import dwt.*;
-import dwt.graphics.*;
-import dwt.widgets.*;
+import dwt.DWT;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Layout;
+import dwt.widgets.Scrollable;
+import dwt.custom.ViewForm;
+import dwt.custom.CLayoutData;
 
 /**
  * This class provides the layout for ViewForm
- * 
+ *
  * @see ViewForm
  */
 class ViewFormLayout : Layout {
 
-protected Point computeSize(Composite composite, int wHint, int hHint, bool flushCache) {
+protected override Point computeSize(Composite composite, int wHint, int hHint, bool flushCache) {
     ViewForm form = cast(ViewForm)composite;
     Control left = form.topLeft;
     Control center = form.topCenter;
     Control right = form.topRight;
     Control content = form.content;
-    
+
     Point leftSize = new Point(0, 0);
     if (left !is null) {
         leftSize = computeChildSize(left, DWT.DEFAULT, DWT.DEFAULT, flushCache);
@@ -51,7 +61,7 @@
         if (center !is null){
             size.y += centerSize.y;
             if (left !is null ||right !is null)size.y += form.verticalSpacing;
-        }   
+        }
     } else {
         size.x = leftSize.x + centerSize.x + rightSize.x;
         int count = -1;
@@ -61,22 +71,22 @@
         if (count > 0) size.x += count * form.horizontalSpacing;
         size.y = Math.max(leftSize.y, Math.max(centerSize.y, rightSize.y));
     }
-    
+
     if (content !is null) {
         if (left !is null || right !is null || center !is null) size.y += 1; // allow space for a vertical separator
         Point contentSize = new Point(0, 0);
-        contentSize = computeChildSize(content, DWT.DEFAULT, DWT.DEFAULT, flushCache); 
+        contentSize = computeChildSize(content, DWT.DEFAULT, DWT.DEFAULT, flushCache);
         size.x = Math.max (size.x, contentSize.x);
         size.y += contentSize.y;
         if (size.y > contentSize.y) size.y += form.verticalSpacing;
     }
-    
+
     size.x += 2*form.marginWidth;
     size.y += 2*form.marginHeight;
-    
+
     if (wHint !is DWT.DEFAULT) size.x  = wHint;
     if (hHint !is DWT.DEFAULT) size.y = hHint;
-    
+
     return size;
 }
 
@@ -90,28 +100,28 @@
 }
 
 int computeTrim(Control c) {
-    if ( null !is cast(Scrollable)c ) {
-        Rectangle rect = (cast(Scrollable) c).computeTrim (0, 0, 0, 0);
+    if ( auto sa = cast(Scrollable)c) {
+        Rectangle rect = sa.computeTrim (0, 0, 0, 0);
         return rect.width;
     }
     return c.getBorderWidth () * 2;
 }
 
-protected bool flushCache(Control control) {
+protected override bool flushCache(Control control) {
     Object data = control.getLayoutData();
-    if (data !is null && null !is cast(CLayoutData)data ) (cast(CLayoutData)data).flushCache();
+    if ( auto ld = cast(CLayoutData)data ) ld.flushCache();
     return true;
 }
 
-protected void layout(Composite composite, bool flushCache) {
+protected override void layout(Composite composite, bool flushCache) {
     ViewForm form = cast(ViewForm)composite;
     Control left = form.topLeft;
     Control center = form.topCenter;
     Control right = form.topRight;
     Control content = form.content;
-    
+
     Rectangle rect = composite.getClientArea();
-    
+
     Point leftSize = new Point(0, 0);
     if (left !is null && !left.isDisposed()) {
         leftSize = computeChildSize(left, DWT.DEFAULT, DWT.DEFAULT, flushCache);
@@ -124,17 +134,17 @@
     if (right !is null && !right.isDisposed()) {
          rightSize = computeChildSize(right, DWT.DEFAULT, DWT.DEFAULT, flushCache);
     }
-    
+
     int minTopWidth = leftSize.x + centerSize.x + rightSize.x + 2*form.marginWidth + 2*form.highlight;
     int count = -1;
     if (leftSize.x > 0) count++;
     if (centerSize.x > 0) count++;
     if (rightSize.x > 0) count++;
     if (count > 0) minTopWidth += count * form.horizontalSpacing;
-        
+
     int x = rect.x + rect.width - form.marginWidth - form.highlight;
     int y = rect.y + form.marginHeight + form.highlight;
-    
+
     bool top = false;
     if (form.separateTopCenter || minTopWidth > rect.width) {
         int topHeight = Math.max(rightSize.y, leftSize.y);
@@ -159,7 +169,7 @@
             centerSize = computeChildSize(center, w, DWT.DEFAULT, false);
             center.setBounds(rect.x + rect.width - form.marginWidth - form.highlight - centerSize.x, y, centerSize.x, centerSize.y);
             y += centerSize.y + form.verticalSpacing;
-        }       
+        }
     } else {
         int topHeight = Math.max(rightSize.y, Math.max(centerSize.y, leftSize.y));
         if (right !is null && !right.isDisposed()) {
@@ -176,7 +186,7 @@
         }
         if (left !is null && !left.isDisposed()) {
             top = true;
-            Rectangle trim = left instanceof Composite ? (cast(Composite)left).computeTrim(0, 0, 0, 0) : new Rectangle(0, 0, 0, 0);
+            Rectangle trim = ( null !is cast(Composite)left ) ? (cast(Composite)left).computeTrim(0, 0, 0, 0) : new Rectangle(0, 0, 0, 0);
             int w = x - rect.x - form.marginWidth - form.highlight - trim.width;
             int h = topHeight - trim.height;
             leftSize = computeChildSize(left, w, h, false);
@@ -187,7 +197,7 @@
     int oldSeperator = form.separator;
     form.separator = -1;
     if (content !is null && !content.isDisposed()) {
-        if (left !is null || right!= null || center !is null){
+        if (left !is null || right !is null || center !is null){
             form.separator = y;
             y++;
         }