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