]> git.saurik.com Git - wxWidgets.git/blob - src/motif/xmcombo/xmcombo.c
Still no such thing as gtkfeatures.h in gtk+ 1.3.1...
[wxWidgets.git] / src / motif / xmcombo / xmcombo.c
1 /*
2 * ComboBox.c - Das schon lange schmerzlich vermisste Combo-Box-
3 * Widget -- nun endlich auf fuer Motif!
4 *
5 * Version 1.32a -- 04.10.95
6 *
7 * Letzte Modifikation:
8 * 04.10.1995 Layoutfehler behoben, der bei angezeigter horizontaler Liste
9 * dazu fuehrt, dass das Listenfeld schrumpft. Daneben wird
10 * jetzt auch der Fall beruecksichtigt, dass das Listenfeld am
11 * unteren Bildschirmrand abgeschnitten wuerde. In diesem Fall
12 * erscheint das Listenfeld oberhalb des Eingabefeldes.
13 * 20.03.1995 XmNscrollbarDisplayPolicy,... koennen nun immer vom Pro-
14 * grammierer gesetzt werden, statische Liste hin und her.
15 * 21.10.1994 Fehler in SetValues behoben, der auftritt, wenn man versucht,
16 * XmNitems und XmNitemCount zu setzen.
17 * 01.10.1994 Externe Sortierung wird nun unterstuetzt sowie seitenweises
18 * Rollen in der Liste mittels PgUp und PgDn.
19 * 25.09.1994 Unterstuetzung fuer XmNautomaticSelection implementiert.
20 * Damit wird die Sache noch ein bischen runder in der Bedienung.
21 * Des weiteren sind etliche Callbacks neu hinzugekommen.
22 * 04.09.1994 Erweiterungen fuer XmSINGLE_SELECT eingebaut. Ausserdem
23 * kann die Liste jetzt auch statisch unterhalb des Eingabe-
24 * felds erscheinen. Damit sind wir nun noch kompatibler ge-
25 * worden -- fragt sich nur, zu was?!
26 * 29.08.1994 Alle Mirror-Ressourcen tauchen nun auch in der Ressourcen-
27 * liste der ComboBox-Klasse auf. Allerdings stehen keine
28 * sinnvollen Werte fuer die Initialisierung 'drin. Weiterhin
29 * den GeometryManager so veraendert, dass ab sofort das
30 * Label in der Breite wachsen oder schrumpfen darf.
31 * 07.06.1994 XmNmnemonic und XmNmnemonicCharSet implementiert.
32 * 29.05.1994 XmNsensitive angepasst. XmNcursorPositionVisible ist nun
33 * False, falls die ComboBox nicht editierbar ist.
34 * 07.05.1994 Drag'n'Drop funktioniert endlich!!! Zudem Anpassung an
35 * den fvwm ausgefuehrt ('st vom Focus-Verhalten ja ein halber
36 * twm). Hach', so'ne Linux-Box mit Motif 1.2 macht doch
37 * einfach Spass... vor allem geht hier so richtig die Post ab.
38 * Das kann man ja von M$ Windoze (Windoze for Mondays) nicht
39 * behaupten!
40 * 14.04.1994 Ein paar Speicherlecks korrigiert.
41 * 21.02.1994 Die Resourcen XmNitems und XmNitemCount lassen sich nun
42 * auch von einer Resourcendatei aus initialisieren. ACHTUNG:
43 * diese beiden Resourcen mussen immer beide beim Aufruf von
44 * XtSetValues zugleich angegeben werden, ansonsten werden
45 * diese Angaben ignoriert.
46 * 03.02.1994 Convenience-Funktionen auf Vordermann gebracht und noch
47 * einen Callback eingebaut, der immer dann aufgerufen wird,
48 * wenn die List angezeigt oder wieder versteckt wird.
49 * 01.02.1994 Motif 1.2-fest!!! Das wird aber heute abend gefeiert!!
50 * Endlich EIN Alptraum weniger! Naja, Drag'n'Drop bleibt
51 * noch zu loesen. Spaeter...
52 * 31.01.1994 VAX-fest (mit Hilfe von Vincenct Li)
53 * owlm sollte man abschaffen! Aber es scheint so, als ob
54 * ich jetzt doch noch das FocusOut-Problem geknackt habe.
55 * Ebenso die OSF...mit viel Arbeit habe ich nun auch noch
56 * eine anstaendige Initialisierung der Fontliste des Label-
57 * Kinds erreicht.
58 * 12.01.1994 Revisionsstand: 1.10a
59 * nun wirklich voll ANSI-faehiger C-Code
60 * Pixmaps werden ggf. aufgeraeumt; Druckrichtung
61 * wird vom Vater erfragt und an das Label weiter-
62 * gegeben.
63 * ESC-Behandlung implementiert.
64 * Spiegel-Ressourcen-Initialisierung aus Ressourcen-Daten-
65 * bank implementiert.
66 * Weitergabe von neu gesetzten Farben an die Kinder
67 * implementiert.
68 * Combo-Box kann jetzt wahlweise auch links neben dem
69 * Eingabefeld ein Label anzeigen.
70 * 09.12.1993 Revisionsstand: 1.00
71 * erste oeffentlich zugaengliche Version der Combo-Box
72 *
73 * (c) 1993, 1994, 1995 Harald Albrecht
74 * Institut fuer Geometrie und Praktische Mathematik
75 * RWTH Aachen, Germany
76 * albrecht@igpm.rwth-aachen.de
77 *
78 * This program is free software; you can redistribute it and/or modify
79 * it under the terms of the GNU General Public License as published by
80 * the Free Software Foundation; either version 2 of the License, or
81 * (at your option) any later version.
82 *
83 * This program is distributed in the hope that it will be useful,
84 * but WITHOUT ANY WARRANTY; without even the implied warranty of
85 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
86 * GNU General Public License for more details.
87 *
88 * You should have received a copy of the GNU General Public License
89 * along with this program (see the file COPYING for more details);
90 * if not, write to the Free Software Foundation, Inc., 675 Mass Ave,
91 * Cambridge, MA 02139, USA.
92 *
93 */
94
95 #include <X11/IntrinsicP.h>
96 #include <X11/StringDefs.h>
97 #include <X11/cursorfont.h>
98 #include <X11/Shell.h>
99 #ifdef VMS /* Huch, wo gibt's denn noch sowas ... ?! */
100 /* Bitte keine Mail bzgl. dieser Bemerkung schicken...
101 * Ich weiss, das ist ein Vorurteil...aber es gibt
102 * ja auch wahre Vorurteile....
103 */
104 #include <Xmu/Converters.h>
105 #else
106 #include <X11/Xmu/Converters.h>
107 #endif
108 #include <Xm/ArrowB.h>
109 #include <Xm/TextF.h>
110 #include <Xm/List.h>
111 #include <Xm/LabelP.h>
112 #include <string.h>
113 #include <ctype.h> /* define toupper */
114 #include "combop.h"
115
116 #include <stdio.h>
117
118 /* --- Systemspezifische Definitionen */
119 #if defined(VMS)
120 #define strcasecmp(s1, s2) strcmp(s1, s2)
121 #elif defined(__EMX__)
122 #define strcasecmp stricmp
123 #endif
124
125 /* --- sonstiger Quark */
126 /* #ifdef DEBUG */
127 #if 0
128 #define LOG(p1) fprintf(stderr, p1);
129 #define LOG2(p1, p2) fprintf(stderr, p1, p2);
130 #define LOG3(p1, p2, p3) fprintf(stderr, p1, p2, p3);
131 #else
132 #define LOG(p1)
133 #define LOG2(p1, p2)
134 #define LOG3(p1, p2, p3)
135 #endif
136
137 /* ---------------------------------------------------------------------------
138 * Resourcen-Liste...
139 * Hier werden diejenigen Resourcen definiert, die von "aussen" - also fuer
140 * den Programmierer oder Anwender - benutzbar und veraenderbar sind.
141 *
142 * Der Aufbau der einzelnen Eintraege ist immer wieder gleich:
143 * Resourcen-Name XmN... oder XtN
144 * Resourcen-Klasse XmC... oder XtC
145 * Resourcen-Type XmR... oder XtR (Datentyp der Variable in der
146 * struct der jeweiligen Widgetinstanz)
147 * Resourcen-Groesse aktuelle Groesse dieses Datentyps
148 * Resourcen-Offset Lage der Variable innerhalb der struct der
149 * Widgetinstanz
150 * Defaultwert-Type Typ des Defaultwertes
151 * Defaultwert (normalerweise) Zeiger auf den Defaultwert
152 */
153 #define offset(field) XtOffsetOf(XmComboBoxRec, field)
154 static XtResource resources[] = {
155 { /* Eingabefeld kann veraendert werden, oder aber es sind nur
156 * die Vorgaben aus der Liste auswaehlbar.
157 */
158 XmNeditable, XmCEditable, XmRBoolean, sizeof(Boolean),
159 offset(combobox.Editable), XmRString, "False"
160 },
161 { /* Liste wird automatisch sortiert -- wie konnten die bei
162 * der OSF denn SOETWAS nur vergessen ??
163 */
164 XmNsorted, XmCSorted, XmRBoolean, sizeof(Boolean),
165 offset(combobox.Sorted), XmRString, "False"
166 },
167 { /* externe Sortierreihenfolge */
168 XmNsortingCallback, XmCSortingCallback, XmRCallback,
169 sizeof(XtCallbackList),
170 offset(combobox.SortingCBL), XmRCallback, NULL
171 },
172 { /* Anzahl auf einmal sichtbarer Eintraege in der Liste (ent-
173 * spricht damit der Listenhoehe.
174 */
175 XmNvisibleItemCount, XmCVisibleItemCount, XmRInt, sizeof(int),
176 offset(combobox.VisibleItemCount), XmRImmediate, (caddr_t) 8
177 },
178 { /* Fuer das Eingabefeld sowie die Liste verwandte Fonts */
179 XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList),
180 offset(combobox.Font), XmRImmediate, NULL
181 },
182 { /* Rueckruf bei Anwahl */
183 XmNselectionCallback, XmCSelectionCallback, XmRCallback,
184 sizeof(XtCallbackList),
185 offset(combobox.SelectionCBL), XmRCallback, NULL
186 },
187 { /* Gegenteil zum vorherigen Callback! */
188 XmNunselectionCallback, XmCUnselectionCallback, XmRCallback,
189 sizeof(XtCallbackList),
190 offset(combobox.UnselectionCBL), XmRCallback, NULL
191 },
192 { /* Doppelklick in der Liste */
193 XmNdefaultActionCallback, XmCCallback, XmRCallback,
194 sizeof(XtCallbackList),
195 offset(combobox.DefaultActionCBL), XmRCallback, NULL
196 },
197 { /* Rueckruf bei Liste ausklappen/verstecken */
198 XmNdropDownCallback, XmCDropDownCallback, XmRCallback,
199 sizeof(XtCallbackList),
200 offset(combobox.DropDownCBL), XmRCallback, NULL
201 },
202 { /* Eingabe abchecken... */
203 XmNmodifyVerifyCallback, XmCCallback, XmRCallback,
204 sizeof(XtCallbackList),
205 offset(combobox.ModifyVerifyCBL), XmRCallback, NULL
206 },
207 {
208 XmNvalueChangedCallback, XmCCallback, XmRCallback,
209 sizeof(XtCallbackList),
210 offset(combobox.ValueChangedCBL), XmRCallback, NULL
211 },
212 {
213 XmNactivateCallback, XmCCallback, XmRCallback,
214 sizeof(XtCallbackList),
215 offset(combobox.ActivateCBL), XmRCallback, NULL
216 },
217 {
218 XmNmotionVerifyCallback, XmCCallback, XmRCallback,
219 sizeof(XtCallbackList),
220 offset(combobox.MotionVerifyCBL), XmRCallback, NULL
221 },
222 { /* Verhalten der ausgeklappten Liste bei Focus-Out */
223 XmNpersistentDropDown, XmCPersistentDropDown, XmRBoolean,
224 sizeof(Boolean),
225 offset(combobox.Persistent), XmRString, "False"
226 },
227 { /* Wie verhaelt sich der Window-Manager? */
228 XmNtwmHandlingOn, XmCTwmHandlingOn, XmRBoolean, sizeof(Boolean),
229 offset(combobox.TwmHandlingOn), XmRString, "False"
230 },
231 { /* Label anzeigen oder nicht? */
232 XmNshowLabel, XmCShowLabel, XmRBoolean, sizeof(Boolean),
233 offset(combobox.ShowLabel), XmRString, "False"
234 },
235 { /* Abstand zw. linkem Rand Eingabefeld und linkem Rand Liste */
236 XmNdropDownOffset, XmCDropDownOffset, XmRPosition,
237 sizeof(Position), offset(combobox.DropDownOffset),
238 XmRImmediate, (caddr_t) -1
239 },
240 { /* Neue Voreinstellung bzgl. des Randes */
241 XmNborderWidth, XmCBorderWidth, XmRDimension, sizeof(Dimension),
242 offset(core.border_width), XmRImmediate, (caddr_t) 0
243 },
244 { /* welcher Cursor soll in der Dropdown-Liste benutzt werden? */
245 XmNdropDownCursor, XmCDropDownCursor, XmRCursor, sizeof(Cursor),
246 offset(combobox.ArrowCursor), XmRString, "center_ptr"
247 },
248 { /* wie lassen sich Eintraege auswaehlen? */
249 XmNselectionPolicy, XmCSelectionPolicy, XmRSelectionPolicy, sizeof(unsigned char),
250 offset(combobox.SelectionPolicy), XmRImmediate, (caddr_t) XmBROWSE_SELECT
251 },
252 { /* Wann werden die Callbacks aufgerufen? */
253 XmNautomaticSelection, XmCAutomaticSelection, XmRBoolean, sizeof(Boolean),
254 offset(combobox.AutomaticSelection), XmRString, "False"
255 },
256 { /* erscheint die Liste staendig? */
257 XmNstaticList, XmCStaticList, XmRBoolean, sizeof(Boolean),
258 offset(combobox.StaticList), XmRString, "False"
259 },
260 {
261 XmNscrollBarDisplayPolicy, XmCScrollBarDisplayPolicy, XmRScrollBarDisplayPolicy, sizeof(unsigned char),
262 offset(combobox.ScrollBarDisplayPolicy), XmRImmediate, (caddr_t) XmAS_NEEDED
263 },
264 {
265 XmNlistSizePolicy, XmCListSizePolicy, XmRListSizePolicy, sizeof(unsigned char),
266 offset(combobox.ListSizePolicy), XmRImmediate, (caddr_t) XmVARIABLE
267 },
268 {
269 XmNsquareArrow, XmCSquareArrow, XmRBoolean, sizeof(Boolean),
270 offset(combobox.SquareArrow), XmRString, "False"
271 },
272 {
273 XmNarrowSpacingOn, XmCArrowSpacingOn, XmRBoolean, sizeof(Boolean),
274 offset(combobox.ArrowSpacingOn), XmRString, "True"
275 },
276 #ifndef DONT_LOOK_IN_THE_MIRROR
277 /* Mirror-Ressourcen, Adressen sind ungueltig!!!! */
278 {
279 XmNalignment, XmCAlignment, XmRAlignment, sizeof(unsigned char),
280 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
281 },
282 {
283 XmNblinkRate, XmCBlinkRate, XmRInt, sizeof(int),
284 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
285 },
286 {
287 XmNcolumns, XmCColumns, XmRShort, sizeof(short),
288 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
289 },
290 {
291 XmNcursorPosition, XmCCursorPosition, XmRTextPosition, sizeof(XmTextPosition),
292 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
293 },
294 {
295 XmNitemCount, XmCItemCount, XmRInt, sizeof(int),
296 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
297 },
298 {
299 XmNitems, XmCItems, XmRXmStringTable, sizeof(XmStringTable),
300 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
301 },
302 {
303 XmNlabelFontList, XmCLabelFontList, XmRFontList, sizeof(XmFontList),
304 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
305 },
306 {
307 XmNlabelInsensitivePixmap, XmCLabelInsensitivePixmap, XmRPixmap, sizeof(Pixmap),
308 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
309 },
310 {
311 XmNlabelMarginBottom, XmCLabelMarginBottom, XmRDimension, sizeof(Dimension),
312 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
313 },
314 {
315 XmNlabelMarginHeight, XmCLabelMarginHeight, XmRDimension, sizeof(Dimension),
316 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
317 },
318 {
319 XmNlabelMarginLeft, XmCLabelMarginLeft, XmRDimension, sizeof(Dimension),
320 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
321 },
322 {
323 XmNlabelMarginRight, XmCLabelMarginRight, XmRDimension, sizeof(Dimension),
324 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
325 },
326 {
327 XmNlabelMarginTop, XmCLabelMarginTop, XmRDimension, sizeof(Dimension),
328 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
329 },
330 {
331 XmNlabelMarginWidth, XmCLabelMarginWidth, XmRDimension, sizeof(Dimension),
332 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
333 },
334 {
335 XmNlabelPixmap, XmCLabelPixmap, XmRPixmap, sizeof(Pixmap),
336 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
337 },
338 {
339 XmNlabelString, XmCLabelString, XmRString, sizeof(XmString),
340 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
341 },
342 {
343 XmNlabelType, XmCLabelType, XmRLabelType, sizeof(unsigned char),
344 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
345 },
346 {
347 XmNlistMarginHeight, XmCListMarginHeight, XmRDimension, sizeof(Dimension),
348 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
349 },
350 {
351 XmNlistMarginWidth, XmCListMarginWidth, XmRDimension, sizeof(Dimension),
352 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
353 },
354 {
355 XmNlistSpacing, XmCListSpacing, XmRDimension, sizeof(Dimension),
356 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
357 },
358 {
359 XmNmarginHeight, XmCMarginHeight, XmRDimension, sizeof(Dimension),
360 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
361 },
362 {
363 XmNmarginWidth, XmCMarginWidth, XmRDimension, sizeof(Dimension),
364 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
365 },
366 {
367 XmNmaxLength, XmCMaxLength, XmRInt, sizeof(int),
368 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
369 },
370 {
371 XmNselectThreshold, XmCSelectThreshold, XmRInt, sizeof(int),
372 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
373 },
374 {
375 XmNstringDirection, XmCStringDirection, XmRStringDirection, sizeof(XmStringDirection),
376 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
377 },
378 {
379 XmNtopItemPosition, XmCTopItemPosition, XmRInt, sizeof(int),
380 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
381 },
382 {
383 XmNvalue, XmCValue, XmRString, sizeof(String),
384 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
385 },
386 {
387 XmNvalue, XmCValue, XmRInt, sizeof(int),
388 offset(combobox.Dummy), XmRImmediate, (caddr_t) 0
389 },
390 #endif
391 }; /* resources[] */
392
393 /* ---------------------------------------------------------------------------
394 * Funktions-Prototypen fuer die 'Methoden' des ComboBox-Widgets. Diese
395 * 'Methoden' werden vom Xt-Toolkit aufgerufen und sorgen dafuer, dass eine
396 * ComboBox sich wie ein anstaendiges Widget verhaelt.
397 */
398 static void Initialize (Widget, XmComboBoxWidget, ArgList,
399 Cardinal *);
400 static void Destroy (XmComboBoxWidget);
401 static void Resize (XmComboBoxWidget);
402 static Boolean SetValues (XmComboBoxWidget, XmComboBoxWidget,
403 XmComboBoxWidget, ArgList, Cardinal *);
404 static void GetValuesAlmost(XmComboBoxWidget, ArgList, Cardinal *);
405 static XtGeometryResult QueryGeometry (XmComboBoxWidget, XtWidgetGeometry *,
406 XtWidgetGeometry *);
407 static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *,
408 XtWidgetGeometry *);
409 static void ClassInit ();
410 static void Realize (XmComboBoxWidget, Mask *,
411 XSetWindowAttributes *);
412 /* ---------------------------------------------------------------------------
413 * diverse restliche Prototypen... naja, hier halt etwas mager! Hierbei
414 */
415 static void ShowHideDropDownList (XmComboBoxWidget w, XEvent *event,
416 Boolean Show);
417 static void ShellCallback (Widget w, XtPointer cbw,
418 XEvent *event, Boolean *ContDispatch);
419 static void DoLayout (XmComboBoxWidget w);
420 /* --------------------------------------------------------------------
421 * Klassen-Definition
422 */
423 XmComboBoxClassRec xmComboBoxClassRec = {
424 { /*** core-Klasse ***/
425 /* superclass */ (WidgetClass) &xmManagerClassRec,
426 /* class_name */ "XmComboBox",
427 /* widget_size */ sizeof(XmComboBoxRec),
428 /* class_initialize */ (XtProc) ClassInit,
429 /* class_part_initialize */ NULL,
430 /* class_inited */ False, /* IMMER mit FALSE initialisieren !! */
431 /* initialize */ (XtInitProc) Initialize,
432 /* initialize_hook */ NULL,
433 /* realize */ (XtRealizeProc) Realize,
434 /* actions */ NULL,
435 /* num_actions */ 0,
436 /* resources */ resources,
437 /* num_resources */ XtNumber(resources),
438 /* xrm_class */ NULLQUARK,
439 /* compress_motion */ True,
440 /* compress_exposure */ XtExposeCompressMultiple,
441 /* compress_enterleave */ True,
442 /* visible_interest */ False,
443 /* destroy */ (XtWidgetProc) Destroy,
444 /* resize */ (XtWidgetProc) Resize,
445 /* expose */ NULL,
446 /* set_values */ (XtSetValuesFunc) SetValues,
447 /* set_values_hook */ NULL,
448 /* set_values_almost */ XtInheritSetValuesAlmost,
449 /* get_values_hook */ (XtArgsProc) GetValuesAlmost,
450 /* accept_focus */ NULL,
451 /* version */ XtVersion,
452 /* callback_private */ NULL,
453 /* tm_table */ NULL,
454 /* query_geometry */ (XtGeometryHandler) QueryGeometry,
455 /* display_accelerator */ XtInheritDisplayAccelerator,
456 /* extension */ NULL
457 },
458 { /*** composite-Klasse ***/
459 /* geometry_manager */ (XtGeometryHandler) GeometryManager,
460 /* change_managed */ XtInheritChangeManaged,
461 /* insert_child */ XtInheritInsertChild,
462 /* delete_child */ XtInheritDeleteChild,
463 /* extension */ NULL
464 },
465 { /*** constraint-Klasse ***/
466 /* resources */ NULL,
467 /* num_resources */ 0,
468 /* constraint_size */ sizeof(XmManagerConstraintPart),
469 /* initialize */ NULL,
470 /* destroy */ NULL,
471 /* set_values */ NULL,
472 /* extension */ NULL
473 },
474 { /*** xmManager-Klasse ***/
475 /* translations */ XtInheritTranslations,
476 /* syn_resources */ NULL,
477 /* num_syn_resources */ 0,
478 /* syn_constraint_resources */ NULL,
479 /* num_syn_constraint_resources */ 0,
480 /* parent_process */ XmInheritParentProcess,
481 /* extension */ NULL
482 },
483 { /*** combobox-Klasse ***/
484 /* */ 0
485 }
486 }; /* xmComboBoxClassRec */
487 WidgetClass xmComboBoxWidgetClass = (WidgetClass) &xmComboBoxClassRec;
488
489 /* --------------------------------------------------------------------
490 * --------------------------------------------------------------------
491 * Translation-Tabelle (hier allerdings fuer das Eingabefeld!)
492 * Tjaja....mit der Reihenfolge von Translations ist das schon so eine
493 * ziemlich boese Sache!
494 */
495 static char newEditTranslations[] =
496 "Alt<Key>osfDown: ComboBox-Manager(show-hide-list) \n\
497 Meta<Key>osfDown: ComboBox-Manager(show-hide-list) \n\
498 Alt<Key>osfUp: ComboBox-Manager(hide-list) \n\
499 Meta<Key>osfUp: ComboBox-Manager(hide-list) \n\
500 <Key>osfUp: ComboBox-Manager(up) \n\
501 <Key>osfDown: ComboBox-Manager(down) \n\
502 <Key>osfPageUp: ComboBox-Manager(page-up) \n\
503 <Key>osfPageDown: ComboBox-Manager(page-down) \n\
504 <Key>osfCancel: ComboBox-Manager(cancel) \n\
505 <Key>Return: ComboBox-Manager(activate) activate()"
506 ;
507 /* speziell bei der nicht editierbaren Combo-Box sind noch einige
508 * andere Tasten belegt, die sonst dem Eingabefeld alleine gehoeren.
509 * Die dazugehoerigen neuen Translations befinden sich in dieser
510 * zusaetzlichen Tabelle, das Anhaengsel ...NE ist dabei die Ab-
511 * kuerzung fuer "non editable".
512 */
513 static char newEditTranslationsNE[] =
514 "<Key>osfDelete: ComboBox-Manager(wipe-out) \n\
515 <Key>osfBeginLine: ComboBox-Manager(top) \n\
516 <Key>osfEndLine: ComboBox-Manager(bottom) "
517 ;
518 /* Momentan gibt es noch Aerger mit dem Drag'n'Drop-Mechanismus
519 * von Motif 1.2. Legen wir ihn deshalb erst einmal still, solange
520 * bis ich weiss, warum, und eine Loesung parat habe. NEU: Nur wenn
521 * Sie mit einer libXm geschlagen sind, die partout nicht funktionieren
522 * will, muessen Sie Drag'n'Drop stillegen, ansonsten klappts doch!
523 */
524 #ifdef NODRAGNDROP
525 static char newListTranslations[] =
526 "<Btn2Down>: ComboBox-Manager(no-operation) ";
527 #endif
528 static char newListTranslationsE[] =
529 "<Key>osfPageUp: ComboBox-Manager(page-up) \n\
530 <Key>osfPageDown: ComboBox-Manager(page-down) ";
531
532 /* ---------------------------------------------------------------------------
533 * ---------------------------------------------------------------------------
534 * Aktionen-Tabelle: Hierdurch werden den einzelnen Translations die dazuge-
535 * hoerigen C-Routinen zugeordnet. Da wir hier ein anstaendiges ANSI-C be-
536 * nutzen, werden hier zuerst einmal die Prototypen faellig... Ach ja, noch
537 * ein Hinweis in eigener Sache... der ComboBox-Manager muss applikationsweit
538 * registriert werden, da er auch von Translationen in den Kindern der Combo-
539 * Box aktiviert wird. Bei diesem Namen der 'Aktion' steht aber nicht zu be-
540 * fuerchten, dass er anderweitig bereits in Anwendung ist.
541 */
542 static void CBoxManager(Widget w, XEvent *event, String *params,
543 Cardinal *num_params);
544
545 static XtActionsRec actions[] = {
546 { "ComboBox-Manager", CBoxManager },
547 { NULL, NULL }
548 }; /* actions */
549
550
551 /* --------------------------------------------------------------------
552 * Eine Instanz dieser Widget-Klasse wird erstmalig in Betrieb ge-
553 * nommen, daher sind noch Vorbereitungen notwendig, die nun hier
554 * durchgefuehrt werden.
555 */
556 static XtTranslations NewEditTranslations, NewEditTranslationsNE,
557 NewListTranslations, NewListTranslationsE;
558
559 static XtConvertArgRec ConverterScreenConvertArg[] = {
560 { XtBaseOffset, (XtPointer) XtOffset(Widget, core.screen),
561 sizeof(Screen *) }
562 };
563
564 static void ClassInit()
565 {
566 NewEditTranslations =
567 XtParseTranslationTable(newEditTranslations);
568 NewEditTranslationsNE =
569 XtParseTranslationTable(newEditTranslationsNE);
570 #ifdef NODRAGNDROP
571 NewListTranslations =
572 XtParseTranslationTable(newListTranslations);
573 #endif
574 NewListTranslationsE =
575 XtParseTranslationTable(newListTranslationsE);
576 XtAddConverter(XtRString, XtRBitmap,
577 XmuCvtStringToBitmap,
578 ConverterScreenConvertArg,
579 XtNumber(ConverterScreenConvertArg));
580 } /* ClassInit */
581
582 /* ---------------------------------------------------------------------------
583 * Weil es sich bei diesem Widget um ein etwas komplizierteres zusammengesetz-
584 * tes Widget handelt, muessen wir hier - wo eigentlich nur das die Combobox
585 * bildende Fenster auf dem X-Server erzeugt wird - noch einmal das Layout
586 * auf Vordermann bringen. Den Aerger loest dabei das Listenfeld der OSF aus,
587 * das einfach keine Geometrie-Nachfragen verschickt, solange es nicht
588 * 'realized' ist!!! Nicht, dass ich mich ueber so einen Sauhaufen aufregen
589 * wuerde...ich doch nicht! ABER MACHT IHR DENN NUR SO'N MIST...? WARUM KOENNT
590 * IHR DENN NICHT EINMAL DIESES ****(BIEP)**** MOTIF TOOLKIT ANSTAENDIG
591 * DOKUMENTIEREN! Ich glaub', ich kann mich nach dem Chaos eigentlich nur noch
592 * hemmungslos besaufen... Die Suche nach der Ursache (bzw. Urheber = OSF) hat
593 * mich doch einige Tage gekostet (jaja...die Mannstunden!).
594 */
595 static void Realize(XmComboBoxWidget w, Mask *ValueMask,
596 XSetWindowAttributes *Attributes)
597 {
598 /*
599 * Also: wenn die Liste staendig sichtbar ist, dann zuerst noch einmal
600 * das Layout berechnen. Sonst wird vorne und hinten 'was abgeschnitten.
601 */
602 if ( w->combobox.StaticList )
603 DoLayout(w);
604 (*w->core.widget_class->core_class.superclass->core_class.realize)
605 ((Widget) w, ValueMask, Attributes);
606 } /* Realize */
607
608 /* ---------------------------------------------------------------------------
609 * Suche dasjenige Fenster, in dem unsere Shell liegt, in der wiederum die
610 * Combo-Box steckt. Diese Information wird benoetigt, um die Drop-Down-Liste
611 * innerhalb des Fensterstacks immer direkt oberhalb der Shell mit der Combo-
612 * Box zu halten. Jajaja -- ich muss halt davon ausgehen, dass der Fenster-
613 * manager ein sog. "reparenting wm" ist; also die Dekorationen in einem
614 * Fenster dargestellt werden und unsere Shell in dieses Fenster hineingepackt
615 * ist. Die Dekoration ist damit ein Kind des 'root window' - wie die Shell,
616 * in der die Drop-Down-Liste steckt. Und da nur Geschwisterfenster (sibling
617 * windows) im gleichen Stapel stecken, reicht das Shellfenster nicht aus.
618 * Alle gaengigen Fenstermanager sind solche "reparenting wm's", so dass ich
619 * hier zu diesem Trick greifen kann, um die Drop-Down-Liste immer ueber der
620 * ComboBox zu halten.
621 *
622 * Parameter:
623 * w Diejenige Combo-Box, fuer die wir dasjenige
624 * Fenster des Window-Managers ermitteln sollen,
625 * dass direkt unterhalb des Root-Fensters liegt.
626 * Ergebnis:
627 * besagtes zu suchendes Fenster, dass die Dekoration enthaelt (hoffentlich
628 * nur echte Bruesseler Spitze!)
629 */
630 static Window GetDecorationWindow(XmComboBoxWidget w)
631 {
632 Window Root, Parent, AWindow;
633 Window *Children;
634 unsigned int NumChildren;
635
636 Parent = XtWindow((Widget) w);
637 /* Suche nach dem Dekorationsfenster des Window-Managers */
638 do {
639 AWindow = Parent;
640 XQueryTree(XtDisplay((Widget) w), AWindow,
641 &Root, &Parent, &Children, &NumChildren);
642 XFree((char *) Children);
643 } while ( Parent != Root );
644 return AWindow;
645 } /* GetDecorationWindow */
646
647 /* --------------------------------------------------------------------
648 * Eine Combo-Box aus dem Wege raeumen...
649 * Momentan muessen wir hier nur den Cursor wieder los werden sowie
650 * eventuell reservierte Pixmaps.
651 * Ups -- natuerlich muss auch wieder der Callback entfernt werden,
652 * der noch an der Shell haengt.
653 */
654 static void Destroy(XmComboBoxWidget w)
655 {
656 /* fprintf(stderr, "Destroy: %08X\n", w->core.window);*/
657 if ( w->combobox.ConvertBitmapToPixmap )
658 XFreePixmap(XtDisplay((Widget) w),
659 w->combobox.LabelPixmap);
660 if ( w->combobox.ConvertBitmapToPixmapInsensitive )
661 XFreePixmap(XtDisplay((Widget) w),
662 w->combobox.LabelInsensitivePixmap);
663 if ( w->combobox.PendingFocusOut )
664 XtRemoveWorkProc(w->combobox.WorkProcID);
665 XtRemoveEventHandler(w->combobox.MyNextShell,
666 StructureNotifyMask | FocusChangeMask,
667 True, (XtEventHandler) ShellCallback,
668 (XtPointer) w);
669 } /* Destroy */
670
671 /* ---------------------------------------------------------------------------
672 * Ueberpruefe, ob fuer die Ressource "DropDownOffset" ein gueltiger Wert vom
673 * Benutzer angegeben wurde. Diese Ressource gibt an, wie weit die Drop-Down-
674 * Liste nach rechts gegenueber dem Eingabefeld eingerueckt sein soll. Wenn
675 * hierfuer ein negativer Wert angegeben ist, so berechne statt dessen einen
676 * Standardwert: dieser entspricht der Breite der Pfeilschaltflaeche, was
677 * optisch ganz gut wirkt (jedenfall nach meinem Dafuerhalten).
678 */
679 static void CheckDropDownOffset(XmComboBoxWidget w)
680 {
681 if ( w->combobox.DropDownOffset < 0 ) {
682 XtWidgetGeometry ArrowGeom;
683
684 XtQueryGeometry(w->combobox.ArrowCtrl, NULL, &ArrowGeom);
685 w->combobox.DropDownOffset = ArrowGeom.width;
686 }
687 } /* CheckDropDownOffset */
688
689 /* --------------------------------------------------------------------
690 * Berechne die voreinzustellende Groesse, die diese Combo-Box be-
691 * sitzen muss, um ausreichenden Raum fuer das Eingabefeld und den
692 * Pfeil rechts daneben zur Verfuegung zu stellen. Bei einer
693 * editierbaren Combo-Box ist zwischen dem Eingabefeld und dem Pfeil
694 * noch ein Angst-Rasen von der halben Breite eines Pfeiles vorhanden.
695 * Wird das Listenfeld staendig dargestellt, so entfallen sowohl Pfeil
696 * als auch der Angstrasen, dafuer muss aber die Hoehe des Listenfelds
697 * beruecksichtigt werden.
698 */
699 static void DefaultGeometry(XmComboBoxWidget w,
700 Dimension *TotalWidth,
701 Dimension *TotalHeight,
702 Dimension *EditCtrlWidth,
703 Dimension *LabelCtrlWidth)
704 {
705 XtWidgetGeometry EditGeom, ArrowGeom, LabelGeom, ListGeom;
706
707 XtQueryGeometry(w->combobox.EditCtrl, NULL, &EditGeom);
708 XtQueryGeometry(w->combobox.ArrowCtrl, NULL, &ArrowGeom);
709 XtQueryGeometry(w->combobox.LabelCtrl, NULL, &LabelGeom);
710
711 /*
712 * Soll die Pfeilschaltflaeche quadratisch, praktisch, gut sein?
713 */
714 if ( w->combobox.SquareArrow )
715 ArrowGeom.width = ArrowGeom.height;
716 else
717 ArrowGeom.width = (ArrowGeom.height * 4) / 5;
718
719 /*
720 * Zuerst einmal ein paar einfache Werte ermitteln und zurueckgeben...
721 */
722 *TotalHeight = EditGeom.height;
723 *EditCtrlWidth = EditGeom.width;
724 *LabelCtrlWidth = LabelGeom.width;
725
726 /*
727 * Ermittele nun die Breite, welche die Combobox benoetigt. Je nach-
728 * dem, ob das Eingabefeld oder die Liste breiter sind, wird der
729 * entsprechende Wert genommen. Diese Auswahl zwischen der Breite von
730 * Eingabefeld und Liste findet aber nur statt, wenn die Liste auch
731 * wirklich staendig sichtbar ist. Waehrend der Initialisierung hat
732 * allerdings XmNcolumns, so dass in diesem Moment die List nicht
733 * mehr die Breite kontrollieren kann!
734 */
735 if ( w->combobox.StaticList ) {
736 /*
737 * Beachte: Frage nicht die Listbox, sondern das ScrolledWindow,
738 * in welchem die Liste eingebettet ist.
739 */
740 CheckDropDownOffset(w);
741 XtQueryGeometry(XtParent(w->combobox.ListCtrl), NULL, &ListGeom);
742 if ( w->combobox.InInit ) {
743 *TotalWidth = EditGeom.width;
744 } else {
745 if ( EditGeom.width < (Dimension)
746 (ListGeom.width + w->combobox.DropDownOffset) )
747 *TotalWidth = ListGeom.width + w->combobox.DropDownOffset;
748 else
749 *TotalWidth = EditGeom.width;
750 }
751 *TotalHeight += ListGeom.height;
752 } else {
753 /*
754 * Das Listenfeld interessiert uns hier nicht. Degegen sollte noch
755 * die Breite fuer den Pfeil und ein evtl. Angstrasen beachtet
756 * werden.
757 */
758 *TotalWidth = EditGeom.width + ArrowGeom.width;
759 if ( w->combobox.Editable && w->combobox.ArrowSpacingOn )
760 *TotalWidth += ArrowGeom.width/2;
761 }
762
763 /*
764 * Vergiss nicht, auch noch ein evtl. sichtbares Schriftfeld zu berueck-
765 * sichtigen!
766 */
767 if ( w->combobox.ShowLabel )
768 *TotalWidth += LabelGeom.width;
769
770 } /* DefaultGeometry */
771
772 /* --------------------------------------------------------------------
773 * Anhand eines Widgets ermittele darueber die Screennummer desjenigen
774 * Screens, auf dem das Widget erscheint.
775 * Parameter:
776 * w betroffenes Widget.
777 * Ergebnis:
778 * Nummer desjenigen Screens, auf dem das Widget angezeigt wird.
779 */
780 static int WidgetToScreen(Widget w)
781 {
782 Screen *screen;
783 Display *display;
784 int NumScreens, i;
785
786 screen = XtScreen(w); NumScreens = ScreenCount(XtDisplay(w));
787 display = DisplayOfScreen(screen);
788 for ( i = 0; i < NumScreens; ++i )
789 if ( ScreenOfDisplay(display, i) == screen )
790 return i;
791 XtError("WidgetToScreen: data structures are destroyed.");
792 } /* WidgetToScreen */
793
794 /* --------------------------------------------------------------------
795 * Positioniere die DropDown-Liste (soweit sie natuerlich auch momentan
796 * sichtbar ist) so auf dem Bildschirm, dass sie sich unterhalb des
797 * Eingabefeldes anschliesst.
798 */
799 static void DoDropDownLayout(XmComboBoxWidget w)
800 {
801 Position abs_x, abs_y;
802 Dimension ArrowWidth, ListWidth, ListHeight;
803 Dimension ScreenHeight, LabelWidth;
804 Window Decoration;
805 XWindowChanges WindowChanges;
806
807 /*
808 * etwa nicht sichtbar ?!! Oder etwa immer sichtbar ?!!
809 * Dann sind wir jetzt sofort fertig.
810 */
811 if ( !w->combobox.ListVisible || w->combobox.StaticList ) return;
812 /*
813 * Finde zuerst einmal heraus, wo wir uns denn auf dem Bildschirm be-
814 * finden sollen... Beachte dabei auch, dass eventuell die Liste zu schmal
815 * werden koennte und gib' ihr dann ggf. eine Mindestbreite, damit es
816 * keinen core-Dump gibt.
817 */
818 XtVaGetValues(w->combobox.ArrowCtrl, XmNwidth, &ArrowWidth, NULL);
819 XtTranslateCoords((Widget) w, 0, w->core.height, &abs_x, &abs_y);
820 CheckDropDownOffset(w);
821 ListWidth = w->core.width - w->combobox.DropDownOffset - 2;
822 abs_x += w->combobox.DropDownOffset;
823 if ( w->combobox.ShowLabel ) {
824 XtVaGetValues(w->combobox.LabelCtrl, XmNwidth, &LabelWidth, NULL);
825 ListWidth -= LabelWidth;
826 abs_x += LabelWidth;
827 }
828 if ( ListWidth < 20 ) ListWidth = 20;
829 XtVaGetValues(XtParent(w->combobox.ListCtrl), XmNheight, &ListHeight, NULL);
830 /*
831 * Hier ueberpruefen wir noch, ob die Liste unten aus dem Bildschirm
832 * herausfallen wuerde. In dem Fall klappen wir die Liste oberhalb des
833 * Eingabefeldes auf.
834 */
835 ScreenHeight = DisplayHeight(XtDisplay((Widget) w),
836 WidgetToScreen((Widget) w));
837 if ( abs_y + ListHeight + 2 > ScreenHeight ) {
838 int y;
839
840 y = ((int) abs_y) - ListHeight - w->core.height - 1;
841 if ( y < 0 ) y = 0;
842 abs_y = (Position) y;
843 }
844 XtConfigureWidget(w->combobox.PopupShell,
845 abs_x, abs_y, ListWidth, ListHeight, 1);
846 /*
847 * So...das hier dient der Kosmetik: hier sorgen wir dafuer, dass die
848 * Liste auch wirklich immer direkt ueber der ComboBox innerhalb des
849 * Fensterstapels schwebt. Siehe dazu auch die Erlaeuterungen und An-
850 * merkungen in GetDecorationWindow().
851 */
852 if ( XtIsRealized((Widget) w) ) {
853 WindowChanges.sibling = GetDecorationWindow(w);
854 WindowChanges.stack_mode = Above;
855 XReconfigureWMWindow(XtDisplay((Widget) w),
856 XtWindow(w->combobox.PopupShell),
857 WidgetToScreen(w->combobox.PopupShell),
858 CWSibling | CWStackMode, &WindowChanges);
859 }
860 } /* DoDropDownLayout */
861
862 /* --------------------------------------------------------------------
863 * Naja... diese Routine scheint ja bereits zu einer Institution beim
864 * Schreiben von Composite-Widgets geworden zu sein.
865 *
866 * Hier beim ComboBox-Widget ist die Aufgabe ziemlich einfach: es
867 * genuegt, die Eingabezeile und den Pfeil-Button entsprechend inner-
868 * halb des ComboBox-Widgets zu plazieren. Seit allerdings noch das
869 * Textlabel hinzukommt, wird's langsam aufwendiger. Nun ja - da sich
870 * das Listenfeld wahlweise auch statisch einblenden laesst, ist nun
871 * noch mehr zu beruecksichtigen, wenn die Kinder-Widgets an ihre
872 * Plaetze geschoben werden.
873 */
874 static void DoLayout(XmComboBoxWidget w)
875 {
876 Dimension EditCtrlWidth, ArrowCtrlWidth, LabelCtrlWidth;
877 Dimension ComboBoxHeight;
878 Dimension BorderWidth;
879 Dimension HighlightThickness;
880 Position EditX;
881
882 XtVaGetValues(w->combobox.ArrowCtrl,
883 XmNheight, &ArrowCtrlWidth, NULL);
884 if ( !w->combobox.SquareArrow )
885 ArrowCtrlWidth = (ArrowCtrlWidth * 4) / 5;
886 XtVaGetValues(w->combobox.LabelCtrl,
887 XmNwidth, &LabelCtrlWidth, NULL);
888
889 /*
890 * In Abhaengigkeit davon, ob die ComboBox editierbar ist und ob das
891 * Listenfeld staendig sichtbar sein soll, hier die Breite einzelner
892 * Widgets bestimmen.
893 */
894 if ( w->combobox.StaticList ) {
895 ComboBoxHeight = w->combobox.EditCtrl->core.height;
896 EditCtrlWidth = w->core.width;
897 } else {
898 ComboBoxHeight = w->core.height;
899 EditCtrlWidth = w->core.width - ArrowCtrlWidth;
900 if ( w->combobox.Editable && w->combobox.ArrowSpacingOn )
901 EditCtrlWidth -= ArrowCtrlWidth/2;
902 }
903 /* Beruecksichtige noch ein evtl. ebenfalls anzuzeigendes Schriftfeld
904 * neben dem Eingabefeld.
905 */
906 if ( w->combobox.ShowLabel ) {
907 EditX = LabelCtrlWidth;
908 EditCtrlWidth -= LabelCtrlWidth;
909 } else
910 EditX = 0;
911 if ( EditCtrlWidth < 20 ) EditCtrlWidth = 20;
912 /* Plaziere nun das Eingabefeld... */
913 XtVaGetValues(w->combobox.EditCtrl,
914 XmNborderWidth, &BorderWidth,
915 XmNhighlightThickness, &HighlightThickness,
916 NULL);
917 XtConfigureWidget(w->combobox.EditCtrl,
918 EditX, 0,
919 EditCtrlWidth, ComboBoxHeight, BorderWidth);
920 /* ...und nun den Pfeil... */
921 XtVaGetValues(w->combobox.ArrowCtrl,
922 XtNborderWidth, &BorderWidth, NULL);
923 XtConfigureWidget(w->combobox.ArrowCtrl,
924 w->core.width-ArrowCtrlWidth, HighlightThickness,
925 ArrowCtrlWidth,
926 ComboBoxHeight - 2 * HighlightThickness,
927 BorderWidth);
928 /* ...und ggf. das Textlabel. */
929 if ( w->combobox.ShowLabel ) {
930 XtVaGetValues(w->combobox.LabelCtrl,
931 XmNborderWidth, &BorderWidth,
932 NULL);
933 XtConfigureWidget(w->combobox.LabelCtrl,
934 0, 0,
935 LabelCtrlWidth, ComboBoxHeight,
936 BorderWidth);
937 }
938 /* Falls da noch die Liste herumgurkt... */
939 if ( w->combobox.StaticList ) {
940 Dimension Width, Height;
941
942 if ( w->core.height > ComboBoxHeight )
943 Height = w->core.height - ComboBoxHeight;
944 else
945 Height = 10;
946
947 if ( w->core.width > (Dimension)(ArrowCtrlWidth + EditX) )
948 Width = w->core.width - ArrowCtrlWidth - EditX;
949 else
950 Width = 10;
951
952 XtConfigureWidget(XtParent(w->combobox.ListCtrl),
953 EditX + ArrowCtrlWidth, ComboBoxHeight, Width, Height, 0);
954 } else if ( w->combobox.ListVisible )
955 DoDropDownLayout(w);
956 } /* DoLayout */
957
958 /* --------------------------------------------------------------------
959 * Pappi fragt nach, wie gross wir denn sein wollen.
960 * Die hier benutzte Vorgehensweise zur Ermittlung der Groesse:
961 * Sobald der Vater uns eine Breite (oder aber Hoehe) vorschlaegt,
962 * die fuer uns eigentlich zu klein ist, meckern wir und schlagen
963 * die von uns benoetigte Breite (Hoehe) vor.
964 * Soweit also zur Theorie... leider sieht es beispielsweise das
965 * Motif Form-Widget ueberhaupt nicht ein, uns auch nur ein einziges
966 * Mal nach unseren Wuenschen zu fragen! Damit es bei derart unum-
967 * gaenglichen Widgets dann doch noch geht, muss ChangedManaged die
968 * Kohlen wieder aus dem Feuer holen mit einer Sondertour.
969 * Parameter:
970 * *Request Vom Vater vorgeschlagene Geometrie
971 * Ergebnis:
972 * *Reply Unsere Antwort auf die vorgeschlagene Geometrie
973 * sowie XtGeometryYes oder XtGeometryAlmost, je nachdem, wie gut
974 * uns Pappis Vorschlag in den Kram passt.
975 */
976 static XtGeometryResult QueryGeometry(XmComboBoxWidget w,
977 XtWidgetGeometry *Request,
978 XtWidgetGeometry *Reply)
979 {
980 XtGeometryResult result = XtGeometryYes;
981 Dimension minW, minH, editW, labelW;
982
983 /* Elternteil will nichts weiter aendern, also ist uns das
984 * recht so.
985 */
986 Request->request_mode &= CWWidth | CWHeight;
987 if ( Request->request_mode == 0 ) return result;
988
989 DefaultGeometry(w, &minW, &minH, &editW, &labelW);
990
991 /* Ueberpruefe, ob uns das in der Breite passt, was Pappi moechte... */
992 if ( Request->request_mode & CWWidth ) {
993 if ( Request->width < minW ) {
994 /* Wenn Pappi uns etwas vorschlaegt, was im wahrsten Sinne des Wortes
995 * vorn und hinten nicht reicht, dann versuchen wir ihn entsprechend
996 * zu korrigieren. ("Versuchen" deshalb, weil er diesen Vorschlag auch
997 * voellig ignorieren kann.)
998 */
999 result = XtGeometryAlmost;
1000 Reply->width = minW;
1001 Reply->request_mode |= CWWidth;
1002 }
1003 }
1004 /* Die ganze Chose nun noch vertikal */
1005 if ( Request->request_mode & CWHeight ) {
1006 if ( Request->height < minH ) {
1007 result = XtGeometryAlmost;
1008 Reply->height = minH;
1009 Reply->request_mode |= CWHeight;
1010 }
1011 }
1012 return result;
1013 } /* QueryGeometry */
1014
1015 /* --------------------------------------------------------------------
1016 * Die Groesse des ComboBox-Widgets hat sich veraendert und deshalb
1017 * mussen alle Kinder neu positioniert werden.
1018 * Letzten Endes laeuft hier alles auf ein ordinaeres DoLayout()
1019 * hinaus, um die Kinder umher zu schieben.
1020 * Parameter:
1021 * w Die bereits hinlaenglich bekannte Instanz dieses
1022 * Widgets
1023 */
1024 static void Resize(XmComboBoxWidget w)
1025 {
1026 DoLayout(w);
1027 } /* Resize */
1028
1029 /* --------------------------------------------------------------------
1030 * Dieses Widget hat sich in irgendeiner Form bewegt (und das nicht
1031 * nur relativ zum Vater, sondern moeglicherweise auch der Vater
1032 * selbst!) bzw. die Shell, in der sich irgendwo unsere Combo-Box
1033 * befindet, hat soeben den Fokus verschusselt und kann ihn nicht
1034 * mehr wiederfinden. Daneben kann es auch sein, dass die Shell
1035 * ikonisiert wurde. (Welch' Vielfalt! Dieses ist hier halt eine
1036 * multifunktionale Routine.)
1037 *
1038 * Parameter:
1039 * w Die naechste Shell in Reichweite ueber unserer
1040 * Combo-Box.
1041 * cbw Diese Combo-Box.
1042 * event ^ auf den Event, enthaelt genauerere Informationen
1043 * (naja... sieht so aus, als ob Motif hier auch
1044 * schon 'mal Schrott 'reinpackt...)
1045 * ContDispatch Auf True setzen, damit dieser Event noch weiter-
1046 * gereicht wird an all' die anderen, die auch noch
1047 * mithoeren.
1048 */
1049 static void ShellCallback(Widget w, XtPointer pClientData,
1050 XEvent *event, Boolean *ContDispatch)
1051 {
1052 XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
1053
1054 switch ( event->type ) {
1055 case ConfigureNotify:
1056 case CirculateNotify:
1057 DoDropDownLayout((XmComboBoxWidget) cbw);
1058 break;
1059 case FocusOut:
1060 LOG3("ShellCallback: FocusOut, mode: %i, detail: %i\n",
1061 (int)event->xfocus.mode, (int)event->xfocus.detail);
1062 if ( cbw->combobox.Persistent )
1063 cbw->combobox.IgnoreFocusOut = True;
1064 else if ( (event->xfocus.mode == NotifyGrab) &&
1065 cbw->combobox.ListVisible )
1066 cbw->combobox.IgnoreFocusOut = True;
1067 break;
1068 case UnmapNotify:
1069 ShowHideDropDownList((XmComboBoxWidget) cbw,
1070 event, False);
1071 break;
1072 }
1073 *ContDispatch = True;
1074 } /* ShellCallback */
1075
1076 /* --------------------------------------------------------------------
1077 * Diese Routine sorgt dafuer, dass die Liste nicht irrtuemlich bei
1078 * manchen Window Managern vom Bildschirm genommen wird, bloss weil
1079 * diese der OverrideShell den Tastaturfocus schenken bzw. diesen
1080 * dem Combo-Box-Widget wegnehmen, sobald der Mauszeiger in die Liste
1081 * bewegt wird.
1082 */
1083 static void OverrideShellCallback(Widget w, XtPointer pClientData,
1084 XEvent *event, Boolean *ContDispatch)
1085
1086 {
1087 XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
1088 switch ( event->type ) {
1089 case EnterNotify:
1090 LOG2("OverrideShellCallback: EnterNotify, PendingFO: %s\n",
1091 cbw->combobox.PendingFocusOut ? "True" : "False");
1092 if ( cbw->combobox.PendingFocusOut )
1093 cbw->combobox.IgnoreFocusOut = True;
1094 if ( cbw->combobox.TwmHandlingOn )
1095 cbw->combobox.PendingOverrideInOut = True;
1096 break;
1097 case LeaveNotify:
1098 LOG("OverrideShellCallback: LeaveNotify\n");
1099 if ( cbw->combobox.TwmHandlingOn )
1100 cbw->combobox.PendingOverrideInOut = True;
1101 break;
1102 }
1103 } /* OverrideShellCallback */
1104
1105 /* --------------------------------------------------------------------
1106 * Ha! Anscheinend kann man das Problem mit der einklappenden Liste,
1107 * sobald man den Arrow-Button anklickt, doch loesen! Allerdings geht
1108 * das auch nur von hinten durch die Brust in's Auge. Hier war die
1109 * Reihenfolge der Events bislang das Problem: Klickt man den Arrow-
1110 * Button an, so verliert das Eingabefeld den Focus, dann wird leider
1111 * schon die WorkProc aktiviert und laesst die Liste verschwinden.
1112 * Danach erst kommt der Arrow-Button-Callback an die Reihe. Um dieses
1113 * Dilemma doch noch zu loesen, wird hier darauf gelauert, wann und
1114 * welcher LeaveNotify kommt. Klickt der Benutzer den Pfeil an, so
1115 * kommt hier noch rechtzeitig ein LeaveNotify vorbei, der aber durch
1116 * einen Grab ausgeloest wurde. Und das ist eben nur beim Anklicken
1117 * der Fall. Damit wissen wir, das der FocusOut getrost ignoriert
1118 * werden darf.
1119 * Puhhh -- ist das ein kompliziertes Chaos.
1120 * Uebrigends...auch wenn manche Befehle zuerst ueberfluessig er-
1121 * scheinen...sie sind erforderlich, damit die ComboBox auch mit unter-
1122 * schiedlichen Window Managern zurechtkommt!
1123 */
1124 static void ArrowCrossingCallback(Widget w, XtPointer pClientData,
1125 XEvent *event, Boolean *ContDispatch)
1126
1127 {
1128 XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
1129 switch ( event->type ) {
1130 case LeaveNotify:
1131 LOG2("ArrowCrossingCallback: LeaveNotify, mode: %i\n",
1132 event->xcrossing.mode);
1133 if ( event->xcrossing.mode == NotifyGrab )
1134 cbw->combobox.IgnoreFocusOut = True;
1135 else
1136 cbw->combobox.IgnoreFocusOut = False;
1137 break;
1138 }
1139 } /* ArrowCrossingCallback */
1140
1141 /* --------------------------------------------------------------------
1142 * Alle Hilfeaufrufe innerhalb der Kinder gehen an das eigentliche
1143 * Combo-Box-Widget weiter, so dass auch hier nach aussen hin die
1144 * Kinder-Widgets nicht in Erscheinung treten.
1145 */
1146 static void HelpCallback(Widget w, XtPointer cbw, XtPointer CallData)
1147 {
1148 XtCallCallbacks((Widget) cbw, XmNhelpCallback, CallData);
1149 } /* HelpCallback */
1150
1151 /* --------------------------------------------------------------------
1152 * Wenn der Benutzer im Eingabefeld osfActivate drueckt, dann dieses
1153 * Ereignis offiziell bekanntgeben.
1154 */
1155 static void ActivateCallback(Widget w, XtPointer cbw, XtPointer CallData)
1156 {
1157 XtCallCallbacks((Widget) cbw, XmNactivateCallback, CallData);
1158 } /* ActivateCallback */
1159
1160 /* --------------------------------------------------------------------
1161 * Ein Kind moechte sein Groesse veraendern und fragt deshalb hier bei
1162 * uns an.
1163 * Parameter:
1164 * w Naja...
1165 * *Request Vorschlag des Kindes
1166 * Ergebnis:
1167 * *Reply Unsere Antwort darauf
1168 * XtGeometryNo, da es uns bislang grundsaetzlich nie passt, es sei
1169 * denn, es ist das Label... Naja, jetzt darf auch schon einmal das
1170 * Listenfeld quengeln (aber nur, wenn es staendig sichtbar ist,
1171 * ansonsten wird es nicht beruecksichtigt!).
1172 */
1173 static XtGeometryResult GeometryManager(Widget w,
1174 XtWidgetGeometry *Request,
1175 XtWidgetGeometry *Reply)
1176 {
1177 XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w);
1178 XtGeometryResult Result = XtGeometryNo;
1179
1180 /*
1181 * Falls das Listenfeld statisch dargestellt wird, muessen wir seine
1182 * Wuensche doch beruecksichtigen. Was fuer ein Aufwand...
1183 */
1184 if ( (w == XtParent(cbw->combobox.ListCtrl)) && cbw->combobox.StaticList ) {
1185 Dimension TotalWidth, TotalHeight, EditWidth, LabelWidth;
1186 XtWidgetGeometry MyRequest, YourReply, EditGeom;
1187
1188 XtQueryGeometry(cbw->combobox.EditCtrl, NULL, &EditGeom);
1189 DefaultGeometry(cbw, &TotalWidth, &TotalHeight,
1190 &EditWidth, &LabelWidth);
1191 CheckDropDownOffset(cbw);
1192
1193 if ( Request->request_mode && CWWidth )
1194 if ( (Dimension)(LabelWidth + cbw->combobox.DropDownOffset +
1195 Request->width) > TotalWidth )
1196 TotalWidth = LabelWidth + cbw->combobox.DropDownOffset +
1197 Request->width;
1198
1199 if ( Request->request_mode && CWHeight )
1200 TotalHeight = EditGeom.height + Request->height;
1201 /*
1202 * Bastele nun eine Anfrage an Pappi zusammen und geh' ihm damit auf den
1203 * Keks. Wenn er zustimmt, ist sofort alles gut, wir muessen dann nur
1204 * noch das Layout aufpolieren, damit das Listenfeld die neue Groesse
1205 * bekommt. Wenn Pappi nur halb zustimmt, akzeptieren wir das und fragen
1206 * ihn damit noch einmal....
1207 */
1208 MyRequest.request_mode = CWWidth | CWHeight;
1209 MyRequest.width = TotalWidth;
1210 MyRequest.height = TotalHeight;
1211 Result = XtMakeGeometryRequest((Widget) cbw, &MyRequest, &YourReply);
1212 if ( Result == XtGeometryAlmost ) {
1213 MyRequest.width = YourReply.width;
1214 MyRequest.height = YourReply.height;
1215 Result = XtMakeGeometryRequest((Widget) cbw, &MyRequest, &YourReply);
1216 }
1217 if ( Result == XtGeometryYes )
1218 DoLayout(cbw);
1219 } else
1220 /*
1221 * Ansonsten darf nur noch das Schriftfeld Ansprueche anmelden.
1222 */
1223 if ( w != cbw->combobox.LabelCtrl )
1224 return XtGeometryNo; /* Was ICH hier vorgegeben habe, gilt! */
1225 else if ( cbw->combobox.ShowLabel ) { /* Naja, 'mal schauen! */
1226 Dimension TotalWidth, TotalHeight, EditWidth, LabelWidth;
1227 XtWidgetGeometry MyRequest;
1228
1229 if ( Request->request_mode & CWWidth ) {
1230 DefaultGeometry(cbw, &TotalWidth, &TotalHeight,
1231 &EditWidth, &LabelWidth);
1232 TotalWidth = TotalWidth - LabelWidth +
1233 Request->width;
1234
1235 MyRequest.request_mode = CWWidth;
1236 MyRequest.width = TotalWidth;
1237 Result = XtMakeGeometryRequest((Widget) cbw, &MyRequest, NULL);
1238
1239 if ( Result == XtGeometryYes )
1240 DoLayout(cbw);
1241 }
1242 }
1243 return Result;
1244 } /* GeometryManager */
1245
1246 /* --------------------------------------------------------------------
1247 * Hier werden auf Wunsch diejenigen Farben, die bei der Combo-Box neu
1248 * gesetzt wurden, an alle Kinder weitergegeben.
1249 */
1250 #define BOTTOMSHADOWCOLOR 0x0001
1251 #define TOPSHADOWCOLOR 0x0002
1252 #define FOREGROUND 0x0004
1253 #define BACKGROUND 0x0008
1254
1255 static struct { String Resource; int Flag; }
1256 ColorResources[] = {
1257 { XmNbottomShadowColor, BOTTOMSHADOWCOLOR },
1258 { XmNtopShadowColor, TOPSHADOWCOLOR },
1259 { XmNforeground, FOREGROUND },
1260 { XmNbackground, BACKGROUND }
1261 };
1262
1263 static UpdateColors(XmComboBoxWidget w, int flags)
1264 {
1265 Pixel Color;
1266 int i, size = XtNumber(ColorResources);
1267 Widget ScrolledWin, ScrollBar;
1268
1269 ScrolledWin = XtParent(w->combobox.ListCtrl);
1270 XtVaGetValues(ScrolledWin, XmNverticalScrollBar, &ScrollBar, NULL);
1271 for ( i=0; i<size; i++ )
1272 if ( flags & ColorResources[i].Flag ) {
1273 XtVaGetValues((Widget) w, ColorResources[i].Resource, &Color,
1274 NULL);
1275 XtVaSetValues(w->combobox.ListCtrl,
1276 ColorResources[i].Resource, Color, NULL);
1277 XtVaSetValues(ScrolledWin,
1278 ColorResources[i].Resource, Color, NULL);
1279 XtVaSetValues(ScrollBar,
1280 ColorResources[i].Resource, Color, NULL);
1281 XtVaSetValues(w->combobox.EditCtrl,
1282 ColorResources[i].Resource, Color, NULL);
1283 XtVaSetValues(w->combobox.LabelCtrl,
1284 ColorResources[i].Resource, Color, NULL);
1285 XtVaSetValues(w->combobox.ArrowCtrl,
1286 ColorResources[i].Resource, Color, NULL);
1287 if ( ColorResources[i].Flag & BACKGROUND )
1288 XtVaSetValues(ScrollBar, XmNtroughColor, Color, NULL);
1289 }
1290
1291 return 1;
1292 } /* UpdateColors */
1293
1294 /* --------------------------------------------------------------------
1295 * Liste aller vorgespiegelten Resourcen, die automatisch verarbeitet
1296 * werden koennen, ohne weiter darueber nachdenken zu muessen...
1297 */
1298 typedef enum { EDITCTRL, LISTCTRL, LABELCTRL } CHILDCTRL;
1299 typedef enum { RO, RW, RWS, RWL, RWI, RWIGNORE } aUniqueName;
1300 typedef struct {
1301 String rsc;
1302 CHILDCTRL ctrl;
1303 /* enum { RO, RW, RWS, RWL, RWI, RWIGNORE } dir; */
1304 aUniqueName dir;
1305 /* nur lesen, lesen&schreiben, lesen&schreiben spezial,
1306 lesen&schreiben label, lesen&schreiben items */
1307 } MIRROR;
1308
1309 /* Alle mit !!! gekennzeichneten Eintraege werden auf die richtigen
1310 * Namen des entsprechenden Widgets umgesetzt.
1311 */
1312 static MIRROR MirroredResources[] = {
1313 { XmNitems, LISTCTRL, RWI }, /* Urgs! */
1314 { XmNitemCount, LISTCTRL, RWIGNORE }, /* dto. */
1315 { XmNlistMarginHeight, LISTCTRL, RW },
1316 { XmNlistMarginWidth, LISTCTRL, RW },
1317 { XmNlistSpacing, LISTCTRL, RW },
1318 { XmNstringDirection, LISTCTRL, RO }, /* Naja? */
1319 { XmNtopItemPosition, LISTCTRL, RO },
1320
1321 { XmNblinkRate, EDITCTRL, RW },
1322 { XmNcolumns, EDITCTRL, RW },
1323 { XmNcursorPosition, EDITCTRL, RW },
1324 { XmNcursorPositionVisible, EDITCTRL, RW },
1325 { XmNmarginHeight, EDITCTRL, RW },
1326 { XmNmarginWidth, EDITCTRL, RW },
1327 { XmNmaxLength, EDITCTRL, RW },
1328 { XmNselectThreshold, EDITCTRL, RW },
1329 { XmNvalue, EDITCTRL, RWS },
1330
1331 { XmNalignment, LABELCTRL, RW },
1332 { XmNmnemonic, LABELCTRL, RW },
1333 { XmNmnemonicCharSet, LABELCTRL, RW },
1334 { XmNlabelPixmap, LABELCTRL, RW },
1335 { XmNlabelInsensitivePixmap, LABELCTRL, RW },
1336 { XmNlabelString, LABELCTRL, RW },
1337 { XmNlabelType, LABELCTRL, RW },
1338 { XmNlabelMarginBottom, LABELCTRL, RWL }, /* !!! */
1339 { XmNlabelMarginHeight, LABELCTRL, RWL }, /* !!! */
1340 { XmNlabelMarginLeft, LABELCTRL, RWL }, /* !!! */
1341 { XmNlabelMarginRight, LABELCTRL, RWL }, /* !!! */
1342 { XmNlabelMarginTop, LABELCTRL, RWL }, /* !!! */
1343 { XmNlabelMarginWidth, LABELCTRL, RWL }, /* !!! */
1344 { XmNlabelFontList, LABELCTRL, RWL }, /* !!! */
1345 };
1346
1347 typedef struct {
1348 char *from, *to;
1349 } TRANSFORMATION;
1350 static TRANSFORMATION Transformations[] = {
1351 { XmNlabelMarginBottom, XmNmarginBottom },
1352 { XmNlabelMarginHeight, XmNmarginHeight },
1353 { XmNlabelMarginLeft, XmNmarginLeft },
1354 { XmNlabelMarginRight, XmNmarginRight },
1355 { XmNlabelMarginTop, XmNmarginTop },
1356 { XmNlabelMarginWidth, XmNmarginWidth },
1357 { XmNlabelFontList, XmNfontList },
1358 };
1359
1360 /* --------------------------------------------------------------------
1361 * Sobald irgendeine Resource veraendert wird, erfolgt der Aufruf
1362 * hierin als Benachrichtigung, einmal nach dem rechten zu sehen.
1363 * Parameter:
1364 * current Kopie der Widget-Instanz, bevor irgendwelche
1365 * Resourcen veraendert oder set_values()-Methoden
1366 * aufgerufen wurden.
1367 * req Kopie der Widget-Instanz, aber bereits mit den
1368 * durch XtSetValues veraenderten Werten
1369 * new aktuellster Zustand der Widget-Instanz mit
1370 * veraenderten Werten (entweder durch XtSetValues
1371 * oder set_values()-Methoden der Superklasse)
1372 * args Argumentenliste beim Aufruf von XtSetValues()
1373 * NumArgs Anzahl der Argumente in der Liste
1374 * Ergebnis:
1375 * True, falls Widget neu gezeichnet werden soll.
1376 */
1377 static Boolean SetValues(XmComboBoxWidget current, XmComboBoxWidget req,
1378 XmComboBoxWidget newW,
1379 ArgList args, Cardinal *NumArgs)
1380 {
1381 Boolean Update = False;
1382 int i, j, MirrorSize = XtNumber(MirroredResources);
1383 int k, TransformationSize = XtNumber(Transformations);
1384 Arg arg;
1385 int Flags;
1386
1387 /*
1388 * Alle Resourcen, die nicht mehr nach dem Erstellen der Widget-Instanz
1389 * veraendert werden koennen.
1390 */
1391 newW->combobox.Editable = current->combobox.Editable;
1392 newW->combobox.ListCtrl = current->combobox.ListCtrl;
1393 newW->combobox.EditCtrl = current->combobox.EditCtrl;
1394 newW->combobox.LabelCtrl = current->combobox.LabelCtrl;
1395 newW->combobox.SelectionPolicy = current->combobox.SelectionPolicy;
1396 newW->combobox.ListSizePolicy = current->combobox.ListSizePolicy;
1397 newW->combobox.StaticList = current->combobox.StaticList;
1398
1399 /*
1400 * Kontrolliere nun alle Resourcen, die sich veraendert haben koennten
1401 * und gebe die neuen Einstellungen entsprechend weiter...
1402 *
1403 * Hat sich der Sensitive-Zustand veraendert? Dann muessen wir hier dafuer
1404 * sorgen, dass alle Kinder ebenfalls den neuen Zustand annehmen.
1405 */
1406 if ( current->core.sensitive != newW->core.sensitive ) {
1407 XtSetSensitive(newW->combobox.ListCtrl, newW->core.sensitive);
1408 XtSetSensitive(newW->combobox.EditCtrl, newW->core.sensitive);
1409 XtSetSensitive(newW->combobox.ArrowCtrl, newW->core.sensitive);
1410 XtSetSensitive(newW->combobox.ListCtrl, newW->core.sensitive);
1411 if ( !newW->core.sensitive )
1412 ShowHideDropDownList(newW, NULL, False);
1413 }
1414 /*
1415 * Die ScrollBarPolicy kann nur dann geaendert werden, wenn das Listenfeld
1416 * dauerhaft dargestellt wird.
1417 */
1418 if ( newW->combobox.ScrollBarDisplayPolicy !=
1419 current->combobox.ScrollBarDisplayPolicy )
1420 if ( newW->combobox.StaticList )
1421 XtVaSetValues(newW->combobox.ListCtrl,
1422 XmNscrollBarDisplayPolicy, newW->combobox.ScrollBarDisplayPolicy,
1423 NULL);
1424 else
1425 XtWarning(
1426 "XmComboBox: ScrollBarDisplayPolicy can not be changed when StaticList == False."
1427 );
1428 /* Anzahl der in der Liste gleichzeitig darstellbaren Eintraege */
1429 if ( current->combobox.VisibleItemCount !=
1430 newW->combobox.VisibleItemCount ) {
1431 XtVaSetValues(newW->combobox.ListCtrl,
1432 XmNvisibleItemCount, newW->combobox.VisibleItemCount,
1433 NULL);
1434 Update = True;
1435 }
1436 if ( current->combobox.AutomaticSelection !=
1437 newW->combobox.AutomaticSelection )
1438 XtVaSetValues(newW->combobox.ListCtrl,
1439 XmNautomaticSelection, newW->combobox.AutomaticSelection,
1440 NULL);
1441
1442 /*
1443 * benutzter Font: hier erhalten Liste und Eingabefeld jeweils die
1444 * gleiche Fontliste, wohingegen das Label getrennt behandelt wird.
1445 * Das macht auch Sinn, denn Liste und Eingabefeld beinhalten gleich-
1446 * artigen Text, so dass hier auch tunlichst der gleiche Font zu
1447 * benutzen ist.
1448 */
1449 if ( current->combobox.Font != newW->combobox.Font ) {
1450 XtVaSetValues(newW->combobox.ListCtrl,
1451 XmNfontList, newW->combobox.Font, NULL);
1452 XtVaSetValues(newW->combobox.EditCtrl,
1453 XmNfontList, newW->combobox.Font, NULL);
1454 Update = True;
1455 }
1456
1457 Flags = 0;
1458 if ( newW->manager.top_shadow_color !=
1459 current->manager.top_shadow_color ) Flags |= TOPSHADOWCOLOR;
1460 if ( newW->manager.bottom_shadow_color !=
1461 current->manager.bottom_shadow_color ) Flags |= BOTTOMSHADOWCOLOR;
1462 if ( newW->manager.foreground !=
1463 current->manager.foreground ) Flags |= FOREGROUND;
1464 if ( newW->core.background_pixel !=
1465 current->core.background_pixel ) Flags |= BACKGROUND;
1466 if ( Flags ) { UpdateColors(newW, Flags); Update = True; }
1467
1468
1469 if ( newW->combobox.ArrowCursor != current->combobox.ArrowCursor ) {
1470 if ( newW->combobox.ListVisible )
1471 XDefineCursor(XtDisplay(newW->combobox.PopupShell),
1472 XtWindow(newW->combobox.PopupShell),
1473 newW->combobox.ArrowCursor);
1474 }
1475 /* Hier werden die vorgespiegelten Resourcen verwaltet, die in
1476 * Wirklichkeit zu einem unserer Kinder gehoeren.
1477 */
1478 for ( i = 0; i < *NumArgs; i++ ) {
1479 /* Ist es eine vorgespiegelte Resource ? Wenn ja, dann leite die
1480 * Anfrage an das entsprechende Kind-Widget weiter.
1481 */
1482 for ( j = 0; j < MirrorSize; j++ ) {
1483 if ( (strcmp(args[i].name, MirroredResources[j].rsc) == 0) ) {
1484 switch ( MirroredResources[j].dir ) {
1485 case RW: /* schreibender Zugriff erlaubt */
1486 XtSetValues(MirroredResources[j].ctrl == LISTCTRL ?
1487 newW->combobox.ListCtrl :
1488 (MirroredResources[j].ctrl == EDITCTRL ?
1489 newW->combobox.EditCtrl :
1490 newW->combobox.LabelCtrl),
1491 &(args[i]), 1);
1492 break;
1493 case RWS: /* schreibender Zugriff unter Kontrolle */
1494 if ( strcmp(args[i].name, XmNvalue) == 0 ) {
1495 if ( newW->combobox.Editable )
1496 XtSetValues(newW->combobox.EditCtrl,
1497 &(args[i]), 1);
1498 }
1499 break;
1500 case RWL: /* Transformation in andere Resource beim
1501 Label-Widget */
1502 for ( k = 0; k < TransformationSize; k++ )
1503 if ( strcmp(args[i].name, Transformations[k].from) == 0 ) {
1504 arg.value = args[i].value;
1505 arg.name = Transformations[k].to;
1506 XtSetValues(newW->combobox.LabelCtrl,
1507 &arg, 1);
1508 break;
1509 }
1510 break;
1511 case RWIGNORE: /* Zugriff auf XmNitemCount */
1512 /* Wird von XmNitems erledigt! */
1513 break;
1514 case RWI: /* Zugriff auf XmNitems */
1515 for ( k = 0; k < *NumArgs; k++ )
1516 if ( strcmp(args[k].name, XmNitemCount) == 0 ) {
1517 Arg MyArgs[2];
1518
1519 MyArgs[0].name = XmNitems;
1520 MyArgs[0].value = args[i].value;
1521 MyArgs[1].name = XmNitemCount;
1522 MyArgs[1].value = args[k].value;
1523 XtSetValues(newW->combobox.ListCtrl,
1524 args, 2);
1525 /*XtVaSetValues(newW->combobox.ListCtrl,
1526 XmNitems, args[i].value,
1527 XmNitemCount, args[k].value,
1528 NULL);*/
1529 break;
1530 }
1531 break;
1532 case RO:
1533 break;
1534 } /* case write mode */
1535 goto ScanForNextResource;
1536 } /* if entry found */
1537 } /* for every mirrored entry */
1538 ScanForNextResource: ;
1539 } /* for every Arg */
1540
1541 if ( (newW->combobox.SquareArrow != current->combobox.SquareArrow) ||
1542 (newW->combobox.ArrowSpacingOn != current->combobox.ArrowSpacingOn) ) {
1543 Update = False;
1544 DoLayout(newW);
1545 }
1546
1547 return Update;
1548 } /* SetValues */
1549
1550 /* --------------------------------------------------------------------
1551 * Werden irgendwelche Resourcen abgefragt, so muessen wir hier erst
1552 * noch vor der Rueckkehr zum Frager klaeren, ob davon eine Resource
1553 * betroffen ist, die nur vorgespiegelt ist, da sie eigentlich einem
1554 * der Widgets gehoert, die von uns hier verwaltet werden, um daraus
1555 * eine ordentliche Combo-Box zu machen.
1556 * Parameter:
1557 * w Widget-Instanz
1558 * args Abgefragte Resourcen
1559 * NumArgs Anzahl der abgefragten Resourcen
1560 */
1561 static void GetValuesAlmost(XmComboBoxWidget w, ArgList args,
1562 Cardinal *NumArgs)
1563 {
1564 int i, j, MirrorSize = XtNumber(MirroredResources);
1565 int k, TransformationSize = XtNumber(Transformations);
1566 Arg arg;
1567
1568 for ( i = 0; i < *NumArgs; i++ ) {
1569 /* Ist es eine vorgespiegelte Resource ? Wenn ja, dann leite die
1570 * Anfrage an das entsprechende Kind-Widget weiter.
1571 */
1572 for ( j = 0; j < MirrorSize; j++ ) {
1573 if ( strcmp(args[i].name, MirroredResources[j].rsc) == 0 ) {
1574 switch ( MirroredResources[j].dir ) {
1575 case RO:
1576 case RW:
1577 case RWS:
1578 case RWI:
1579 XtGetValues(MirroredResources[j].ctrl == LISTCTRL ?
1580 w->combobox.ListCtrl :
1581 MirroredResources[j].ctrl == EDITCTRL ?
1582 w->combobox.EditCtrl :
1583 w->combobox.LabelCtrl,
1584 &(args[i]), 1);
1585 break;
1586 case RWL: /* Umzuleitende Resource bei Label-Widget */
1587 for ( k = 0; k < TransformationSize; k++ )
1588 if ( strcmp(args[i].name, Transformations[k].from) == 0 ) {
1589 arg.value = args[i].value;
1590 arg.name = Transformations[k].to;
1591 XtGetValues(w->combobox.LabelCtrl,
1592 (ArgList) &arg, 1);
1593 break;
1594 }
1595 break;
1596 } /* case read mode */
1597 } /* if entry found */
1598 } /* for every mirrored entry */
1599 } /* for every Arg */
1600 } /* GetValuesAlmost */
1601
1602 /* --------------------------------------------------------------------
1603 * Zeige beziehungsweise verstecke die Drop-Down-Liste der Combo-Box.
1604 * Falls die Liste bereits den entsprechenden Zustand hat, geht's
1605 * sofort zum Aufrufer zurueck.
1606 * Parameter:
1607 * w Her Royal Majesty ComboBox
1608 * Show True, falls anzuzeigen, andernfalls False
1609 */
1610 static void ShowHideDropDownList(XmComboBoxWidget w, XEvent *event,
1611 Boolean Show)
1612 {
1613 XmComboBoxDropDownCallbackStruct info;
1614
1615 if ( w->combobox.StaticList ||
1616 (Show == w->combobox.ListVisible) ) return;
1617 w->combobox.ListVisible = Show;
1618 if ( Show ) { /* Klapp' die Liste aus! */
1619 DoDropDownLayout(w);
1620 info.reason = XmCR_SHOW_LIST;
1621 info.event = event;
1622 XtCallCallbacks((Widget) w, XmNdropDownCallback,
1623 (XtPointer) &info);
1624 XDefineCursor(XtDisplay(w->combobox.PopupShell),
1625 XtWindow(w->combobox.PopupShell),
1626 w->combobox.ArrowCursor);
1627 XtPopup(w->combobox.PopupShell, XtGrabNone);
1628 XtVaSetValues(w->combobox.ArrowCtrl,
1629 XmNarrowDirection, XmARROW_UP, NULL);
1630 } else { /* Klapp' die Liste wieder ein... */
1631 XtPopdown(w->combobox.PopupShell);
1632 XtVaSetValues(w->combobox.ArrowCtrl,
1633 XmNarrowDirection, XmARROW_DOWN, NULL);
1634 info.reason = XmCR_HIDE_LIST;
1635 info.event = event;
1636 XtCallCallbacks((Widget) w, XmNdropDownCallback,
1637 (XtPointer) &info);
1638 }
1639 } /* ShowHideDropDownList */
1640
1641 /* --------------------------------------------------------------------
1642 * Hier laeuft die Nachricht auf, dass der Pfeil ausgeloest wurde...
1643 * (Daraufhin sollte die Liste aus- oder eingeklappt werden)
1644 * ...oder dass der Benutzer da draussen auf der anderen Seite der
1645 * Mattscheibe den Pfeil bereits anklickte ohne aber bereits losge-
1646 * gelassen zu haben. Bereits hier bekommt das Eingabefeld den Fokus
1647 * vor den Latz geknallt, denn sonst kann es passieren, dass zwar die
1648 * Liste ausgeklappt ist, aber das Eingabefeld noch keinen Tastatur-
1649 * fokus erhalten hat. Das sollte aber nicht so sein, denn es ist dann
1650 * keine konsequente Tastaturbedienung.
1651 */
1652 static void ArrowCallback(Widget w, XtPointer pClientData,
1653 XmAnyCallbackStruct *info)
1654 {
1655 XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w);
1656
1657 switch ( info->reason ) {
1658 case XmCR_ARM:
1659 LOG("ArrowCallback: XmCR_ARM\n");
1660 XmProcessTraversal(cbw->combobox.EditCtrl, XmTRAVERSE_CURRENT);
1661 if ( cbw->combobox.TwmHandlingOn && cbw->combobox.ListVisible )
1662 cbw->combobox.IgnoreFocusOut = True;
1663 break;
1664 case XmCR_ACTIVATE:
1665 XmProcessTraversal(cbw->combobox.EditCtrl, XmTRAVERSE_CURRENT);
1666 ShowHideDropDownList(cbw, info->event,
1667 (Boolean)(!cbw->combobox.ListVisible));
1668 break;
1669 }
1670 } /* ArrowCallback */
1671
1672 /* --------------------------------------------------------------------
1673 * Diese Benachrichtigung moechte uns nur mitteilen, dass wir soeben
1674 * den Fokus verloren haben (Ohhhh!) Sollte allerdings der Fokus nur
1675 * aus dem Grunde perdue sein, dass der Anwender den Mauszeiger ausser-
1676 * halb des Applikationsfensters plaziert hat, so koennen wir diese
1677 * Nachricht uebergehen. Erst wenn der Fokus an ein anderes Widget in
1678 * unserer Applikation verlorenging, muessen wir auf diese Information
1679 * reagieren.
1680 * Und jetzt zu noch einem total beknackten Problem - alles nur wegen
1681 * Motif und den diversen Window-Managern (bspw. olwm)... Leider kommt
1682 * beim FocusOut kein richtiger Hinweis auf den tatsaechlichen Event,
1683 * der dieses Callback ausloeste -- warum liefert denn dann Motif ueber-
1684 * haupt noch den Event???? Und ueberhauupt, die Geschichte mit dem
1685 * Fokus ist schon der reinste Horror. Aktueller Ausweg: wenn wir die
1686 * Benachrichtigung ueber den Focusabgang bekommen, registrieren wir
1687 * eine Work-Prozedur, die, sobald der Rechner wieder Luft hat, auf-
1688 * gerufen wird. Sie kann dann nachschauen, ob nicht inzwischen die
1689 * OverrideShell den Focus bekahm. Wenn ja, koennen wir den FocusOut
1690 * uebergehen, ansonsten muessen wir ihn beruecksichtigen.
1691 * -- Ist das eine ^@#$^*(#$^&! (Meine gute Erziehung hindert mich
1692 * daran, diesen Begriff hier zu nennen.)
1693 */
1694 static Boolean DelayedFocusOutWorkProc(XtPointer pClientData)
1695 {
1696 XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
1697 LOG2("DelayedFocusOutWorkProc: IgnoreFocusOut: %s\n",
1698 cbw->combobox.IgnoreFocusOut ? "True" : "False");
1699 if ( !cbw->combobox.IgnoreFocusOut )
1700 ShowHideDropDownList(cbw, &(cbw->combobox.xevent), False);
1701 cbw->combobox.IgnoreFocusOut = False;
1702 cbw->combobox.PendingFocusOut = False;
1703 return True; /* diese Routine wird nicht mehr benoetigt. */
1704 } /* DelayedFocusOutWorkProc */
1705
1706 static void EditFocusCallback(Widget w, XtPointer pClientData,
1707 XmAnyCallbackStruct *info)
1708 {
1709 XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w);
1710
1711 if ( cbw->combobox.StaticList ) return;
1712
1713 if ( info->reason == XmCR_LOSING_FOCUS ) {
1714 LOG2("EditFocusCallback: PendingFocusOut: %s, ",
1715 cbw->combobox.PendingFocusOut ? "True" : "False");
1716 LOG3("mode: %i, detail: %i, ", (int)info->event->xcrossing.mode,
1717 (int)info->event->xcrossing.detail);
1718 LOG2("PendingOverrideInOut: %s\n",
1719 cbw->combobox.PendingOverrideInOut ? "True" : "False");
1720 if ( !cbw->combobox.PendingFocusOut &&
1721 !cbw->combobox.PendingOverrideInOut ) {
1722 /* Normalerweise duerfen aber keine NULL-Events hier
1723 * vorbeikommen...aber man weiss ja nie so genau und
1724 * sicher ist sicher. Defensiv programmieren!
1725 */
1726 if ( info->event )
1727 cbw->combobox.xevent = *info->event;
1728 cbw->combobox.WorkProcID = XtAppAddWorkProc(
1729 XtWidgetToApplicationContext((Widget) cbw),
1730 (XtWorkProc) DelayedFocusOutWorkProc,
1731 (XtPointer) cbw);
1732 cbw->combobox.PendingFocusOut = True;
1733 }
1734 cbw->combobox.PendingOverrideInOut = False;
1735 }
1736 } /* EditFocusCallback */
1737
1738 /* --------------------------------------------------------------------
1739 * Hier wird der angegebene Eintrag in der Listbox der Combo-Box
1740 * markiert und zudem in den sichtbaren Bereich gerollt, sollte er
1741 * sich ausserhalb des dargestellten Bereichs der Liste befinden.
1742 * Parameter:
1743 * w Die Combo-Box (ueblicher Parameter)
1744 * Index Index des neu zu markierenden Eintrages.
1745 * Notify Schickt Mitteilung via Callback
1746 * Ergebnis:
1747 * Index des markierten Eintrages oder 0, falls die Listbox leer
1748 * war und deshalb auch kein Eintrag markiert werden konnte.
1749 */
1750 static int SetSelectionPos(XmComboBoxWidget w, int Index, Boolean Notify)
1751 {
1752 Widget ListBox = w->combobox.ListCtrl;
1753 int ItemCount; /* Anzahl Eintraege in Listbox */
1754 int TopItem, VisibleItems;
1755
1756 XtVaGetValues(ListBox, XmNitemCount, &ItemCount,
1757 XmNtopItemPosition, &TopItem,
1758 XmNvisibleItemCount, &VisibleItems,
1759 NULL);
1760 if ( Index < 1 ) Index = 1;
1761 if ( Index > ItemCount ) Index = ItemCount;
1762 if ( Index != 0 && ItemCount != 0 ) {
1763 if ( Index < TopItem )
1764 XmListSetPos(ListBox, Index);
1765 if ( Index >= TopItem + VisibleItems )
1766 XmListSetBottomPos(ListBox, Index);
1767 XmListSelectPos(ListBox, Index, Notify);
1768 return Index;
1769 } else
1770 return 0;
1771 } /* SetSelectionPos */
1772
1773 /* --------------------------------------------------------------------
1774 * Diese Routine kuemmert sich darum, denjenigen Eintrag aus der List-
1775 * box mit der angegebenen Nummer herauszufischen und an die Eingabe-
1776 * zeile zu uebergeben. Dabei wird der Index auf den Eintrag auto-
1777 * matisch auf den zulaessigen Bereich begrenzt. Zugleich wird auch
1778 * noch der angegebene Eintrag in der Listbox markiert.
1779 */
1780 static void TransferToEditCtrl(XmComboBoxWidget w, int SelectionIndex,
1781 Boolean MayWipeOut)
1782 {
1783 Widget ListBox = w->combobox.ListCtrl;
1784 XmStringTable Items;
1785 char *pItemText;
1786
1787 XtVaGetValues(ListBox, XmNitems, &Items, NULL);
1788
1789 if ( MayWipeOut &&
1790 (SelectionIndex == w->combobox.LastSelection) &&
1791 (w->combobox.SelectionPolicy == XmSINGLE_SELECT) ) {
1792 SelectionIndex = 0;
1793 }
1794
1795 if ( (SelectionIndex == 0) &&
1796 (w->combobox.SelectionPolicy == XmSINGLE_SELECT) ) {
1797 XmListDeselectAllItems(w->combobox.ListCtrl);
1798 w->combobox.PassVerification = True;
1799 XmTextFieldSetString(w->combobox.EditCtrl, "");
1800 } else {
1801 SelectionIndex = SetSelectionPos(w, SelectionIndex, False);
1802 if ( SelectionIndex > 0 ) {
1803 XmStringGetLtoR(Items[SelectionIndex-1],
1804 XmSTRING_DEFAULT_CHARSET, &pItemText);
1805 w->combobox.PassVerification = True;
1806 XmTextFieldSetString(w->combobox.EditCtrl, pItemText);
1807 XtFree(pItemText);
1808 }
1809 }
1810 w->combobox.LastSelection = SelectionIndex;
1811 } /* TransferToEditCtrl */
1812
1813 /* --------------------------------------------------------------------
1814 * Alle registrierten Callbacks bei Anwahl eines neuen Eintrages in
1815 * der Listbox aktivieren.
1816 */
1817 static void CallSelectionCBL(XmComboBoxWidget w, XEvent *Event)
1818 {
1819 int index;
1820
1821 index = XmComboBoxGetSelectedPos((Widget) w);
1822 /*
1823 * Wenn momentan KEIN Eintrag selektiert ist, dann rufe den neuen
1824 * XmNunselectionCallback auf!
1825 */
1826 if ( index == 0 ) {
1827 XmComboBoxUnselectionCallbackStruct info;
1828
1829 info.reason = XmCR_UNSELECT;
1830 info.event = Event;
1831 XtCallCallbacks((Widget) w, XmNunselectionCallback, (XtPointer) &info);
1832 } else {
1833 /*
1834 * Ansonsten den ueblichen SelectionCallback!
1835 */
1836 XmComboBoxSelectionCallbackStruct info;
1837 XmStringTable Items;
1838
1839 info.reason = w->combobox.SelectionPolicy == XmSINGLE_SELECT ?
1840 XmCR_SINGLE_SELECT : XmCR_BROWSE_SELECT;
1841 info.event = Event;
1842 info.index = index;
1843 XtVaGetValues(w->combobox.ListCtrl, XmNitems, &Items, NULL);
1844 info.value = Items[info.index-1];
1845 XtCallCallbacks((Widget) w, XmNselectionCallback, (XtPointer) &info);
1846 }
1847 } /* CallSelectionCBL */
1848
1849 /* --------------------------------------------------------------------
1850 * Hier laeuft das Tastatur-Management fuer die ComboBox zusammen.
1851 * ACHTUNG: Der 'w'-Parameter wird nur benoetigt, um das eigentliche
1852 * ComboBox-Widget zu ermitteln. Er muss daher die ID eines direkten
1853 * Kinds der ComboBox enthalten!
1854 */
1855 static void CBoxManager(Widget w, XEvent *Event, String *params,
1856 Cardinal *num_params)
1857 {
1858 XmComboBoxWidget cbw;
1859 Widget ListBox;
1860 int *SelectionList;
1861 int SelectionCount;
1862 int SelectionIndex; /* Wer denn nun markiert wird... */
1863 int ItemCount; /* Anzahl Eintraege in Listbox */
1864 int VisibleItems; /* Hoehe der Liste in Eintraegen */
1865 char opt;
1866
1867 /*
1868 * Nur wenn eine der Translationen page-up und page-down direkt im
1869 * Listenfeld ausgeloest wurden, wird auch als "w" die Liste ueber-
1870 * geben. Bei allen anderen Faellen ist dieses zumeist das TextField.
1871 */
1872 if ( XtClass(w) == xmListWidgetClass )
1873 cbw = (XmComboBoxWidget) XtParent(XtParent(w));
1874 else
1875 cbw = (XmComboBoxWidget) XtParent(w);
1876 ListBox = cbw->combobox.ListCtrl;
1877
1878 switch ( *(params[0]) ) {
1879 /* --------------------------------------------------------------------
1880 * Klappe die Liste auf Wunsch des Benutzers aus oder wieder ein.
1881 */
1882 case 's': /* show-hide-list */
1883 ShowHideDropDownList(cbw, Event,
1884 (Boolean)(!cbw->combobox.ListVisible));
1885 break;
1886 case 'h': /* hide-list */
1887 ShowHideDropDownList(cbw, Event, False);
1888 break;
1889 /* --------------------------------------------------------------------
1890 * Hier werden die Bewegungen in der Listbox behandelt.
1891 */
1892 case 'u': /* up */
1893 case 'd': /* down */
1894 case 't': /* top */
1895 case 'b': /* bottom */
1896 case 'p': /* page-up/page-down */
1897 opt = *(params[0]);
1898 XtVaGetValues(ListBox, XmNitemCount, &ItemCount,
1899 XmNvisibleItemCount, &VisibleItems, NULL);
1900 if ( XmListGetSelectedPos(ListBox,
1901 &SelectionList, &SelectionCount) ) {
1902 SelectionIndex = *SelectionList;
1903 XtFree((char *)SelectionList);
1904 switch ( opt ) {
1905 case 'u': SelectionIndex--; break;
1906 case 'd': SelectionIndex++; break;
1907 case 't': SelectionIndex = 1; break;
1908 case 'b': SelectionIndex = ItemCount; break;
1909 case 'p': if ( *(params[0]+5) == 'u' )
1910 SelectionIndex -= VisibleItems;
1911 else
1912 SelectionIndex += VisibleItems;
1913 break;
1914 }
1915 } else { /* momentan noch kein Eintrag in der Liste ausgewaehlt */
1916 if ( opt == 'b' ) SelectionIndex = ItemCount;
1917 else SelectionIndex = 1; /* nun ersten Eintrag nehmen */
1918 }
1919 TransferToEditCtrl(cbw, SelectionIndex, False);
1920 CallSelectionCBL(cbw, Event);
1921 break;
1922 /* --------------------------------------------------------------------
1923 * Der Benutzer hat die Eingabetaste gedrueckt oder einen Eintrag in
1924 * der Listbox angeklickt.
1925 */
1926 case 'a': /* Return = activate */
1927 case 'S': /* Selection */
1928 if ( !cbw->combobox.StaticList && !cbw->combobox.ListVisible ) break;
1929 XtVaGetValues(ListBox, XmNitemCount, &ItemCount, NULL);
1930 if ( ItemCount == 0 ) break;
1931 if ( XmListGetSelectedPos(ListBox,
1932 &SelectionList, &SelectionCount) ) {
1933 SelectionIndex = *SelectionList;
1934 XtFree((char *)SelectionList);
1935 } else {
1936 if ( cbw->combobox.SelectionPolicy != XmSINGLE_SELECT )
1937 SelectionIndex = 1;
1938 else
1939 SelectionIndex = 0;
1940 }
1941
1942 TransferToEditCtrl(cbw, SelectionIndex,
1943 *(params[0]) == 'S');
1944 CallSelectionCBL(cbw, Event);
1945 ShowHideDropDownList(cbw, Event, (Boolean)
1946 (*(params[0]) == 'S' ? True : False));
1947 break;
1948 /* --------------------------------------------------------------------
1949 * Der Benutzer hat die ESC-Taste gedrueckt. Ist die Liste zu diesem
1950 * Zeitpunkt noch ausgeklappt, so wird sie einfach nur eingeklappt und
1951 * weiter passiert nichts. Ist die Liste jedoch eingeklappt, so wird
1952 * das ESC an die normale Action-Routine des Eingabefeldes weiter-
1953 * gegeben, damit damit bspw. Dialog u.a. abgebrochen werden koennen.
1954 */
1955 case 'c': /* Cancel */
1956 if ( cbw->combobox.ListVisible )
1957 ShowHideDropDownList(cbw, Event, False);
1958 else
1959 XtCallActionProc(cbw->combobox.EditCtrl,
1960 "process-cancel", Event, NULL, 0);
1961 break;
1962 /* --------------------------------------------------------------------
1963 * Wenn es erlaubt ist, dass auch einmal kein Eintrag in einer ComboBox
1964 * mit nicht editierbarem Eingabefeld ausgewaehlt ist, dann darf der
1965 * Anwender mittels osfDelete den aktuellen Eintrag deselektieren.
1966 */
1967 case 'w': /* wipe */
1968 if ( cbw->combobox.SelectionPolicy == XmSINGLE_SELECT ) {
1969 TransferToEditCtrl(cbw, 0, True);
1970 CallSelectionCBL(cbw, Event);
1971 }
1972 break;
1973 /* --------------------------------------------------------------------
1974 * Dummy-Operation
1975 */
1976 case 'n': /* no-operation */
1977 break;
1978 }
1979 } /* CBoxManager */
1980
1981 /* --------------------------------------------------------------------
1982 * Der Benutzer hat einen Eintrag in der Listbox angeklickt. Der Ein-
1983 * fachkeit halber wird einfach nur ein Druecken der Eingabetaste
1984 * simuliert.
1985 */
1986 static void ListSelectionCallback(Widget w, XtPointer pClientData,
1987 XmAnyCallbackStruct *info)
1988 {
1989 String paramsMouse[1] = { "a" }, paramsKeyboard[1] = { "S" };
1990 Cardinal NumParams = 1;
1991 XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
1992 /*
1993 * Wurde der Event durch die Tastatur oder einen Mausklick
1994 * ausgeloest? Wenn es ein Mausklick auf das Listenfeld war und es
1995 * sich um ein staendig angezeigtes Listenfeld einer nicht editierbaren
1996 * ComboBox handelt, dann gib' dem Eingabefeld den Tastaturfokus.
1997 */
1998 if ( info->event == NULL )
1999 CBoxManager(cbw->combobox.EditCtrl, info->event,
2000 paramsKeyboard, &NumParams);
2001 else {
2002 CBoxManager(cbw->combobox.EditCtrl, info->event,
2003 paramsMouse, &NumParams);
2004 if ( !cbw->combobox.StaticList ||
2005 (cbw->combobox.StaticList && !cbw->combobox.Editable) )
2006 XmProcessTraversal(cbw->combobox.EditCtrl,
2007 XmTRAVERSE_CURRENT);
2008 }
2009 } /* ListSelectionCallback */
2010
2011 /* --------------------------------------------------------------------
2012 * Nach einem Doppelklick innerhalb des Listenfelds wird diese Routine
2013 * aufgerufen. Zunaechst einmal wird ganz normal wie bei einem ein-
2014 * fachen Anklicken vorgegangen, danach aber noch der ein spezieller
2015 * Callback aufgerufen.
2016 */
2017 static void ListDefaultActionCallback(Widget w, XtPointer pClientData,
2018 XmAnyCallbackStruct *OldInfo)
2019 {
2020 XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
2021 XmComboBoxDefaultActionCallbackStruct info;
2022 XmStringTable Items;
2023
2024 ListSelectionCallback(w, pClientData, OldInfo);
2025 info.reason = XmCR_DEFAULT_ACTION;
2026 info.event = OldInfo->event;
2027 info.index = XmComboBoxGetSelectedPos((Widget) cbw);
2028 XtVaGetValues(cbw->combobox.ListCtrl, XmNitems, &Items, NULL);
2029 info.value = Items[info.index-1];
2030 XtCallCallbacks((Widget) cbw, XmNdefaultActionCallback, (XtPointer) &info);
2031 } /* ListDefaultActionCallback */
2032
2033
2034 /* --------------------------------------------------------------------
2035 * Ohweh!! Diese Routine wurde erforderlich, um XmNautomaticSelection
2036 * zu unterstuetzen. Denn wenn der Benutzer in der Liste herumsucht und
2037 * automaticSelection 'True' ist, kommt kein Callback-Aufruf mehr, wenn
2038 * die Maustaste losgelassen wird. Und damit wuessten wir sonst nicht,
2039 * wann die Liste einzuklappen ist! Irgendwie wird das alles mit der
2040 * Zeit immer konfuser und aufwendiger. Wenn das Chaos gequantelt
2041 * sein sollte, dann muss das Chaos-Quant (sog. 'Chaotonen') aber jede
2042 * Menge Chaos transportieren!!!
2043 */
2044 static void Button1UpInList(Widget w, XtPointer pClientData,
2045 XEvent *Event, Boolean *ContDispatch)
2046 {
2047 XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData;
2048
2049 if ( Event->xbutton.button == Button1 ) {
2050 if ( cbw->combobox.AutomaticSelection )
2051 ShowHideDropDownList(cbw, Event, False);
2052 }
2053 } /* Button1UpInList */
2054
2055 /* --------------------------------------------------------------------
2056 * Sobald sich irgendetwas im Eingabefeld veraenderte, kommt das
2057 * TextField-Widget zuerst zu uns gelaufen, um sich unser Okay zu
2058 * holen. Bei einer nicht editierbaren Combo-Box wird hierueber die
2059 * Schnellsuche realisiert.
2060 */
2061 static void EditVerifyCallback(Widget w, XtPointer pClientData,
2062 XmTextVerifyCallbackStruct *info)
2063 {
2064 XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w);
2065
2066 /*
2067 * Sollte gerade dem Eingabefeld Text aus der Listbox einverleibt
2068 * werden, so duerfen wir hier darueber natuerlich nicht meckern,
2069 * sondern unser <<ok>> dazu geben. (D.h. in diesem Fall haben wir
2070 * kein Recht, zu intervenieren.)
2071 */
2072 if ( cbw->combobox.PassVerification ) {
2073 cbw->combobox.PassVerification = False;
2074 info->doit = True;
2075 return;
2076 }
2077 /*
2078 * Ist es eine Combo-Box, in die kein Text vom Benutzer eingegeben
2079 * werden kann, so wird bei der Eingabe von Zeichen die Schnellsuche
2080 * ausgeloest.
2081 */
2082 if ( !cbw->combobox.Editable ) {
2083 Widget ListBox = cbw->combobox.ListCtrl;
2084 char WarpCharLow, WarpCharHigh;
2085 XmString Item;
2086 XmStringTable Items;
2087 int *SelectionList;
2088 int SelectionCount;
2089 int i, ItemCount, Start, End;
2090 char *pItem;
2091 Boolean Ignore;
2092
2093 info->doit = False;
2094 if ( (info->text == NULL ) ||
2095 (info->text->length == 0 ) ) return; /* Hoppala! */
2096 /*
2097 * Nun aus dem Zeichen einen String (Motif-like) basteln und
2098 * in der Listbox danach auf die Suche gehen.
2099 */
2100 if ( info->text->length > 1 ) {
2101 /* Das ist nun endweder ein normaler Paste, oder aber
2102 * das Ergebnis einer Drag'n'Drop-Operation.
2103 */
2104 Item = XmStringCreateSimple(info->text->ptr);
2105 XmComboBoxSelectItem((Widget) cbw, Item, True);
2106 XmStringFree(Item);
2107 } else {
2108 /* Ansonsten soll nur eine Schnellsuche ausgefuehrt
2109 * werden, der entsprechende Buchstabe ist das einzige
2110 * Zeichen im dem Callback uebergebenen Text.
2111 */
2112 WarpCharLow = tolower(*(info->text->ptr));
2113 WarpCharHigh = toupper(WarpCharLow);
2114
2115 XtVaGetValues(ListBox, XmNitemCount, &ItemCount,
2116 XmNitems, &Items,
2117 NULL);
2118 if ( ItemCount < 1 ) return;
2119 /* Ermittele, wo's los geht mit der Suche... */
2120 if ( XmListGetSelectedPos(ListBox,
2121 &SelectionList, &SelectionCount) ) {
2122 Start = *SelectionList; i = Start + 1;
2123 XtFree((char *)SelectionList);
2124 } else i = Start = 1;
2125
2126 if ( i > ItemCount ) i = 1;
2127 Ignore = True;
2128 while ( i != Start || Ignore ) {
2129 Ignore = False;
2130 XmStringGetLtoR(Items[i-1], XmSTRING_DEFAULT_CHARSET,
2131 &pItem);
2132 if ( (strchr(pItem, WarpCharLow ) == pItem) ||
2133 (strchr(pItem, WarpCharHigh) == pItem) ) {
2134 XtFree(pItem);
2135 TransferToEditCtrl(cbw, i, False);
2136 CallSelectionCBL(cbw, info->event);
2137 break;
2138 }
2139 XtFree(pItem);
2140 if ( ++i > ItemCount ) i = 1;
2141 }
2142 }
2143 } else {
2144 /*
2145 * Wenn das Eingabefeld editierbar ist, dann fragen wir ueber die Callbacks
2146 * nach, ob es genehm ist, den neuen Text einzufuegen.
2147 */
2148 XtCallCallbacks((Widget) cbw, XmNmodifyVerifyCallback,
2149 (XtPointer) info);
2150 }
2151 } /* EditVerifyCallback */
2152
2153 /* --------------------------------------------------------------------
2154 * Dieser Callback wird immer dann aufgerufen, wenn in einer ComboBox
2155 * mit einem veraenderlichem Eingabefeld der Eingabetext veraendert
2156 * wurde. In diesem Fall suchen wir hier nach einem passenden gleich-
2157 * lautenden Eintrag. Wenn wir einen finden, heben wir ihn in der Liste
2158 * sogleich hervor, ansonsten ist kein Eintrag hervorgehoben.
2159 */
2160 static void EditChangedCallback(Widget w, XtPointer pClientDate,
2161 XmAnyCallbackStruct *info)
2162 {
2163 XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w);
2164 XmStringTable Items;
2165 int ItemCount, i;
2166 XmString EditStr;
2167 String EditLine;
2168
2169 /*
2170 * Zuerst nach einem passenden Eintrag zum Eingabefeld in der Liste
2171 * suchen...
2172 */
2173 XtVaGetValues(cbw->combobox.EditCtrl, XmNvalue, &EditLine, NULL);
2174 XtVaGetValues(cbw->combobox.ListCtrl,
2175 XmNitemCount, &ItemCount,
2176 XmNitems, &Items,
2177 NULL);
2178 EditStr = XmStringCreateSimple(EditLine);
2179 XtVaSetValues(cbw->combobox.ListCtrl, XmNselectedItemCount, 0, NULL);
2180 if ( ItemCount < 1 ) return;
2181 for ( i = 0; i < ItemCount; i++ )
2182 if ( XmStringCompare(Items[i], EditStr) ) {
2183 SetSelectionPos(cbw, i+1, False);
2184 break;
2185 }
2186 XmStringFree(EditStr);
2187 /*
2188 * Zum Abschluss noch den Callback aufrufen...
2189 */
2190 XtCallCallbacks((Widget) cbw, XmNvalueChangedCallback, (XtPointer) info);
2191 } /* EditChangedCallback */
2192
2193 /* --------------------------------------------------------------------
2194 * Dieser Callback wird immer dann aufgerufen, wenn in einer ComboBox
2195 * mit einem veraenderlichem Eingabefeld der Cursor bewegt wurde.
2196 * Dieser Callback ist nur fuer echte Fans von Callbacks da...
2197 */
2198 static void MotionVerifyCallback(Widget w, XtPointer pClientDate,
2199 XmTextVerifyCallbackStruct *info)
2200 {
2201 XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w);
2202
2203 XtCallCallbacks((Widget) cbw, XmNmotionVerifyCallback, (XtPointer) info);
2204 } /* MotionVerifyCallback */
2205
2206 /* --------------------------------------------------------------------
2207 * Bastele einen vollstaendigen Namens- und Klassenbezeichner anhand
2208 * des angegebenen Widgets zusammen.
2209 */
2210 static void MakeNameAndClass(Widget w, char *NameBuff, char *ClassBuff)
2211 {
2212 Widget Parent = XtParent(w);
2213
2214 if ( Parent ) MakeNameAndClass(Parent, NameBuff, ClassBuff);
2215 if ( XtIsSubclass(w, applicationShellWidgetClass) ) {
2216 /* Wenn wir ganz oben angekommen sind, holen wir uns den
2217 * Namen und die Klasse der Applikation selbst und nicht die
2218 * des Widgets.
2219 */
2220 String AppName, AppClass;
2221 XtGetApplicationNameAndClass(
2222 XtDisplayOfObject(w), &AppName, &AppClass);
2223 strcpy(NameBuff, AppName);
2224 strcpy(ClassBuff, AppClass);
2225 } else {
2226 /* Ansonsten sind wir noch mitten irgendwo in der Hierarchie
2227 * und besorgen uns den Namen und die Klasse dieses Widgets
2228 */
2229 strcat(NameBuff, ".");
2230 strcat(NameBuff, XtName(w));
2231 strcat(ClassBuff, ".");
2232 strcat(ClassBuff, ((CoreClassRec *) XtClass(w))->core_class.class_name);
2233 }
2234 } /* MakeNameAndClass */
2235
2236 /* --------------------------------------------------------------------
2237 * Eine einzelne Resource aus der Datenbank herausholen. Diese Resource
2238 * kommt im Allgemeinen immer als String zurueck und muss daher erst
2239 * noch in das gewuenschte Zielformat konvertiert werden.
2240 */
2241 static Boolean FetchResource(Widget w,
2242 char *FullName, char *FullClass,
2243 char *RscName, char *RscClass,
2244 XrmValue *RscValue,
2245 String *RepresentationType)
2246 {
2247 Boolean ok;
2248 char *EndOfName = FullName + strlen(FullName);
2249 char *EndOfClass = FullClass + strlen(FullClass);
2250
2251 strcat(FullName, "."); strcat(FullName, RscName);
2252 strcat(FullClass, "."); strcat(FullClass, RscClass);
2253 ok = XrmGetResource(
2254 XtDatabase(XtDisplayOfObject(w)),
2255 FullName, FullClass, RepresentationType, RscValue);
2256 /* Wieder den alten Namens- und Klassenrumpf herstellen */
2257 *EndOfName = 0; *EndOfClass = 0;
2258 return ok;
2259 } /* FetchResource */
2260
2261 /* --------------------------------------------------------------------
2262 * Nun folgen diejenigen Routinen, mit denen die Konvertierung in das
2263 * gewuenschte Zielformat einer Resource moeglich ist.
2264 * Verfuegbar:
2265 * String --> Int
2266 * String --> Short
2267 * String XmPIXMAP / XmSTRING --> unsigned char
2268 * String --> Dimension
2269 * String --> XmString
2270 * String --> XmStringTable
2271 * String --> XmFontList
2272 * String --> Pixmap (genauer: Bitmap)
2273 * String --> String
2274 * String --> KeySym
2275 */
2276 static Boolean FetchIntResource(Widget w,
2277 char *FullName, char *FullClass,
2278 char *RscName, char *RscClass,
2279 int *pInt)
2280 {
2281 XrmValue RscValue, RscDest;
2282 String RepresentationType;
2283
2284 if ( FetchResource(w, FullName, FullClass,
2285 RscName, RscClass,
2286 &RscValue, &RepresentationType) ) {
2287 RscDest.size = sizeof(int);
2288 RscDest.addr = (caddr_t) pInt;
2289 if ( XtConvertAndStore(w, RepresentationType, &RscValue,
2290 XtRInt, &RscDest) )
2291 return True;
2292 }
2293 return False;
2294 } /* FetchIntResource */
2295
2296 static Boolean FetchShortResource(Widget w,
2297 char *FullName, char *FullClass,
2298 char *RscName, char *RscClass,
2299 short *pShort)
2300 {
2301 XrmValue RscValue, RscDest;
2302 String RepresentationType;
2303
2304 if ( FetchResource(w, FullName, FullClass,
2305 RscName, RscClass,
2306 &RscValue, &RepresentationType) ) {
2307 RscDest.size = sizeof(short);
2308 RscDest.addr = (caddr_t) pShort;
2309 if ( XtConvertAndStore(w, RepresentationType, &RscValue,
2310 XtRShort, &RscDest) )
2311 return True;
2312 }
2313 return False;
2314 } /* FetchShortResource */
2315
2316 static Boolean FetchLabelTypeResource(Widget w,
2317 char *FullName, char *FullClass,
2318 char *RscName, char *RscClass,
2319 unsigned char *pUChar)
2320 {
2321 XrmValue RscValue, RscDest;
2322 String RepresentationType;
2323 int AInt;
2324
2325 if ( FetchResource(w, FullName, FullClass,
2326 RscName, RscClass,
2327 &RscValue, &RepresentationType) ) {
2328 if ( strcasecmp((char *) RscValue.addr, "XmPIXMAP") == 0 )
2329 *pUChar = XmPIXMAP;
2330 else
2331 *pUChar = XmSTRING;
2332 return True;
2333 }
2334 return False;
2335 } /* FetchLabelTypeResource */
2336
2337 static Boolean FetchDimensionResource(Widget w,
2338 char *FullName, char *FullClass,
2339 char *RscName, char *RscClass,
2340 Dimension *pDimension)
2341 {
2342 XrmValue RscValue, RscDest;
2343 String RepresentationType;
2344
2345 if ( FetchResource(w, FullName, FullClass,
2346 RscName, RscClass,
2347 &RscValue, &RepresentationType) ) {
2348 RscDest.size = sizeof(Dimension);
2349 RscDest.addr = (caddr_t) pDimension;
2350 if ( XtConvertAndStore(w, RepresentationType, &RscValue,
2351 XtRDimension, &RscDest) )
2352 return True;
2353 }
2354 return False;
2355 } /* FetchDimensionResource */
2356
2357 static Boolean FetchStringResource(Widget w,
2358 char *FullName, char *FullClass,
2359 char *RscName, char *RscClass,
2360 String *pString)
2361 {
2362 XrmValue RscValue;
2363 String RepresentationType;
2364
2365 if ( FetchResource(w, FullName, FullClass,
2366 RscName, RscClass,
2367 &RscValue, &RepresentationType) ) {
2368 *pString = (char *) RscValue.addr;
2369 return True;
2370 }
2371 return False;
2372 } /* FetchStringResource */
2373
2374 static Boolean FetchKeySymResource(Widget w,
2375 char *FullName, char *FullClass,
2376 char *RscName, char *RscClass,
2377 KeySym *pKeySym)
2378 {
2379 XrmValue RscValue, RscDest;
2380 String RepresentationType;
2381
2382 if ( FetchResource(w, FullName, FullClass,
2383 RscName, RscClass,
2384 &RscValue, &RepresentationType) ) {
2385 RscDest.size = sizeof(KeySym);
2386 RscDest.addr = (caddr_t) pKeySym;
2387 if ( XtConvertAndStore(w, RepresentationType, &RscValue,
2388 XmRKeySym, &RscDest) )
2389 return True;
2390 }
2391 return False;
2392 } /* FetchKeySymResource */
2393
2394 static Boolean FetchXmStringResource(Widget w,
2395 char *FullName, char *FullClass,
2396 char *RscName, char *RscClass,
2397 XmString *pString)
2398 {
2399 XrmValue RscValue;
2400 String RepresentationType;
2401
2402 if ( FetchResource(w, FullName, FullClass,
2403 RscName, RscClass,
2404 &RscValue, &RepresentationType) ) {
2405 *pString = XmCvtCTToXmString((char *) RscValue.addr);
2406 return True;
2407 }
2408 return False;
2409 } /* FetchXmStringResource */
2410
2411 static Boolean FetchXmStringTableResource(Widget w,
2412 char *FullName, char *FullClass,
2413 char *RscName, char *RscClass,
2414 XmStringTable *pStringTable,
2415 int *pTableSize)
2416 {
2417 XrmValue RscValue;
2418 String RepresentationType;
2419 String TmpList, p, pStart;
2420 int Entries, Entry;
2421
2422 if ( FetchResource(w, FullName, FullClass,
2423 RscName, RscClass,
2424 &RscValue, &RepresentationType) ) {
2425 /*
2426 * Zuerst eine Kopie erzeugen und dann daraus die Liste
2427 * zusammenbasteln.
2428 */
2429 TmpList = XtNewString((String)RscValue.addr);
2430 if ( TmpList == NULL ) return False;
2431 if ( *TmpList == 0 ) { XtFree(TmpList); return False; }
2432 /* Ermittele, wieviele Eintrage in der Liste sind und
2433 * erstelle dann daraus die Liste.
2434 */
2435 Entries = 1; p = TmpList;
2436 while ( *p )
2437 if ( *p++ == ',' ) ++Entries;
2438 *pStringTable = (XmStringTable)
2439 XtMalloc(Entries * sizeof(XmString));
2440
2441 p = TmpList;
2442 for ( Entry = 0; Entry < Entries; ++Entry ) {
2443 pStart = p;
2444 while ( (*p != 0) && (*p != ',') ) ++p;
2445 *p++ = 0;
2446 (*pStringTable)[Entry] = (XmString)
2447 XmStringCreateSimple(pStart);
2448 }
2449 /* Hier geht ausnahmsweise einmal Rueckgabe vor
2450 * Entschaedigung... hey, das war doch nur ein
2451 * (wenn auch ziemlich miserabler) Scherz
2452 */
2453 XtFree(TmpList);
2454 *pTableSize = Entries;
2455 return True;
2456 }
2457 return False;
2458 } /* FetchXmStringTableResource */
2459
2460 static Boolean FetchXmFontListResource(Widget w,
2461 char *FullName, char *FullClass,
2462 char *RscName, char *RscClass,
2463 XmFontList *pFontList)
2464 {
2465 XrmValue RscValue, RscDest;
2466 String RepresentationType;
2467
2468 if ( FetchResource(w, FullName, FullClass,
2469 RscName, RscClass,
2470 &RscValue, &RepresentationType) ) {
2471 RscDest.size = sizeof(XmFontList);
2472 RscDest.addr = (caddr_t) pFontList;
2473 if ( XtConvertAndStore(w, RepresentationType, &RscValue,
2474 XmRFontList, &RscDest) )
2475 return True;
2476 }
2477 return False;
2478 } /* FetchXmFontListResource */
2479
2480 static Boolean FetchPixmapResource(Widget w,
2481 char *FullName, char *FullClass,
2482 char *RscName, char *RscClass,
2483 Pixmap *pPixmap)
2484 {
2485 XrmValue RscValue, RscDest;
2486 String RepresentationType;
2487
2488 if ( FetchResource(w, FullName, FullClass,
2489 RscName, RscClass,
2490 &RscValue, &RepresentationType) ) {
2491 RscDest.size = sizeof(Pixmap);
2492 RscDest.addr = (caddr_t) pPixmap;
2493 if ( XtConvertAndStore(w, RepresentationType, &RscValue,
2494 XtRBitmap, &RscDest) )
2495 return True;
2496 }
2497 return False;
2498 } /* FetchPixmapResource */
2499
2500 /* --------------------------------------------------------------------
2501 * Waehrend der Initialisierung alle gespiegelten Resourcen, fuer die
2502 * Eintraege in der Resourcen-Datenbank existieren an die passenden
2503 * Kinder-Widgets weiterleiten. Der Trick an der Sache: wir setzen
2504 * die betroffenen Resourcen vie XtSetValues mit uns selbst als Ziel.
2505 * Dadurch bekommt SetValues die Arbeit aufgehalst, die Resourcen den
2506 * richtigen Kindern zuzuordnen...
2507 */
2508
2509 #define RInt 0
2510 #define RShort 1
2511 #define RLType 2
2512 #define RDimension 3
2513 #define RXmString 4
2514 #define RPixmap 5
2515 #define RXmFontList 6
2516 #define RKeySym 7
2517 #define RString 8
2518 #define RXmStringTable 9
2519 #define RXmItemCount 10
2520
2521
2522 typedef struct
2523 {
2524 String Name, Class;
2525
2526 int Converter;
2527
2528 } RESOURCEMIRROR;
2529
2530 static RESOURCEMIRROR ResourceMirror[] = {
2531 { XmNblinkRate, XmCBlinkRate, RInt, },
2532 { XmNcolumns, XmCColumns, RShort, },
2533 { XmNmaxLength, XmCMaxLength, RInt, },
2534 { XmNmarginHeight, XmCMarginHeight, RDimension },
2535 { XmNmarginWidth, XmCMarginWidth, RDimension },
2536 { XmNselectThreshold, XmCSelectThreshold, RInt },
2537
2538 { XmNlistMarginHeight, XmCListMarginHeight, RDimension },
2539 { XmNlistMarginWidth, XmCListMarginWidth, RDimension },
2540 { XmNlistSpacing, XmCListSpacing, RDimension },
2541 { XmNitems, XmCItems, RXmStringTable },
2542 { XmNitemCount, XmCItemCount, RXmItemCount },
2543
2544 { XmNmnemonic, XmCMnemonic, RKeySym },
2545 { XmNmnemonicCharSet, XmCMnemonicCharSet, RString },
2546 { XmNlabelString, XmCLabelString, RXmString },
2547 { XmNlabelMarginBottom, XmCLabelMarginBottom, RDimension },
2548 { XmNlabelMarginHeight, XmCLabelMarginHeight, RDimension },
2549 { XmNlabelMarginLeft, XmCLabelMarginLeft, RDimension },
2550 { XmNlabelMarginRight, XmCLabelMarginRight, RDimension },
2551 { XmNlabelMarginTop, XmCLabelMarginTop, RDimension },
2552 { XmNlabelMarginWidth, XmCLabelMarginWidth, RDimension },
2553 { XmNlabelPixmap, XmCLabelPixmap, RPixmap },
2554 { XmNlabelInsensitivePixmap, XmCLabelInsensitivePixmap, RPixmap },
2555 { XmNlabelType, XmCLabelType, RLType },
2556 { XmNlabelFontList, XmCLabelFontList, RXmFontList },
2557 };
2558
2559 static void InitMirrorResources(XmComboBoxWidget w)
2560 {
2561 char FullName[1024], FullClass[1024];
2562 int AInt, TableSize;
2563 short AShort;
2564 unsigned char AUChar;
2565 Dimension ADimension;
2566 XmString AXmString;
2567 XmStringTable AStringTable;
2568 Pixmap APixmap;
2569 XmFontList AFontList;
2570 XrmValue RscValue;
2571 String AString;
2572 KeySym AKeySym;
2573 int i, size = XtNumber(ResourceMirror);
2574
2575 FullName[0] = 0; FullClass[0] = 0;
2576 MakeNameAndClass((Widget) w, FullName, FullClass);
2577
2578 for ( i=0; i < size; i++ ) {
2579 switch ( ResourceMirror[i].Converter ) {
2580 case RInt:
2581 if ( FetchIntResource((Widget) w,
2582 FullName, FullClass,
2583 ResourceMirror[i].Name, ResourceMirror[i].Class,
2584 &AInt) )
2585 XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2586 AInt, NULL);
2587 break;
2588 case RXmItemCount:
2589 if ( FetchIntResource((Widget) w,
2590 FullName, FullClass,
2591 ResourceMirror[i].Name, ResourceMirror[i].Class,
2592 &AInt) && ( AInt != 0) )
2593 XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2594 AInt, NULL);
2595 break;
2596 case RShort:
2597 if ( FetchShortResource((Widget) w,
2598 FullName, FullClass,
2599 ResourceMirror[i].Name, ResourceMirror[i].Class,
2600 &AShort) )
2601 XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2602 AShort, NULL);
2603 break;
2604 case RLType:
2605 if ( FetchLabelTypeResource((Widget) w,
2606 FullName, FullClass,
2607 ResourceMirror[i].Name, ResourceMirror[i].Class,
2608 &AUChar) )
2609 XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2610 AUChar, NULL);
2611 break;
2612 case RDimension:
2613 if ( FetchDimensionResource((Widget) w,
2614 FullName, FullClass,
2615 ResourceMirror[i].Name, ResourceMirror[i].Class,
2616 &ADimension) )
2617 XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2618 ADimension, NULL);
2619 break;
2620 case RXmString:
2621 if ( FetchXmStringResource((Widget) w,
2622 FullName, FullClass,
2623 ResourceMirror[i].Name, ResourceMirror[i].Class,
2624 &AXmString) )
2625 XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2626 AXmString, NULL);
2627 break;
2628 case RXmStringTable:
2629 if ( FetchXmStringTableResource((Widget) w,
2630 FullName, FullClass,
2631 ResourceMirror[i].Name, ResourceMirror[i].Class,
2632 &AStringTable, &TableSize) ) {
2633 XtVaSetValues((Widget) w,
2634 XmNitems, (XtPointer) AStringTable,
2635 XmNitemCount, TableSize, NULL);
2636 }
2637 break;
2638 case RKeySym:
2639 if ( FetchKeySymResource((Widget) w,
2640 FullName, FullClass,
2641 ResourceMirror[i].Name, ResourceMirror[i].Class,
2642 &AKeySym) )
2643 XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2644 AKeySym, NULL);
2645 break;
2646 case RString:
2647 if ( FetchStringResource((Widget) w,
2648 FullName, FullClass,
2649 ResourceMirror[i].Name, ResourceMirror[i].Class,
2650 &AString) )
2651 XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2652 AString, NULL);
2653 break;
2654 case RPixmap:
2655 if ( FetchPixmapResource((Widget) w,
2656 FullName, FullClass,
2657 ResourceMirror[i].Name, ResourceMirror[i].Class,
2658 &APixmap) ) {
2659 XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2660 APixmap, NULL);
2661 if ( strcmp(ResourceMirror[i].Name, XmNlabelPixmap) == 0 )
2662 w->combobox.ConvertBitmapToPixmap = True;
2663 else
2664 w->combobox.ConvertBitmapToPixmapInsensitive = True;
2665 }
2666 break;
2667 case RXmFontList:
2668 if ( FetchXmFontListResource((Widget) w,
2669 FullName, FullClass,
2670 ResourceMirror[i].Name, ResourceMirror[i].Class,
2671 &AFontList) )
2672 XtVaSetValues((Widget) w, ResourceMirror[i].Name,
2673 AFontList, NULL);
2674 break;
2675 }
2676 }
2677 } /* InitMirrorResources */
2678
2679 /* --------------------------------------------------------------------
2680 * Wandelt ein 1-Bit tiefes Bitmap in ein n-Bit tiefes Pixmap um, dass
2681 * die gleiche Tiefe besitzt, wie der Bildschirm, auf dem das Pixmap
2682 * spaeter erscheinen soll.
2683 */
2684 static Pixmap BitmapToPixmap(XmComboBoxWidget w,
2685 String Resource, GC ColorGC)
2686 {
2687 Pixmap LabelPixmap, LabelBitmap;
2688 Display *display = XtDisplay(w);
2689 Window root;
2690 int PixX, PixY;
2691 unsigned int PixW, PixH, PixBW, PixDepth;
2692
2693 XtVaGetValues(w->combobox.LabelCtrl, Resource, &LabelBitmap, NULL);
2694 XGetGeometry(display, LabelBitmap, &root,
2695 &PixX, &PixY, &PixW, &PixH, &PixBW, &PixDepth);
2696 LabelPixmap = XCreatePixmap(
2697 display, RootWindowOfScreen(XtScreen(w)),
2698 PixW, PixH,
2699 (w->combobox.LabelCtrl)->core.depth);
2700 XCopyPlane(display, LabelBitmap, LabelPixmap,
2701 ColorGC, 0, 0, PixW, PixH, 0, 0, 1);
2702 XtVaSetValues(w->combobox.LabelCtrl, Resource, LabelPixmap, NULL);
2703 XFreePixmap(display, LabelBitmap);
2704 return LabelPixmap;
2705 } /* BitmapToPixmap */
2706
2707 /* --------------------------------------------------------------------
2708 * Alles initialisieren, sobald das Widget eingerichtet wird. Das sagt
2709 * sich hier so einfach, ist es aber *definitiv* nicht!!!!
2710 */
2711 static void Initialize(Widget request, XmComboBoxWidget newW,
2712 ArgList wargs, Cardinal *ArgCount)
2713 {
2714 Dimension width, height, dummy;
2715 Widget w;
2716 Arg args[10];
2717 int n = 0;
2718 XmString xmstr;
2719 Pixel BackgroundColor;
2720
2721 /*
2722 * Da zu allem Ueberfluss die einzelnen Instanzen einer XmComboBox
2723 * auf verschiedenen Displays auftauchen koennen, wird hier:
2724 * 1. pro Widget ein eigener Cursor erzeugt (benoetigt fuer die Liste)
2725 * 2. pro Widget (hier = pro Applikation) die benoetigte Action-Routine
2726 * registiert. Doppelte Registrierung macht dem Toolkit nichts aus, da es
2727 * dann eine evtl. aeltere Definition loescht.
2728 */
2729 XtAppAddActions(XtWidgetToApplicationContext((Widget) newW),
2730 actions, XtNumber(actions));
2731
2732 /* Allgemeine Initialisierungen... */
2733 newW->combobox.ConvertBitmapToPixmap = False;
2734 newW->combobox.ConvertBitmapToPixmapInsensitive = False;
2735
2736 newW->combobox.LastSelection = 0;
2737
2738 newW->combobox.InInit = True;
2739
2740 /*
2741 * Das folgende Problem mit der Kontrolle, ob sich das Widget absolut auf
2742 * dem Bildschirm verschoben hat, trifft uns nur, wenn die Liste nicht
2743 * dauernd auf dem Bildschirm erscheint:
2744 * Lass' dich benachrichtigen, sobald dieses Widget in irgendeiner
2745 * Form bewegt wird -- und sei es nur, dass das gesamte Applikations-
2746 * fenster umhergeschoben wurde. Um die Benachrichtigung ueberhaupt
2747 * zu erreichen, ist es erforderlich, sich benachrichtigen zu lassen,
2748 * sobald die naechste Shell (oder ein Nachkomme) im Widget-Instanzen-
2749 * Baum verschoben wurde.
2750 */
2751 if ( !newW->combobox.StaticList ) {
2752 w = (Widget) newW;
2753 while ( !XtIsSubclass(w, shellWidgetClass) )
2754 w = XtParent(w);
2755 newW->combobox.MyNextShell = w;
2756 XtAddEventHandler(w,
2757 StructureNotifyMask | FocusChangeMask,
2758 False, (XtEventHandler) ShellCallback,
2759 (XtPointer) newW);
2760 }
2761
2762 /* Richte nun alle zu diesem Widget gehoerenden Kinder ein, als da
2763 * waeren:
2764 * 1 x editierbares Eingabefeld
2765 * 1 x ein Pfeil nach unten
2766 * 1 x ein Schriftfeld
2767 */
2768 newW->combobox.EditCtrl = XtVaCreateManagedWidget(
2769 "edit", xmTextFieldWidgetClass, (Widget) newW,
2770 XmNverifyBell, False,
2771 NULL);
2772 XtAddCallback(newW->combobox.EditCtrl,
2773 XmNlosingFocusCallback,
2774 (XtCallbackProc) EditFocusCallback, NULL);
2775 XtAddCallback(newW->combobox.EditCtrl,
2776 XmNmodifyVerifyCallback,
2777 (XtCallbackProc) EditVerifyCallback, NULL);
2778 XtAddCallback(newW->combobox.EditCtrl,
2779 XmNvalueChangedCallback,
2780 (XtCallbackProc) EditChangedCallback, NULL);
2781 XtAddCallback(newW->combobox.EditCtrl,
2782 XmNhelpCallback,
2783 (XtCallbackProc) HelpCallback,
2784 (XtPointer) newW);
2785 XtAddCallback(newW->combobox.EditCtrl,
2786 XmNactivateCallback,
2787 (XtCallbackProc) ActivateCallback,
2788 (XtPointer) newW);
2789 if ( newW->combobox.Editable )
2790 XtAddCallback(newW->combobox.EditCtrl,
2791 XmNmotionVerifyCallback,
2792 (XtCallbackProc) MotionVerifyCallback,
2793 (XtPointer) newW);
2794 /* Neue Translations fuer das Eingabefeld aufnehmen */
2795 XtOverrideTranslations(newW->combobox.EditCtrl,
2796 NewEditTranslations);
2797 if ( !newW->combobox.Editable ) {
2798 XtOverrideTranslations(newW->combobox.EditCtrl,
2799 NewEditTranslationsNE);
2800 XtVaSetValues(newW->combobox.EditCtrl,
2801 XmNcursorPositionVisible, False, NULL);
2802 }
2803 #ifdef NODRAGNDROP
2804 XtOverrideTranslations(newW->combobox.EditCtrl,
2805 NewListTranslations); /* Btn2Dwn aus! */
2806 #endif
2807
2808 /* --- */
2809 newW->combobox.ArrowCtrl = XtVaCreateManagedWidget(
2810 "arrow", xmArrowButtonWidgetClass, (Widget) newW,
2811 XmNarrowDirection, XmARROW_DOWN,
2812 XmNtraversalOn, False,
2813 XmNnavigationType, XmNONE,
2814 XmNborderWidth, 0,
2815 XmNhighlightThickness, 0,
2816 NULL);
2817 XmRemoveTabGroup(newW->combobox.ArrowCtrl);
2818 if ( newW->combobox.StaticList ) {
2819 XtVaSetValues(newW->combobox.ArrowCtrl,
2820 XmNmappedWhenManaged, False, NULL);
2821 } else {
2822 XtAddEventHandler(newW->combobox.ArrowCtrl,
2823 EnterWindowMask | LeaveWindowMask,
2824 False, (XtEventHandler) ArrowCrossingCallback,
2825 (XtPointer) newW);
2826 XtAddCallback(newW->combobox.ArrowCtrl,
2827 XmNactivateCallback,
2828 (XtCallbackProc) ArrowCallback, NULL);
2829 XtAddCallback(newW->combobox.ArrowCtrl,
2830 XmNarmCallback,
2831 (XtCallbackProc) ArrowCallback, NULL);
2832 XtAddCallback(newW->combobox.ArrowCtrl,
2833 XmNhelpCallback,
2834 (XtCallbackProc) HelpCallback,
2835 (XtPointer) newW);
2836 }
2837
2838 /* --- */
2839 newW->combobox.LabelCtrl = XtVaCreateWidget(
2840 "label", xmLabelWidgetClass, (Widget) newW,
2841 XmNstringDirection, newW->manager.string_direction,
2842 NULL);
2843 if ( newW->combobox.ShowLabel ) {
2844 XtManageChild((Widget) newW->combobox.LabelCtrl);
2845 XtAddCallback(newW->combobox.LabelCtrl,
2846 XmNhelpCallback,
2847 (XtCallbackProc) HelpCallback,
2848 (XtPointer) newW);
2849 }
2850
2851 /*
2852 * Zuerst noch die Shell erzeugen, die so einfach mir nichts dir nichts
2853 * frei auf dem Bildschirm herumschweben kann und damit das Ausklappen
2854 * der Liste erst ermoeglicht -- und uns allerhand Scherereien bereitet!
2855 * War das ein bloeder Fehler in Motif 1.2! Diese Version vertraegt ab-
2856 * solut keine ShellWidgetClass noch overrideShellWidgetClass!!!! Naja,
2857 * mit einer vendorShellWidgetClass laesst sich aber exakt der gleiche
2858 * Effekt erreichen. NEU: vor allem funktioniert dann endlich auch
2859 * Drag'n'Drop!!!
2860 * Noch neuer: Wenn die Liste dauerhaft angezeigt werden muss, entfaellt
2861 * diese Shell zwangslaeufig. Dann ist das Listenfeld ein direktes Kind
2862 * der ComboBox.
2863 */
2864 if ( !newW->combobox.StaticList ) {
2865 newW->combobox.PopupShell = XtVaCreateWidget(
2866 "combobox_shell", vendorShellWidgetClass, (Widget) newW,
2867 XmNoverrideRedirect, True,
2868 XmNsaveUnder, False,
2869 XmNallowShellResize, True,
2870 NULL);
2871 XtAddEventHandler(newW->combobox.PopupShell,
2872 EnterWindowMask | LeaveWindowMask,
2873 False, (XtEventHandler) OverrideShellCallback,
2874 (XtPointer) newW);
2875 } else {
2876 /*
2877 * Sieht ja pervers nach einer Rekursion aus...daher: OBACHT!
2878 */
2879 newW->combobox.PopupShell = (Widget) newW;
2880 }
2881
2882 /*
2883 * Nun kommt die Drop-Down-Liste an die Reihe. Die Liste muss dabei
2884 * mit einer Convenience-Funktion erstellt werden, damit ein Rollbalken
2885 * 'dran ist und das Ganze wird dann in eine Override-Shell gepackt.
2886 * Nicht zu vergessen ist der XtManageChild-Aufruf, damit die Liste
2887 * sofort nach dem Aufklappen der Shell sichtbar wird.
2888 */
2889 XtSetArg(args[n], XmNselectionPolicy, newW->combobox.SelectionPolicy); n++;
2890
2891 if ( !newW->combobox.StaticList ) {
2892 /*
2893 * Es gibt halt so eine ganze Reihe von Einstellungen, die koennen nicht
2894 * veraendert werden, wenn das Listenfeld nur bei Bedarf ausgeklappt wird.
2895 */
2896 XtSetArg(args[n], XmNhighlightThickness, 0); n++;
2897 }
2898 XtSetArg(args[n], XmNlistSizePolicy,
2899 newW->combobox.ListSizePolicy); n++;
2900 XtSetArg(args[n], XmNscrollBarDisplayPolicy,
2901 newW->combobox.ScrollBarDisplayPolicy); n++;
2902
2903 XtSetArg(args[n], XmNautomaticSelection,
2904 newW->combobox.AutomaticSelection); n++;
2905 XtSetArg(args[n], XmNvisibleItemCount,
2906 newW->combobox.VisibleItemCount); n++;
2907 newW->combobox.ListCtrl = XmCreateScrolledList(
2908 newW->combobox.PopupShell, "list",
2909 args, n);
2910
2911 /*
2912 * Fuer den Fall, dass die Liste in einer eigenen Shell steckt und daher frei
2913 * auf dem Bildschirm herumschweben kann, sollten wir sicherheitshalber die
2914 * Tastaturbedienung (Fokus) abschalten, um Probleme zu vermeiden (jedenfalls
2915 * hoffentlich...!)
2916 */
2917 if ( !newW->combobox.StaticList ) {
2918 XtVaSetValues(newW->combobox.ListCtrl,
2919 XmNtraversalOn, False, NULL);
2920 XtVaSetValues(XtParent(newW->combobox.ListCtrl),
2921 XmNtraversalOn, False, NULL);
2922 } else {
2923 if ( !newW->combobox.Editable ) {
2924 XtVaSetValues(XtParent(newW->combobox.ListCtrl),
2925 XmNtraversalOn, False, NULL);
2926 XmRemoveTabGroup(newW->combobox.ListCtrl);
2927 }
2928 }
2929
2930 XtManageChild(newW->combobox.ListCtrl);
2931 XtAddCallback(newW->combobox.ListCtrl,
2932 XmNsingleSelectionCallback,
2933 (XtCallbackProc) ListSelectionCallback,
2934 (XtPointer) newW);
2935 XtAddCallback(newW->combobox.ListCtrl,
2936 XmNbrowseSelectionCallback,
2937 (XtCallbackProc) ListSelectionCallback,
2938 (XtPointer) newW);
2939 XtAddCallback(newW->combobox.ListCtrl,
2940 XmNdefaultActionCallback,
2941 (XtCallbackProc) ListDefaultActionCallback,
2942 (XtPointer) newW);
2943 XtAddCallback(newW->combobox.ListCtrl,
2944 XmNhelpCallback,
2945 (XtCallbackProc) HelpCallback,
2946 (XtPointer) newW);
2947
2948 XtAddEventHandler(newW->combobox.ListCtrl,
2949 ButtonReleaseMask,
2950 False, (XtEventHandler) Button1UpInList,
2951 (XtPointer) newW);
2952
2953 #ifdef NODRAGNDROP
2954 XtOverrideTranslations(newW->combobox.ListCtrl,
2955 NewListTranslations);
2956 #endif
2957 if ( newW->combobox.StaticList && newW->combobox.Editable )
2958 XtOverrideTranslations(newW->combobox.ListCtrl,
2959 NewListTranslationsE);
2960
2961 /* Jetzt wird es dann erst richtig spannend... Zuerst alle evtl.
2962 * in der Resource-Datenbank abgelegten Resourcen an die Kinder
2963 * weitergeben. Danach die uebergebenen Parameter ebenfalls an
2964 * die Kinder weiterreichen und schliesslich das Layout ermitteln.
2965 */
2966 InitMirrorResources(newW);
2967 UpdateColors(newW, -1);
2968 SetValues(newW, newW, newW, wargs, ArgCount);
2969
2970 if ( newW->combobox.ConvertBitmapToPixmap )
2971 newW->combobox.LabelPixmap =
2972 BitmapToPixmap(newW, XmNlabelPixmap,
2973 ((XmLabelRec *) newW->combobox.LabelCtrl)->
2974 label.normal_GC);
2975 if ( newW->combobox.ConvertBitmapToPixmapInsensitive )
2976 newW->combobox.LabelInsensitivePixmap =
2977 BitmapToPixmap(newW, XmNlabelInsensitivePixmap,
2978 ((XmLabelRec *) newW->combobox.LabelCtrl)->
2979 label.insensitive_GC);
2980
2981 DefaultGeometry(newW, &width, &height, &dummy, &dummy);
2982 if ( newW->core.width == 0 )
2983 newW->core.width = width;
2984 if ( newW->core.height == 0 )
2985 newW->core.height = height;
2986
2987 /*
2988 * Falls wir keine Fontliste besitzen, dann nehmen wir die von
2989 * dem Eingabefeld...
2990 */
2991 if ( newW->combobox.Font == NULL ) {
2992 XtVaGetValues(newW->combobox.EditCtrl,
2993 XmNfontList, &newW->combobox.Font, NULL);
2994 XtVaSetValues(newW->combobox.ListCtrl,
2995 XmNfontList, newW->combobox.Font, NULL);
2996 } else {
2997 XtVaSetValues(newW->combobox.ListCtrl,
2998 XmNfontList, newW->combobox.Font, NULL);
2999 XtVaSetValues(newW->combobox.EditCtrl,
3000 XmNfontList, newW->combobox.Font, NULL);
3001 }
3002
3003 /*
3004 * Initialisiere alle Statusflaggen, die mit diesem unseligen Focus-
3005 * problem zu tun haben...
3006 */
3007 newW->combobox.ListVisible = False;
3008 newW->combobox.IgnoreFocusOut = False;
3009 newW->combobox.PendingFocusOut = False;
3010 newW->combobox.PendingOverrideInOut = False;
3011
3012 newW->combobox.PassVerification = False;
3013
3014 /*
3015 * Jooa... bei der OSF pennen die wohl komplett?! Zusammen mit Form-
3016 * Widgets gibt das wohl immer Aerger...daher hier ein DoLayout()
3017 * aufrufen, damit Eingabefeld und Pfeil sowie das Listenfeld an der
3018 * richtigen Stelle sitzen!
3019 */
3020 DoLayout(newW);
3021 /*
3022 * Endlich fertig mit der Initialisierung. Das hier ist aber auch
3023 * wirklich viel Arbeit fuer so ein Widget!
3024 */
3025 newW->combobox.InInit = False;
3026 } /* Initialize */
3027
3028 /* --------------------------------------------------------------------
3029 * Diese Funktionen bitte nur im aeussersten Notfall benutzen, da sie
3030 * die Abstraktion dieser neuen Klasse umgehen und Informationen ueber
3031 * den internen Aufbau voraussetzen.
3032 */
3033 Widget XmComboBoxGetEditWidget(Widget w)
3034 {
3035 return ((XmComboBoxWidget) w)->combobox.EditCtrl;
3036 } /* XmComboBoxGetEditWidget */
3037
3038 Widget XmComboBoxGetListWidget(Widget w)
3039 {
3040 return ((XmComboBoxWidget) w)->combobox.ListCtrl;
3041 } /* XmComboBoxGetListWidget */
3042
3043 Widget XmComboBoxGetLabelWidget(Widget w)
3044 {
3045 return ((XmComboBoxWidget) w)->combobox.LabelCtrl;
3046 } /* XmComboBoxGetLabelWidget */
3047
3048
3049 /* --------------------------------------------------------------------
3050 * Sobald sich im Listenfeld Eintraege veraenderten, sei es, dass sie
3051 * geloescht wurden, sei es, dass sie veraendert wurden, so muss hier
3052 * gegebenenfalls auch der Text im Eingabefeld angepasst werden.
3053 * Letzteres betrifft aber nur Combo-Boxen mit nicht editierbarem
3054 * Eingabefeld. In jedem Fall wird aber bei jeder Combo-Box-Type in
3055 * dem Fall, dass ein Eintrag geloescht wird, der darauffolgende
3056 * Eintrag markiert. Eigentlich ist dieses nur eine nette Geste
3057 * gegenueber dem Benutzer...
3058 *
3059 * Parameter:
3060 * w Combo-Box-Widget
3061 * Index Index auf denjenigen Eintrag der sich geaendert
3062 * hat, oder der geloescht wurde.
3063 * Deleted Zeigt an, ob der Eintrag geloescht wurde (True)
3064 * oder sich nur veraenderte (False)
3065 */
3066 static UpdateComboBox(XmComboBoxWidget w, int Index, Boolean Deleted)
3067 {
3068 int OldIndex, ItemCount;
3069
3070 OldIndex = XmComboBoxGetSelectedPos((Widget) w);
3071 if ( OldIndex == Index ) {
3072 /* Es betrifft den Eintrag, der auch momentan ausgewaehlt ist.
3073 * Sollte er geloescht werden, so nimm' (soweit vorhanden) den
3074 * naechsten Eintrag, wurde er ausgetauscht, so lass ihn ausge-
3075 * waehlt.
3076 */
3077 if ( Deleted ) {
3078 XtVaGetValues(w->combobox.ListCtrl,
3079 XmNitemCount, &ItemCount, NULL);
3080 if ( ItemCount != 0 ) {
3081 if ( Index >= ItemCount ) Index = ItemCount;
3082 /* Markieren des Eintrags, ohne jedoch jetzt schon
3083 * den Eintrag in die Eingabezeile zu kopieren.
3084 */
3085 SetSelectionPos(w, Index, False);
3086 }
3087 }
3088 }
3089 /* Das Problem betrifft uns nur bei nicht editierbaren Combo-Boxen
3090 * im vollen Umfang. Denn dann muss auch der Text im Eingabefeld
3091 * veraendert werden.
3092 */
3093 if ( !w->combobox.Editable ) {
3094 TransferToEditCtrl(w, Index, False);
3095 }
3096
3097 return 1;
3098 } /* UpdateComboBox */
3099
3100
3101 /* --------------------------------------------------------------------
3102 * Die Eintragsposition finden, an der der Eintrag sortiert stehen
3103 * muesste. Naja, es wurde ja 'mal langsam Zeit, diese Routine etwas
3104 * aufzupolieren, damit sie schneller wird.
3105 */
3106 static int FindSortedItemPos(XmComboBoxWidget w, XmString item)
3107 {
3108 Widget ListBox = w->combobox.ListCtrl;
3109 XmStringTable Items;
3110 int ItemCount, index, Left, Right, Result;
3111 char *pItemText, *pCompareText;
3112 Boolean ExternSort;
3113 XmComboBoxSortingCallbackStruct data;
3114
3115 XtVaGetValues(ListBox, XmNitems, &Items,
3116 XmNitemCount, &ItemCount, NULL);
3117 if ( ItemCount == 0 ) return 1;
3118
3119 /*
3120 * Moechte das Programm die Kontrolle ueber den Sortiervorgang
3121 * uebernehmen? Dann bereite alles vor...
3122 */
3123 ExternSort = XtHasCallbacks((Widget) w, XmNsortingCallback) ==
3124 XtCallbackHasSome;
3125 if ( ExternSort ) {
3126 data.reason = XmCR_SORTING;
3127 data.event = NULL;
3128 data.operation = XmOP_INIT;
3129 data.item = item;
3130 XtCallCallbacks((Widget) w, XmNsortingCallback, (XtPointer) &data);
3131 } else
3132 XmStringGetLtoR(item, XmSTRING_DEFAULT_CHARSET, &pCompareText);
3133
3134 Left = 0; Right = ItemCount - 1;
3135 do {
3136 index = (Left + Right) / 2;
3137 if ( ExternSort ) {
3138 data.operation = XmOP_COMPARE;
3139 data.item = Items[index];
3140 data.result = 1;
3141 XtCallCallbacks((Widget) w, XmNsortingCallback, (XtPointer) &data);
3142 Result = data.result;
3143 } else {
3144 XmStringGetLtoR(Items[index], XmSTRING_DEFAULT_CHARSET, &pItemText);
3145 Result = strcmp(pCompareText, pItemText);
3146 XtFree(pItemText);
3147 }
3148 if ( Result < 0 ) Right = index - 1;
3149 else if ( Result > 0 ) Left = index + 1;
3150 } while ( (Result != 0) && (Left <= Right) );
3151
3152 /*
3153 * Nach Gebrauch wieder alles aufraeumen (bei einer externen Sortierung
3154 * muss das das Programm uebernehmen!)
3155 */
3156 if ( ExternSort ) {
3157 data.operation = XmOP_DONE;
3158 XtCallCallbacks((Widget) w, XmNsortingCallback, (XtPointer) &data);
3159 } else
3160 XtFree(pCompareText);
3161
3162 if ( Result < 0 )
3163 return index + 1; /* Beachte, dass Indizes mit 1 beginnen! */
3164 else
3165 return index + 2; /* Beachte, dass Indizes mit 1 beginnen! */
3166 } /* FindSortedItemPos */
3167
3168 /* --------------------------------------------------------------------
3169 * Kontrolliere, ob es sich ueberhaupt um eine Combo-Box (bzw. einen
3170 * hypothetischen Nachkommen) handelt -- ansonsten mecker kraeftig
3171 * herum!
3172 * Ergebnis:
3173 * True, falls wir hier ein falsches Widget untergejubelt bekommen!
3174 */
3175 static Boolean CheckComboBox(Widget w, char *pFuncName)
3176 {
3177 char buff[256];
3178 char *pWName;
3179
3180 #if (XmVersion >= 2000)
3181 return False; /* temporary workaround */
3182 #else
3183 if ( XmIsComboBox(w) ) return False;
3184 pWName = XrmQuarkToString(w->core.xrm_name);
3185 sprintf(buff,
3186 "Warning: %s called on widget named %s beeing \
3187 not a descendant of class XmComboBox!",
3188 pFuncName, pWName);
3189 XtWarning(buff);
3190 return True;
3191 #endif
3192 } /* CheckComboBox */
3193
3194 /* --------------------------------------------------------------------
3195 * Saemtliche Interface-Routinen zur Combo-Box
3196 */
3197 /* Zunaechst alles fuer die Listbox */
3198 #define ListBox (((XmComboBoxWidget) w)->combobox.ListCtrl)
3199 #define EditBox (((XmComboBoxWidget) w)->combobox.EditCtrl)
3200 #define ComboBox ((XmComboBoxWidget) w)
3201
3202 /* !!!
3203 * So angepasst, dass bei doppelt auftretenden Eintraegen, der
3204 * alte Eintrag weiterhin markiert bleibt. Diese Massnahme soll
3205 * eigentlich nur verhindern, dass zufaellig zwei Eintraege
3206 * markiert sind, falls nach der Anwahl eines Eintrages ein zweiter
3207 * gleichlautender Eintrag hinzugefuegt wurde.
3208 * Was hier die reine Lehre (oder war das die Leere?) anbetrifft:
3209 * in einer Combo-Box sollten sich sowieso nie gleichlautende
3210 * Eintraege befinden, da sie dort unsinnig sind und den Benutzer
3211 * nur verwirren...
3212 */
3213 void XmComboBoxAddItem(Widget w, XmString item, int pos)
3214 {
3215 int OldIndex = XmComboBoxGetSelectedPos(w);
3216
3217 if ( CheckComboBox(w, "XmComboBoxAddItem") ) return;
3218 if ( ComboBox->combobox.Sorted )
3219 pos = FindSortedItemPos(ComboBox, item);
3220 XmListAddItem(ListBox, item, pos);
3221 if ( OldIndex != XmComboBoxGetSelectedPos(w) )
3222 /* Hier SetSelectionPos() statt XmComboBoxSelectPos(),
3223 * da der Text nicht in das Eingabefeld uebertragen werden
3224 * soll!
3225 */
3226 SetSelectionPos(ComboBox, OldIndex, False);
3227 } /* XmComboBoxAddItem */
3228 /* !!!
3229 * Hier gilt das bereits oben gesagte (siehe XmComboBoxAddItem).
3230 * Bei sortierten Listboxen wird die Sortierung beim Gebrauch dieser
3231 * Funktion zerstoert!
3232 */
3233 void XmComboBoxAddItems(Widget w, XmString *items, int item_count, int pos)
3234 {
3235 int OldIndex = XmComboBoxGetSelectedPos(w);
3236
3237 if ( CheckComboBox(w, "XmComboBoxAddItems") ) return;
3238 XmListAddItems(ListBox, items, item_count, pos);
3239 if ( OldIndex != XmComboBoxGetSelectedPos(w) )
3240 /* Siehe Anmerkung in XmComboBoxAddItem */
3241 SetSelectionPos(ComboBox, OldIndex, False);
3242 } /* XmComboBoxAddItems */
3243
3244 void XmComboBoxAddItemUnselected(Widget w, XmString item, int pos)
3245 { XmListAddItemUnselected(ListBox, item, pos); }
3246
3247 /* !!!
3248 * Da bei den folgenden Routinen jeweils ein oder mehrere Eintraege
3249 * geloescht oder veraendert werden, muss gegebenefalls das Eingabe-
3250 * feld bei nicht editierbaren Combo-Boxen auf Vordermann gebracht
3251 * werden.
3252 */
3253 void XmComboBoxDeleteItem(Widget w, XmString item)
3254 {
3255 int Index = XmListItemPos(ListBox, item);
3256
3257 if ( CheckComboBox(w, "XmComboBoxDeleteItem") ) return;
3258 if ( Index ) XmComboBoxDeletePos(w, Index);
3259 } /* XmComboBoxDeleteItem */
3260
3261 void XmComboBoxDeleteItems(Widget w, XmString *items, int item_count)
3262 {
3263 int i;
3264
3265 if ( CheckComboBox(w, "XmComboBoxDeleteItems") ) return;
3266 for ( i = 0; i < item_count; i++ )
3267 XmListDeleteItem(w, items[i]);
3268 } /* XmComboBoxDeleteItems */
3269
3270 void XmComboBoxDeletePos(Widget w, int pos)
3271 {
3272 int OldIndex = XmComboBoxGetSelectedPos(w);
3273
3274 if ( CheckComboBox(w, "XmComboBoxDeletePos") ) return;
3275 XmListDeletePos(ListBox, pos);
3276 if ( pos == OldIndex ) UpdateComboBox(ComboBox, pos, True);
3277 } /* XmComboBoxDeletePos */
3278
3279 void XmComboBoxDeleteItemsPos(Widget w, int item_count, int pos)
3280 {
3281 int i;
3282
3283 if ( CheckComboBox(w, "XmComboBoxDeleteItemsPos") ) return;
3284 for ( i = 0; i < item_count; i++ )
3285 XmComboBoxDeletePos(w, pos++);
3286 } /* XmComboBoxDeleteItemsPos */
3287
3288 void XmComboBoxDeleteAllItems(Widget w)
3289 {
3290 if ( CheckComboBox(w, "XmComboBoxAllDeleteItems") ) return;
3291 XmListDeleteAllItems(ListBox);
3292 UpdateComboBox(ComboBox, 0, True);
3293 } /* XmComboBoxDeleteAllItems */
3294
3295 /* !!!
3296 * Werden Eintraege ausgetauscht, so heisst es fuer uns, auch hierbei
3297 * auf der Hut zu sein.
3298 */
3299 void XmComboBoxReplaceItems(Widget w, XmString *old_items, int item_count, XmString *new_items)
3300 {
3301 if ( CheckComboBox(w, "XmComboBoxReplaceItems") ) return;
3302 XmListReplaceItems(ListBox, old_items, item_count, new_items);
3303 UpdateComboBox(ComboBox, XmComboBoxGetSelectedPos(w), False);
3304 } /* XmComboBoxReplaceItems */
3305
3306 void XmComboBoxReplaceItemsPos(Widget w, XmString *new_items, int item_count, int position)
3307 {
3308 int OldIndex = XmComboBoxGetSelectedPos(w);
3309
3310 if ( CheckComboBox(w, "XmComboBoxReplaceItemsPos") ) return;
3311 XmListReplaceItemsPos(ListBox, new_items, item_count, position);
3312 if ( (OldIndex >= position) && (OldIndex < position + item_count) )
3313 UpdateComboBox(ComboBox, OldIndex, False);
3314 } /* XmComboBoxReplaceItemsPos */
3315
3316 Boolean XmComboBoxItemExists(Widget w, XmString item)
3317 {
3318 if ( CheckComboBox(w, "XmComboBoxItemExists") ) return False;
3319 return XmListItemExists(ListBox, item);
3320 } /* XmComboBoxItemExists */
3321
3322 int XmComboBoxItemPos(Widget w, XmString item)
3323 {
3324 if ( CheckComboBox(w, "XmComboBoxItemPos") ) return 0;
3325 return XmListItemPos(ListBox, item);
3326 } /* XmComboBoxItemPos */
3327
3328 Boolean XmComboBoxGetMatchPos(Widget w, XmString item, int **pos_list, int *pos_count)
3329 {
3330 if ( CheckComboBox(w, "XmComboBoxGetMatchPos") ) return False;
3331 return XmListGetMatchPos(ListBox, item, pos_list, pos_count);
3332 } /* XmComboBoxGetMatchPos */
3333
3334 /* !!!
3335 * Sobald ein anderer Eintrag in der Listbox ausgewaehlt werden soll,
3336 * muessen wir hier helfend eingreifen.
3337 */
3338 void XmComboBoxSelectPos(Widget w, int pos, Boolean notify)
3339 {
3340 int index;
3341
3342 if ( CheckComboBox(w, "XmComboBoxSelectPos") ) return;
3343 index = SetSelectionPos(ComboBox, pos, notify);
3344 if ( index ) TransferToEditCtrl(ComboBox, index, False);
3345 } /* XmComboBoxSelectPos */
3346
3347 /* !!!
3348 * dto. analog zu XmComboBoxSelectPos, nur statt des Index wird der
3349 * Eintragstext angegeben, um einen Eintrag in der Listbox zu
3350 * markieren.
3351 */
3352 void XmComboBoxSelectItem(Widget w, XmString item, Boolean notify)
3353 {
3354 int index;
3355
3356 if ( CheckComboBox(w, "XmComboBoxSelectItem") ) return;
3357 XmListSelectItem(ListBox, item, notify);
3358 index = SetSelectionPos(ComboBox, XmComboBoxGetSelectedPos(w), False);
3359 if ( index ) TransferToEditCtrl(ComboBox, index, False);
3360 } /* XmComboBoxSelectItem */
3361
3362 /* !!!
3363 * Geaendert gegenueber dem ListBox-Pendant! Da in einer Combo-Box die
3364 * Liste nur maximal einen ausgewaehlten Eintrag besitzt, macht die
3365 * 'alte' Funktionalitaet von XmListGetSelectedPos ziemlich wenig Sinn.
3366 * Die neue Routine liefert statt dessen direkt den Index des aus-
3367 * gewaehlten Eintrages oder 0 zurueck.
3368 */
3369 int XmComboBoxGetSelectedPos(Widget w)
3370 {
3371 int *SelectionList, SelectionCount, SelectionIndex;
3372
3373 if ( CheckComboBox(w, "XmComboBoxGetSelectedPos") ) return 0;
3374 if ( XmListGetSelectedPos(ListBox,
3375 &SelectionList, &SelectionCount) ) {
3376 SelectionIndex = *SelectionList;
3377 XtFree((char *)SelectionList);
3378 } else SelectionIndex = 0;
3379 return SelectionIndex;
3380 } /* XmComboBoxGetSelectedPos */
3381
3382
3383
3384 void XmComboBoxClearSelection(Widget w, Time time)
3385 {
3386 XmTextFieldClearSelection(EditBox, time);
3387 } /* XmComboBoxClearSelection */
3388
3389 Boolean XmComboBoxCopy(Widget w, Time time)
3390 {
3391 return XmTextFieldCopy(EditBox, time);
3392 } /* XmComboBoxCopy */
3393
3394 Boolean XmComboBoxCut(Widget w, Time time)
3395 {
3396 return XmTextFieldCut(EditBox, time);
3397 } /* XmComboBoxCut */
3398
3399 XmTextPosition XmComboBoxGetInsertionPosition(Widget w)
3400 {
3401 return XmTextFieldGetInsertionPosition(EditBox);
3402 } /* XmComboBoxGetInsertionPosition */
3403
3404 XmTextPosition XmComboBoxGetLastPosition(Widget w)
3405 {
3406 return XmTextFieldGetLastPosition(EditBox);
3407 } /* XmComboBoxGetLastPosition */
3408
3409 int XmComboBoxGetMaxLength(Widget w)
3410 {
3411 return XmTextFieldGetMaxLength(EditBox);
3412 } /* XmComboBoxGetMaxLength */
3413
3414 char * XmComboBoxGetSelection(Widget w)
3415 {
3416 return XmTextFieldGetSelection(EditBox);
3417 } /* XmComboBoxGetSelection */
3418
3419 Boolean XmComboBoxGetSelectionPosition(Widget w, XmTextPosition *left,
3420 XmTextPosition *right)
3421 {
3422 return XmTextFieldGetSelectionPosition(EditBox, left, right);
3423 } /* XmComboBoxGetSelectionPosition */
3424
3425 char * XmComboBoxGetString(Widget w)
3426 {
3427 return XmTextFieldGetString(EditBox);
3428 } /* XmComboBoxGetString */
3429
3430 void XmComboBoxInsert(Widget w, XmTextPosition position, char *value)
3431 {
3432 XmTextFieldInsert(EditBox, position, value);
3433 } /* XmComboBoxInsert */
3434
3435 Boolean XmComboBoxPaste(Widget w)
3436 {
3437 return XmTextFieldPaste(EditBox);
3438 } /* XmComboBoxPaste */
3439
3440 Boolean XmComboBoxRemove(Widget w)
3441 {
3442 return XmTextFieldRemove(EditBox);
3443 } /* XmComboBoxRemove */
3444
3445 void XmComboBoxReplace(Widget w, XmTextPosition from_pos,
3446 XmTextPosition to_pos, char *value)
3447 {
3448 XmTextFieldReplace(EditBox, from_pos, to_pos, value);
3449 } /* XmComboBoxReplace */
3450
3451 void XmComboBoxSetAddMode(Widget w, Boolean state)
3452 {
3453 XmTextFieldSetAddMode(EditBox, state);
3454 } /* XmComboBoxSetAddMode */
3455
3456 void XmComboBoxSetHighlight(Widget w, XmTextPosition left,
3457 XmTextPosition right, XmHighlightMode mode)
3458 {
3459 XmTextFieldSetHighlight(EditBox, left, right, mode);
3460 } /* XmComboBoxSetHighlight */
3461
3462 void XmComboBoxSetInsertionPosition(Widget w, XmTextPosition position)
3463 {
3464 XmTextFieldSetInsertionPosition(EditBox, position);
3465 } /* XmComboBoxSetInsertionPosition */
3466
3467 void XmComboBoxSetMaxLength(Widget w, int max_length)
3468 {
3469 XmTextFieldSetMaxLength(EditBox, max_length);
3470 } /* XmComboBoxSetMaxLength */
3471
3472 void XmComboBoxSetSelection(Widget w, XmTextPosition first,
3473 XmTextPosition last, Time time)
3474 {
3475 XmTextFieldSetSelection(EditBox, first, last, time);
3476 } /* XmComboBoxSetSelection */
3477
3478 void XmComboBoxSetString(Widget w, char *value)
3479 {
3480 /* Liebe OSF...ihr ^&*#%$*&)*(@$(*^(*&%# habt doch einen ziemlich gemeinen
3481 * Fehler in XmTextFieldSetString() drin... wenn man einen leeren String
3482 * (also "") angiebt, gibt's nur noch Aerger, wenn man spaeter wieder an
3483 * den Inhalt des Eingabefeldes heranwill.
3484 */
3485 if ( (value == NULL) || (*value == 0) )
3486 XtVaSetValues(w, XmNvalue, "", NULL);
3487 else
3488 XmTextFieldSetString(EditBox, value);
3489 } /* XmComboBoxSetString */
3490
3491 void XmComboBoxShowPosition(Widget w, XmTextPosition position)
3492 {
3493 XmTextFieldShowPosition(EditBox, position);
3494 } /* XmComboBoxShowPosition */
3495
3496 /*
3497 * Loescht einen evtl. noch ausgewaehlten Eintrag in einer Combo Box,
3498 * wenn diese eine SelectionPolicy von XmSINGLE_SELECT hat.
3499 */
3500 void XmComboBoxClearItemSelection(Widget w)
3501 {
3502 int index;
3503
3504 if ( CheckComboBox(w, "XmComboBoxClearItemSelection") ) return;
3505
3506 /*
3507 * Wenn bereits kein Eintrag markiert ist, dann loeschen wir nur noch
3508 * eben das Eingabefeld.
3509 */
3510 index = XmComboBoxGetSelectedPos(w);
3511 if ( index == 0 ) {
3512 XmComboBoxSetString(w, "");
3513 } else {
3514 /*
3515 * Ansonsten aktuellen Eintrag entsorgen (wie bei der Methode wipe-out)
3516 */
3517 TransferToEditCtrl(ComboBox, 0, True);
3518 CallSelectionCBL(ComboBox, NULL);
3519 }
3520 } /* XmComboBoxClearItemSelection */
3521
3522 /* Die Drop-Down-Liste ein oder ausklappen */
3523 void XmComboBoxShowList(Widget w)
3524 {
3525 if ( CheckComboBox(w, "XmComboBoxShowList") ) return;
3526 ShowHideDropDownList((XmComboBoxWidget) w, NULL, False);
3527 } /* XmComboBoxShowList */
3528
3529 void XmComboBoxHideList(Widget w)
3530 {
3531 if ( CheckComboBox(w, "XmComboBoxHideList") ) return;
3532 ShowHideDropDownList((XmComboBoxWidget) w, NULL, True);
3533 } /* XmComboBoxShowList */
3534
3535 /*
3536 * Naja, ich komm' ja doch nicht um diese olle Funktion herum...
3537 */
3538 Widget XmCreateComboBox(Widget parent, String name, ArgList arglist,
3539 Cardinal argcount)
3540 {
3541 return XtCreateWidget(name, xmComboBoxWidgetClass, parent,
3542 arglist, argcount);
3543 } /* XmCreateComboBox */
3544
3545 /* Ende von ComboBox.c */