Source code: org/eclipse/swt/widgets/Scrollable.java
1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.swt.widgets;
12
13
14 import org.eclipse.swt.*;
15 import org.eclipse.swt.internal.gtk.*;
16 import org.eclipse.swt.graphics.*;
17
18 /**
19 * This class is the abstract superclass of all classes which
20 * represent controls that have standard scroll bars.
21 * <dl>
22 * <dt><b>Styles:</b></dt>
23 * <dd>H_SCROLL, V_SCROLL</dd>
24 * <dt><b>Events:</b>
25 * <dd>(none)</dd>
26 * </dl>
27 * <p>
28 * IMPORTANT: This class is intended to be subclassed <em>only</em>
29 * within the SWT implementation.
30 * </p>
31 */
32 public abstract class Scrollable extends Control {
33 long /*int*/ scrolledHandle;
34 ScrollBar horizontalBar, verticalBar;
35
36 /**
37 * Prevents uninitialized instances from being created outside the package.
38 */
39 Scrollable () {}
40
41 /**
42 * Constructs a new instance of this class given its parent
43 * and a style value describing its behavior and appearance.
44 * <p>
45 * The style value is either one of the style constants defined in
46 * class <code>SWT</code> which is applicable to instances of this
47 * class, or must be built by <em>bitwise OR</em>'ing together
48 * (that is, using the <code>int</code> "|" operator) two or more
49 * of those <code>SWT</code> style constants. The class description
50 * lists the style constants that are applicable to the class.
51 * Style bits are also inherited from superclasses.
52 * </p>
53 *
54 * @param parent a composite control which will be the parent of the new instance (cannot be null)
55 * @param style the style of control to construct
56 *
57 * @exception IllegalArgumentException <ul>
58 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
59 * </ul>
60 * @exception SWTException <ul>
61 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
62 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
63 * </ul>
64 *
65 * @see SWT#H_SCROLL
66 * @see SWT#V_SCROLL
67 * @see Widget#checkSubclass
68 * @see Widget#getStyle
69 */
70 public Scrollable (Composite parent, int style) {
71 super (parent, style);
72 }
73
74 long /*int*/ clientHandle () {
75 return handle;
76 }
77
78 /**
79 * Given a desired <em>client area</em> for the receiver
80 * (as described by the arguments), returns the bounding
81 * rectangle which would be required to produce that client
82 * area.
83 * <p>
84 * In other words, it returns a rectangle such that, if the
85 * receiver's bounds were set to that rectangle, the area
86 * of the receiver which is capable of displaying data
87 * (that is, not covered by the "trimmings") would be the
88 * rectangle described by the arguments (relative to the
89 * receiver's parent).
90 * </p>
91 *
92 * @param x the desired x coordinate of the client area
93 * @param y the desired y coordinate of the client area
94 * @param width the desired width of the client area
95 * @param height the desired height of the client area
96 * @return the required bounds to produce the given client area
97 *
98 * @exception SWTException <ul>
99 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
100 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
101 * </ul>
102 *
103 * @see #getClientArea
104 */
105 public Rectangle computeTrim (int x, int y, int width, int height) {
106 checkWidget();
107 int border = 0;
108 if (fixedHandle != 0) border += OS.gtk_container_get_border_width (fixedHandle);
109 if (scrolledHandle != 0) border += OS.gtk_container_get_border_width (scrolledHandle);
110 int trimX = x - border, trimY = y - border;
111 int trimWidth = width + (border * 2), trimHeight = height + (border * 2);
112 trimHeight += hScrollBarWidth ();
113 trimWidth += vScrollBarWidth ();
114 if (scrolledHandle != 0) {
115 if (OS.gtk_scrolled_window_get_shadow_type (scrolledHandle) != OS.GTK_SHADOW_NONE) {
116 long /*int*/ style = OS.gtk_widget_get_style (scrolledHandle);
117 int xthickness = OS.gtk_style_get_xthickness (style);
118 int ythickness = OS.gtk_style_get_ythickness (style);
119 trimX -= xthickness;
120 trimY -= ythickness;
121 trimWidth += xthickness * 2;
122 trimHeight += ythickness * 2;
123 }
124 }
125 return new Rectangle (trimX, trimY, trimWidth, trimHeight);
126 }
127
128 ScrollBar createScrollBar (int style) {
129 if (scrolledHandle == 0) return null;
130 ScrollBar bar = new ScrollBar ();
131 bar.parent = this;
132 bar.style = style;
133 bar.display = display;
134 bar.state |= HANDLE;
135 if ((style & SWT.H_SCROLL) != 0) {
136 bar.handle = OS.gtk_scrolled_window_get_hadjustment (scrolledHandle);
137 } else {
138 bar.handle = OS.gtk_scrolled_window_get_vadjustment (scrolledHandle);
139 }
140 bar.hookEvents ();
141 bar.register ();
142 return bar;
143 }
144
145 void createWidget (int index) {
146 super.createWidget (index);
147 if ((style & SWT.H_SCROLL) != 0) horizontalBar = createScrollBar (SWT.H_SCROLL);
148 if ((style & SWT.V_SCROLL) != 0) verticalBar = createScrollBar (SWT.V_SCROLL);
149 }
150
151 void deregister () {
152 super.deregister ();
153 if (scrolledHandle != 0) display.removeWidget (scrolledHandle);
154 }
155
156 public int getBorderWidth () {
157 checkWidget();
158 int border = 0;
159 if (fixedHandle != 0) border += OS.gtk_container_get_border_width (fixedHandle);
160 if (scrolledHandle != 0) {
161 border += OS.gtk_container_get_border_width (scrolledHandle);
162 if (OS.gtk_scrolled_window_get_shadow_type (scrolledHandle) != OS.GTK_SHADOW_NONE) {
163 border += OS.gtk_style_get_xthickness (OS.gtk_widget_get_style (scrolledHandle));
164 }
165 }
166 return border;
167 }
168
169 /**
170 * Returns a rectangle which describes the area of the
171 * receiver which is capable of displaying data (that is,
172 * not covered by the "trimmings").
173 *
174 * @return the client area
175 *
176 * @exception SWTException <ul>
177 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
178 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
179 * </ul>
180 *
181 * @see #computeTrim
182 */
183 public Rectangle getClientArea () {
184 checkWidget ();
185 //FIXME - List, Table, Tree, ...
186 long /*int*/ clientHandle = clientHandle ();
187 int width = OS.GTK_WIDGET_WIDTH (clientHandle);
188 int height = OS.GTK_WIDGET_HEIGHT (clientHandle);
189 if ((state & CANVAS) != 0) {
190 return new Rectangle (0, 0, width, height);
191 }
192 int x = OS.GTK_WIDGET_X (clientHandle);
193 int y = OS.GTK_WIDGET_Y (clientHandle);
194 return new Rectangle (x, y, width, height);
195 }
196 /**
197 * Returns the receiver's horizontal scroll bar if it has
198 * one, and null if it does not.
199 *
200 * @return the horizontal scroll bar (or null)
201 *
202 * @exception SWTException <ul>
203 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
204 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
205 * </ul>
206 */
207 public ScrollBar getHorizontalBar () {
208 checkWidget ();
209 return horizontalBar;
210 }
211 /**
212 * Returns the receiver's vertical scroll bar if it has
213 * one, and null if it does not.
214 *
215 * @return the vertical scroll bar (or null)
216 *
217 * @exception SWTException <ul>
218 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
219 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
220 * </ul>
221 */
222 public ScrollBar getVerticalBar () {
223 checkWidget ();
224 return verticalBar;
225 }
226
227 int hScrollBarWidth() {
228 if (horizontalBar==null) return 0;
229 long /*int*/ hBarHandle = OS.GTK_SCROLLED_WINDOW_HSCROLLBAR(scrolledHandle);
230 if (hBarHandle==0) return 0;
231 GtkRequisition requisition = new GtkRequisition();
232 OS.gtk_widget_size_request(hBarHandle, requisition);
233 int spacing = OS.GTK_SCROLLED_WINDOW_SCROLLBAR_SPACING(scrolledHandle);
234 return requisition.height + spacing;
235 }
236
237 void setOrientation () {
238 if ((style & SWT.RIGHT_TO_LEFT) != 0) {
239 if (scrolledHandle != 0) {
240 OS.gtk_scrolled_window_set_placement (scrolledHandle, OS.GTK_CORNER_TOP_RIGHT);
241 }
242 }
243 }
244
245 void register () {
246 super.register ();
247 if (scrolledHandle != 0) display.addWidget (scrolledHandle, this);
248 }
249
250 void releaseHandle () {
251 super.releaseHandle ();
252 scrolledHandle = 0;
253 }
254
255 void releaseWidget () {
256 if (horizontalBar != null) horizontalBar.releaseResources ();
257 if (verticalBar != null) verticalBar.releaseResources ();
258 horizontalBar = verticalBar = null;
259 super.releaseWidget ();
260 }
261
262 void resizeHandle (int width, int height) {
263 if (fixedHandle != 0) {
264 OS.gtk_widget_set_size_request (fixedHandle, width, height);
265 }
266 /*
267 * Feature in GTK. Some widgets do not allocate the size
268 * of their internal children in gtk_widget_size_allocate().
269 * Instead this is done in gtk_widget_size_request(). This
270 * means that the client area of the widget is not correct.
271 * The fix is to call gtk_widget_size_request() (and throw
272 * the results away).
273 *
274 * Note: The following widgets rely on this feature:
275 * GtkScrolledWindow
276 * GtkNotebook
277 * GtkFrame
278 * GtkCombo
279 */
280 GtkRequisition requisition = new GtkRequisition ();
281 if (scrolledHandle != 0) {
282 OS.gtk_widget_set_size_request (scrolledHandle, width, height);
283 OS.gtk_widget_size_request (scrolledHandle, requisition);
284 } else {
285 OS.gtk_widget_set_size_request (handle, width, height);
286 OS.gtk_widget_size_request (handle, requisition);
287 }
288 }
289
290 long /*int*/ topHandle () {
291 if (fixedHandle != 0) return fixedHandle;
292 if (scrolledHandle != 0) return scrolledHandle;
293 return super.topHandle ();
294 }
295
296 int vScrollBarWidth() {
297 if (verticalBar == null) return 0;
298 long /*int*/ vBarHandle = OS.GTK_SCROLLED_WINDOW_VSCROLLBAR(scrolledHandle);
299 if (vBarHandle == 0) return 0;
300 GtkRequisition requisition = new GtkRequisition();
301 OS.gtk_widget_size_request (vBarHandle, requisition);
302 int spacing = OS.GTK_SCROLLED_WINDOW_SCROLLBAR_SPACING(scrolledHandle);
303 return requisition.width + spacing;
304 }
305 }