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