root/dwt/widgets/Sash.d

Revision 246:fd9c62a2998e, 14.7 kB (checked in by Frank Benoit <benoit@tionex.de>, 5 months ago)

Updater SWT 3.4M7 to 3.4

Line 
1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module dwt.widgets.Sash;
14
15
16
17 import dwt.DWT;
18 import dwt.DWTException;
19 import dwt.events.SelectionEvent;
20 import dwt.events.SelectionListener;
21 import dwt.graphics.Point;
22 import dwt.internal.win32.OS;
23
24 import dwt.widgets.Control;
25 import dwt.widgets.Composite;
26 import dwt.widgets.TypedListener;
27 import dwt.widgets.Event;
28
29 import dwt.dwthelper.utils;
30
31 /**
32  * Instances of the receiver represent a selectable user interface object
33  * that allows the user to drag a rubber banded outline of the sash within
34  * the parent control.
35  * <dl>
36  * <dt><b>Styles:</b></dt>
37  * <dd>HORIZONTAL, VERTICAL, SMOOTH</dd>
38  * <dt><b>Events:</b></dt>
39  * <dd>Selection</dd>
40  * </dl>
41  * <p>
42  * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
43  * </p><p>
44  * IMPORTANT: This class is intended to be subclassed <em>only</em>
45  * within the DWT implementation.
46  * </p>
47  *
48  * @see <a href="http://www.eclipse.org/swt/snippets/#sash">Sash snippets</a>
49  * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: ControlExample</a>
50  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
51  */
52 public class Sash : Control {
53
54     alias Control.computeSize computeSize;
55     alias Control.windowProc windowProc;
56
57     bool dragging;
58     int startX, startY, lastX, lastY;
59     const static int INCREMENT = 1;
60     const static int PAGE_INCREMENT = 9;
61
62 /**
63  * Constructs a new instance of this class given its parent
64  * and a style value describing its behavior and appearance.
65  * <p>
66  * The style value is either one of the style constants defined in
67  * class <code>DWT</code> which is applicable to instances of this
68  * class, or must be built by <em>bitwise OR</em>'ing together
69  * (that is, using the <code>int</code> "|" operator) two or more
70  * of those <code>DWT</code> style constants. The class description
71  * lists the style constants that are applicable to the class.
72  * Style bits are also inherited from superclasses.
73  * </p>
74  *
75  * @param parent a composite control which will be the parent of the new instance (cannot be null)
76  * @param style the style of control to construct
77  *
78  * @exception IllegalArgumentException <ul>
79  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
80  * </ul>
81  * @exception DWTException <ul>
82  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
83  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
84  * </ul>
85  *
86  * @see DWT#HORIZONTAL
87  * @see DWT#VERTICAL
88  * @see Widget#checkSubclass
89  * @see Widget#getStyle
90  */
91 public this (Composite parent, int style) {
92     super (parent, checkStyle (style));
93 }
94
95 /**
96  * Adds the listener to the collection of listeners who will
97  * be notified when the control is selected by the user, by sending
98  * it one of the messages defined in the <code>SelectionListener</code>
99  * interface.
100  * <p>
101  * When <code>widgetSelected</code> is called, the x, y, width, and height fields of the event object are valid.
102  * If the receiver is being dragged, the event object detail field contains the value <code>DWT.DRAG</code>.
103  * <code>widgetDefaultSelected</code> is not called.
104  * </p>
105  *
106  * @param listener the listener which should be notified when the control is selected by the user
107  *
108  * @exception IllegalArgumentException <ul>
109  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
110  * </ul>
111  * @exception DWTException <ul>
112  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
113  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
114  * </ul>
115  *
116  * @see SelectionListener
117  * @see #removeSelectionListener
118  * @see SelectionEvent
119  */
120 public void addSelectionListener (SelectionListener listener) {
121     checkWidget ();
122     if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
123     TypedListener typedListener = new TypedListener (listener);
124     addListener (DWT.Selection,typedListener);
125     addListener (DWT.DefaultSelection,typedListener);
126 }
127
128 override int callWindowProc (HWND hwnd, int msg, int wParam, int lParam) {
129     if (handle is null) return 0;
130     return OS.DefWindowProc (hwnd, msg, wParam, lParam);
131 }
132
133 override void createHandle () {
134     super.createHandle ();
135     state |= THEME_BACKGROUND;
136 }
137
138 static int checkStyle (int style) {
139     return checkBits (style, DWT.HORIZONTAL, DWT.VERTICAL, 0, 0, 0, 0);
140 }
141
142 override public Point computeSize (int wHint, int hHint, bool changed) {
143     checkWidget ();
144     int border = getBorderWidth ();
145     int width = border * 2, height = border * 2;
146     if ((style & DWT.HORIZONTAL) !is 0) {
147         width += DEFAULT_WIDTH;  height += 3;
148     } else {
149         width += 3; height += DEFAULT_HEIGHT;
150     }
151     if (wHint !is DWT.DEFAULT) width = wHint + (border * 2);
152     if (hHint !is DWT.DEFAULT) height = hHint + (border * 2);
153     return new Point (width, height);
154 }
155
156 void drawBand (int x, int y, int width, int height) {
157     if ((style & DWT.SMOOTH) !is 0) return;
158     HWND hwndTrack = parent.handle;
159     byte [] bits = [-86, 0, 85, 0, -86, 0, 85, 0, -86, 0, 85, 0, -86, 0, 85, 0];
160     auto stippleBitmap = OS.CreateBitmap (8, 8, 1, 1, bits.ptr);
161     auto stippleBrush = OS.CreatePatternBrush (stippleBitmap);
162     auto hDC = OS.GetDCEx (hwndTrack, null, OS.DCX_CACHE);
163     auto oldBrush = OS.SelectObject (hDC, stippleBrush);
164     OS.PatBlt (hDC, x, y, width, height, OS.PATINVERT);
165     OS.SelectObject (hDC, oldBrush);
166     OS.ReleaseDC (hwndTrack, hDC);
167     OS.DeleteObject (stippleBrush);
168     OS.DeleteObject (stippleBitmap);
169 }
170
171 /**
172  * Removes the listener from the collection of listeners who will
173  * be notified when the control is selected by the user.
174  *
175  * @param listener the listener which should no longer be notified
176  *
177  * @exception IllegalArgumentException <ul>
178  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
179  * </ul>
180  * @exception DWTException <ul>
181  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
182  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
183  * </ul>
184  *
185  * @see SelectionListener
186  * @see #addSelectionListener
187  */
188 public void removeSelectionListener(SelectionListener listener) {
189     checkWidget ();
190     if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
191     if (eventTable is null) return;
192     eventTable.unhook (DWT.Selection, listener);
193     eventTable.unhook (DWT.DefaultSelection,listener);
194 }
195
196 override String windowClass () {
197     return display.windowClass();
198 }
199
200 override int windowProc () {
201     return display.windowProc();
202 }
203
204 override LRESULT WM_ERASEBKGND (int wParam, int lParam) {
205     super.WM_ERASEBKGND (wParam, lParam);
206     drawBackground (cast(HANDLE) wParam);
207     return LRESULT.ONE;
208 }
209
210 override LRESULT WM_KEYDOWN (int wParam, int lParam) {
211     LRESULT result = super.WM_KEYDOWN (wParam, lParam);
212     if (result !is null) return result;
213     switch (wParam) {
214         case OS.VK_LEFT:
215         case OS.VK_RIGHT:
216         case OS.VK_UP:
217         case OS.VK_DOWN:
218
219             /* Calculate the new x or y position */
220             if (OS.GetKeyState (OS.VK_LBUTTON) < 0) return result;
221             int step = OS.GetKeyState (OS.VK_CONTROL) < 0 ? INCREMENT : PAGE_INCREMENT;
222             POINT pt;
223             if ((style & DWT.VERTICAL) !is 0) {
224                 if (wParam is OS.VK_UP || wParam is OS.VK_DOWN) break;
225                 pt.x = wParam is OS.VK_LEFT ? -step : step;
226             } else {
227                 if (wParam is OS.VK_LEFT || wParam is OS.VK_RIGHT) break;
228                 pt.y = wParam is OS.VK_UP ? -step : step;
229             }
230             auto hwndTrack = parent.handle;
231             OS.MapWindowPoints (handle, hwndTrack, &pt, 1);
232             RECT rect, clientRect;
233             OS.GetWindowRect (handle, &rect);
234             int width = rect.right - rect.left;
235             int height = rect.bottom - rect.top;
236             OS.GetClientRect (hwndTrack, &clientRect);
237             int clientWidth = clientRect.right - clientRect.left;
238             int clientHeight = clientRect.bottom - clientRect.top;
239             int newX = lastX, newY = lastY;
240             if ((style & DWT.VERTICAL) !is 0) {
241                 newX = Math.min (Math.max (0, pt.x - startX), clientWidth - width);
242             } else {
243                 newY = Math.min (Math.max (0, pt.y - startY), clientHeight - height);
244             }
245             if (newX is lastX && newY is lastY) return result;
246
247             /* Update the pointer position */
248             POINT cursorPt;
249             cursorPt.x = pt.x;  cursorPt.y = pt.y;
250             OS.ClientToScreen (hwndTrack, &cursorPt);
251             if ((style & DWT.VERTICAL) !is 0) {
252                 cursorPt.y += height / 2;
253             }
254             else {
255                 cursorPt.x += width / 2;
256             }
257             OS.SetCursorPos (cursorPt.x, cursorPt.y);
258
259             Event event = new Event ();
260             event.x = newX;
261             event.y = newY;
262             event.width = width;
263             event.height = height;
264             sendEvent (DWT.Selection, event);
265             if (isDisposed ()) return LRESULT.ZERO;
266             if (event.doit) {
267                 if ((style & DWT.SMOOTH) !is 0) {
268                     setBounds (event.x, event.y, width, height);
269                 }
270             }
271             return result;
272         default:
273     }
274     return result;
275 }
276
277 override LRESULT WM_GETDLGCODE (int wParam, int lParam) {
278     return new LRESULT (OS.DLGC_STATIC);
279 }
280
281 override LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
282     LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
283     if (result is LRESULT.ZERO) return result;
284
285     /* Compute the banding rectangle */
286     auto hwndTrack = parent.handle;
287     POINT pt;
288     OS.POINTSTOPOINT (pt, lParam);
289     RECT rect;
290     OS.GetWindowRect (handle, &rect);
291     OS.MapWindowPoints (handle, null, &pt, 1);
292     startX = pt.x - rect.left;
293     startY = pt.y - rect.top;
294     OS.MapWindowPoints (null, hwndTrack, cast(POINT*) &rect, 2);
295     lastX = rect.left;
296     lastY = rect.top;
297     int width = rect.right - rect.left;
298     int height = rect.bottom - rect.top;
299
300     /* The event must be sent because doit flag is used */
301     Event event = new Event ();
302     event.x = lastX;
303     event.y = lastY;
304     event.width = width;
305     event.height = height;
306     if ((style & DWT.SMOOTH) is 0) {
307         event.detail = DWT.DRAG;
308     }
309     sendEvent (DWT.Selection, event);
310     if (isDisposed ()) return LRESULT.ZERO;
311
312     /* Draw the banding rectangle */
313     if (event.doit) {
314         dragging = true;
315         lastX = event.x;
316         lastY = event.y;
317         menuShell ().bringToTop ();
318         if (isDisposed ()) return LRESULT.ZERO;
319         static if (OS.IsWinCE) {
320             OS.UpdateWindow (hwndTrack);
321         } else {
322             int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
323             OS.RedrawWindow (hwndTrack, null, null, flags);
324         }
325         drawBand (event.x, event.y, width, height);
326         if ((style & DWT.SMOOTH) !is 0) {
327             setBounds (event.x, event.y, width, height);
328             // widget could be disposed at this point
329         }
330     }
331     return result;
332 }
333
334 override LRESULT WM_LBUTTONUP (int wParam, int lParam) {
335     LRESULT result = super.WM_LBUTTONUP (wParam, lParam);
336     if (result is LRESULT.ZERO) return result;
337
338     /* Compute the banding rectangle */
339     if (!dragging) return result;
340     dragging = false;
341     RECT rect;
342     OS.GetWindowRect (handle, &rect);
343     int width = rect.right - rect.left;
344     int height = rect.bottom - rect.top;
345
346     /* The event must be sent because doit flag is used */
347     Event event = new Event ();
348     event.x = lastX;
349     event.y = lastY;
350     event.width = width;
351     event.height = height;
352     drawBand (event.x, event.y, width, height);
353     sendEvent (DWT.Selection, event);
354     if (isDisposed ()) return result;
355     if (event.doit) {
356         if ((style & DWT.SMOOTH) !is 0) {
357             setBounds (event.x, event.y, width, height);
358             // widget could be disposed at this point
359         }
360     }
361     return result;
362 }
363
364 override LRESULT WM_MOUSEMOVE (int wParam, int lParam) {
365     LRESULT result = super.WM_MOUSEMOVE (wParam, lParam);
366     if (result !is null) return result;
367     if (!dragging || (wParam & OS.MK_LBUTTON) is 0) return result;
368
369     /* Compute the banding rectangle */
370     POINT pt;
371     OS.POINTSTOPOINT (pt, lParam);
372     auto hwndTrack = parent.handle;
373     OS.MapWindowPoints (handle, hwndTrack, &pt, 1);
374     RECT rect, clientRect;
375     OS.GetWindowRect (handle, &rect);
376     int width = rect.right - rect.left;
377     int height = rect.bottom - rect.top;
378     OS.GetClientRect (hwndTrack, &clientRect);
379     int newX = lastX, newY = lastY;
380     if ((style & DWT.VERTICAL) !is 0) {
381         int clientWidth = clientRect.right - clientRect.left;
382         newX = Math.min (Math.max (0, pt.x - startX), clientWidth - width);
383     } else {
384         int clientHeight = clientRect.bottom - clientRect.top;
385         newY = Math.min (Math.max (0, pt.y - startY), clientHeight - height);
386     }
387     if (newX is lastX && newY is lastY) return result;
388     drawBand (lastX, lastY, width, height);
389
390     /* The event must be sent because doit flag is used */
391     Event event = new Event ();
392     event.x = newX;
393     event.y = newY;
394     event.width = width;
395     event.height = height;
396     if ((style & DWT.SMOOTH) is 0) {
397         event.detail = DWT.DRAG;
398     }
399     sendEvent (DWT.Selection, event);
400     if (isDisposed ()) return LRESULT.ZERO;
401     if (event.doit) {
402         lastX = event.x;
403         lastY = event.y;
404     }
405     static if (OS.IsWinCE) {
406         OS.UpdateWindow (hwndTrack);
407     } else {
408         int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
409         OS.RedrawWindow (hwndTrack, null, null, flags);
410     }
411     drawBand (lastX, lastY, width, height);
412     if ((style & DWT.SMOOTH) !is 0) {
413         setBounds (lastX, lastY, width, height);
414         // widget could be disposed at this point
415     }
416     return result;
417 }
418
419 override LRESULT WM_SETCURSOR (int wParam, int lParam) {
420     LRESULT result = super.WM_SETCURSOR (wParam, lParam);
421     if (result !is null) return result;
422     int hitTest = cast(short) OS.LOWORD (lParam);
423     if (hitTest is OS.HTCLIENT) {
424         HCURSOR hCursor;
425         if ((style & DWT.HORIZONTAL) !is 0) {
426             hCursor = OS.LoadCursor (null, cast(TCHAR*)OS.IDC_SIZENS);
427         } else {
428             hCursor = OS.LoadCursor (null, cast(TCHAR*)OS.IDC_SIZEWE);
429         }
430         OS.SetCursor (hCursor);
431         return LRESULT.ONE;
432     }
433     return result;
434 }
435
436 }
Note: See TracBrowser for help on using the browser.