25
|
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 org.eclipse.swt.widgets.Combo;
|
|
14
|
|
15
|
|
16 import org.eclipse.swt.SWT;
|
|
17 import org.eclipse.swt.internal.gtk.OS;
|
|
18 import org.eclipse.swt.graphics.Point;
|
|
19 import org.eclipse.swt.events.SelectionListener;
|
|
20 import org.eclipse.swt.events.SelectionEvent;
|
|
21 import org.eclipse.swt.events.ModifyListener;
|
|
22 import org.eclipse.swt.events.VerifyListener;
|
|
23 import org.eclipse.swt.widgets.Shell;
|
|
24 import org.eclipse.swt.widgets.Composite;
|
|
25 import org.eclipse.swt.widgets.Event;
|
|
26 import org.eclipse.swt.widgets.TypedListener;
|
|
27
|
|
28 import java.lang.all;
|
|
29
|
|
30 /**
|
|
31 * Instances of this class are controls that allow the user
|
|
32 * to choose an item from a list of items, or optionally
|
|
33 * enter a new value by typing it into an editable text
|
|
34 * field. Often, <code>Combo</code>s are used in the same place
|
|
35 * where a single selection <code>List</code> widget could
|
|
36 * be used but space is limited. A <code>Combo</code> takes
|
|
37 * less space than a <code>List</code> widget and shows
|
|
38 * similar information.
|
|
39 * <p>
|
|
40 * Note: Since <code>Combo</code>s can contain both a list
|
|
41 * and an editable text field, it is possible to confuse methods
|
|
42 * which access one versus the other (compare for example,
|
|
43 * <code>clearSelection()</code> and <code>deselectAll()</code>).
|
|
44 * The API documentation is careful to indicate either "the
|
|
45 * receiver's list" or the "the receiver's text field" to
|
|
46 * distinguish between the two cases.
|
|
47 * </p><p>
|
|
48 * Note that although this class is a subclass of <code>Composite</code>,
|
|
49 * it does not make sense to add children to it, or set a layout on it.
|
|
50 * </p>
|
|
51 * <dl>
|
|
52 * <dt><b>Styles:</b></dt>
|
|
53 * <dd>DROP_DOWN, READ_ONLY, SIMPLE</dd>
|
|
54 * <dt><b>Events:</b></dt>
|
|
55 * <dd>DefaultSelection, Modify, Selection, Verify</dd>
|
|
56 * </dl>
|
|
57 * <p>
|
|
58 * Note: Only one of the styles DROP_DOWN and SIMPLE may be specified.
|
|
59 * </p><p>
|
|
60 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
|
|
61 * </p>
|
|
62 *
|
|
63 * @see List
|
|
64 * @see <a href="http://www.eclipse.org/swt/snippets/#combo">Combo snippets</a>
|
|
65 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
|
|
66 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
|
|
67 */
|
|
68 public class Combo : Composite {
|
|
69
|
|
70 alias Composite.computeSize computeSize;
|
|
71 alias Composite.createHandle createHandle;
|
|
72 alias Composite.dragDetect dragDetect;
|
|
73 alias Composite.gtk_button_press_event gtk_button_press_event;
|
|
74 alias Composite.setBackgroundColor setBackgroundColor;
|
|
75 alias Composite.setBounds setBounds;
|
|
76 alias Composite.setForegroundColor setForegroundColor;
|
|
77 alias Composite.setToolTipText setToolTipText;
|
|
78 alias Composite.translateTraversal translateTraversal;
|
|
79
|
|
80 GtkWidget* buttonHandle, entryHandle, listHandle, textRenderer, cellHandle, popupHandle;
|
|
81 int lastEventTime, visibleCount = 5;
|
|
82 GdkEventKey* gdkEventKey;
|
|
83 int fixStart = -1, fixEnd = -1;
|
|
84 String[] items;
|
|
85 bool ignoreSelect, lockText;
|
|
86
|
|
87 static const int INNER_BORDER = 2;
|
|
88
|
|
89 /**
|
|
90 * the operating system limit for the number of characters
|
|
91 * that the text field in an instance of this class can hold
|
|
92 */
|
|
93 public const static int LIMIT = 0xFFFF;
|
|
94
|
|
95 /*
|
|
96 * These values can be different on different platforms.
|
|
97 * Therefore they are not initialized in the declaration
|
|
98 * to stop the compiler from inlining.
|
|
99 */
|
|
100 //static {
|
|
101 // LIMIT = 0xFFFF;
|
|
102 //}
|
|
103
|
|
104 /**
|
|
105 * Constructs a new instance of this class given its parent
|
|
106 * and a style value describing its behavior and appearance.
|
|
107 * <p>
|
|
108 * The style value is either one of the style constants defined in
|
|
109 * class <code>SWT</code> which is applicable to instances of this
|
|
110 * class, or must be built by <em>bitwise OR</em>'ing together
|
|
111 * (that is, using the <code>int</code> "|" operator) two or more
|
|
112 * of those <code>SWT</code> style constants. The class description
|
|
113 * lists the style constants that are applicable to the class.
|
|
114 * Style bits are also inherited from superclasses.
|
|
115 * </p>
|
|
116 *
|
|
117 * @param parent a composite control which will be the parent of the new instance (cannot be null)
|
|
118 * @param style the style of control to construct
|
|
119 *
|
|
120 * @exception IllegalArgumentException <ul>
|
|
121 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
|
|
122 * </ul>
|
|
123 * @exception SWTException <ul>
|
|
124 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
|
|
125 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
|
|
126 * </ul>
|
|
127 *
|
|
128 * @see SWT#DROP_DOWN
|
|
129 * @see SWT#READ_ONLY
|
|
130 * @see SWT#SIMPLE
|
|
131 * @see Widget#checkSubclass
|
|
132 * @see Widget#getStyle
|
|
133 */
|
|
134 public this (Composite parent, int style) {
|
|
135 super (parent, checkStyle (style));
|
|
136 }
|
|
137
|
|
138 /**
|
|
139 * Adds the argument to the end of the receiver's list.
|
|
140 *
|
|
141 * @param string the new item
|
|
142 *
|
|
143 * @exception SWTException <ul>
|
|
144 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
145 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
146 * </ul>
|
|
147 *
|
|
148 * @see #add(String,int)
|
|
149 */
|
|
150 public void add (String string) {
|
|
151 checkWidget();
|
|
152 // SWT extension: allow null for zero length string
|
|
153 //if (string is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
154 add (string, items.length);
|
|
155 }
|
|
156
|
|
157 /**
|
|
158 * Adds the argument to the receiver's list at the given
|
|
159 * zero-relative index.
|
|
160 * <p>
|
|
161 * Note: To add an item at the end of the list, use the
|
|
162 * result of calling <code>getItemCount()</code> as the
|
|
163 * index or use <code>add(String)</code>.
|
|
164 * </p>
|
|
165 *
|
|
166 * @param string the new item
|
|
167 * @param index the index for the item
|
|
168 *
|
|
169 * @exception IllegalArgumentException <ul>
|
|
170 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li>
|
|
171 * </ul>
|
|
172 * @exception SWTException <ul>
|
|
173 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
174 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
175 * </ul>
|
|
176 *
|
|
177 * @see #add(String)
|
|
178 */
|
|
179 public void add (String string, int index) {
|
|
180 checkWidget();
|
|
181 // SWT extension: allow null for zero length string
|
|
182 //if (string is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
183 if (!(0 <= index && index <= items.length)) {
|
|
184 error (SWT.ERROR_INVALID_RANGE);
|
|
185 }
|
|
186 String [] newItems = new String[]( items.length + 1 );
|
|
187 System.arraycopy (items, 0, newItems, 0, index);
|
|
188 newItems [index] = string;
|
|
189 System.arraycopy (items, index, newItems, index + 1, items.length - index);
|
|
190 items = newItems;
|
|
191 char* buffer = string.toStringzValidPtr();
|
|
192 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
193 OS.gtk_combo_box_insert_text (handle, index, buffer);
|
|
194 if ((style & SWT.RIGHT_TO_LEFT) !is 0 && popupHandle !is null) {
|
|
195 display.doSetDirectionProc( popupHandle, OS.GTK_TEXT_DIR_RTL);
|
|
196 }
|
|
197 } else {
|
|
198 /*
|
|
199 * Feature in GTK. When the list is empty and the first item
|
|
200 * is added, the combo box selects that item replacing the
|
|
201 * text in the entry field. The fix is to avoid this by
|
|
202 * stopping the "delete" and "insert_text" signal emission.
|
|
203 */
|
|
204 ignoreSelect = lockText = true;
|
|
205 auto item = OS.gtk_list_item_new_with_label (buffer);
|
|
206 auto label = OS.gtk_bin_get_child (item);
|
|
207 setForegroundColor (label, getForegroundColor ());
|
|
208 OS.gtk_widget_modify_font (label, getFontDescription ());
|
|
209 OS.gtk_widget_set_direction (label, OS.gtk_widget_get_direction (handle));
|
|
210 OS.gtk_widget_show (item);
|
|
211 auto items = OS.g_list_append (null, item);
|
|
212 OS.gtk_list_insert_items (listHandle, items, index);
|
|
213 ignoreSelect = lockText = false;
|
|
214 }
|
|
215 }
|
|
216
|
|
217 /**
|
|
218 * Adds the listener to the collection of listeners who will
|
|
219 * be notified when the receiver's text is modified, by sending
|
|
220 * it one of the messages defined in the <code>ModifyListener</code>
|
|
221 * interface.
|
|
222 *
|
|
223 * @param listener the listener which should be notified
|
|
224 *
|
|
225 * @exception IllegalArgumentException <ul>
|
|
226 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
|
|
227 * </ul>
|
|
228 * @exception SWTException <ul>
|
|
229 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
230 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
231 * </ul>
|
|
232 *
|
|
233 * @see ModifyListener
|
|
234 * @see #removeModifyListener
|
|
235 */
|
|
236 public void addModifyListener (ModifyListener listener) {
|
|
237 checkWidget();
|
|
238 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
239 TypedListener typedListener = new TypedListener (listener);
|
|
240 addListener (SWT.Modify, typedListener);
|
|
241 }
|
|
242
|
|
243 /**
|
|
244 * Adds the listener to the collection of listeners who will
|
|
245 * be notified when the user changes the receiver's selection, by sending
|
|
246 * it one of the messages defined in the <code>SelectionListener</code>
|
|
247 * interface.
|
|
248 * <p>
|
|
249 * <code>widgetSelected</code> is called when the user changes the combo's list selection.
|
|
250 * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed the combo's text area.
|
|
251 * </p>
|
|
252 *
|
|
253 * @param listener the listener which should be notified
|
|
254 *
|
|
255 * @exception IllegalArgumentException <ul>
|
|
256 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
|
|
257 * </ul>
|
|
258 * @exception SWTException <ul>
|
|
259 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
260 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
261 * </ul>
|
|
262 *
|
|
263 * @see SelectionListener
|
|
264 * @see #removeSelectionListener
|
|
265 * @see SelectionEvent
|
|
266 */
|
|
267 public void addSelectionListener(SelectionListener listener) {
|
|
268 checkWidget();
|
|
269 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
270 TypedListener typedListener = new TypedListener (listener);
|
|
271 addListener (SWT.Selection,typedListener);
|
|
272 addListener (SWT.DefaultSelection,typedListener);
|
|
273 }
|
|
274
|
|
275 /**
|
|
276 * Adds the listener to the collection of listeners who will
|
|
277 * be notified when the receiver's text is verified, by sending
|
|
278 * it one of the messages defined in the <code>VerifyListener</code>
|
|
279 * interface.
|
|
280 *
|
|
281 * @param listener the listener which should be notified
|
|
282 *
|
|
283 * @exception IllegalArgumentException <ul>
|
|
284 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
|
|
285 * </ul>
|
|
286 * @exception SWTException <ul>
|
|
287 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
288 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
289 * </ul>
|
|
290 *
|
|
291 * @see VerifyListener
|
|
292 * @see #removeVerifyListener
|
|
293 *
|
|
294 * @since 3.1
|
|
295 */
|
|
296 public void addVerifyListener (VerifyListener listener) {
|
|
297 checkWidget ();
|
|
298 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
299 TypedListener typedListener = new TypedListener (listener);
|
|
300 addListener (SWT.Verify, typedListener);
|
|
301 }
|
|
302
|
|
303 static int checkStyle (int style) {
|
|
304 /*
|
|
305 * Feature in Windows. It is not possible to create
|
|
306 * a combo box that has a border using Windows style
|
|
307 * bits. All combo boxes draw their own border and
|
|
308 * do not use the standard Windows border styles.
|
|
309 * Therefore, no matter what style bits are specified,
|
|
310 * clear the BORDER bits so that the SWT style will
|
|
311 * match the Windows widget.
|
|
312 *
|
|
313 * The Windows behavior is currently implemented on
|
|
314 * all platforms.
|
|
315 */
|
|
316 style &= ~SWT.BORDER;
|
|
317
|
|
318 /*
|
|
319 * Even though it is legal to create this widget
|
|
320 * with scroll bars, they serve no useful purpose
|
|
321 * because they do not automatically scroll the
|
|
322 * widget's client area. The fix is to clear
|
|
323 * the SWT style.
|
|
324 */
|
|
325 style &= ~(SWT.H_SCROLL | SWT.V_SCROLL);
|
|
326 style = checkBits (style, SWT.DROP_DOWN, SWT.SIMPLE, 0, 0, 0, 0);
|
|
327 if ((style & SWT.SIMPLE) !is 0) return style & ~SWT.READ_ONLY;
|
|
328 return style;
|
|
329 }
|
|
330
|
|
331 protected override void checkSubclass () {
|
|
332 if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
|
|
333 }
|
|
334
|
|
335 /**
|
|
336 * Sets the selection in the receiver's text field to an empty
|
|
337 * selection starting just before the first character. If the
|
|
338 * text field is editable, this has the effect of placing the
|
|
339 * i-beam at the start of the text.
|
|
340 * <p>
|
|
341 * Note: To clear the selected items in the receiver's list,
|
|
342 * use <code>deselectAll()</code>.
|
|
343 * </p>
|
|
344 *
|
|
345 * @exception SWTException <ul>
|
|
346 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
347 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
348 * </ul>
|
|
349 *
|
|
350 * @see #deselectAll
|
|
351 */
|
|
352 public void clearSelection () {
|
|
353 checkWidget();
|
|
354 if (entryHandle !is null) {
|
|
355 int position = OS.gtk_editable_get_position (entryHandle);
|
|
356 OS.gtk_editable_select_region (entryHandle, position, position);
|
|
357 }
|
|
358 }
|
|
359
|
|
360 void clearText () {
|
|
361 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
362 OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
363 if ((style & SWT.READ_ONLY) !is 0) {
|
|
364 int index = OS.gtk_combo_box_get_active (handle);
|
|
365 if (index !is -1) {
|
|
366 auto modelHandle = OS.gtk_combo_box_get_model (handle);
|
|
367 char* ptr;
|
|
368 GtkTreeIter iter;
|
|
369 OS.gtk_tree_model_iter_nth_child (modelHandle, &iter, null, index);
|
|
370 OS.gtk_tree_model_get1 (modelHandle, &iter, 0, cast(void**)&ptr );
|
|
371 if (fromStringz(ptr).length > 0) postEvent (SWT.Modify);
|
|
372 OS.g_free (ptr);
|
|
373 }
|
|
374 } else {
|
|
375 char dummy = '\0';
|
|
376 OS.gtk_entry_set_text (entryHandle, &dummy );
|
|
377 }
|
|
378 OS.gtk_combo_box_set_active (handle, -1);
|
|
379 OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
380 }
|
|
381 }
|
|
382
|
|
383 public override Point computeSize (int wHint, int hHint, bool changed) {
|
|
384 checkWidget ();
|
|
385 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
386 return computeNativeSize (handle, wHint, hHint, changed);
|
|
387 }
|
|
388 if (wHint !is SWT.DEFAULT && wHint < 0) wHint = 0;
|
|
389 if (hHint !is SWT.DEFAULT && hHint < 0) hHint = 0;
|
|
390 int w, h;
|
|
391 OS.gtk_widget_realize (entryHandle);
|
|
392 auto layout = OS.gtk_entry_get_layout (entryHandle);
|
|
393 OS.pango_layout_get_size (layout, &w, &h);
|
|
394 int xborder = INNER_BORDER, yborder = INNER_BORDER;
|
|
395 auto style = OS.gtk_widget_get_style (entryHandle);
|
|
396 xborder += OS.gtk_style_get_xthickness (style);
|
|
397 yborder += OS.gtk_style_get_ythickness (style);
|
|
398 int property;
|
|
399 OS.gtk_widget_style_get1 (entryHandle, OS.interior_focus.ptr, &property);
|
|
400 if (property is 0) {
|
|
401 OS.gtk_widget_style_get1 (entryHandle, OS.focus_line_width.ptr, &property);
|
|
402 xborder += property ;
|
|
403 yborder += property ;
|
|
404 }
|
|
405 int width = OS.PANGO_PIXELS (w ) + xborder * 2;
|
|
406 int height = OS.PANGO_PIXELS (h ) + yborder * 2;
|
|
407
|
|
408 GtkRequisition arrowRequesition;
|
|
409 OS.gtk_widget_size_request (buttonHandle, &arrowRequesition);
|
|
410 GtkRequisition listRequesition;
|
|
411 auto listParent = OS.gtk_widget_get_parent (listHandle);
|
|
412 OS.gtk_widget_size_request (listParent !is null ? listParent : listHandle, &listRequesition);
|
|
413
|
|
414 width = Math.max (listRequesition.width, width) + arrowRequesition.width + 4;
|
|
415 width = wHint is SWT.DEFAULT ? width : wHint;
|
|
416 height = hHint is SWT.DEFAULT ? height : hHint;
|
|
417 return new Point (width, height);
|
|
418 }
|
|
419
|
|
420 /**
|
|
421 * Copies the selected text.
|
|
422 * <p>
|
|
423 * The current selection is copied to the clipboard.
|
|
424 * </p>
|
|
425 *
|
|
426 * @exception SWTException <ul>
|
|
427 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
428 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
429 * </ul>
|
|
430 *
|
|
431 * @since 2.1
|
|
432 */
|
|
433 public void copy () {
|
|
434 checkWidget ();
|
|
435 if (entryHandle !is null) OS.gtk_editable_copy_clipboard (entryHandle);
|
|
436 }
|
|
437
|
|
438 override void createHandle (int index) {
|
|
439 state |= HANDLE | MENU;
|
|
440 fixedHandle = cast(GtkWidget*)OS.g_object_new (display.gtk_fixed_get_type (), null);
|
|
441 if (fixedHandle is null) error (SWT.ERROR_NO_HANDLES);
|
|
442 OS.gtk_fixed_set_has_window (fixedHandle, true);
|
|
443 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
444 auto oldList = OS.gtk_window_list_toplevels ();
|
|
445 if ((style & SWT.READ_ONLY) !is 0) {
|
|
446 handle = OS.gtk_combo_box_new_text ();
|
|
447 if (handle is null) error (SWT.ERROR_NO_HANDLES);
|
|
448 cellHandle = OS.gtk_bin_get_child (handle);
|
|
449 if (cellHandle is null) error (SWT.ERROR_NO_HANDLES);
|
|
450 } else {
|
|
451 handle = OS.gtk_combo_box_entry_new_text ();
|
|
452 if (handle is null) error (SWT.ERROR_NO_HANDLES);
|
|
453 entryHandle = OS.gtk_bin_get_child (handle);
|
|
454 if (entryHandle is null) error (SWT.ERROR_NO_HANDLES);
|
|
455 }
|
|
456 popupHandle = findPopupHandle (oldList);
|
|
457 OS.gtk_container_add (fixedHandle, handle);
|
|
458 textRenderer = cast(GtkWidget*)OS.gtk_cell_renderer_text_new ();
|
|
459 if (textRenderer is null) error (SWT.ERROR_NO_HANDLES);
|
|
460 /*
|
|
461 * Feature in GTK. In order to make a read only combo box the same
|
|
462 * height as an editable combo box the ypad must be set to 0. In
|
|
463 * versions 2.4.x of GTK, a pad of 0 will clip some letters. The
|
|
464 * fix is to set the pad to 1.
|
|
465 */
|
|
466 int pad = 0;
|
|
467 if (OS.GTK_VERSION < OS.buildVERSION(2, 6, 0)) pad = 1;
|
|
468 OS.g_object_set1 (textRenderer, OS.ypad.ptr, pad);
|
|
469 /*
|
|
470 * Feature in GTK. In version 2.4.9 of GTK, a warning is issued
|
|
471 * when a call to gtk_cell_layout_clear() is made. The fix is to hide
|
|
472 * the warning.
|
|
473 */
|
|
474 bool warnings = display.getWarnings ();
|
|
475 display.setWarnings (false);
|
|
476 OS.gtk_cell_layout_clear (handle);
|
|
477 display.setWarnings (warnings);
|
|
478 OS.gtk_cell_layout_pack_start (handle, textRenderer, true);
|
|
479 OS.gtk_cell_layout_set_attributes1 (handle, textRenderer, OS.text.ptr, null);
|
|
480
|
|
481 /*
|
|
482 * Feature in GTK. There is no API to query the button
|
|
483 * handle from a combo box although it is possible to get the
|
|
484 * text field. The button handle is needed to hook events. The
|
|
485 * fix is to walk the combo tree and find the first child that is
|
|
486 * an instance of button.
|
|
487 */
|
|
488 display.allChildrenCollect (handle, 0);
|
|
489 if (display.allChildren !is null) {
|
|
490 auto list = display.allChildren;
|
|
491 while (list !is null) {
|
|
492 auto widget = OS.g_list_data (list);
|
|
493 if (OS.GTK_IS_BUTTON (cast(GTypeInstance*)widget)) {
|
|
494 buttonHandle = cast(GtkWidget*)widget;
|
|
495 break;
|
|
496 }
|
|
497 list = OS.g_list_next (list);
|
|
498 }
|
|
499 OS.g_list_free (display.allChildren);
|
|
500 display.allChildren = null;
|
|
501 }
|
|
502 /*
|
|
503 * Feature in GTK. By default, read only combo boxes
|
|
504 * process the RETURN key rather than allowing the
|
|
505 * default button to process the key. The fix is to
|
|
506 * clear the GTK_RECEIVES_DEFAULT flag.
|
|
507 */
|
|
508 if ((style & SWT.READ_ONLY) !is 0 && buttonHandle !is null) {
|
|
509 OS.GTK_WIDGET_UNSET_FLAGS (buttonHandle, OS.GTK_RECEIVES_DEFAULT);
|
|
510 }
|
|
511 } else {
|
|
512 handle = OS.gtk_combo_new ();
|
|
513 if (handle is null) error (SWT.ERROR_NO_HANDLES);
|
|
514 OS.gtk_container_add (fixedHandle, handle);
|
|
515 GtkCombo* combo = cast(GtkCombo*)handle;
|
|
516 entryHandle = combo.entry;
|
|
517 listHandle = combo.list;
|
|
518
|
|
519 if (OS.GTK_VERSION < OS.buildVERSION (2, 4, 0)) {
|
|
520 GtkWidget* parentHandle = null;
|
|
521 auto temp = listHandle;
|
|
522 while ((temp = OS.gtk_widget_get_parent(temp)) !is null) {
|
|
523 parentHandle = temp;
|
|
524 }
|
|
525 popupHandle = parentHandle;
|
|
526 if (popupHandle !is null) {
|
|
527 GtkWidget* modalGroup = getShell().modalGroup;
|
|
528 if (modalGroup !is null) {
|
|
529 OS.gtk_window_group_add_window (modalGroup, popupHandle);
|
|
530 }
|
|
531 }
|
|
532 }
|
|
533 /*
|
|
534 * Feature in GTK. There is no API to query the arrow
|
|
535 * handle from a combo box although it is possible to
|
|
536 * get the list and text field. The arrow handle is needed
|
|
537 * to hook events. The fix is to find the first child that is
|
|
538 * not the entry or list and assume this is the arrow handle.
|
|
539 */
|
|
540 auto list = OS.gtk_container_get_children (handle);
|
|
541 if (list !is null) {
|
|
542 int i = 0, count = OS.g_list_length (list);
|
|
543 while (i<count) {
|
|
544 auto childHandle = OS.g_list_nth_data (list, i);
|
|
545 if (childHandle !is entryHandle && childHandle !is listHandle) {
|
|
546 buttonHandle = cast(GtkWidget*)childHandle;
|
|
547 break;
|
|
548 }
|
|
549 i++;
|
|
550 }
|
|
551 OS.g_list_free (list);
|
|
552 }
|
|
553
|
|
554 bool editable = (style & SWT.READ_ONLY) is 0;
|
|
555 OS.gtk_editable_set_editable (entryHandle, editable);
|
|
556 OS.gtk_combo_disable_activate (handle);
|
|
557 OS.gtk_combo_set_case_sensitive (handle, true);
|
|
558 }
|
|
559 }
|
|
560
|
|
561 /**
|
|
562 * Cuts the selected text.
|
|
563 * <p>
|
|
564 * The current selection is first copied to the
|
|
565 * clipboard and then deleted from the widget.
|
|
566 * </p>
|
|
567 *
|
|
568 * @exception SWTException <ul>
|
|
569 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
570 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
571 * </ul>
|
|
572 *
|
|
573 * @since 2.1
|
|
574 */
|
|
575 public void cut () {
|
|
576 checkWidget ();
|
|
577 if (entryHandle !is null) OS.gtk_editable_cut_clipboard (entryHandle);
|
|
578 }
|
|
579
|
|
580 override void deregister () {
|
|
581 super.deregister ();
|
|
582 if (buttonHandle !is null) display.removeWidget (buttonHandle);
|
|
583 if (entryHandle !is null) display.removeWidget (entryHandle);
|
|
584 if (listHandle !is null) display.removeWidget (listHandle);
|
|
585 auto imContext = imContext ();
|
|
586 if (imContext !is null) display.removeWidget (cast(GtkWidget*)imContext);
|
|
587 }
|
|
588
|
|
589 override bool filterKey (int keyval, GdkEventKey* event) {
|
|
590 int time = OS.gdk_event_get_time (cast(GdkEvent*)event);
|
|
591 if (time !is lastEventTime) {
|
|
592 lastEventTime = time;
|
|
593 auto imContext = imContext ();
|
|
594 if (imContext !is null) {
|
|
595 return cast(bool)OS.gtk_im_context_filter_keypress (imContext, event);
|
|
596 }
|
|
597 }
|
|
598 gdkEventKey = event;
|
|
599 return false;
|
|
600 }
|
|
601
|
|
602 GtkWidget* findPopupHandle (GList* oldList) {
|
|
603 GtkWidget* hdl = null;
|
|
604 GList* currentList = OS.gtk_window_list_toplevels();
|
|
605 GList* oldFromList = oldList;
|
|
606 GList* newFromList = currentList;
|
|
607 bool isFound;
|
|
608 while (newFromList !is null) {
|
|
609 void* newToplevel = OS.g_list_data(newFromList);
|
|
610 isFound = false;
|
|
611 oldFromList = oldList;
|
|
612 while (oldFromList !is null) {
|
|
613 void* oldToplevel = OS.g_list_data(oldFromList);
|
|
614 if (newToplevel is oldToplevel) {
|
|
615 isFound = true;
|
|
616 break;
|
|
617 }
|
|
618 oldFromList = OS.g_list_next(oldFromList);
|
|
619 }
|
|
620 if (!isFound) {
|
|
621 hdl = cast(GtkWidget*)newToplevel;
|
|
622 break;
|
|
623 }
|
|
624 newFromList = OS.g_list_next(newFromList);
|
|
625 }
|
|
626 OS.g_list_free(oldList);
|
|
627 OS.g_list_free(currentList);
|
|
628 return hdl;
|
|
629 }
|
|
630
|
|
631 override void fixModal (GtkWidget* group, GtkWidget* modalGroup) {
|
|
632 if (popupHandle !is null) {
|
|
633 if (group !is null) {
|
|
634 OS.gtk_window_group_add_window (group, popupHandle);
|
|
635 } else {
|
|
636 if (modalGroup !is null) {
|
|
637 OS.gtk_window_group_remove_window (modalGroup, popupHandle);
|
|
638 }
|
|
639 }
|
|
640 }
|
|
641 }
|
|
642
|
|
643 void fixIM () {
|
|
644 /*
|
|
645 * The IM filter has to be called one time for each key press event.
|
|
646 * When the IM is open the key events are duplicated. The first event
|
|
647 * is filtered by SWT and the second event is filtered by GTK. In some
|
|
648 * cases the GTK handler does not run (the widget is destroyed, the
|
|
649 * application code consumes the event, etc), for these cases the IM
|
|
650 * filter has to be called by SWT.
|
|
651 */
|
|
652 if (gdkEventKey !is null && gdkEventKey !is cast(GdkEventKey*)-1) {
|
|
653 auto imContext = imContext ();
|
|
654 if (imContext !is null) {
|
|
655 OS.gtk_im_context_filter_keypress (imContext, gdkEventKey);
|
|
656 gdkEventKey = cast(GdkEventKey*)-1;
|
|
657 return;
|
|
658 }
|
|
659 }
|
|
660 gdkEventKey = null;
|
|
661 }
|
|
662
|
|
663 override GtkWidget* fontHandle () {
|
|
664 if (entryHandle !is null) return entryHandle;
|
|
665 return super.fontHandle ();
|
|
666 }
|
|
667
|
|
668 override GtkWidget* focusHandle () {
|
|
669 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
670 if ((style & SWT.READ_ONLY) !is 0 && buttonHandle !is null) return buttonHandle;
|
|
671 }
|
|
672 if (entryHandle !is null) return entryHandle;
|
|
673 return super.focusHandle ();
|
|
674 }
|
|
675
|
|
676 override bool hasFocus () {
|
|
677 if (super.hasFocus ()) return true;
|
|
678 if (entryHandle !is null && OS.GTK_WIDGET_HAS_FOCUS (entryHandle)) return true;
|
|
679 if (listHandle !is null && OS.GTK_WIDGET_HAS_FOCUS (listHandle)) return true;
|
|
680 return false;
|
|
681 }
|
|
682
|
|
683 override void hookEvents () {
|
|
684 super.hookEvents ();
|
|
685 if (OS.GTK_VERSION >= OS.buildVERSION(2, 4, 0)) {
|
|
686 OS.g_signal_connect_closure (handle, OS.changed.ptr, display.closures [CHANGED], true);
|
|
687 }
|
|
688
|
|
689 if (entryHandle !is null) {
|
|
690 OS.g_signal_connect_closure (entryHandle, OS.changed.ptr, display.closures [CHANGED], true);
|
|
691 OS.g_signal_connect_closure (entryHandle, OS.insert_text.ptr, display.closures [INSERT_TEXT], false);
|
|
692 OS.g_signal_connect_closure (entryHandle, OS.delete_text.ptr, display.closures [DELETE_TEXT], false);
|
|
693 OS.g_signal_connect_closure (entryHandle, OS.activate.ptr, display.closures [ACTIVATE], false);
|
|
694 OS.g_signal_connect_closure (entryHandle, OS.populate_popup.ptr, display.closures [POPULATE_POPUP], false);
|
|
695 }
|
|
696 int eventMask = OS.GDK_POINTER_MOTION_MASK | OS.GDK_BUTTON_PRESS_MASK |
|
|
697 OS.GDK_BUTTON_RELEASE_MASK;
|
|
698 GtkWidget*[] handles = [ buttonHandle, entryHandle, listHandle ];
|
|
699 for (int i=0; i<handles.length; i++) {
|
|
700 auto eventHandle = handles [i];
|
|
701 if (eventHandle !is null) {
|
|
702 /* Connect the mouse signals */
|
|
703 OS.gtk_widget_add_events (eventHandle, eventMask);
|
|
704 OS.g_signal_connect_closure_by_id (eventHandle, display.signalIds [BUTTON_PRESS_EVENT], 0, display.closures [BUTTON_PRESS_EVENT], false);
|
|
705 OS.g_signal_connect_closure_by_id (eventHandle, display.signalIds [BUTTON_RELEASE_EVENT], 0, display.closures [BUTTON_RELEASE_EVENT], false);
|
|
706 OS.g_signal_connect_closure_by_id (eventHandle, display.signalIds [MOTION_NOTIFY_EVENT], 0, display.closures [MOTION_NOTIFY_EVENT], false);
|
|
707 /*
|
|
708 * Feature in GTK. Events such as mouse move are propagated up
|
|
709 * the widget hierarchy and are seen by the parent. This is the
|
|
710 * correct GTK behavior but not correct for SWT. The fix is to
|
|
711 * hook a signal after and stop the propagation using a negative
|
|
712 * event number to distinguish this case.
|
|
713 */
|
|
714 OS.g_signal_connect_closure_by_id (eventHandle, display.signalIds [BUTTON_PRESS_EVENT], 0, display.closures [BUTTON_PRESS_EVENT_INVERSE], true);
|
|
715 OS.g_signal_connect_closure_by_id (eventHandle, display.signalIds [BUTTON_RELEASE_EVENT], 0, display.closures [BUTTON_RELEASE_EVENT_INVERSE], true);
|
|
716 OS.g_signal_connect_closure_by_id (eventHandle, display.signalIds [MOTION_NOTIFY_EVENT], 0, display.closures [MOTION_NOTIFY_EVENT_INVERSE], true);
|
|
717
|
|
718 /* Connect the event_after signal for both key and mouse */
|
|
719 if (eventHandle !is focusHandle ()) {
|
|
720 OS.g_signal_connect_closure_by_id (eventHandle, display.signalIds [EVENT_AFTER], 0, display.closures [EVENT_AFTER], false);
|
|
721 }
|
|
722 }
|
|
723 }
|
|
724 auto imContext = imContext ();
|
|
725 if (imContext !is null) {
|
|
726 OS.g_signal_connect_closure (imContext, OS.commit.ptr, display.closures [COMMIT], false);
|
|
727 int id = OS.g_signal_lookup (OS.commit.ptr, OS.gtk_im_context_get_type ());
|
|
728 int blockMask = OS.G_SIGNAL_MATCH_DATA | OS.G_SIGNAL_MATCH_ID;
|
|
729 OS.g_signal_handlers_block_matched (imContext, blockMask, id, 0, null, null, entryHandle);
|
|
730 }
|
|
731 }
|
|
732
|
|
733 GtkIMContext* imContext () {
|
|
734 return entryHandle !is null ? OS.GTK_ENTRY_IM_CONTEXT (entryHandle) : null;
|
|
735 }
|
|
736
|
|
737 /**
|
|
738 * Deselects the item at the given zero-relative index in the receiver's
|
|
739 * list. If the item at the index was already deselected, it remains
|
|
740 * deselected. Indices that are out of range are ignored.
|
|
741 *
|
|
742 * @param index the index of the item to deselect
|
|
743 *
|
|
744 * @exception SWTException <ul>
|
|
745 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
746 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
747 * </ul>
|
|
748 */
|
|
749 public void deselect (int index) {
|
|
750 checkWidget();
|
|
751 if (index < 0 || index >= items.length) return;
|
|
752 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
753 if (OS.gtk_combo_box_get_active (handle) is index) {
|
|
754 clearText ();
|
|
755 }
|
|
756 } else {
|
|
757 ignoreSelect = true;
|
|
758 auto children = OS.gtk_container_get_children (listHandle);
|
|
759 auto item = OS.g_list_nth_data (children, index);
|
|
760 bool selected = OS.GTK_WIDGET_STATE (item) is OS.GTK_STATE_SELECTED;
|
|
761 if (selected) {
|
|
762 OS.gtk_list_unselect_all (listHandle);
|
|
763 OS.gtk_entry_set_text (entryHandle, "".ptr );
|
|
764 }
|
|
765 OS.g_list_free (children);
|
|
766 ignoreSelect = false;
|
|
767 }
|
|
768 }
|
|
769
|
|
770 /**
|
|
771 * Deselects all selected items in the receiver's list.
|
|
772 * <p>
|
|
773 * Note: To clear the selection in the receiver's text field,
|
|
774 * use <code>clearSelection()</code>.
|
|
775 * </p>
|
|
776 *
|
|
777 * @exception SWTException <ul>
|
|
778 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
779 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
780 * </ul>
|
|
781 *
|
|
782 * @see #clearSelection
|
|
783 */
|
|
784 public void deselectAll () {
|
|
785 checkWidget();
|
|
786 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
787 clearText ();
|
|
788 } else {
|
|
789 ignoreSelect = true;
|
|
790 OS.gtk_list_unselect_all (listHandle);
|
|
791 OS.gtk_entry_set_text (entryHandle, "".ptr );
|
|
792 ignoreSelect = false;
|
|
793 }
|
|
794 }
|
|
795
|
|
796
|
|
797 override bool dragDetect(int x, int y, bool filter, bool* consume) {
|
|
798 if (filter && entryHandle !is null) {
|
|
799 int index;
|
|
800 int trailing;
|
|
801 auto layout = OS.gtk_entry_get_layout (entryHandle);
|
|
802 OS.pango_layout_xy_to_index (layout, x * OS.PANGO_SCALE, y * OS.PANGO_SCALE, &index, &trailing);
|
|
803 auto ptr = OS.pango_layout_get_text (layout);
|
|
804 int position = cast(int)/*64*/OS.g_utf8_pointer_to_offset (ptr, ptr + index) + trailing;
|
|
805 Point selection = getSelection ();
|
|
806 if (selection.x <= position && position < selection.y) {
|
|
807 if (super.dragDetect (x, y, filter, consume)) {
|
|
808 if (consume !is null) *consume = true;
|
|
809 return true;
|
|
810 }
|
|
811 }
|
|
812 return false;
|
|
813 }
|
|
814 return super.dragDetect (x, y, filter, consume);
|
|
815 }
|
|
816
|
|
817 override GtkWidget* enterExitHandle () {
|
|
818 return fixedHandle;
|
|
819 }
|
|
820
|
|
821 override GdkDrawable* eventWindow () {
|
|
822 return paintWindow ();
|
|
823 }
|
|
824
|
|
825 override GdkColor* getBackgroundColor () {
|
|
826 return getBaseColor ();
|
|
827 }
|
|
828
|
|
829 override GdkColor* getForegroundColor () {
|
|
830 return getTextColor ();
|
|
831 }
|
|
832
|
|
833 /**
|
|
834 * Returns the item at the given, zero-relative index in the
|
|
835 * receiver's list. Throws an exception if the index is out
|
|
836 * of range.
|
|
837 *
|
|
838 * @param index the index of the item to return
|
|
839 * @return the item at the given index
|
|
840 *
|
|
841 * @exception IllegalArgumentException <ul>
|
|
842 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
|
|
843 * </ul>
|
|
844 * @exception SWTException <ul>
|
|
845 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
846 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
847 * </ul>
|
|
848 */
|
|
849 public String getItem (int index) {
|
|
850 checkWidget();
|
|
851 if (!(0 <= index && index < items.length)) {
|
|
852 error (SWT.ERROR_INVALID_RANGE);
|
|
853 }
|
|
854 return items [index];
|
|
855 }
|
|
856
|
|
857 /**
|
|
858 * Returns the number of items contained in the receiver's list.
|
|
859 *
|
|
860 * @return the number of items
|
|
861 *
|
|
862 * @exception SWTException <ul>
|
|
863 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
864 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
865 * </ul>
|
|
866 */
|
|
867 public int getItemCount () {
|
|
868 checkWidget();
|
|
869 return items.length;
|
|
870 }
|
|
871
|
|
872 /**
|
|
873 * Returns the height of the area which would be used to
|
|
874 * display <em>one</em> of the items in the receiver's list.
|
|
875 *
|
|
876 * @return the height of one item
|
|
877 *
|
|
878 * @exception SWTException <ul>
|
|
879 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
880 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
881 * </ul>
|
|
882 */
|
|
883 public int getItemHeight () {
|
|
884 checkWidget();
|
|
885 return fontHeight (getFontDescription (), listHandle !is null ? listHandle : handle);
|
|
886 }
|
|
887
|
|
888 /**
|
|
889 * Returns a (possibly empty) array of <code>String</code>s which are
|
|
890 * the items in the receiver's list.
|
|
891 * <p>
|
|
892 * Note: This is not the actual structure used by the receiver
|
|
893 * to maintain its list of items, so modifying the array will
|
|
894 * not affect the receiver.
|
|
895 * </p>
|
|
896 *
|
|
897 * @return the items in the receiver's list
|
|
898 *
|
|
899 * @exception SWTException <ul>
|
|
900 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
901 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
902 * </ul>
|
|
903 */
|
|
904 public String [] getItems () {
|
|
905 checkWidget();
|
|
906 String [] result = new String[](items.length);
|
|
907 System.arraycopy (items, 0, result, 0, items.length);
|
|
908 return result;
|
|
909 }
|
|
910
|
|
911 /**
|
|
912 * Returns <code>true</code> if the receiver's list is visible,
|
|
913 * and <code>false</code> otherwise.
|
|
914 * <p>
|
|
915 * If one of the receiver's ancestors is not visible or some
|
|
916 * other condition makes the receiver not visible, this method
|
|
917 * may still indicate that it is considered visible even though
|
|
918 * it may not actually be showing.
|
|
919 * </p>
|
|
920 *
|
|
921 * @return the receiver's list's visibility state
|
|
922 *
|
|
923 * @exception SWTException <ul>
|
|
924 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
925 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
926 * </ul>
|
|
927 *
|
|
928 * @since 3.4
|
|
929 */
|
|
930 public bool getListVisible () {
|
|
931 checkWidget ();
|
|
932 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
933 return popupHandle !is null && OS.GTK_WIDGET_VISIBLE (popupHandle);
|
|
934 }
|
|
935 return false;
|
|
936 }
|
|
937
|
|
938 String getNameText () {
|
|
939 return getText ();
|
|
940 }
|
|
941
|
|
942 /**
|
|
943 * Returns the orientation of the receiver.
|
|
944 *
|
|
945 * @return the orientation style
|
|
946 *
|
|
947 * @exception SWTException <ul>
|
|
948 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
949 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
950 * </ul>
|
|
951 *
|
|
952 * @since 2.1.2
|
|
953 */
|
|
954 public int getOrientation () {
|
|
955 checkWidget();
|
|
956 return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
|
|
957 }
|
|
958
|
|
959 /**
|
|
960 * Returns a <code>Point</code> whose x coordinate is the
|
|
961 * character position representing the start of the selection
|
|
962 * in the receiver's text field, and whose y coordinate is the
|
|
963 * character position representing the end of the selection.
|
|
964 * An "empty" selection is indicated by the x and y coordinates
|
|
965 * having the same value.
|
|
966 * <p>
|
|
967 * Indexing is zero based. The range of a selection is from
|
|
968 * 0..N where N is the number of characters in the widget.
|
|
969 * </p>
|
|
970 *
|
|
971 * @return a point representing the selection start and end
|
|
972 *
|
|
973 * @exception SWTException <ul>
|
|
974 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
975 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
976 * </ul>
|
|
977 */
|
|
978 public Point getSelection () {
|
|
979 checkWidget ();
|
|
980 if ((style & SWT.READ_ONLY) !is 0) {
|
|
981 int length = 0;
|
|
982 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
983 int index = OS.gtk_combo_box_get_active (handle);
|
|
984 if (index !is -1) length = getItem (index).length;
|
|
985 } else {
|
|
986 auto str = OS.gtk_entry_get_text (entryHandle);
|
|
987 if (str !is null) length = cast(int)/*64*/OS.g_utf8_strlen (str, -1);
|
|
988 }
|
|
989 return new Point (0, length);
|
|
990 }
|
|
991 int start;
|
|
992 int end;
|
|
993 if (entryHandle !is null) {
|
|
994 OS.gtk_editable_get_selection_bounds (entryHandle, &start, &end);
|
|
995 }
|
|
996 return new Point(start, end);
|
|
997 }
|
|
998
|
|
999 /**
|
|
1000 * Returns the zero-relative index of the item which is currently
|
|
1001 * selected in the receiver's list, or -1 if no item is selected.
|
|
1002 *
|
|
1003 * @return the index of the selected item
|
|
1004 *
|
|
1005 * @exception SWTException <ul>
|
|
1006 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1007 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1008 * </ul>
|
|
1009 */
|
|
1010 public int getSelectionIndex () {
|
|
1011 checkWidget();
|
|
1012 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1013 return OS.gtk_combo_box_get_active (handle);
|
|
1014 }
|
|
1015 int index = 0, result = -1;
|
|
1016 auto children = OS.gtk_container_get_children (listHandle);
|
|
1017 auto temp = children;
|
|
1018 while (temp !is null) {
|
|
1019 auto item = OS.g_list_data (temp);
|
|
1020 if (OS.GTK_WIDGET_STATE (item) is OS.GTK_STATE_SELECTED) {
|
|
1021 result = index;
|
|
1022 break;
|
|
1023 }
|
|
1024 index++;
|
|
1025 temp = OS.g_list_next (temp);
|
|
1026 }
|
|
1027 OS.g_list_free (children);
|
|
1028 return result;
|
|
1029 }
|
|
1030
|
|
1031 /**
|
|
1032 * Returns a string containing a copy of the contents of the
|
|
1033 * receiver's text field, or an empty string if there are no
|
|
1034 * contents.
|
|
1035 *
|
|
1036 * @return the receiver's text
|
|
1037 *
|
|
1038 * @exception SWTException <ul>
|
|
1039 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1040 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1041 * </ul>
|
|
1042 */
|
|
1043 public String getText () {
|
|
1044 checkWidget();
|
|
1045 if (entryHandle !is null) {
|
|
1046 auto str = OS.gtk_entry_get_text (entryHandle);
|
|
1047 if (str is null) return "";
|
51
|
1048 return fromStringz(str)._idup();
|
25
|
1049 } else {
|
|
1050 int index = OS.gtk_combo_box_get_active (handle);
|
|
1051 return index !is -1 ? getItem (index) : "";
|
|
1052 }
|
|
1053 }
|
|
1054
|
|
1055 String getText (int start, int stop) {
|
|
1056 /*
|
|
1057 * NOTE: The current implementation uses substring ()
|
|
1058 * which can reference a potentially large character
|
|
1059 * array.
|
|
1060 */
|
|
1061 return getText ()[ start .. stop - 1];
|
|
1062 }
|
|
1063
|
|
1064 /**
|
|
1065 * Returns the height of the receivers's text field.
|
|
1066 *
|
|
1067 * @return the text height
|
|
1068 *
|
|
1069 * @exception SWTException <ul>
|
|
1070 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1071 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1072 * </ul>
|
|
1073 */
|
|
1074 public int getTextHeight () {
|
|
1075 checkWidget();
|
|
1076 GtkRequisition requisition;
|
|
1077 gtk_widget_size_request (handle, &requisition);
|
|
1078 return OS.GTK_WIDGET_REQUISITION_HEIGHT (handle);
|
|
1079 }
|
|
1080
|
|
1081 /**
|
|
1082 * Returns the maximum number of characters that the receiver's
|
|
1083 * text field is capable of holding. If this has not been changed
|
|
1084 * by <code>setTextLimit()</code>, it will be the constant
|
|
1085 * <code>Combo.LIMIT</code>.
|
|
1086 *
|
|
1087 * @return the text limit
|
|
1088 *
|
|
1089 * @exception SWTException <ul>
|
|
1090 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1091 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1092 * </ul>
|
|
1093 *
|
|
1094 * @see #LIMIT
|
|
1095 */
|
|
1096 public int getTextLimit () {
|
|
1097 checkWidget();
|
|
1098 int limit = entryHandle !is null ? OS.gtk_entry_get_max_length (entryHandle) : 0;
|
|
1099 return limit is 0 ? LIMIT : limit;
|
|
1100 }
|
|
1101
|
|
1102 /**
|
|
1103 * Gets the number of items that are visible in the drop
|
|
1104 * down portion of the receiver's list.
|
|
1105 * <p>
|
|
1106 * Note: This operation is a hint and is not supported on
|
|
1107 * platforms that do not have this concept.
|
|
1108 * </p>
|
|
1109 *
|
|
1110 * @return the number of items that are visible
|
|
1111 *
|
|
1112 * @exception SWTException <ul>
|
|
1113 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1114 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1115 * </ul>
|
|
1116 *
|
|
1117 * @since 3.0
|
|
1118 */
|
|
1119 public int getVisibleItemCount () {
|
|
1120 checkWidget ();
|
|
1121 return visibleCount;
|
|
1122 }
|
|
1123
|
|
1124 override int /*long*/ gtk_activate (GtkWidget* widget) {
|
|
1125 postEvent (SWT.DefaultSelection);
|
|
1126 return 0;
|
|
1127 }
|
|
1128
|
|
1129 override int /*long*/ gtk_button_press_event (GtkWidget* widget, GdkEventButton* event) {
|
|
1130 /*
|
|
1131 * Feature in GTK. Depending on where the user clicks, GTK prevents
|
|
1132 * the left mouse button event from being propagated. The fix is to
|
|
1133 * send the mouse event from the event_after handler.
|
|
1134 */
|
|
1135 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1136 GdkEventButton* gdkEvent = event;
|
|
1137 if (gdkEvent.type is OS.GDK_BUTTON_PRESS && gdkEvent.button is 1 && (style & SWT.READ_ONLY) !is 0) {
|
|
1138 return gtk_button_press_event(widget, event, false);
|
|
1139 }
|
|
1140
|
|
1141 }
|
|
1142 return super.gtk_button_press_event (widget, event);
|
|
1143 }
|
|
1144
|
|
1145 override int gtk_changed (GtkWidget* widget) {
|
|
1146 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1147 if (widget is handle) {
|
|
1148 if (entryHandle is null) {
|
|
1149 sendEvent(SWT.Modify);
|
|
1150 if (isDisposed ()) return 0;
|
|
1151 }
|
|
1152 /*
|
|
1153 * Feature in GTK. GTK emits a changed signal whenever
|
|
1154 * the contents of a combo box are altered by typing or
|
|
1155 * by selecting an item in the list, but the event should
|
|
1156 * only be sent when the list is selected. The fix is to
|
|
1157 * only send out a selection event when there is a selected
|
|
1158 * item.
|
|
1159 *
|
|
1160 * NOTE: This code relies on GTK clearing the selected
|
|
1161 * item and not matching the item as the user types.
|
|
1162 */
|
|
1163 int index = OS.gtk_combo_box_get_active (handle);
|
|
1164 if (index !is -1) postEvent (SWT.Selection);
|
|
1165 return 0;
|
|
1166 }
|
|
1167 } else {
|
|
1168 if (!ignoreSelect) {
|
|
1169 auto ptr = OS.gtk_entry_get_text (entryHandle);
|
51
|
1170 String text = fromStringz(ptr)._idup();
|
25
|
1171 for (int i = 0; i < items.length; i++) {
|
|
1172 if (items [i] ==/*eq*/ text) {
|
|
1173 postEvent (SWT.Selection);
|
|
1174 break;
|
|
1175 }
|
|
1176 }
|
|
1177 }
|
|
1178 }
|
|
1179 /*
|
|
1180 * Feature in GTK. When the user types, GTK positions
|
|
1181 * the caret after sending the changed signal. This
|
|
1182 * means that application code that attempts to position
|
|
1183 * the caret during a changed signal will fail. The fix
|
|
1184 * is to post the modify event when the user is typing.
|
|
1185 */
|
|
1186 bool keyPress = false;
|
|
1187 auto eventPtr = OS.gtk_get_current_event ();
|
|
1188 if (eventPtr !is null) {
|
|
1189 GdkEventKey* gdkEvent = cast(GdkEventKey*)eventPtr;
|
|
1190 switch (gdkEvent.type) {
|
|
1191 case OS.GDK_KEY_PRESS:
|
|
1192 keyPress = true;
|
|
1193 break;
|
|
1194 default:
|
|
1195 }
|
|
1196 OS.gdk_event_free (eventPtr);
|
|
1197 }
|
|
1198 if (keyPress) {
|
|
1199 postEvent (SWT.Modify);
|
|
1200 } else {
|
|
1201 sendEvent (SWT.Modify);
|
|
1202 }
|
|
1203 return 0;
|
|
1204 }
|
|
1205
|
|
1206 override int gtk_commit (GtkIMContext* imContext, char* text) {
|
|
1207 if (text is null) return 0;
|
|
1208 if (!OS.gtk_editable_get_editable (entryHandle)) return 0;
|
|
1209 char [] chars = fromStringz(text);
|
|
1210 if (chars.length is 0) return 0;
|
|
1211 char [] newChars = sendIMKeyEvent (SWT.KeyDown, null, chars);
|
|
1212 if (newChars is null) return 0;
|
|
1213 /*
|
|
1214 * Feature in GTK. For a GtkEntry, during the insert-text signal,
|
|
1215 * GTK allows the programmer to change only the caret location,
|
|
1216 * not the selection. If the programmer changes the selection,
|
|
1217 * the new selection is lost. The fix is to detect a selection
|
|
1218 * change and set it after the insert-text signal has completed.
|
|
1219 */
|
|
1220 fixStart = fixEnd = -1;
|
|
1221 OS.g_signal_handlers_block_matched (imContext, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCOMMIT);
|
|
1222 int id = OS.g_signal_lookup (OS.commit.ptr, OS.gtk_im_context_get_type ());
|
|
1223 int mask = OS.G_SIGNAL_MATCH_DATA | OS.G_SIGNAL_MATCH_ID;
|
|
1224 OS.g_signal_handlers_unblock_matched (imContext, mask, id, 0, null, null, entryHandle);
|
|
1225 if (newChars is chars) {
|
|
1226 OS.g_signal_emit_by_name1 (imContext, OS.commit.ptr, cast(int)text);
|
|
1227 } else {
|
|
1228 OS.g_signal_emit_by_name1 (imContext, OS.commit.ptr, cast(int)toStringz(newChars));
|
|
1229 }
|
|
1230 OS.g_signal_handlers_unblock_matched (imContext, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCOMMIT);
|
|
1231 OS.g_signal_handlers_block_matched (imContext, mask, id, 0, null, null, entryHandle);
|
|
1232 if (fixStart !is -1 && fixEnd !is -1) {
|
|
1233 OS.gtk_editable_set_position (entryHandle, fixStart);
|
|
1234 OS.gtk_editable_select_region (entryHandle, fixStart, fixEnd);
|
|
1235 }
|
|
1236 fixStart = fixEnd = -1;
|
|
1237 return 0;
|
|
1238 }
|
|
1239
|
|
1240 override int gtk_delete_text (GtkWidget* widget, int start_pos, int end_pos) {
|
|
1241 if (lockText) {
|
|
1242 OS.gtk_list_unselect_item (listHandle, 0);
|
|
1243 OS.g_signal_stop_emission_by_name (entryHandle, OS.delete_text.ptr);
|
|
1244 return 0;
|
|
1245 }
|
|
1246 if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return 0;
|
|
1247 String newText = verifyText ("", cast(int)/*64*/start_pos, cast(int)/*64*/end_pos);
|
|
1248 if (newText is null) {
|
|
1249 OS.g_signal_stop_emission_by_name (entryHandle, OS.delete_text.ptr);
|
|
1250 } else {
|
|
1251 if (newText.length > 0) {
|
|
1252 int pos;
|
|
1253 pos = cast(int)/*64*/end_pos;
|
|
1254 OS.g_signal_handlers_block_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1255 OS.g_signal_handlers_block_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udINSERT_TEXT);
|
|
1256 OS.gtk_editable_insert_text (entryHandle, newText.ptr, newText.length, &pos);
|
|
1257 OS.g_signal_handlers_unblock_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udINSERT_TEXT);
|
|
1258 OS.g_signal_handlers_unblock_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1259 OS.gtk_editable_set_position (entryHandle, pos );
|
|
1260 }
|
|
1261 }
|
|
1262 return 0;
|
|
1263 }
|
|
1264
|
|
1265 override int /*long*/ gtk_event_after (GtkWidget* widget, GdkEvent* event) {
|
|
1266 /*
|
|
1267 * Feature in GTK. Depending on where the user clicks, GTK prevents
|
|
1268 * the left mouse button event from being propagated. The fix is to
|
|
1269 * send the mouse event from the event_after handler.
|
|
1270 *
|
|
1271 * Feature in GTK. When the user clicks anywhere in an editable
|
|
1272 * combo box, a single focus event should be issued, despite the
|
|
1273 * fact that focus might switch between the drop down button and
|
|
1274 * the text field. The fix is to use gtk_combo_box_set_focus_on_click ()
|
|
1275 * to eat all focus events while focus is in the combo box. When the
|
|
1276 * user clicks on the drop down button focus is assigned to the text
|
|
1277 * field.
|
|
1278 */
|
|
1279 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1280 switch (event.type) {
|
|
1281 case OS.GDK_BUTTON_PRESS: {
|
|
1282 GdkEventButton* gdkEventButton = cast(GdkEventButton*)event;
|
|
1283 if (gdkEventButton.button is 1) {
|
|
1284 if ((style & SWT.READ_ONLY) !is 0 && !sendMouseEvent (SWT.MouseDown, gdkEventButton.button, display.clickCount, 0, false, gdkEventButton.time, gdkEventButton.x_root, gdkEventButton.y_root, false, gdkEventButton.state)) {
|
|
1285 return 1;
|
|
1286 }
|
|
1287 if (OS.GTK_VERSION >= OS.buildVERSION (2, 6, 0)) {
|
|
1288 if ((style & SWT.READ_ONLY) is 0 && widget is buttonHandle) {
|
|
1289 OS.gtk_widget_grab_focus (entryHandle);
|
|
1290 }
|
|
1291 }
|
|
1292 }
|
|
1293 break;
|
|
1294 }
|
|
1295 case OS.GDK_FOCUS_CHANGE: {
|
|
1296 if (OS.GTK_VERSION >= OS.buildVERSION (2, 6, 0)) {
|
|
1297 if ((style & SWT.READ_ONLY) is 0) {
|
|
1298 GdkEventFocus* gdkEventFocus = cast(GdkEventFocus*)event;
|
|
1299 if (gdkEventFocus.in_ !is 0) {
|
|
1300 OS.gtk_combo_box_set_focus_on_click (handle, false);
|
|
1301 } else {
|
|
1302 OS.gtk_combo_box_set_focus_on_click (handle, true);
|
|
1303 }
|
|
1304 }
|
|
1305 }
|
|
1306 break;
|
|
1307 }
|
|
1308 default:
|
|
1309 }
|
|
1310 }
|
|
1311 return super.gtk_event_after(widget, event);
|
|
1312 }
|
|
1313
|
|
1314 override int gtk_focus_out_event (GtkWidget* widget, GdkEventFocus* event) {
|
|
1315 fixIM ();
|
|
1316 return super.gtk_focus_out_event (widget, event);
|
|
1317 }
|
|
1318
|
|
1319 override int gtk_insert_text (GtkEditable* widget, char* new_text, int new_text_length, int position) {
|
|
1320 if (lockText) {
|
|
1321 OS.gtk_list_unselect_item (listHandle, 0);
|
|
1322 OS.g_signal_stop_emission_by_name (entryHandle, OS.insert_text.ptr);
|
|
1323 return 0;
|
|
1324 }
|
|
1325 if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return 0;
|
|
1326 if (new_text is null || new_text_length is 0) return 0;
|
51
|
1327 String oldText = new_text[0..new_text_length]._idup();
|
25
|
1328 int pos;
|
|
1329 pos = position;
|
|
1330 if (pos is -1) {
|
|
1331 auto ptr = OS.gtk_entry_get_text (entryHandle);
|
|
1332 pos = fromStringz(ptr).length;
|
|
1333 }
|
|
1334 String newText = verifyText (oldText, pos, pos);
|
|
1335 if (newText !is oldText) {
|
|
1336 int newStart, newEnd;
|
|
1337 OS.gtk_editable_get_selection_bounds (entryHandle, &newStart, &newEnd);
|
|
1338 if (newText !is null) {
|
|
1339 if (newStart !is newEnd) {
|
|
1340 OS.g_signal_handlers_block_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udDELETE_TEXT);
|
|
1341 OS.g_signal_handlers_block_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1342 OS.gtk_editable_delete_selection (entryHandle);
|
|
1343 OS.g_signal_handlers_unblock_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udDELETE_TEXT);
|
|
1344 OS.g_signal_handlers_unblock_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1345 }
|
|
1346 OS.g_signal_handlers_block_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udINSERT_TEXT);
|
|
1347 OS.gtk_editable_insert_text (entryHandle, newText.ptr, newText.length, &pos);
|
|
1348 OS.g_signal_handlers_unblock_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udINSERT_TEXT);
|
|
1349 newStart = newEnd = pos;
|
|
1350 }
|
|
1351 pos = newEnd;
|
|
1352 if (newStart !is newEnd) {
|
|
1353 fixStart = newStart;
|
|
1354 fixEnd = newEnd;
|
|
1355 }
|
|
1356 position = pos;
|
|
1357 OS.g_signal_stop_emission_by_name (entryHandle, OS.insert_text.ptr);
|
|
1358 }
|
|
1359 return 0;
|
|
1360 }
|
|
1361
|
|
1362 override int gtk_key_press_event (GtkWidget* widget, GdkEventKey* event) {
|
|
1363 auto result = super.gtk_key_press_event (widget, event);
|
|
1364 if (result !is 0) fixIM ();
|
|
1365 if (gdkEventKey is cast(GdkEventKey*)-1) result = 1;
|
|
1366 gdkEventKey = null;
|
|
1367 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0) && (style & SWT.READ_ONLY) is 0) {
|
|
1368 GdkEventKey* keyEvent = cast(GdkEventKey*)event;
|
|
1369 int oldIndex = OS.gtk_combo_box_get_active (handle);
|
|
1370 int newIndex = oldIndex;
|
|
1371 int key = keyEvent.keyval;
|
|
1372 switch (key) {
|
|
1373 case OS.GDK_Down:
|
|
1374 case OS.GDK_KP_Down:
|
|
1375 if (oldIndex !is (items.length - 1)) {
|
|
1376 newIndex = oldIndex + 1;
|
|
1377 }
|
|
1378 break;
|
|
1379 case OS.GDK_Up:
|
|
1380 case OS.GDK_KP_Up:
|
|
1381 if (oldIndex !is -1 && oldIndex !is 0) {
|
|
1382 newIndex = oldIndex - 1;
|
|
1383 }
|
|
1384 break;
|
|
1385 /*
|
|
1386 * Feature in GTK. In gtk_combo_box, the PageUp and PageDown keys
|
|
1387 * go the first and last items in the list rather than scrolling
|
|
1388 * a page at a time. The fix is to emulate this behavior for
|
|
1389 * gtk_combo_box_entry.
|
|
1390 */
|
|
1391 case OS.GDK_Page_Up:
|
|
1392 case OS.GDK_KP_Page_Up:
|
|
1393 newIndex = 0;
|
|
1394 break;
|
|
1395 case OS.GDK_Page_Down:
|
|
1396 case OS.GDK_KP_Page_Down:
|
|
1397 newIndex = items.length - 1;
|
|
1398 break;
|
|
1399 default:
|
|
1400 }
|
|
1401 if (newIndex !is oldIndex) {
|
|
1402 OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1403 OS.gtk_combo_box_set_active (handle, newIndex);
|
|
1404 OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1405 return 1;
|
|
1406 }
|
|
1407 }
|
|
1408 return result;
|
|
1409 }
|
|
1410
|
|
1411 override int /*long*/ gtk_populate_popup (GtkWidget* widget, GtkWidget* menu) {
|
|
1412 if ((style & SWT.RIGHT_TO_LEFT) !is 0) {
|
|
1413 OS.gtk_widget_set_direction (menu, OS.GTK_TEXT_DIR_RTL);
|
|
1414 display.doSetDirectionProc(menu, OS.GTK_TEXT_DIR_RTL);
|
|
1415 }
|
|
1416 return 0;
|
|
1417 }
|
|
1418
|
|
1419 /**
|
|
1420 * Searches the receiver's list starting at the first item
|
|
1421 * (index 0) until an item is found that is equal to the
|
|
1422 * argument, and returns the index of that item. If no item
|
|
1423 * is found, returns -1.
|
|
1424 *
|
|
1425 * @param string the search item
|
|
1426 * @return the index of the item
|
|
1427 *
|
|
1428 * @exception SWTException <ul>
|
|
1429 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1430 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1431 * </ul>
|
|
1432 */
|
|
1433 public int indexOf (String string) {
|
|
1434 checkWidget();
|
|
1435 return indexOf (string, 0);
|
|
1436 }
|
|
1437
|
|
1438 /**
|
|
1439 * Searches the receiver's list starting at the given,
|
|
1440 * zero-relative index until an item is found that is equal
|
|
1441 * to the argument, and returns the index of that item. If
|
|
1442 * no item is found or the starting index is out of range,
|
|
1443 * returns -1.
|
|
1444 *
|
|
1445 * @param string the search item
|
|
1446 * @param start the zero-relative index at which to begin the search
|
|
1447 * @return the index of the item
|
|
1448 *
|
|
1449 * @exception SWTException <ul>
|
|
1450 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1451 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1452 * </ul>
|
|
1453 */
|
|
1454 public int indexOf (String string, int start) {
|
|
1455 checkWidget();
|
|
1456 // SWT extension: allow null for zero length string
|
|
1457 //if (string is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
1458 if (!(0 <= start && start < items.length)) return -1;
|
|
1459 for (int i=start; i<items.length; i++) {
|
|
1460 if (string.equals (items [i])) return i;
|
|
1461 }
|
|
1462 return -1;
|
|
1463 }
|
|
1464
|
|
1465 override bool isFocusHandle(GtkWidget* widget) {
|
|
1466 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1467 if (buttonHandle !is null && widget is buttonHandle) return true;
|
|
1468 if (entryHandle !is null && widget is entryHandle) return true;
|
|
1469 }
|
|
1470 return super.isFocusHandle (widget);
|
|
1471 }
|
|
1472
|
|
1473 override GdkDrawable* paintWindow () {
|
|
1474 auto childHandle = entryHandle !is null ? entryHandle : handle;
|
|
1475 OS.gtk_widget_realize (childHandle);
|
|
1476 auto window = OS.GTK_WIDGET_WINDOW (childHandle);
|
|
1477 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1478 if ((style & SWT.READ_ONLY) !is 0) return window;
|
|
1479 }
|
|
1480 auto children = OS.gdk_window_get_children (window);
|
|
1481 if (children !is null) window = cast(GdkDrawable*)OS.g_list_data (children);
|
|
1482 OS.g_list_free (children);
|
|
1483 return window;
|
|
1484 }
|
|
1485
|
|
1486 /**
|
|
1487 * Pastes text from clipboard.
|
|
1488 * <p>
|
|
1489 * The selected text is deleted from the widget
|
|
1490 * and new text inserted from the clipboard.
|
|
1491 * </p>
|
|
1492 *
|
|
1493 * @exception SWTException <ul>
|
|
1494 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1495 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1496 * </ul>
|
|
1497 *
|
|
1498 * @since 2.1
|
|
1499 */
|
|
1500 public void paste () {
|
|
1501 checkWidget ();
|
|
1502 if (entryHandle !is null) OS.gtk_editable_paste_clipboard (entryHandle);
|
|
1503 }
|
|
1504
|
|
1505 override GtkWidget* parentingHandle() {
|
|
1506 return fixedHandle;
|
|
1507 }
|
|
1508
|
|
1509 override void register () {
|
|
1510 super.register ();
|
|
1511 if (buttonHandle !is null) display.addWidget (buttonHandle, this);
|
|
1512 if (entryHandle !is null) display.addWidget (entryHandle, this);
|
|
1513 if (listHandle !is null) display.addWidget (listHandle, this);
|
|
1514 auto imContext = imContext ();
|
|
1515 if (imContext !is null) display.addWidget (cast(GtkWidget*)imContext, this);
|
|
1516 }
|
|
1517
|
|
1518 override void releaseHandle () {
|
|
1519 super.releaseHandle ();
|
|
1520 buttonHandle = entryHandle = listHandle = null;
|
|
1521 }
|
|
1522
|
|
1523 override void releaseWidget () {
|
|
1524 super.releaseWidget ();
|
|
1525 textRenderer = null;
|
|
1526 fixIM ();
|
|
1527 }
|
|
1528
|
|
1529 /**
|
|
1530 * Removes the item from the receiver's list at the given
|
|
1531 * zero-relative index.
|
|
1532 *
|
|
1533 * @param index the index for the item
|
|
1534 *
|
|
1535 * @exception IllegalArgumentException <ul>
|
|
1536 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
|
|
1537 * </ul>
|
|
1538 * @exception SWTException <ul>
|
|
1539 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1540 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1541 * </ul>
|
|
1542 */
|
|
1543 public void remove (int index) {
|
|
1544 checkWidget();
|
|
1545 if (!(0 <= index && index < items.length)) {
|
|
1546 error (SWT.ERROR_INVALID_RANGE);
|
|
1547 }
|
|
1548 String [] oldItems = items;
|
|
1549 String [] newItems = new String[]( oldItems.length - 1 );
|
|
1550 System.arraycopy (oldItems, 0, newItems, 0, index);
|
|
1551 System.arraycopy (oldItems, index + 1, newItems, index, oldItems.length - index - 1);
|
|
1552 items = newItems;
|
|
1553 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1554 if (OS.gtk_combo_box_get_active (handle) is index) clearText ();
|
|
1555 OS.gtk_combo_box_remove_text (handle, index);
|
|
1556 } else {
|
|
1557 ignoreSelect = true;
|
|
1558 auto children = OS.gtk_container_get_children (listHandle);
|
|
1559 auto item = OS.g_list_nth_data (children, index);
|
|
1560 bool selected = OS.GTK_WIDGET_STATE (item) is OS.GTK_STATE_SELECTED;
|
|
1561 auto items = OS.g_list_append (null, item);
|
|
1562 OS.gtk_list_remove_items (listHandle, items);
|
|
1563 OS.g_list_free (items);
|
|
1564 OS.g_list_free (children);
|
|
1565 if (selected) {
|
|
1566 OS.gtk_entry_set_text (entryHandle, "".ptr);
|
|
1567 }
|
|
1568 ignoreSelect = false;
|
|
1569 }
|
|
1570 }
|
|
1571
|
|
1572 /**
|
|
1573 * Removes the items from the receiver's list which are
|
|
1574 * between the given zero-relative start and end
|
|
1575 * indices (inclusive).
|
|
1576 *
|
|
1577 * @param start the start of the range
|
|
1578 * @param end the end of the range
|
|
1579 *
|
|
1580 * @exception IllegalArgumentException <ul>
|
|
1581 * <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>
|
|
1582 * </ul>
|
|
1583 * @exception SWTException <ul>
|
|
1584 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1585 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1586 * </ul>
|
|
1587 */
|
|
1588 public void remove (int start, int end) {
|
|
1589 checkWidget();
|
|
1590 if (start > end) return;
|
|
1591 if (!(0 <= start && start <= end && end < items.length)) {
|
|
1592 error (SWT.ERROR_INVALID_RANGE);
|
|
1593 }
|
|
1594 String [] oldItems = items;
|
|
1595 String [] newItems = new String[](oldItems.length - (end - start + 1));
|
|
1596 System.arraycopy (oldItems, 0, newItems, 0, start);
|
|
1597 System.arraycopy (oldItems, end + 1, newItems, start, oldItems.length - end - 1);
|
|
1598 items = newItems;
|
|
1599 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1600 int index = OS.gtk_combo_box_get_active (handle);
|
|
1601 if (start <= index && index <= end) clearText();
|
|
1602 for (int i = end; i >= start; i--) {
|
|
1603 OS.gtk_combo_box_remove_text (handle, i);
|
|
1604 }
|
|
1605 } else {
|
|
1606 bool selected = false;
|
|
1607 ignoreSelect = true;
|
|
1608 GList* items;
|
|
1609 auto children = OS.gtk_container_get_children (listHandle);
|
|
1610 for (int i = start; i <= end; i++) {
|
|
1611 auto item = OS.g_list_nth_data (children, i);
|
|
1612 selected |= OS.GTK_WIDGET_STATE (item) is OS.GTK_STATE_SELECTED;
|
|
1613 items = OS.g_list_append (items, item);
|
|
1614 }
|
|
1615 OS.gtk_list_remove_items (listHandle, items);
|
|
1616 OS.g_list_free (items);
|
|
1617 OS.g_list_free (children);
|
|
1618 if (selected) {
|
|
1619 OS.gtk_entry_set_text (entryHandle, "".ptr );
|
|
1620 }
|
|
1621 ignoreSelect = false;
|
|
1622 }
|
|
1623 }
|
|
1624
|
|
1625 /**
|
|
1626 * Searches the receiver's list starting at the first item
|
|
1627 * until an item is found that is equal to the argument,
|
|
1628 * and removes that item from the list.
|
|
1629 *
|
|
1630 * @param string the item to remove
|
|
1631 *
|
|
1632 * @exception IllegalArgumentException <ul>
|
|
1633 * <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li>
|
|
1634 * </ul>
|
|
1635 * @exception SWTException <ul>
|
|
1636 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1637 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1638 * </ul>
|
|
1639 */
|
|
1640 public void remove (String string) {
|
|
1641 checkWidget();
|
|
1642 // SWT extension: allow null for zero length string
|
|
1643 //if (string is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
1644 int index = indexOf (string, 0);
|
|
1645 if (index is -1) error (SWT.ERROR_INVALID_ARGUMENT);
|
|
1646 remove (index);
|
|
1647 }
|
|
1648
|
|
1649 /**
|
|
1650 * Removes all of the items from the receiver's list and clear the
|
|
1651 * contents of receiver's text field.
|
|
1652 * <p>
|
|
1653 * @exception SWTException <ul>
|
|
1654 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1655 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1656 * </ul>
|
|
1657 */
|
|
1658 public void removeAll () {
|
|
1659 checkWidget();
|
|
1660 int count = items.length;
|
|
1661 items = null;
|
|
1662 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1663 clearText ();
|
|
1664 for (int i = count - 1; i >= 0; i--) {
|
|
1665 OS.gtk_combo_box_remove_text (handle, i);
|
|
1666 }
|
|
1667 } else {
|
|
1668 ignoreSelect = true;
|
|
1669 OS.gtk_list_clear_items (listHandle, 0, -1);
|
|
1670 OS.gtk_entry_set_text (entryHandle, "".ptr);
|
|
1671 ignoreSelect = false;
|
|
1672 }
|
|
1673 }
|
|
1674
|
|
1675 /**
|
|
1676 * Removes the listener from the collection of listeners who will
|
|
1677 * be notified when the receiver's text is modified.
|
|
1678 *
|
|
1679 * @param listener the listener which should no longer be notified
|
|
1680 *
|
|
1681 * @exception IllegalArgumentException <ul>
|
|
1682 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
|
|
1683 * </ul>
|
|
1684 * @exception SWTException <ul>
|
|
1685 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1686 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1687 * </ul>
|
|
1688 *
|
|
1689 * @see ModifyListener
|
|
1690 * @see #addModifyListener
|
|
1691 */
|
|
1692 public void removeModifyListener (ModifyListener listener) {
|
|
1693 checkWidget();
|
|
1694 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
1695 if (eventTable is null) return;
|
|
1696 eventTable.unhook (SWT.Modify, listener);
|
|
1697 }
|
|
1698
|
|
1699 /**
|
|
1700 * Removes the listener from the collection of listeners who will
|
|
1701 * be notified when the user changes the receiver's selection.
|
|
1702 *
|
|
1703 * @param listener the listener which should no longer be notified
|
|
1704 *
|
|
1705 * @exception IllegalArgumentException <ul>
|
|
1706 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
|
|
1707 * </ul>
|
|
1708 * @exception SWTException <ul>
|
|
1709 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1710 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1711 * </ul>
|
|
1712 *
|
|
1713 * @see SelectionListener
|
|
1714 * @see #addSelectionListener
|
|
1715 */
|
|
1716 public void removeSelectionListener (SelectionListener listener) {
|
|
1717 checkWidget();
|
|
1718 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
1719 if (eventTable is null) return;
|
|
1720 eventTable.unhook (SWT.Selection, listener);
|
|
1721 eventTable.unhook (SWT.DefaultSelection,listener);
|
|
1722 }
|
|
1723
|
|
1724 /**
|
|
1725 * Removes the listener from the collection of listeners who will
|
|
1726 * be notified when the control is verified.
|
|
1727 *
|
|
1728 * @param listener the listener which should no longer be notified
|
|
1729 *
|
|
1730 * @exception IllegalArgumentException <ul>
|
|
1731 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
|
|
1732 * </ul>
|
|
1733 * @exception SWTException <ul>
|
|
1734 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1735 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1736 * </ul>
|
|
1737 *
|
|
1738 * @see VerifyListener
|
|
1739 * @see #addVerifyListener
|
|
1740 *
|
|
1741 * @since 3.1
|
|
1742 */
|
|
1743 public void removeVerifyListener (VerifyListener listener) {
|
|
1744 checkWidget ();
|
|
1745 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
1746 if (eventTable is null) return;
|
|
1747 eventTable.unhook (SWT.Verify, listener);
|
|
1748 }
|
|
1749
|
|
1750 /**
|
|
1751 * Selects the item at the given zero-relative index in the receiver's
|
|
1752 * list. If the item at the index was already selected, it remains
|
|
1753 * selected. Indices that are out of range are ignored.
|
|
1754 *
|
|
1755 * @param index the index of the item to select
|
|
1756 *
|
|
1757 * @exception SWTException <ul>
|
|
1758 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1759 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1760 * </ul>
|
|
1761 */
|
|
1762 public void select (int index) {
|
|
1763 checkWidget();
|
|
1764 if (index < 0 || index >= items.length) return;
|
|
1765 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1766 OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1767 OS.gtk_combo_box_set_active (handle, index);
|
|
1768 OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1769 if ((style & SWT.READ_ONLY) !is 0) {
|
|
1770 /*
|
|
1771 * Feature in GTK. Read Only combo boxes do not get a chance to send out a
|
|
1772 * Modify event in the gtk_changed callback. The fix is to send a Modify event
|
|
1773 * here.
|
|
1774 */
|
|
1775 sendEvent (SWT.Modify);
|
|
1776 }
|
|
1777 } else {
|
|
1778 ignoreSelect = true;
|
|
1779 OS.gtk_list_select_item (listHandle, index);
|
|
1780 ignoreSelect = false;
|
|
1781 }
|
|
1782 }
|
|
1783
|
|
1784 override void setBackgroundColor (GdkColor* color) {
|
|
1785 super.setBackgroundColor (color);
|
|
1786 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1787 if (entryHandle !is null) OS.gtk_widget_modify_base (entryHandle, 0, color);
|
|
1788 OS.g_object_set1 (textRenderer, OS.background_gdk.ptr, cast(int)color);
|
|
1789 } else {
|
|
1790 OS.gtk_widget_modify_base (entryHandle, 0, color);
|
|
1791 if (listHandle !is null) OS.gtk_widget_modify_base (listHandle, 0, color);
|
|
1792 }
|
|
1793 }
|
|
1794
|
|
1795 override int setBounds (int x, int y, int width, int height, bool move, bool resize) {
|
|
1796 int newHeight = height;
|
|
1797 if (resize) newHeight = Math.max (getTextHeight (), height);
|
|
1798 return super.setBounds (x, y, width, newHeight, move, resize);
|
|
1799 }
|
|
1800
|
|
1801 override void setFontDescription (PangoFontDescription* font) {
|
|
1802 super.setFontDescription (font);
|
|
1803 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1804 if (entryHandle !is null) OS.gtk_widget_modify_font (entryHandle, font);
|
|
1805 OS.g_object_set1 (textRenderer, OS.font_desc.ptr, cast(int)font);
|
|
1806 if ((style & SWT.READ_ONLY) !is 0) {
|
|
1807 /*
|
|
1808 * Bug in GTK. Setting the font can leave the combo box with an
|
|
1809 * invalid minimum size. The fix is to temporarily change the
|
|
1810 * selected item to force the combo box to resize.
|
|
1811 */
|
|
1812 int index = OS.gtk_combo_box_get_active (handle);
|
|
1813 OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1814 OS.gtk_combo_box_set_active (handle, -1);
|
|
1815 OS.gtk_combo_box_set_active (handle, index);
|
|
1816 OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1817 }
|
|
1818 } else {
|
|
1819 OS.gtk_widget_modify_font (entryHandle, font);
|
|
1820 if (listHandle !is null) {
|
|
1821 OS.gtk_widget_modify_font (listHandle, font);
|
|
1822 auto itemsList = OS.gtk_container_get_children (listHandle);
|
|
1823 if (itemsList !is null) {
|
|
1824 int count = OS.g_list_length (itemsList);
|
|
1825 for (int i=count - 1; i>=0; i--) {
|
|
1826 auto widget = OS.gtk_bin_get_child (OS.g_list_nth_data (itemsList, i));
|
|
1827 OS.gtk_widget_modify_font (widget, font);
|
|
1828 }
|
|
1829 OS.g_list_free (itemsList);
|
|
1830 }
|
|
1831 }
|
|
1832 }
|
|
1833 }
|
|
1834
|
|
1835 override void setForegroundColor (GdkColor* color) {
|
|
1836 super.setForegroundColor (color);
|
|
1837 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1838 if (entryHandle !is null) setForegroundColor (entryHandle, color);
|
|
1839 OS.g_object_set1 (textRenderer, OS.foreground_gdk.ptr, cast(int)color);
|
|
1840 } else {
|
|
1841 setForegroundColor (entryHandle, color);
|
|
1842 if (listHandle !is null) {
|
|
1843 setForegroundColor (listHandle, color);
|
|
1844 auto itemsList = OS.gtk_container_get_children (listHandle);
|
|
1845 if (itemsList !is null) {
|
|
1846 int count = OS.g_list_length (itemsList);
|
|
1847 for (int i=count - 1; i>=0; i--) {
|
|
1848 auto widget = OS.gtk_bin_get_child (OS.g_list_nth_data (itemsList, i));
|
|
1849 setForegroundColor (widget, color);
|
|
1850 }
|
|
1851 OS.g_list_free (itemsList);
|
|
1852 }
|
|
1853 }
|
|
1854 }
|
|
1855 }
|
|
1856
|
|
1857 /**
|
|
1858 * Sets the text of the item in the receiver's list at the given
|
|
1859 * zero-relative index to the string argument.
|
|
1860 *
|
|
1861 * @param index the index for the item
|
|
1862 * @param string the new text for the item
|
|
1863 *
|
|
1864 * @exception IllegalArgumentException <ul>
|
|
1865 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
|
|
1866 * </ul>
|
|
1867 * @exception SWTException <ul>
|
|
1868 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1869 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1870 * </ul>
|
|
1871 */
|
|
1872 public void setItem (int index, String string) {
|
|
1873 checkWidget();
|
|
1874 // SWT extension: allow null for zero length string
|
|
1875 //if (string is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
1876 if (!(0 <= index && index < items.length)) {
|
|
1877 error (SWT.ERROR_INVALID_ARGUMENT);
|
|
1878 }
|
|
1879 items [index] = string;
|
|
1880 char* buffer = string.toStringzValidPtr();
|
|
1881 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1882 OS.gtk_combo_box_remove_text (handle, index);
|
|
1883 OS.gtk_combo_box_insert_text (handle, index, buffer);
|
|
1884 if ((style & SWT.RIGHT_TO_LEFT) !is 0 && popupHandle !is null) {
|
|
1885 display.doSetDirectionProc(popupHandle, OS.GTK_TEXT_DIR_RTL);
|
|
1886 }
|
|
1887 } else {
|
|
1888 ignoreSelect = true;
|
|
1889 auto children = OS.gtk_container_get_children (listHandle);
|
|
1890 auto item = OS.g_list_nth_data (children, index);
|
|
1891 auto label = OS.gtk_bin_get_child (item);
|
|
1892 OS.gtk_label_set_text (label, buffer);
|
|
1893 OS.g_list_free (children);
|
|
1894 ignoreSelect = false;
|
|
1895 }
|
|
1896 }
|
|
1897
|
|
1898 /**
|
|
1899 * Sets the receiver's list to be the given array of items.
|
|
1900 *
|
|
1901 * @param items the array of items
|
|
1902 *
|
|
1903 * @exception IllegalArgumentException <ul>
|
|
1904 * <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li>
|
|
1905 * </ul>
|
|
1906 * @exception SWTException <ul>
|
|
1907 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1908 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1909 * </ul>
|
|
1910 */
|
|
1911 public void setItems (String [] items) {
|
|
1912 checkWidget();
|
|
1913 // SWT extension: allow null for zero length string
|
|
1914 //if (items is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
1915 for (int i=0; i<items.length; i++) {
|
|
1916 if (items [i] is null) error (SWT.ERROR_INVALID_ARGUMENT);
|
|
1917 }
|
|
1918 int count = this.items.length;
|
|
1919 this.items = new String[](items.length);
|
|
1920 System.arraycopy (items, 0, this.items, 0, items.length);
|
|
1921 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1922 clearText ();
|
|
1923 for (int i = count - 1; i >= 0; i--) {
|
|
1924 OS.gtk_combo_box_remove_text (handle, i);
|
|
1925 }
|
|
1926 for (int i = 0; i < items.length; i++) {
|
|
1927 String string = items [i];
|
|
1928 char* buffer = string.toStringzValidPtr();
|
|
1929 OS.gtk_combo_box_insert_text (handle, i, buffer);
|
|
1930 if ((style & SWT.RIGHT_TO_LEFT) !is 0 && popupHandle !is null) {
|
|
1931 display.doSetDirectionProc(popupHandle, OS.GTK_TEXT_DIR_RTL);
|
|
1932 }
|
|
1933 }
|
|
1934 } else {
|
|
1935 lockText = ignoreSelect = true;
|
|
1936 OS.gtk_list_clear_items (listHandle, 0, -1);
|
|
1937 auto font = getFontDescription ();
|
|
1938 GdkColor* color = getForegroundColor ();
|
|
1939 int direction = OS.gtk_widget_get_direction (handle);
|
|
1940 int i = 0;
|
|
1941 while (i < items.length) {
|
|
1942 String string = items [i];
|
|
1943 char * buffer = string.toStringzValidPtr();
|
|
1944 auto item = OS.gtk_list_item_new_with_label (buffer);
|
|
1945 auto label = OS.gtk_bin_get_child (item);
|
|
1946 setForegroundColor (label, color);
|
|
1947 OS.gtk_widget_modify_font (label, font);
|
|
1948 OS.gtk_widget_set_direction (label, direction);
|
|
1949 OS.gtk_container_add (listHandle, item);
|
|
1950 OS.gtk_widget_show (item);
|
|
1951 i++;
|
|
1952 }
|
|
1953 lockText = ignoreSelect = false;
|
|
1954 OS.gtk_entry_set_text (entryHandle, "".ptr);
|
|
1955 }
|
|
1956 }
|
|
1957
|
|
1958 /**
|
|
1959 * Marks the receiver's list as visible if the argument is <code>true</code>,
|
|
1960 * and marks it invisible otherwise.
|
|
1961 * <p>
|
|
1962 * If one of the receiver's ancestors is not visible or some
|
|
1963 * other condition makes the receiver not visible, marking
|
|
1964 * it visible may not actually cause it to be displayed.
|
|
1965 * </p>
|
|
1966 *
|
|
1967 * @param visible the new visibility state
|
|
1968 *
|
|
1969 * @exception SWTException <ul>
|
|
1970 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1971 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1972 * </ul>
|
|
1973 *
|
|
1974 * @since 3.4
|
|
1975 */
|
|
1976 public void setListVisible (bool visible) {
|
|
1977 checkWidget ();
|
|
1978 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
1979 if (visible) {
|
|
1980 OS.gtk_combo_box_popup (handle);
|
|
1981 } else {
|
|
1982 OS.gtk_combo_box_popdown (handle);
|
|
1983 }
|
|
1984 }
|
|
1985 }
|
|
1986
|
|
1987 override void setOrientation() {
|
|
1988 super.setOrientation();
|
|
1989 if ((style & SWT.RIGHT_TO_LEFT) !is 0) {
|
|
1990 if (listHandle !is null) OS.gtk_widget_set_direction (listHandle, OS.GTK_TEXT_DIR_RTL);
|
|
1991 if (entryHandle !is null) OS.gtk_widget_set_direction (entryHandle, OS.GTK_TEXT_DIR_RTL);
|
|
1992 if (cellHandle !is null) OS.gtk_widget_set_direction (cellHandle, OS.GTK_TEXT_DIR_RTL);
|
|
1993 }
|
|
1994 }
|
|
1995
|
|
1996 /**
|
|
1997 * Sets the orientation of the receiver, which must be one
|
|
1998 * of the constants <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>.
|
|
1999 * <p>
|
|
2000 *
|
|
2001 * @param orientation new orientation style
|
|
2002 *
|
|
2003 * @exception SWTException <ul>
|
|
2004 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2005 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2006 * </ul>
|
|
2007 *
|
|
2008 * @since 2.1.2
|
|
2009 */
|
|
2010 public void setOrientation (int orientation) {
|
|
2011 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
2012 checkWidget();
|
|
2013 int flags = SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT;
|
|
2014 if ((orientation & flags) is 0 || (orientation & flags) is flags) return;
|
|
2015 style &= ~flags;
|
|
2016 style |= orientation & flags;
|
|
2017 int dir = (orientation & SWT.RIGHT_TO_LEFT) !is 0 ? OS.GTK_TEXT_DIR_RTL : OS.GTK_TEXT_DIR_LTR;
|
|
2018 OS.gtk_widget_set_direction (fixedHandle, dir);
|
|
2019 OS.gtk_widget_set_direction (handle, dir);
|
|
2020 if (entryHandle !is null) OS.gtk_widget_set_direction (entryHandle, dir);
|
|
2021 if (listHandle !is null) {
|
|
2022 OS.gtk_widget_set_direction (listHandle, dir);
|
|
2023 auto itemsList = OS.gtk_container_get_children (listHandle);
|
|
2024 if (itemsList !is null) {
|
|
2025 int count = OS.g_list_length (itemsList);
|
|
2026 for (int i=count - 1; i>=0; i--) {
|
|
2027 auto widget = OS.gtk_bin_get_child (OS.g_list_nth_data (itemsList, i));
|
|
2028 OS.gtk_widget_set_direction (widget, dir);
|
|
2029 }
|
|
2030 OS.g_list_free (itemsList);
|
|
2031 }
|
|
2032 }
|
|
2033 if (cellHandle !is null) OS.gtk_widget_set_direction (cellHandle, dir);
|
|
2034 if (popupHandle !is null) display.doSetDirectionProc (popupHandle, dir);
|
|
2035 }
|
|
2036 }
|
|
2037
|
|
2038 /**
|
|
2039 * Sets the selection in the receiver's text field to the
|
|
2040 * range specified by the argument whose x coordinate is the
|
|
2041 * start of the selection and whose y coordinate is the end
|
|
2042 * of the selection.
|
|
2043 *
|
|
2044 * @param selection a point representing the new selection start and end
|
|
2045 *
|
|
2046 * @exception IllegalArgumentException <ul>
|
|
2047 * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
|
|
2048 * </ul>
|
|
2049 * @exception SWTException <ul>
|
|
2050 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2051 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2052 * </ul>
|
|
2053 */
|
|
2054 public void setSelection (Point selection) {
|
|
2055 checkWidget();
|
|
2056 if (selection is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
2057 if ((style & SWT.READ_ONLY) !is 0) return;
|
|
2058 if (entryHandle !is null) {
|
|
2059 OS.gtk_editable_set_position (entryHandle, selection.x);
|
|
2060 OS.gtk_editable_select_region (entryHandle, selection.x, selection.y);
|
|
2061 }
|
|
2062 }
|
|
2063
|
|
2064 /**
|
|
2065 * Sets the contents of the receiver's text field to the
|
|
2066 * given string.
|
|
2067 * <p>
|
|
2068 * Note: The text field in a <code>Combo</code> is typically
|
|
2069 * only capable of displaying a single line of text. Thus,
|
|
2070 * setting the text to a string containing line breaks or
|
|
2071 * other special characters will probably cause it to
|
|
2072 * display incorrectly.
|
|
2073 * </p>
|
|
2074 *
|
|
2075 * @param string the new text
|
|
2076 *
|
|
2077 * @exception SWTException <ul>
|
|
2078 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2079 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2080 * </ul>
|
|
2081 */
|
|
2082 public void setText (String string) {
|
|
2083 checkWidget();
|
|
2084 // SWT extension: allow null for zero length string
|
|
2085 //if (string is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
2086 if ((style & SWT.READ_ONLY) !is 0) {
|
|
2087 int index = indexOf (string);
|
|
2088 if (index is -1) return;
|
|
2089 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
2090 OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2091 OS.gtk_combo_box_set_active (handle, index);
|
|
2092 OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2093 /*
|
|
2094 * Feature in GTK. Read Only combo boxes do not get a chance to send out a
|
|
2095 * Modify event in the gtk_changed callback. The fix is to send a Modify event
|
|
2096 * here.
|
|
2097 */
|
|
2098 sendEvent (SWT.Modify);
|
|
2099 return;
|
|
2100 }
|
|
2101 }
|
|
2102 /*
|
|
2103 * Feature in gtk. When text is set in gtk, separate events are fired for the deletion and
|
|
2104 * insertion of the text. This is not wrong, but is inconsistent with other platforms. The
|
|
2105 * fix is to block the firing of these events and fire them ourselves in a consistent manner.
|
|
2106 */
|
|
2107 if (hooks (SWT.Verify) || filters (SWT.Verify)) {
|
|
2108 auto ptr = OS.gtk_entry_get_text (entryHandle);
|
|
2109 string = verifyText (string, 0, cast(int)/*64*/OS.g_utf8_strlen (ptr, -1));
|
|
2110 if (string is null) return;
|
|
2111 }
|
|
2112 auto buffer = string.toStringzValidPtr();
|
|
2113 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
2114 OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2115 }
|
|
2116 OS.g_signal_handlers_block_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2117 OS.g_signal_handlers_block_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udDELETE_TEXT);
|
|
2118 OS.g_signal_handlers_block_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udINSERT_TEXT);
|
|
2119 OS.gtk_entry_set_text (entryHandle, buffer);
|
|
2120 if (OS.GTK_VERSION >= OS.buildVERSION (2, 4, 0)) {
|
|
2121 OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2122 }
|
|
2123 OS.g_signal_handlers_unblock_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2124 OS.g_signal_handlers_unblock_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udDELETE_TEXT);
|
|
2125 OS.g_signal_handlers_unblock_matched (entryHandle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udINSERT_TEXT);
|
|
2126 sendEvent (SWT.Modify);
|
|
2127 }
|
|
2128
|
|
2129 /**
|
|
2130 * Sets the maximum number of characters that the receiver's
|
|
2131 * text field is capable of holding to be the argument.
|
|
2132 * <p>
|
|
2133 * To reset this value to the default, use <code>setTextLimit(Combo.LIMIT)</code>.
|
|
2134 * Specifying a limit value larger than <code>Combo.LIMIT</code> sets the
|
|
2135 * receiver's limit to <code>Combo.LIMIT</code>.
|
|
2136 * </p>
|
|
2137 * @param limit new text limit
|
|
2138 *
|
|
2139 * @exception IllegalArgumentException <ul>
|
|
2140 * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li>
|
|
2141 * </ul>
|
|
2142 * @exception SWTException <ul>
|
|
2143 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2144 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2145 * </ul>
|
|
2146 *
|
|
2147 * @see #LIMIT
|
|
2148 */
|
|
2149 public void setTextLimit (int limit) {
|
|
2150 checkWidget();
|
|
2151 if (limit is 0) error (SWT.ERROR_CANNOT_BE_ZERO);
|
|
2152 if (entryHandle !is null) OS.gtk_entry_set_max_length (entryHandle, limit);
|
|
2153 }
|
|
2154
|
|
2155 override void setToolTipText (Shell shell, String newString) {
|
|
2156 if (entryHandle !is null) shell.setToolTipText (entryHandle, newString);
|
|
2157 if (buttonHandle !is null) shell.setToolTipText (buttonHandle, newString);
|
|
2158 }
|
|
2159
|
|
2160 /**
|
|
2161 * Sets the number of items that are visible in the drop
|
|
2162 * down portion of the receiver's list.
|
|
2163 * <p>
|
|
2164 * Note: This operation is a hint and is not supported on
|
|
2165 * platforms that do not have this concept.
|
|
2166 * </p>
|
|
2167 *
|
|
2168 * @param count the new number of items to be visible
|
|
2169 *
|
|
2170 * @exception SWTException <ul>
|
|
2171 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2172 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2173 * </ul>
|
|
2174 *
|
|
2175 * @since 3.0
|
|
2176 */
|
|
2177 public void setVisibleItemCount (int count) {
|
|
2178 checkWidget ();
|
|
2179 if (count < 0) return;
|
|
2180 visibleCount = count;
|
|
2181 }
|
|
2182
|
|
2183 override bool translateTraversal (GdkEventKey* keyEvent) {
|
|
2184 int key = keyEvent.keyval;
|
|
2185 switch (key) {
|
|
2186 case OS.GDK_KP_Enter:
|
|
2187 case OS.GDK_Return: {
|
|
2188 auto imContext = imContext ();
|
|
2189 if (imContext !is null) {
|
|
2190 char* preeditString;
|
|
2191 OS.gtk_im_context_get_preedit_string (imContext, &preeditString, null, null);
|
|
2192 if (preeditString !is null) {
|
|
2193 int length = fromStringz(preeditString).length;
|
|
2194 OS.g_free (preeditString);
|
|
2195 if (length !is 0) return false;
|
|
2196 }
|
|
2197 }
|
|
2198 }
|
|
2199 default:
|
|
2200 }
|
|
2201 return super.translateTraversal (keyEvent);
|
|
2202 }
|
|
2203
|
|
2204 String verifyText (String string, int start, int end) {
|
|
2205 if (string.length is 0 && start is end) return null;
|
|
2206 Event event = new Event ();
|
|
2207 event.text = string;
|
|
2208 event.start = start;
|
|
2209 event.end = end;
|
|
2210 auto eventPtr = OS.gtk_get_current_event ();
|
|
2211 if (eventPtr !is null) {
|
|
2212 GdkEventKey* gdkEvent = cast(GdkEventKey*)eventPtr;
|
|
2213 switch (gdkEvent.type) {
|
|
2214 case OS.GDK_KEY_PRESS:
|
|
2215 setKeyState (event, gdkEvent);
|
|
2216 break;
|
|
2217 default:
|
|
2218 }
|
|
2219 OS.gdk_event_free (eventPtr);
|
|
2220 }
|
|
2221 /*
|
|
2222 * It is possible (but unlikely), that application
|
|
2223 * code could have disposed the widget in the verify
|
|
2224 * event. If this happens, answer null to cancel
|
|
2225 * the operation.
|
|
2226 */
|
|
2227 sendEvent (SWT.Verify, event);
|
|
2228 if (!event.doit || isDisposed ()) return null;
|
|
2229 return event.text;
|
|
2230 }
|
|
2231
|
|
2232 }
|