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