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