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