001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.swt.widgets;
011:
012: import org.eclipse.swt.internal.carbon.OS;
013: import org.eclipse.swt.internal.carbon.CGRect;
014: import org.eclipse.swt.internal.carbon.Rect;
015: import org.eclipse.swt.internal.carbon.ControlKind;
016:
017: import org.eclipse.swt.*;
018: import org.eclipse.swt.graphics.*;
019:
020: /**
021: * This class is the abstract superclass of all classes which
022: * represent controls that have standard scroll bars.
023: * <dl>
024: * <dt><b>Styles:</b></dt>
025: * <dd>H_SCROLL, V_SCROLL</dd>
026: * <dt><b>Events:</b>
027: * <dd>(none)</dd>
028: * </dl>
029: * <p>
030: * IMPORTANT: This class is intended to be subclassed <em>only</em>
031: * within the SWT implementation.
032: * </p>
033: */
034: public abstract class Scrollable extends Control {
035: int scrolledHandle;
036: ScrollBar horizontalBar, verticalBar;
037:
038: Scrollable() {
039: /* Do nothing */
040: }
041:
042: /**
043: * Constructs a new instance of this class given its parent
044: * and a style value describing its behavior and appearance.
045: * <p>
046: * The style value is either one of the style constants defined in
047: * class <code>SWT</code> which is applicable to instances of this
048: * class, or must be built by <em>bitwise OR</em>'ing together
049: * (that is, using the <code>int</code> "|" operator) two or more
050: * of those <code>SWT</code> style constants. The class description
051: * lists the style constants that are applicable to the class.
052: * Style bits are also inherited from superclasses.
053: * </p>
054: *
055: * @param parent a composite control which will be the parent of the new instance (cannot be null)
056: * @param style the style of control to construct
057: *
058: * @exception IllegalArgumentException <ul>
059: * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
060: * </ul>
061: * @exception SWTException <ul>
062: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
063: * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
064: * </ul>
065: *
066: * @see SWT#H_SCROLL
067: * @see SWT#V_SCROLL
068: * @see Widget#checkSubclass
069: * @see Widget#getStyle
070: */
071: public Scrollable(Composite parent, int style) {
072: super (parent, style);
073: }
074:
075: /**
076: * Given a desired <em>client area</em> for the receiver
077: * (as described by the arguments), returns the bounding
078: * rectangle which would be required to produce that client
079: * area.
080: * <p>
081: * In other words, it returns a rectangle such that, if the
082: * receiver's bounds were set to that rectangle, the area
083: * of the receiver which is capable of displaying data
084: * (that is, not covered by the "trimmings") would be the
085: * rectangle described by the arguments (relative to the
086: * receiver's parent).
087: * </p>
088: *
089: * @param x the desired x coordinate of the client area
090: * @param y the desired y coordinate of the client area
091: * @param width the desired width of the client area
092: * @param height the desired height of the client area
093: * @return the required bounds to produce the given client area
094: *
095: * @exception SWTException <ul>
096: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
097: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
098: * </ul>
099: *
100: * @see #getClientArea
101: */
102: public Rectangle computeTrim(int x, int y, int width, int height) {
103: checkWidget();
104: int[] outMetric = new int[1];
105: OS.GetThemeMetric(OS.kThemeMetricScrollBarWidth, outMetric);
106: if (horizontalBar != null)
107: height += outMetric[0];
108: if (verticalBar != null)
109: width += outMetric[0];
110: Rect inset = inset();
111: x -= inset.left;
112: y -= inset.top;
113: width += inset.left + inset.right;
114: height += inset.top + inset.bottom;
115: return new Rectangle(x, y, width, height);
116: }
117:
118: ScrollBar createScrollBar(int style) {
119: return new ScrollBar(this , style);
120: }
121:
122: ScrollBar createStandardBar(int style) {
123: int parentHandle = scrolledHandle != 0 ? scrolledHandle
124: : handle;
125: short[] count = new short[1];
126: OS.CountSubControls(parentHandle, count);
127: if (count[0] == 0)
128: return null;
129: int barHandle = 0;
130: int[] outMetric = new int[1];
131: OS.GetThemeMetric(OS.kThemeMetricScrollBarWidth, outMetric);
132: int[] outControl = new int[1];
133: ControlKind kind = new ControlKind();
134: for (int i = 0; i < count[0]; i++) {
135: OS.GetIndexedSubControl(parentHandle, (short) (i + 1),
136: outControl);
137: OS.GetControlKind(outControl[0], kind);
138: if (kind.kind == OS.kControlKindScrollBar) {
139: Point point = getControlSize(outControl[0]);
140: if ((style & SWT.H_SCROLL) != 0) {
141: if (point.y == outMetric[0])
142: barHandle = outControl[0];
143: } else {
144: if (point.x == outMetric[0])
145: barHandle = outControl[0];
146: }
147: }
148: }
149: if (barHandle == 0)
150: return null;
151: ScrollBar bar = new ScrollBar();
152: bar.parent = this ;
153: bar.style = style;
154: bar.display = display;
155: bar.handle = barHandle;
156: bar.register();
157: bar.hookEvents();
158: return bar;
159: }
160:
161: void createWidget() {
162: super .createWidget();
163: if ((style & SWT.H_SCROLL) != 0)
164: horizontalBar = createScrollBar(SWT.H_SCROLL);
165: if ((style & SWT.V_SCROLL) != 0)
166: verticalBar = createScrollBar(SWT.V_SCROLL);
167: }
168:
169: void deregister() {
170: super .deregister();
171: if (scrolledHandle != 0)
172: display.removeWidget(scrolledHandle);
173: }
174:
175: /**
176: * Returns a rectangle which describes the area of the
177: * receiver which is capable of displaying data (that is,
178: * not covered by the "trimmings").
179: *
180: * @return the client area
181: *
182: * @exception SWTException <ul>
183: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
184: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
185: * </ul>
186: *
187: * @see #computeTrim
188: */
189: public Rectangle getClientArea() {
190: checkWidget();
191: Rect rect = new Rect();
192: OS.GetControlBounds(handle, rect);
193: return new Rectangle(0, 0, rect.right - rect.left, rect.bottom
194: - rect.top);
195: }
196:
197: /**
198: * Returns the receiver's horizontal scroll bar if it has
199: * one, and null if it does not.
200: *
201: * @return the horizontal scroll bar (or null)
202: *
203: * @exception SWTException <ul>
204: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
205: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
206: * </ul>
207: */
208: public ScrollBar getHorizontalBar() {
209: checkWidget();
210: return horizontalBar;
211: }
212:
213: /**
214: * Returns the receiver's vertical scroll bar if it has
215: * one, and null if it does not.
216: *
217: * @return the vertical scroll bar (or null)
218: *
219: * @exception SWTException <ul>
220: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
221: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
222: * </ul>
223: */
224: public ScrollBar getVerticalBar() {
225: checkWidget();
226: return verticalBar;
227: }
228:
229: void hookEvents() {
230: super .hookEvents();
231: if ((state & CANVAS) != 0 && scrolledHandle != 0) {
232: int controlProc = display.controlProc;
233: int[] mask = new int[] { OS.kEventClassControl,
234: OS.kEventControlDraw, };
235: int controlTarget = OS
236: .GetControlEventTarget(scrolledHandle);
237: OS.InstallEventHandler(controlTarget, controlProc,
238: mask.length / 2, mask, scrolledHandle, null);
239: }
240: }
241:
242: boolean hooksKeys() {
243: return hooks(SWT.KeyDown) || hooks(SWT.KeyUp)
244: || hooks(SWT.Traverse);
245: }
246:
247: Rect inset() {
248: if ((state & CANVAS) != 0) {
249: Rect rect = new Rect();
250: int[] outMetric = new int[1];
251: if (drawFocusRing() && (style & SWT.NO_FOCUS) == 0
252: && hooksKeys()) {
253: OS.GetThemeMetric(OS.kThemeMetricFocusRectOutset,
254: outMetric);
255: rect.left += outMetric[0];
256: rect.top += outMetric[0];
257: rect.right += outMetric[0];
258: rect.bottom += outMetric[0];
259: }
260: if (hasBorder()) {
261: OS.GetThemeMetric(OS.kThemeMetricEditTextFrameOutset,
262: outMetric);
263: rect.left += outMetric[0];
264: rect.top += outMetric[0];
265: rect.right += outMetric[0];
266: rect.bottom += outMetric[0];
267: }
268: return rect;
269: }
270: return EMPTY_RECT;
271: }
272:
273: boolean isTrimHandle(int trimHandle) {
274: if (horizontalBar != null && horizontalBar.handle == trimHandle)
275: return true;
276: if (verticalBar != null && verticalBar.handle == trimHandle)
277: return true;
278: return trimHandle == scrolledHandle;
279: }
280:
281: int kEventMouseWheelMoved(int nextHandler, int theEvent,
282: int userData) {
283: int vPosition = verticalBar == null ? 0 : verticalBar
284: .getSelection();
285: int hPosition = horizontalBar == null ? 0 : horizontalBar
286: .getSelection();
287: int result = super .kEventMouseWheelMoved(nextHandler, theEvent,
288: userData);
289: boolean redraw = false;
290: if (verticalBar != null) {
291: int position = verticalBar.getSelection();
292: if (position != vPosition) {
293: Event event = new Event();
294: event.detail = position < vPosition ? SWT.PAGE_UP
295: : SWT.PAGE_DOWN;
296: verticalBar.sendEvent(SWT.Selection, event);
297: redraw = true;
298: }
299: }
300: if (horizontalBar != null) {
301: int position = horizontalBar.getSelection();
302: if (position != hPosition) {
303: Event event = new Event();
304: event.detail = position < vPosition ? SWT.PAGE_UP
305: : SWT.PAGE_DOWN;
306: horizontalBar.sendEvent(SWT.Selection, event);
307: redraw = true;
308: }
309: }
310: if (redraw)
311: redrawBackgroundImage();
312: return result;
313: }
314:
315: void redrawBackgroundImage() {
316: if (scrolledHandle == 0) {
317: Control control = findBackgroundControl();
318: if (control != null && control.backgroundImage != null) {
319: redrawWidget(handle, false);
320: }
321: }
322: }
323:
324: void register() {
325: super .register();
326: if (scrolledHandle != 0)
327: display.addWidget(scrolledHandle, this );
328: }
329:
330: void releaseHandle() {
331: super .releaseHandle();
332: scrolledHandle = 0;
333: }
334:
335: void releaseChildren(boolean destroy) {
336: if (horizontalBar != null) {
337: horizontalBar.release(false);
338: horizontalBar = null;
339: }
340: if (verticalBar != null) {
341: verticalBar.release(false);
342: verticalBar = null;
343: }
344: super .releaseChildren(destroy);
345: }
346:
347: void resetVisibleRegion(int control) {
348: if (verticalBar != null)
349: verticalBar.resetVisibleRegion(control);
350: if (horizontalBar != null)
351: horizontalBar.resetVisibleRegion(control);
352: super .resetVisibleRegion(control);
353: }
354:
355: void resizeClientArea() {
356: if (scrolledHandle == 0)
357: return;
358: if ((state & CANVAS) == 0)
359: return;
360: int vWidth = 0, hHeight = 0;
361: int[] outMetric = new int[1];
362: OS.GetThemeMetric(OS.kThemeMetricScrollBarWidth, outMetric);
363: boolean isVisibleHBar = horizontalBar != null
364: && horizontalBar.getVisible();
365: boolean isVisibleVBar = verticalBar != null
366: && verticalBar.getVisible();
367: if (isVisibleHBar)
368: hHeight = outMetric[0];
369: if (isVisibleVBar)
370: vWidth = outMetric[0];
371: int width, height;
372: CGRect rect = new CGRect();
373: OS.HIViewGetBounds(scrolledHandle, rect);
374: width = (int) rect.width;
375: height = (int) rect.height;
376: Rect inset = inset();
377: width = Math.max(0, width - vWidth - inset.left - inset.right);
378: height = Math.max(0, height - hHeight - inset.top
379: - inset.bottom);
380: setBounds(handle, inset.left, inset.top, width, height, true,
381: true, false);
382: if (isVisibleHBar) {
383: setBounds(horizontalBar.handle, inset.left, inset.top
384: + height, width, hHeight, true, true, false);
385: }
386: if (isVisibleVBar) {
387: setBounds(verticalBar.handle, inset.left + width,
388: inset.top, vWidth, height, true, true, false);
389: }
390: }
391:
392: boolean sendMouseWheel(short wheelAxis, int wheelDelta) {
393: if ((state & CANVAS) != 0) {
394: ScrollBar bar = wheelAxis == OS.kEventMouseWheelAxisX ? horizontalBar
395: : verticalBar;
396: if (bar != null && bar.getEnabled()) {
397: bar.setSelection(Math.max(0, bar.getSelection()
398: - bar.getIncrement() * wheelDelta));
399: Event event = new Event();
400: event.detail = wheelDelta > 0 ? SWT.PAGE_UP
401: : SWT.PAGE_DOWN;
402: bar.sendEvent(SWT.Selection, event);
403: return true;
404: }
405: }
406: return false;
407: }
408:
409: int setBounds(int x, int y, int width, int height, boolean move,
410: boolean resize, boolean events) {
411: int result = super .setBounds(x, y, width, height, move, resize,
412: false);
413: if ((result & MOVED) != 0) {
414: if (events)
415: sendEvent(SWT.Move);
416: }
417: if ((result & RESIZED) != 0) {
418: resizeClientArea();
419: if (events)
420: sendEvent(SWT.Resize);
421: }
422: return result;
423: }
424:
425: boolean setScrollBarVisible(ScrollBar bar, boolean visible) {
426: if (scrolledHandle == 0)
427: return false;
428: if ((state & CANVAS) == 0)
429: return false;
430: if (visible) {
431: if ((bar.state & HIDDEN) == 0)
432: return false;
433: bar.state &= ~HIDDEN;
434: } else {
435: if ((bar.state & HIDDEN) != 0)
436: return false;
437: bar.state |= HIDDEN;
438: }
439: resizeClientArea();
440: setVisible(bar.handle, visible);
441: bar.sendEvent(visible ? SWT.Show : SWT.Hide);
442: sendEvent(SWT.Resize);
443: return true;
444: }
445:
446: void setZOrder() {
447: super .setZOrder();
448: if (scrolledHandle != 0)
449: OS.HIViewAddSubview(scrolledHandle, handle);
450: }
451:
452: int topHandle() {
453: if (scrolledHandle != 0)
454: return scrolledHandle;
455: return handle;
456: }
457:
458: }
|