source: branches/profile/WINDOW/AW_button.cxx

Last change on this file was 12930, checked in by westram, 10 years ago
  • sync behavior with gtk
    • allow gfx-labels before input- and text-fields
    • force text in option menus
  • fail assertion if gfx used for option-menu-label (afaik unused; can't use in motif)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 72.6 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : AW_button.cxx                                     //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "aw_at.hxx"
12#include "aw_Xm.hxx"
13#include "aw_select.hxx"
14#include "aw_nawar.hxx"
15#include "aw_awar.hxx"
16#include "aw_window_Xm.hxx"
17#include "aw_msg.hxx"
18#include "aw_root.hxx"
19#include "aw_question.hxx"
20#include "aw_xargs.hxx"
21
22#include <arb_algo.h>
23#include <ad_cb.h>
24
25#include <Xm/Frame.h>
26#include <Xm/MenuShell.h>
27#include <Xm/RowColumn.h>
28#include <Xm/ToggleB.h>
29#include <Xm/Label.h>
30#include <Xm/List.h>
31#include <Xm/PushB.h>
32#include <Xm/Text.h>
33#include <Xm/TextF.h>
34#include <Xm/ScrolledW.h>
35
36#include <iostream>
37
38#if defined(DEBUG)
39// #define DUMP_BUTTON_CREATION
40#endif // DEBUG
41
42class VarUpdateInfo : virtual Noncopyable { // used to refresh single items on change
43    AW_window         *aw_parent;
44    Widget             widget;
45    AW_widget_type     widget_type;
46    AW_awar           *awar;
47    AW_scalar          value;
48    AW_cb             *cbs;
49    AW_selection_list *sellist;
50
51public:
52    VarUpdateInfo(AW_window *aw, Widget w, AW_widget_type wtype, AW_awar *a, AW_cb *cbs_)
53        : aw_parent(aw), widget(w), widget_type(wtype), awar(a),
54          value(a),
55          cbs(cbs_), sellist(NULL)
56    {
57    }
58    template<typename T>
59    VarUpdateInfo(AW_window *aw, Widget w, AW_widget_type wtype, AW_awar *a, T t, AW_cb *cbs_)
60        : aw_parent(aw), widget(w), widget_type(wtype), awar(a),
61          value(t),
62          cbs(cbs_), sellist(NULL)
63    {
64    }
65
66    void change_from_widget(XtPointer call_data);
67
68    void set_widget(Widget w) { widget = w; }
69    void set_sellist(AW_selection_list *asl) { sellist = asl; }
70};
71
72static void AW_variable_update_callback(Widget /*wgt*/, XtPointer variable_update_struct, XtPointer call_data) {
73    VarUpdateInfo *vui = (VarUpdateInfo *) variable_update_struct;
74    aw_assert(vui);
75
76    vui->change_from_widget(call_data);
77}
78
79struct TrackedAwarChange {
80    AW_awar *awar;
81    bool     changed;
82
83    TrackedAwarChange(AW_awar *awar_) : awar(awar_), changed(false) {}
84};
85
86static void track_awar_change_cb(GBDATA *IF_ASSERTION_USED(gbd), TrackedAwarChange *tac, GB_CB_TYPE IF_ASSERTION_USED(cb_type)) {
87    aw_assert(cb_type == GB_CB_CHANGED);
88    aw_assert(tac->awar->gb_var == gbd);
89    tac->changed = true;
90}
91
92void VarUpdateInfo::change_from_widget(XtPointer call_data) {
93    AW_cb::useraction_init();
94   
95    GB_ERROR  error = NULL;
96    AW_root  *root  = awar->root;
97
98    if (root->value_changed) {
99        root->changer_of_variable = widget;
100    }
101
102    TrackedAwarChange tac(awar);
103    if (root->is_tracking()) {
104        // add a callback which writes macro-code (BEFORE any other callback happens; last added, first calledback)
105        GB_transaction ta(awar->gb_var);
106        GB_add_callback(awar->gb_var, GB_CB_CHANGED, makeDatabaseCallback(track_awar_change_cb, &tac));
107    }
108
109    bool run_cb = true;
110    switch (widget_type) {
111        case AW_WIDGET_INPUT_FIELD:
112        case AW_WIDGET_TEXT_FIELD:
113            if (!root->value_changed) {
114                run_cb = false;
115            }
116            else {
117                char *new_text = XmTextGetString((widget));
118                error          = awar->write_as_string(new_text);
119                XtFree(new_text);
120            }
121            break;
122
123        case AW_WIDGET_TOGGLE:
124            root->changer_of_variable = 0;
125            error = awar->toggle_toggle();
126            break;
127
128        case AW_WIDGET_TOGGLE_FIELD:
129            if (XmToggleButtonGetState(widget) == False) break; // no toggle is selected (?)
130            // fall-through
131        case AW_WIDGET_CHOICE_MENU:
132            error = value.write_to(awar);
133            break;
134
135        case AW_WIDGET_SELECTION_LIST: {
136            char *selected; {
137                XmListCallbackStruct *xml = (XmListCallbackStruct*)call_data;
138                XmStringGetLtoR(xml->item, XmSTRING_DEFAULT_CHARSET, &selected);
139            }
140
141            AW_selection_list_entry *entry = sellist->list_table;
142            while (entry && strcmp(entry->get_displayed(), selected) != 0) {
143                entry = entry->next;
144            }
145
146            if (!entry) {   
147                entry = sellist->default_select; // use default selection
148                if (!entry) GBK_terminate("no default specified for selection list"); // or die
149            }
150            entry->value.write_to(awar);
151            XtFree(selected);
152            break;
153        }
154
155        case AW_WIDGET_LABEL_FIELD:
156            break;
157
158        default:
159            GBK_terminatef("Unknown widget type %i in AW_variable_update_callback", widget_type);
160            break;
161    }
162
163    if (root->is_tracking()) {
164        {
165            GB_transaction ta(awar->gb_var);
166            GB_remove_callback(awar->gb_var, GB_CB_CHANGED, makeDatabaseCallback(track_awar_change_cb, &tac));
167        }
168        if (tac.changed) {
169            root->track_awar_change(awar);
170        }
171    }
172
173    if (error) {
174        root->changer_of_variable = 0;
175        awar->update();
176        aw_message(error);
177    }
178    else {
179        if (cbs && run_cb) cbs->run_callbacks();
180        root->value_changed = false;
181
182        if (GB_have_error()) aw_message(GB_await_error()); // show error exported by awar-change-callback
183    }
184
185    AW_cb::useraction_done(aw_parent);
186}
187
188
189static void AW_value_changed_callback(Widget /*wgt*/, XtPointer rooti, XtPointer /*call_data*/) {
190    AW_root *root = (AW_root *)rooti;
191    root->value_changed = true;
192}
193
194static void aw_attach_widget(Widget w, AW_at *_at, int default_width = -1) {
195    short height = 0;
196    short width = 0;
197    if (!_at->to_position_exists) {
198        XtVaGetValues(w, XmNheight, &height, XmNwidth, &width, NULL);
199        if (default_width >0) width = default_width;
200
201        switch (_at->correct_for_at_center) {
202            case 0:             // left justified
203                _at->to_position_x      = _at->x_for_next_button + width;
204                break;
205            case 1:             // centered
206                _at->to_position_x      = _at->x_for_next_button + width/2;
207                _at->x_for_next_button -= width/2;
208                break;
209            case 2:             // right justified
210                _at->to_position_x      = _at->x_for_next_button;
211                _at->x_for_next_button -= width;
212                break;
213        }
214        _at->to_position_y = _at->y_for_next_button + height;
215        _at->attach_x      = _at->attach_lx;
216        _at->attach_y      = _at->attach_ly;
217    }
218
219#define MIN_RIGHT_OFFSET  10
220#define MIN_BOTTOM_OFFSET 10
221
222    aw_xargs args(4*2);
223
224    if (_at->attach_x) {
225        int right_offset = _at->max_x_size - _at->to_position_x;
226        if (right_offset<MIN_RIGHT_OFFSET) {
227            right_offset    = MIN_RIGHT_OFFSET;
228            _at->max_x_size = _at->to_position_x+right_offset;
229        }
230
231        args.add(XmNrightAttachment, XmATTACH_FORM);
232        args.add(XmNrightOffset,     right_offset);
233    }
234    else {
235        args.add(XmNrightAttachment, XmATTACH_OPPOSITE_FORM);
236        args.add(XmNrightOffset,     -_at->to_position_x);
237    }
238
239    if (_at->attach_lx) {
240        args.add(XmNleftAttachment, XmATTACH_NONE);
241        args.add(XmNwidth,          _at->to_position_x - _at->x_for_next_button);
242    }
243    else {
244        args.add(XmNleftAttachment, XmATTACH_FORM);
245        args.add(XmNleftOffset,     _at->x_for_next_button);
246    }
247
248    if (_at->attach_y) {
249        int bottom_offset = _at->max_y_size - _at->to_position_y;
250        if (bottom_offset<MIN_BOTTOM_OFFSET) {
251            bottom_offset   = MIN_BOTTOM_OFFSET;
252            _at->max_y_size = _at->to_position_y+bottom_offset;
253        }
254
255        args.add(XmNbottomAttachment, XmATTACH_FORM);
256        args.add(XmNbottomOffset,     bottom_offset);
257    }
258    else {
259        args.add(XmNbottomAttachment, XmATTACH_OPPOSITE_FORM);
260        args.add(XmNbottomOffset,     - _at->to_position_y);
261    }
262    if (_at->attach_ly) {
263        args.add(XmNtopAttachment, XmATTACH_NONE);
264        args.add(XmNheight,        _at->to_position_y - _at->y_for_next_button);
265    }
266    else {
267        args.add(XmNtopAttachment, XmATTACH_FORM);
268        args.add(XmNtopOffset,     _at->y_for_next_button);
269    }
270
271    args.assign_to_widget(w);
272}
273
274const char *AW_get_pixmapPath(const char *pixmapName) {
275    // const char *pixmapsDir = "pixmaps"; // normal pixmaps (as used in gtk branch)
276    const char *pixmapsDir = "motifHack/pixmaps"; // see ../lib/motifHack/README
277
278    return GB_path_in_ARBLIB(pixmapsDir, pixmapName);
279}
280
281static char *pixmapPath(const char *pixmapName) {
282    return nulldup(AW_get_pixmapPath(pixmapName));
283}
284
285
286#define MAX_LINE_LENGTH 200
287__ATTR__USERESULT static GB_ERROR detect_bitmap_size(const char *pixmapname, int *width, int *height) {
288    GB_ERROR err = 0;
289
290    *width  = 0;
291    *height = 0;
292
293    char *path = pixmapPath(pixmapname);
294    FILE *in   = fopen(path, "rt");
295    if (in) {
296        const char *subdir = strrchr(pixmapname, '/');
297        char       *name   = strdup(subdir ? subdir+1 : pixmapname);
298        {
299            char *dot       = strrchr(name, '.');
300            if (dot) dot[0] = 0;
301            else  err       = "'.' expected";
302        }
303        int  namelen = strlen(name);
304        char buffer[MAX_LINE_LENGTH];
305        bool done    = false;
306
307        while (!done && !err) {
308            if (!fgets(buffer, MAX_LINE_LENGTH, in)) {
309                err = GB_IO_error("reading", pixmapname);
310            }
311            else if (strchr(buffer, 0)[-1] != '\n') {
312                err = GBS_global_string("Line too long ('%s')", buffer); // increase MAX_LINE_LENGTH above
313            }
314            else if (strncmp(buffer, "#define", 7) != 0) {
315                done = true;
316            }
317            else {
318                char *name_pos = strstr(buffer+7, name);
319                if (name_pos) {
320                    char *behind = name_pos+namelen;
321                    if (strncmp(behind, "_width ", 7) == 0) *width = atoi(behind+7);
322                    else if (strncmp(behind, "_height ", 8) == 0) *height = atoi(behind+8);
323                }
324            }
325        }
326
327        if (done && ((*width == 0) || (*height == 0))) {
328            if (strstr(buffer, "XPM") != NULL) {
329                if (!fgets(buffer, MAX_LINE_LENGTH, in) || !fgets(buffer, MAX_LINE_LENGTH, in)) {
330                    err = GB_IO_error("reading", pixmapname);
331                }
332                else {
333                    char *temp = strtok(buffer+1, " ");
334                    *width     = atoi(temp);
335                    temp       = strtok(NULL,  " ");
336                    *height    = atoi(temp);
337                }
338            }
339            else {
340                err = "can't detect size";
341            }
342        }
343
344        free(name);
345        fclose(in);
346    }
347    else {
348        err = "no such file";
349    }
350
351    if (err) {
352        err = GBS_global_string("%s: %s", pixmapname, err);
353    }
354
355#if defined(DUMP_BUTTON_CREATION)
356    printf("Bitmap '%s' has size %i/%i\n", pixmapname, *width, *height);
357#endif // DUMP_BUTTON_CREATION
358
359    free(path);
360    return err;
361}
362#undef MAX_LINE_LENGTH
363
364inline void calculate_textsize(const char *str, int *width, int *height) {
365    int textwidth  = 0;
366    int textheight = 1;
367    int linewidth  = 0;
368
369    for (int p = 0; str[p]; ++p) {
370        if (str[p] == '\n') {
371            if (linewidth>textwidth) textwidth = linewidth;
372
373            linewidth = 0;
374            textheight++;
375        }
376        else {
377            linewidth++;
378        }
379    }
380
381    if (linewidth>textwidth) textwidth = linewidth;
382
383    *width  = textwidth;
384    *height = textheight;
385}
386
387void AW_window::calculate_label_size(int *width, int *height, bool in_pixel, const char *non_at_label) {
388    // in_pixel == true -> calculate size in pixels
389    // in_pixel == false -> calculate size in characters
390
391    const char *label_ = non_at_label ? non_at_label : _at->label_for_inputfield;
392    if (label_) {
393        calculate_textsize(label_, width, height);
394        if (_at->length_of_label_for_inputfield) {
395            *width = _at->length_of_label_for_inputfield;
396        }
397        if (in_pixel) {
398            *width  = calculate_string_width(*width);
399            *height = calculate_string_height(*height, 0);
400        }
401    }
402    else {
403        *width  = 0;
404        *height = 0;
405    }
406}
407
408Widget AW_window::get_last_widget() const {
409    return p_global->get_last_widget();
410}
411
412void aw_detect_text_size(const char *text, size_t& width, size_t& height) {
413    size_t text_width = strcspn(text, "\n");
414
415    if (text[text_width]) {
416        aw_assert(text[text_width] == '\n');
417
418        aw_detect_text_size(text+text_width+1, width, height);
419        if (text_width>width) width = text_width;
420        height++;
421    }
422    else { // EOS
423        width  = text_width;
424        height = 1;
425    }
426}
427
428void AW_window::create_autosize_button(const char *macro_name, AW_label buttonlabel, const  char *mnemonic, unsigned xtraSpace) {
429    aw_assert(!AW_IS_IMAGEREF(buttonlabel));    // use create_button for graphical buttons!
430    aw_assert(!_at->to_position_exists); // wont work if to-position exists
431
432    AW_awar *is_awar = get_root()->label_is_awar(buttonlabel);
433    size_t   width, height;
434    if (is_awar) {
435        char *content = is_awar->read_as_string();
436        aw_assert(content[0]); /* you need to fill the awar before calling create_autosize_button,
437                                * otherwise size cannot be detected */
438        aw_detect_text_size(content, width, height);
439    }
440    else {
441        aw_detect_text_size(buttonlabel, width, height);
442    }
443
444    int   len               = width+(xtraSpace*2);
445    short length_of_buttons = _at->length_of_buttons;
446    short height_of_buttons = _at->height_of_buttons;
447
448    _at->length_of_buttons = len+1;
449    _at->height_of_buttons = height;
450    create_button(macro_name, buttonlabel, mnemonic);
451    _at->length_of_buttons = length_of_buttons;
452    _at->height_of_buttons = height_of_buttons;
453}
454
455void AW_window::create_button(const char *macro_name, AW_label buttonlabel, const char */*mnemonic*/, const char *color) {
456    // Create a button or text display.
457    //
458    // If a callback is bound via at->callback(), a button is created.
459    // Otherwise a text display is created.
460    //
461    // if buttonlabel starts with '#' the rest of buttonlabel is used as name of pixmap file used for button
462    // if buttonlabel contains a '/' it's interpreted as AWAR name and the button displays the content of the awar
463    // otherwise buttonlabel is interpreted as button label (may contain '\n').
464    //
465    // Note 1: Button width 0 does not work together with labels!
466
467    // Note 2: "color" may be specified for the button background (see TuneOrSetBackground for details)
468
469    TuneOrSetBackground(_at->attach_any ? INFO_FORM : INFO_WIDGET, // set background for buttons / text displays
470                        color,
471                        _callback ? TUNE_BUTTON : 0);
472
473#if defined(DUMP_BUTTON_CREATION)
474    printf("------------------------------ Button '%s'\n", buttonlabel);
475    printf("x_for_next_button=%i y_for_next_button=%i\n", _at->x_for_next_button, _at->y_for_next_button);
476#endif // DUMP_BUTTON_CREATION
477
478    if (_callback && ((long)_callback != 1))
479    {
480        if (macro_name) {
481            _callback->id = GBS_global_string_copy("%s/%s", this->window_defaults_name, macro_name);
482            get_root()->define_remote_command(_callback);
483        }
484        else {
485            _callback->id = 0;
486        }
487    }
488#if defined(DEVEL_RALF) && 1
489    else {
490        aw_assert(!macro_name); // please pass NULL for buttons w/o callback
491    }
492#endif
493
494#define SPACE_BEHIND_LABEL  10
495#define SPACE_BEHIND_BUTTON 3
496
497#define BUTTON_TEXT_X_PADDING 4
498#define BUTTON_TEXT_Y_PADDING 10
499
500#define BUTTON_GRAPHIC_PADDING 12
501#define FLAT_GRAPHIC_PADDING   4 // for buttons w/o callback
502
503    bool is_graphical_button = AW_IS_IMAGEREF(buttonlabel);
504
505#if defined(ASSERTION_USED)
506    AW_awar *is_awar = is_graphical_button ? NULL : get_root()->label_is_awar(buttonlabel);
507#endif // ASSERTION_USED
508
509    int width_of_button = -1, height_of_button = -1;
510
511    int width_of_label, height_of_label;
512    calculate_label_size(&width_of_label, &height_of_label, true, 0);
513    int width_of_label_and_spacer = _at->label_for_inputfield ? width_of_label+SPACE_BEHIND_LABEL : 0;
514
515    bool let_motif_choose_size  = false;
516
517    if (_at->to_position_exists) { // size has explicitly been specified in xfig -> calculate
518        width_of_button  = _at->to_position_x - _at->x_for_next_button - width_of_label_and_spacer;
519        height_of_button = _at->to_position_y - _at->y_for_next_button;
520    }
521    else if (_at->length_of_buttons) { // button width specified from client code
522        width_of_button  = BUTTON_TEXT_X_PADDING + calculate_string_width(_at->length_of_buttons+1);
523
524        if (!is_graphical_button) {
525            if (_at->height_of_buttons) { // button height specified from client code
526                height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(_at->height_of_buttons, 0);
527            }
528            else {
529                int textwidth, textheight;
530                calculate_textsize(buttonlabel, &textwidth, &textheight);
531                height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(textheight, 0);
532            }
533        }
534        else {
535            height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(1, 0);
536        }
537    }
538    else { // no button_length() specified
539        aw_assert(!is_awar); // please specify button_length() for AWAR button!
540
541        if (is_graphical_button) {
542            int      width, height;
543            GB_ERROR err = detect_bitmap_size(buttonlabel+1, &width, &height);
544
545            if (!err) {
546                int gpadding = _callback ? BUTTON_GRAPHIC_PADDING : FLAT_GRAPHIC_PADDING;
547
548                width_of_button  = width+gpadding;
549                height_of_button = height+gpadding;
550            }
551            else {
552                err = GBS_global_string("button gfx error: %s", err);
553                aw_message(err);
554                let_motif_choose_size = true;
555            }
556        }
557        else {
558            int textwidth, textheight;
559            calculate_textsize(buttonlabel, &textwidth, &textheight);
560
561            width_of_button  = BUTTON_TEXT_X_PADDING + calculate_string_width(textwidth+1);
562            height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(textheight, 0);
563        }
564    }
565
566    if (!let_motif_choose_size) {
567        if (height_of_button<height_of_label) height_of_button = height_of_label;
568        aw_assert(width_of_button && height_of_button);
569    }
570
571    int x_label  = _at->x_for_next_button;
572    int y_label  = _at->y_for_next_button;
573    int x_button = x_label + width_of_label_and_spacer;
574    int y_button = y_label;
575
576    int org_correct_for_at_center = _at->correct_for_at_center; // store original justification
577    int org_y_for_next_button     = _at->y_for_next_button; // store original y pos (modified while creating label)
578
579    if (!let_motif_choose_size) { // don't correct position of button w/o known size
580        // calculate justification manually
581
582        int width_of_button_and_highlight = width_of_button + (_at->highlight ? 2*(_at->shadow_thickness+1)+1 : 0);
583        int width_of_label_and_button     = width_of_label_and_spacer+width_of_button_and_highlight;
584
585        if (_at->correct_for_at_center) { // not if left justified
586            int shiftback = width_of_label_and_button; // shiftback for right justification
587            if (_at->correct_for_at_center == 1) { // center justification
588                shiftback /= 2;
589            }
590            x_label  -= shiftback;
591            x_button -= shiftback;
592        }
593
594        // we already did the justification by calculating all positions manually, so..
595        _at->correct_for_at_center = 0; // ..from now on act like "left justified"!
596    }
597
598    // correct label Y position
599    if (_callback) {            // only if button is a real 3D-button
600        y_label += (height_of_button-height_of_label)/2;
601    }
602
603    Widget parent_widget = (_at->attach_any) ? INFO_FORM : INFO_WIDGET;
604    Widget tmp_label         = 0;
605
606    if (_at->label_for_inputfield) {
607        _at->x_for_next_button = x_label;
608        _at->y_for_next_button = y_label;
609
610        tmp_label = XtVaCreateManagedWidget("label",
611                                            xmLabelWidgetClass,
612                                            parent_widget,
613                                            XmNwidth, (int)(width_of_label + 2),
614                                            RES_LABEL_CONVERT(_at->label_for_inputfield),
615                                            XmNrecomputeSize, false,
616                                            XmNalignment, XmALIGNMENT_BEGINNING,
617                                            XmNfontList, p_global->fontlist,
618                                            XmNx, (int)(x_label),
619                                            XmNy, (int)(y_label),
620                                            NULL);
621
622        if (_at->attach_any) aw_attach_widget(tmp_label, _at);
623        AW_label_in_awar_list(this, tmp_label, _at->label_for_inputfield);
624    }
625
626    _at->x_for_next_button = x_button;
627    _at->y_for_next_button = y_button;
628
629    Widget fatherwidget = parent_widget; // used as father for button below
630    if (_at->highlight) {
631        if (_at->attach_any) {
632#if defined(DEBUG)
633            printf("Attaching highlighted buttons does not work - "
634                   "highlight ignored for button '%s'!\n", buttonlabel);
635#endif // DEBUG
636            _at->highlight = false;
637        }
638        else {
639            int shadow_offset = _at->shadow_thickness;
640            int x_shadow      = x_button - shadow_offset;
641            int y_shadow      = y_button - shadow_offset;
642
643            fatherwidget = XtVaCreateManagedWidget("draw_area",
644                                                   xmFrameWidgetClass,
645                                                   INFO_WIDGET,
646                                                   XmNx, (int)(x_shadow),
647                                                   XmNy, (int)(y_shadow),
648                                                   XmNshadowType, XmSHADOW_IN,
649                                                   XmNshadowThickness, _at->shadow_thickness,
650                                                   NULL);
651        }
652    }
653
654    Widget button = 0;
655
656    {
657        aw_xargs args(9);
658        args.add(XmNx, x_button);
659        args.add(XmNy, y_button);
660
661        args.add(XmNfontList,   (XtArgVal)p_global->fontlist);
662        args.add(XmNbackground, _at->background_color);
663
664        if (!let_motif_choose_size) {
665            args.add(XmNwidth,  width_of_button);
666            args.add(XmNheight, height_of_button);
667        }
668
669        if (_callback) {
670            args.add(XmNshadowThickness, _at->shadow_thickness);
671            args.add(XmNalignment,       XmALIGNMENT_CENTER);
672
673            button = XtVaCreateManagedWidget("button", xmPushButtonWidgetClass, fatherwidget, RES_LABEL_CONVERT(buttonlabel), NULL);
674        }
675        else { // button w/o callback; (flat, not clickable)
676            button = XtVaCreateManagedWidget("label", xmLabelWidgetClass, parent_widget, RES_LABEL_CONVERT(buttonlabel), NULL);
677            args.add(XmNalignment, (org_correct_for_at_center == 1) ? XmALIGNMENT_CENTER : XmALIGNMENT_BEGINNING);
678        }
679
680        if (!_at->attach_any || !_callback) args.add(XmNrecomputeSize, false);
681        args.assign_to_widget(button);
682        if (_at->attach_any) aw_attach_widget(button, _at);
683
684        if (_callback) {
685            root->make_sensitive(button, _at->widget_mask);
686        }
687        else {
688            aw_assert(_at->correct_for_at_center == 0);
689            AW_JUSTIFY_LABEL(button, _at->correct_for_at_center); // @@@ strange, again sets XmNalignment (already done above). maybe some relict. does nothing if (_at->correct_for_at_center == 0)
690        }
691
692        AW_label_in_awar_list(this, button, buttonlabel);
693    }
694
695    short height = 0;
696    short width  = 0;
697
698    if (_at->to_position_exists) {
699        // size has explicitly been specified in xfig -> calculate
700        height = _at->to_position_y - _at->y_for_next_button;
701        width  = _at->to_position_x - _at->x_for_next_button;
702    }
703
704    {
705        Widget  toRecenter   = 0;
706        int     recenterSize = 0;
707
708        if (!height || !width) {
709            // ask motif for real button size
710            Widget ButOrHigh = _at->highlight ? fatherwidget : button;
711            XtVaGetValues(ButOrHigh, XmNheight, &height, XmNwidth, &width, NULL);
712
713            if (let_motif_choose_size) {
714                if (_at->correct_for_at_center) {
715                    toRecenter   = ButOrHigh;
716                    recenterSize = width;
717                }
718                width = 0;          // ignore the used size (because it may use more than the window size)
719            }
720        }
721
722        if (toRecenter) {
723            int shiftback = 0;
724            switch (_at->correct_for_at_center) {
725                case 1: shiftback = recenterSize/2; break;
726                case 2: shiftback = recenterSize; break;
727            }
728            if (shiftback) {
729                XtVaSetValues(toRecenter, XmNx, x_button-shiftback, NULL);
730            }
731        }
732    }
733
734    _at->correct_for_at_center = org_correct_for_at_center; // restore original justification
735    _at->y_for_next_button     = org_y_for_next_button;
736
737    p_w->toggle_field = button;
738    this->_set_activate_callback((void *)button);
739    this->unset_at_commands();
740    this->increment_at_commands(width+SPACE_BEHIND_BUTTON, height);
741}
742
743void AW_window::dump_at_position(const char *tmp_label) const {
744    printf("%s at x = %i / y = %i\n", tmp_label, _at->x_for_next_button, _at->y_for_next_button);
745}
746
747void AW_window::update_label(Widget widget, const char *var_value) {
748    if (get_root()->changer_of_variable != widget) {
749        XtVaSetValues(widget, RES_CONVERT(XmNlabelString, var_value), NULL);
750    }
751    else {
752        get_root()->changer_of_variable = 0;
753    }
754}
755
756// ----------------------
757//      on/off toggle
758
759struct aw_toggle_data {
760    bool  isTextToggle;
761    char *bitmapOrText[2];
762    int   buttonWidth; // wanted width in characters
763};
764
765void AW_window::update_toggle(Widget widget, const char *var, AW_CL cd_toggle_data) {
766    aw_toggle_data *tdata = (aw_toggle_data*)cd_toggle_data;
767    const char     *text  = tdata->bitmapOrText[(var[0] == '0' || var[0] == 'n') ? 0 : 1];
768
769    if (tdata->isTextToggle) {
770        XtVaSetValues(widget, RES_CONVERT(XmNlabelString, text), NULL);
771    }
772    else {
773        char *path = pixmapPath(text+1);
774        XtVaSetValues(widget, RES_CONVERT(XmNlabelPixmap, path), NULL);
775        free(path);
776    }
777}
778
779void AW_window::create_toggle(const char *var_name, aw_toggle_data *tdata) {
780    AW_cb *cbs = _callback;
781    _callback         = (AW_cb *)1;
782
783    {
784        int old_length_of_buttons = _at->length_of_buttons;
785
786        if (tdata->buttonWidth == 0) {
787            if (tdata->isTextToggle) {
788                int l1 = strlen(tdata->bitmapOrText[0]);
789                int l2 = strlen(tdata->bitmapOrText[1]);
790
791                _at->length_of_buttons = l1>l2 ? l1 : l2; // use longer text for button size
792            }
793            else {
794                _at->length_of_buttons = 0;
795            }
796        }
797        else {
798            _at->length_of_buttons = tdata->buttonWidth;
799        }
800
801        create_button(0, tdata->bitmapOrText[0], 0);
802
803        _at->length_of_buttons = old_length_of_buttons;
804    }
805
806    AW_awar *vs = this->get_root()->awar(var_name);
807    {
808        char *var_value = vs->read_as_string();
809
810        this->update_toggle(p_w->toggle_field, var_value, (AW_CL)tdata);
811        free(var_value);
812    }
813
814    VarUpdateInfo *vui;
815    vui = new VarUpdateInfo(this, p_w->toggle_field, AW_WIDGET_TOGGLE, vs, cbs);
816
817    XtAddCallback(p_w->toggle_field, XmNactivateCallback,
818                  (XtCallbackProc) AW_variable_update_callback,
819                  (XtPointer) vui);
820
821    vs->tie_widget((AW_CL)tdata, p_w->toggle_field, AW_WIDGET_TOGGLE, this);
822}
823
824
825void AW_window::create_toggle(const char *var_name, const char *no, const char *yes, int buttonWidth) {
826    aw_toggle_data *tdata  = new aw_toggle_data;
827    tdata->isTextToggle    = false;
828
829    aw_assert(AW_IS_IMAGEREF(no));
830    aw_assert(AW_IS_IMAGEREF(yes));
831
832    tdata->bitmapOrText[0] = strdup(no);
833    tdata->bitmapOrText[1] = strdup(yes);
834
835    tdata->buttonWidth = buttonWidth;
836
837    create_toggle(var_name, tdata);
838}
839
840void AW_window::create_text_toggle(const char *var_name, const char *noText, const char *yesText, int buttonWidth) {
841    aw_toggle_data *tdata  = new aw_toggle_data;
842    tdata->isTextToggle    = true;
843    tdata->bitmapOrText[0] = strdup(noText);
844    tdata->bitmapOrText[1] = strdup(yesText);
845    tdata->buttonWidth     = buttonWidth;
846
847    create_toggle(var_name, tdata);
848}
849
850
851void AW_window::create_toggle(const char *var_name) {
852    create_toggle(var_name, "#no.xpm", "#yes.xpm");
853}
854
855void AW_window::create_inverse_toggle(const char *var_name) {
856    // like create_toggle, but displays inverse value
857    // (i.e. it's checked if value is zero, and unchecked otherwise)
858    create_toggle(var_name, "#yes.xpm", "#no.xpm");
859}
860
861// ---------------------
862//      input fields
863
864void AW_window::create_input_field(const char *var_name,   int columns) {
865    Widget         textField      = 0;
866    Widget         tmp_label      = 0;
867    AW_cb  *cbs;
868    VarUpdateInfo *vui;
869    char          *str;
870    int            xoff_for_label = 0;
871
872    if (!columns) columns = _at->length_of_buttons;
873
874    AW_awar *vs = root->awar(var_name);
875    str         = root->awar(var_name)->read_as_string();
876
877    int width_of_input_label, height_of_input_label;
878    calculate_label_size(&width_of_input_label, &height_of_input_label, true, 0);
879    // @@@ FIXME: use height_of_input_label for propper Y-adjusting of label
880    // width_of_input_label = this->calculate_string_width( calculate_label_length() );
881
882    int width_of_input = this->calculate_string_width(columns+1) + 9;
883    // calculate width for 1 additional character (input field is not completely used)
884    // + 4 pixel for shadow + 4 unknown missing pixels + 1 add. pixel needed for visible text area
885
886    Widget parentWidget = _at->attach_any ? INFO_FORM : INFO_WIDGET;
887
888    if (_at->label_for_inputfield) {
889        tmp_label = XtVaCreateManagedWidget("label",
890                                            xmLabelWidgetClass,
891                                            parentWidget,
892                                            XmNwidth, (int)(width_of_input_label + 2),
893                                            XmNhighlightThickness, 0,
894                                            RES_LABEL_CONVERT(_at->label_for_inputfield),
895                                            XmNrecomputeSize, false,
896                                            XmNalignment, XmALIGNMENT_BEGINNING,
897                                            XmNfontList, p_global->fontlist,
898                                            (_at->attach_any) ? NULL : XmNx, (int)_at->x_for_next_button,
899                                            XmNy, (int)(_at->y_for_next_button) + root->y_correction_for_input_labels -1,
900                                            NULL);
901        if (_at->attach_any) aw_attach_widget(tmp_label, _at);
902        xoff_for_label = width_of_input_label + 10;
903    }
904
905
906    int width_of_last_widget = xoff_for_label + width_of_input + 2;
907
908    if (_at->to_position_exists) {
909        width_of_input = _at->to_position_x - _at->x_for_next_button - xoff_for_label + 2;
910        width_of_last_widget = _at->to_position_x - _at->x_for_next_button;
911    }
912
913    {
914        TuneBackground(parentWidget, TUNE_INPUT);
915        textField = XtVaCreateManagedWidget("textField",
916                                            xmTextFieldWidgetClass,
917                                            parentWidget,
918                                            XmNwidth, (int)width_of_input,
919                                            XmNrows, 1,
920                                            XmNvalue, str,
921                                            XmNfontList, p_global->fontlist,
922                                            XmNbackground, _at->background_color,
923                                            (_at->attach_any) ? NULL : XmNx, (int)(_at->x_for_next_button + xoff_for_label),
924                                            XmNy, (int)(_at->y_for_next_button + 5) - 8,
925                                            NULL);
926        if (_at->attach_any) {
927            _at->x_for_next_button += xoff_for_label;
928            aw_attach_widget(textField, _at);
929            _at->x_for_next_button -= xoff_for_label;
930        }
931    }
932
933    free(str);
934
935    // user-own callback
936    cbs = _callback;
937
938    // callback for enter
939    vui = new VarUpdateInfo(this, textField, AW_WIDGET_INPUT_FIELD, vs, cbs);
940
941    XtAddCallback(textField, XmNactivateCallback,
942                  (XtCallbackProc) AW_variable_update_callback,
943                  (XtPointer) vui);
944    if (_d_callback) {
945        XtAddCallback(textField, XmNactivateCallback,
946                      (XtCallbackProc) AW_server_callback,
947                      (XtPointer) _d_callback);
948        _d_callback->id = GBS_global_string_copy("INPUT:%s", var_name);
949        get_root()->define_remote_command(_d_callback);
950    }
951
952    // callback for losing focus
953    XtAddCallback(textField, XmNlosingFocusCallback,
954                  (XtCallbackProc) AW_variable_update_callback,
955                  (XtPointer) vui);
956    // callback for value changed
957    XtAddCallback(textField, XmNvalueChangedCallback,
958                  (XtCallbackProc) AW_value_changed_callback,
959                  (XtPointer) root);
960
961    vs->tie_widget(0, textField, AW_WIDGET_INPUT_FIELD, this);
962    root->make_sensitive(textField, _at->widget_mask);
963
964    short height;
965    XtVaGetValues(textField, XmNheight, &height, NULL);
966    int height_of_last_widget = height;
967
968    if (_at->correct_for_at_center == 1) {   // middle centered
969        XtVaSetValues(textField, XmNx, ((int)(_at->x_for_next_button + xoff_for_label) - (int)(width_of_last_widget/2) + 1), NULL);
970        if (tmp_label) {
971            XtVaSetValues(tmp_label, XmNx, ((int)(_at->x_for_next_button) - (int)(width_of_last_widget/2) + 1), NULL);
972        }
973        width_of_last_widget = width_of_last_widget / 2;
974    }
975    if (_at->correct_for_at_center == 2) {   // right centered
976        XtVaSetValues(textField, XmNx, (int)(_at->x_for_next_button + xoff_for_label - width_of_last_widget + 3), NULL);
977        if (tmp_label) {
978            XtVaSetValues(tmp_label, XmNx, (int)(_at->x_for_next_button - width_of_last_widget + 3), NULL);
979        }
980        width_of_last_widget = 0;
981    }
982    width_of_last_widget -= 2;
983
984    this->unset_at_commands();
985    this->increment_at_commands(width_of_last_widget, height_of_last_widget);
986
987}
988
989void AW_window::update_input_field(Widget widget, const char *var_value) {
990    XtVaSetValues(widget, XmNvalue, var_value, NULL);
991}
992
993void AW_window::create_text_field(const char *var_name, int columns, int rows) {
994    Widget         scrolledWindowText;
995    Widget         scrolledText;
996    Widget         tmp_label             = 0;
997    AW_cb         *cbs;
998    VarUpdateInfo *vui;
999    char          *str                   = NULL;
1000    short          width_of_last_widget  = 0;
1001    short          height_of_last_widget = 0;
1002    int            width_of_text         = 0;
1003    int            height_of_text        = 0;
1004    int            xoff_for_label        = 0;
1005
1006    AW_awar *vs = root->awar(var_name);
1007    str         = root->awar(var_name)->read_string();
1008
1009    int width_of_text_label, height_of_text_label;
1010    calculate_label_size(&width_of_text_label, &height_of_text_label, true, 0);
1011    // @@@ FIXME: use height_of_text_label for propper Y-adjusting of label
1012
1013    // width_of_text_label = this->calculate_string_width( calculate_label_length() );
1014    width_of_text = this->calculate_string_width(columns) + 18;
1015    height_of_text = this->calculate_string_height(rows, rows*4) + 9;
1016
1017
1018    if (_at->label_for_inputfield) {
1019        tmp_label = XtVaCreateManagedWidget("label",
1020                                            xmLabelWidgetClass,
1021                                            INFO_WIDGET,
1022                                            XmNx, (int)_at->x_for_next_button,
1023                                            XmNy, (int)(_at->y_for_next_button) + this->get_root()->y_correction_for_input_labels + 5 - 6,
1024                                            XmNwidth, (int)(width_of_text_label + 2),
1025                                            RES_LABEL_CONVERT(_at->label_for_inputfield),
1026                                            XmNrecomputeSize, false,
1027                                            XmNalignment, XmALIGNMENT_BEGINNING,
1028                                            XmNfontList, p_global->fontlist,
1029                                            NULL);
1030
1031        xoff_for_label = width_of_text_label + 10;
1032
1033    }
1034
1035    {
1036        aw_xargs args(6);
1037        args.add(XmNscrollingPolicy,        XmAPPLICATION_DEFINED);
1038        args.add(XmNvisualPolicy,           XmVARIABLE);
1039        args.add(XmNscrollBarDisplayPolicy, XmSTATIC);
1040        args.add(XmNfontList,               (XtArgVal)p_global->fontlist);
1041
1042        if (_at->to_position_exists) {
1043            scrolledWindowText = XtVaCreateManagedWidget("scrolledWindowList1", xmScrolledWindowWidgetClass, INFO_FORM, NULL);
1044            args.assign_to_widget(scrolledWindowText);
1045
1046            aw_attach_widget(scrolledWindowText, _at);
1047            width_of_text = _at->to_position_x - _at->x_for_next_button - xoff_for_label - 18;
1048            if (_at->y_for_next_button < _at->to_position_y - 18) {
1049                height_of_text = _at->to_position_y - _at->y_for_next_button - 18;
1050            }
1051        }
1052        else {
1053            scrolledWindowText = XtVaCreateManagedWidget("scrolledWindowText", xmScrolledWindowWidgetClass, INFO_WIDGET, NULL);
1054            args.add(XmNx, 10);
1055            args.add(XmNy, _at->y_for_next_button);
1056            args.assign_to_widget(scrolledWindowText);
1057        }
1058    }
1059
1060    TuneBackground(scrolledWindowText, TUNE_INPUT);
1061    scrolledText = XtVaCreateManagedWidget("scrolledText1",
1062                                           xmTextWidgetClass,
1063                                           scrolledWindowText,
1064                                           XmNeditMode, XmMULTI_LINE_EDIT,
1065                                           XmNvalue, str,
1066                                           XmNscrollLeftSide, false,
1067                                           XmNwidth, (int)width_of_text,
1068                                           XmNheight, (int)height_of_text,
1069                                           XmNfontList, p_global->fontlist,
1070                                           XmNbackground, _at->background_color,
1071                                           NULL);
1072    free(str);
1073
1074    if (!_at->to_position_exists) {
1075        XtVaGetValues(scrolledWindowText,   XmNheight, &height_of_last_widget,
1076                      XmNwidth, &width_of_last_widget, NULL);
1077
1078        width_of_last_widget += (short)xoff_for_label;
1079
1080        switch (_at->correct_for_at_center) {
1081            case 0: // left centered
1082                XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + xoff_for_label), NULL);
1083                break;
1084
1085            case 1: // middle centered
1086                XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + xoff_for_label - (width_of_last_widget/2)), NULL);
1087                if (_at->label_for_inputfield) {
1088                    XtVaSetValues(tmp_label, XmNx, (int)(_at->x_for_next_button - (width_of_last_widget/2)), NULL);
1089                }
1090                width_of_last_widget = width_of_last_widget / 2;
1091                break;
1092
1093            case 2: // right centered
1094                XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + xoff_for_label - width_of_last_widget),     NULL);
1095                if (_at->label_for_inputfield) {
1096                    XtVaSetValues(tmp_label, XmNx, (int)(_at->x_for_next_button - width_of_last_widget), NULL);
1097                }
1098                width_of_last_widget = 0;
1099                break;
1100        }
1101    }
1102
1103    // user-own callback
1104    cbs = _callback;
1105
1106    // callback for enter
1107    vui = new VarUpdateInfo(this, scrolledText, AW_WIDGET_TEXT_FIELD, vs, cbs);
1108    XtAddCallback(scrolledText, XmNactivateCallback, (XtCallbackProc) AW_variable_update_callback, (XtPointer) vui);
1109    // callback for losing focus
1110    XtAddCallback(scrolledText, XmNlosingFocusCallback, (XtCallbackProc) AW_variable_update_callback, (XtPointer) vui);
1111    // callback for value changed
1112    XtAddCallback(scrolledText, XmNvalueChangedCallback, (XtCallbackProc) AW_value_changed_callback, (XtPointer) root);
1113
1114    vs->tie_widget(0, scrolledText, AW_WIDGET_TEXT_FIELD, this);
1115    root->make_sensitive(scrolledText, _at->widget_mask);
1116
1117    this->unset_at_commands();
1118    this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1119}
1120
1121
1122void AW_window::update_text_field(Widget widget, const char *var_value) {
1123    XtVaSetValues(widget, XmNvalue, var_value, NULL);
1124}
1125
1126// -----------------------
1127//      selection list
1128
1129
1130static void scroll_sellist(Widget scrolledList, bool upwards) {
1131    int oldPos, visible, items;
1132    XtVaGetValues(scrolledList,
1133                  XmNtopItemPosition, &oldPos,
1134                  XmNvisibleItemCount, &visible,
1135                  XmNitemCount,  &items, 
1136                  NULL);
1137
1138    int amount = visible/5;
1139    if (amount<1) amount = 1;
1140    if (upwards) amount = -amount;
1141
1142    int newPos = force_in_range(1, oldPos + amount, items-visible+2);
1143    if (newPos != oldPos) XmListSetPos(scrolledList, newPos);
1144}
1145
1146static void scroll_sellist_up(Widget scrolledList, XEvent*, String*, Cardinal*) { scroll_sellist(scrolledList, true); }
1147static void scroll_sellist_dn(Widget scrolledList, XEvent*, String*, Cardinal*) { scroll_sellist(scrolledList, false); }
1148
1149AW_selection_list* AW_window::create_selection_list(const char *var_name, int columns, int rows, bool /*fallback2default*/) {
1150    // Note: fallback2default has no meaning in motif-version (always acts like 'false', i.e. never does fallback)
1151    // see also .@create_option_menu
1152
1153    Widget         scrolledWindowList; // @@@ fix locals
1154    Widget         scrolledList;
1155    VarUpdateInfo *vui;
1156    AW_cb         *cbs;
1157
1158    int width_of_list;
1159    int height_of_list;
1160    int width_of_last_widget  = 0;
1161    int height_of_last_widget = 0;
1162
1163    aw_assert(!_at->label_for_inputfield); // labels have no effect for selection lists
1164
1165    AW_awar *vs = 0;
1166
1167    aw_assert(var_name); // @@@ case where var_name == NULL is relict from multi-selection-list (not used; removed)
1168
1169    if (var_name) vs = root->awar(var_name);
1170
1171    width_of_list  = this->calculate_string_width(columns) + 9;
1172    height_of_list = this->calculate_string_height(rows, 4*rows) + 9;
1173
1174    {
1175        aw_xargs args(7);
1176        args.add(XmNvisualPolicy,           XmVARIABLE);
1177        args.add(XmNscrollBarDisplayPolicy, XmSTATIC);
1178        args.add(XmNshadowThickness,        0);
1179        args.add(XmNfontList,               (XtArgVal)p_global->fontlist);
1180
1181        if (_at->to_position_exists) {
1182            width_of_list = _at->to_position_x - _at->x_for_next_button - 18;
1183            if (_at->y_for_next_button  < _at->to_position_y - 18) {
1184                height_of_list = _at->to_position_y - _at->y_for_next_button - 18;
1185            }
1186            scrolledWindowList = XtVaCreateManagedWidget("scrolledWindowList1", xmScrolledWindowWidgetClass, INFO_FORM, NULL);
1187
1188            args.assign_to_widget(scrolledWindowList);
1189            aw_attach_widget(scrolledWindowList, _at);
1190
1191            width_of_last_widget = _at->to_position_x - _at->x_for_next_button;
1192            height_of_last_widget = _at->to_position_y - _at->y_for_next_button;
1193        }
1194        else {
1195            scrolledWindowList = XtVaCreateManagedWidget("scrolledWindowList1", xmScrolledWindowWidgetClass, INFO_WIDGET, NULL);
1196
1197            args.add(XmNscrollingPolicy, XmAPPLICATION_DEFINED);
1198            args.add(XmNx, 10);
1199            args.add(XmNy, _at->y_for_next_button);
1200            args.assign_to_widget(scrolledWindowList);
1201        }
1202    }
1203
1204    {
1205        int select_type = XmMULTIPLE_SELECT;
1206        if (vs) select_type = XmBROWSE_SELECT;
1207
1208        TuneBackground(scrolledWindowList, TUNE_INPUT);
1209        scrolledList = XtVaCreateManagedWidget("scrolledList1",
1210                                               xmListWidgetClass,
1211                                               scrolledWindowList,
1212                                               XmNwidth, (int)width_of_list,
1213                                               XmNheight, (int) height_of_list,
1214                                               XmNscrollBarDisplayPolicy, XmSTATIC,
1215                                               XmNselectionPolicy, select_type,
1216                                               XmNlistSizePolicy, XmCONSTANT,
1217                                               XmNfontList, p_global->fontlist,
1218                                               XmNbackground, _at->background_color,
1219                                               NULL);
1220
1221        static bool actionsAdded = false;
1222        if (!actionsAdded) {
1223            struct _XtActionsRec actions[2] = {
1224                {(char*)"scroll_sellist_up", scroll_sellist_up},
1225                {(char*)"scroll_sellist_dn", scroll_sellist_dn}
1226            };
1227
1228            XtAppAddActions(p_global->context, actions, 2);
1229        }
1230
1231        XtTranslations translations = XtParseTranslationTable(
1232            "<Btn4Down>:scroll_sellist_up()\n"
1233            "<Btn5Down>:scroll_sellist_dn()\n"
1234            );
1235        XtAugmentTranslations(scrolledList, translations);
1236    }
1237
1238    if (!_at->to_position_exists) {
1239        short height;
1240        XtVaGetValues(scrolledList, XmNheight, &height, NULL);
1241        height_of_last_widget = height + 20;
1242        width_of_last_widget  = width_of_list + 20;
1243
1244        switch (_at->correct_for_at_center) {
1245            case 3: break;
1246            case 0: // left aligned
1247                XtVaSetValues(scrolledWindowList, XmNx, (int)(_at->x_for_next_button), NULL);
1248                break;
1249
1250            case 1: // center aligned
1251                XtVaSetValues(scrolledWindowList, XmNx, (int)(_at->x_for_next_button - (width_of_last_widget/2)), NULL);
1252                width_of_last_widget = width_of_last_widget / 2;
1253                break;
1254
1255            case 2: // right aligned
1256                XtVaSetValues(scrolledWindowList, XmNx, (int)(_at->x_for_next_button - width_of_list - 18), NULL);
1257                width_of_last_widget = 0;
1258                break;
1259        }
1260
1261    }
1262
1263    {
1264        int type = GB_STRING;
1265        if (vs)  type = vs->variable_type;
1266
1267        if (p_global->selection_list) {
1268            p_global->last_selection_list->next = new AW_selection_list(var_name, type, scrolledList);
1269            p_global->last_selection_list = p_global->last_selection_list->next;
1270        }
1271        else {
1272            p_global->last_selection_list = p_global->selection_list = new AW_selection_list(var_name, type, scrolledList);
1273        }
1274    }
1275
1276
1277    // user-own callback
1278    cbs = _callback;
1279
1280    // callback for enter
1281    if (vs) {
1282        vui = new VarUpdateInfo(this, scrolledList, AW_WIDGET_SELECTION_LIST, vs, cbs);
1283        vui->set_sellist(p_global->last_selection_list);
1284
1285        XtAddCallback(scrolledList, XmNbrowseSelectionCallback,
1286                      (XtCallbackProc) AW_variable_update_callback,
1287                      (XtPointer) vui);
1288
1289        if (_d_callback) {
1290            XtAddCallback(scrolledList, XmNdefaultActionCallback,
1291                          (XtCallbackProc) AW_server_callback,
1292                          (XtPointer) _d_callback);
1293        }
1294        vs->tie_widget((AW_CL)p_global->last_selection_list, scrolledList, AW_WIDGET_SELECTION_LIST, this);
1295        root->make_sensitive(scrolledList, _at->widget_mask);
1296    }
1297
1298    this->unset_at_commands();
1299    this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1300    return p_global->last_selection_list;
1301}
1302
1303__ATTR__NORETURN inline void option_type_mismatch(const char *triedType) { type_mismatch(triedType, "option-menu"); }
1304__ATTR__NORETURN inline void toggle_type_mismatch(const char *triedType) { type_mismatch(triedType, "toggle"); }
1305
1306// ----------------------
1307//      Options-Menu
1308
1309AW_option_menu_struct *AW_window::create_option_menu(const char *awar_name, bool /*fallback2default*/) {
1310    // Note: fallback2default has no meaning in motif-version (always acts like 'false', i.e. never does fallback)
1311    // see also .@create_selection_list
1312
1313    Widget optionMenu_shell;
1314    Widget optionMenu;
1315    Widget optionMenu1;
1316    int    x_for_position_of_menu;
1317
1318    const char *tmp_label = _at->label_for_inputfield;
1319    if (tmp_label && !tmp_label[0]) {
1320        aw_assert(0); // do not specify empty labels (causes misalignment)
1321        tmp_label = NULL;
1322    }
1323
1324    _at->saved_x           = _at->x_for_next_button - (tmp_label ? 0 : 10);
1325    x_for_position_of_menu = 10;
1326
1327    optionMenu_shell = XtVaCreatePopupShell ("optionMenu shell",
1328                                             xmMenuShellWidgetClass,
1329                                             INFO_WIDGET,
1330                                             XmNwidth, 1,
1331                                             XmNheight, 1,
1332                                             XmNallowShellResize, true,
1333                                             XmNoverrideRedirect, true,
1334                                             XmNfontList, p_global->fontlist,
1335                                             NULL);
1336
1337    optionMenu = XtVaCreateWidget("optionMenu_p1",
1338                                  xmRowColumnWidgetClass,
1339                                  optionMenu_shell,
1340                                  XmNrowColumnType, XmMENU_PULLDOWN,
1341                                  XmNfontList, p_global->fontlist,
1342                                  NULL);
1343    {
1344        aw_xargs args(3);
1345        args.add(XmNfontList, (XtArgVal)p_global->fontlist);
1346        if (!_at->attach_x && !_at->attach_lx) args.add(XmNx, x_for_position_of_menu);
1347        if (!_at->attach_y && !_at->attach_ly) args.add(XmNy, _at->y_for_next_button-5);
1348
1349        if (tmp_label) {
1350            int   width_help_label, height_help_label;
1351            calculate_label_size(&width_help_label, &height_help_label, false, tmp_label);
1352            // @@@ FIXME: use height_help_label for Y-alignment
1353#if defined(DUMP_BUTTON_CREATION)
1354            printf("width_help_label=%i label='%s'\n", width_help_label, tmp_label);
1355#endif // DUMP_BUTTON_CREATION
1356
1357            {
1358                aw_assert(!AW_IS_IMAGEREF(tmp_label)); // using images as labels for option menus will work in gtk (wont fix in motif)
1359
1360                char *help_label = this->align_string(tmp_label, width_help_label);
1361                optionMenu1      = XtVaCreateManagedWidget("optionMenu1",
1362                                                           xmRowColumnWidgetClass,
1363                                                           (_at->attach_any) ? INFO_FORM : INFO_WIDGET,
1364                                                           XmNrowColumnType, XmMENU_OPTION,
1365                                                           XmNsubMenuId, optionMenu,
1366                                                           RES_CONVERT(XmNlabelString, help_label),
1367                                                           NULL);
1368                free(help_label);
1369            }
1370        }
1371        else {
1372            _at->x_for_next_button = _at->saved_x;
1373
1374            optionMenu1 = XtVaCreateManagedWidget("optionMenu1",
1375                                                  xmRowColumnWidgetClass,
1376                                                  (_at->attach_any) ? INFO_FORM : INFO_WIDGET,
1377                                                  XmNrowColumnType, XmMENU_OPTION,
1378                                                  XmNsubMenuId, optionMenu,
1379                                                  NULL);
1380        }
1381        args.assign_to_widget(optionMenu1);
1382    }
1383
1384#if 0
1385    // setting background color for radio button only does not work.
1386    // works only for label and button together, but that's not what we want.
1387    TuneBackground(optionMenu_shell, TUNE_BUTTON); // set background color for radio button
1388    XtVaSetValues(optionMenu1, // colorizes background and label
1389                  XmNbackground, _at->background_color,
1390                  NULL);
1391#endif
1392
1393    get_root()->number_of_option_menus++;
1394
1395    AW_awar *vs = root->awar(awar_name);
1396    {
1397        AW_option_menu_struct *next =
1398            new AW_option_menu_struct(get_root()->number_of_option_menus,
1399                                      awar_name,
1400                                      vs->variable_type,
1401                                      optionMenu1,
1402                                      optionMenu,
1403                                      _at->x_for_next_button - 7,
1404                                      _at->y_for_next_button,
1405                                      _at->correct_for_at_center);
1406
1407        if (p_global->option_menu_list) {
1408            p_global->last_option_menu->next = next;
1409            p_global->last_option_menu = p_global->last_option_menu->next;
1410        }
1411        else {
1412            p_global->last_option_menu = p_global->option_menu_list = next;
1413        }
1414    }
1415
1416    p_global->current_option_menu = p_global->last_option_menu;
1417
1418    vs->tie_widget((AW_CL)p_global->current_option_menu, optionMenu, AW_WIDGET_CHOICE_MENU, this);
1419    root->make_sensitive(optionMenu1, _at->widget_mask);
1420
1421    return p_global->current_option_menu;
1422}
1423
1424static void remove_option_from_option_menu(AW_root *aw_root, AW_widget_value_pair *os) {
1425    aw_root->remove_button_from_sens_list(os->widget);
1426    XtDestroyWidget(os->widget);
1427}
1428
1429void AW_window::clear_option_menu(AW_option_menu_struct *oms) {
1430    p_global->current_option_menu = oms; // define as current (for subsequent inserts)
1431
1432    AW_widget_value_pair *next_os;
1433    for (AW_widget_value_pair *os = oms->first_choice; os; os = next_os) {
1434        next_os  = os->next;
1435        os->next = 0;
1436        remove_option_from_option_menu(root, os);
1437        delete os;
1438    }
1439
1440    if (oms->default_choice) {
1441        remove_option_from_option_menu(root, oms->default_choice);
1442        oms->default_choice = 0;
1443    }
1444
1445    oms->first_choice   = 0;
1446    oms->last_choice    = 0;
1447}
1448
1449void *AW_window::_create_option_entry(AW_VARIABLE_TYPE IF_ASSERTION_USED(type), const char *name, const char */*mnemonic*/, const char *name_of_color) {
1450    Widget                 entry;
1451    AW_option_menu_struct *oms = p_global->current_option_menu;
1452
1453    aw_assert(oms->variable_type == type); // adding wrong entry type
1454
1455    TuneOrSetBackground(oms->menu_widget, name_of_color, TUNE_BUTTON); // set background color for radio button entries
1456    entry = XtVaCreateManagedWidget("optionMenu_entry",
1457                                    xmPushButtonWidgetClass,
1458                                    oms->menu_widget,
1459                                    RES_CONVERT(XmNlabelString, name), // force text (as gtk version does)
1460                                    XmNfontList, p_global->fontlist,
1461                                    XmNbackground, _at->background_color,
1462                                    NULL);
1463    AW_label_in_awar_list(this, entry, name);
1464    return (void *)entry;
1465}
1466
1467inline void option_menu_add_option(AW_option_menu_struct *oms, AW_widget_value_pair *os, bool default_option) {
1468    if (default_option) {
1469        oms->default_choice = os;
1470    }
1471    else {
1472        if (oms->first_choice) {
1473            oms->last_choice->next = os;
1474            oms->last_choice       = oms->last_choice->next;
1475        }
1476        else {
1477            oms->last_choice = oms->first_choice = os;
1478        }
1479    }
1480}
1481
1482// for string :
1483
1484void AW_window::insert_option_internal(AW_label option_name, const char *mnemonic, const char *var_value, const char *name_of_color, bool default_option) {
1485    AW_option_menu_struct *oms = p_global->current_option_menu;
1486    if (oms->variable_type != AW_STRING) {
1487        option_type_mismatch("string");
1488    }
1489    else {
1490        Widget        entry = (Widget)_create_option_entry(AW_STRING, option_name, mnemonic, name_of_color);
1491        AW_cb *cbs   = _callback; // user-own callback
1492
1493        // callback for new choice
1494        XtAddCallback(entry, XmNactivateCallback,
1495                      (XtCallbackProc) AW_variable_update_callback,
1496                      (XtPointer) new VarUpdateInfo(this, NULL, AW_WIDGET_CHOICE_MENU, root->awar(oms->variable_name), var_value, cbs));
1497
1498        option_menu_add_option(p_global->current_option_menu, new AW_widget_value_pair(var_value, entry), default_option);
1499        root->make_sensitive(entry, _at->widget_mask);
1500        this->unset_at_commands();
1501    }
1502}
1503void AW_window::insert_option_internal(AW_label option_name, const char *mnemonic, int var_value, const char *name_of_color, bool default_option) {
1504    AW_option_menu_struct *oms = p_global->current_option_menu;
1505
1506    if (oms->variable_type != AW_INT) {
1507        option_type_mismatch("int");
1508    }
1509    else {
1510        Widget        entry = (Widget)_create_option_entry(AW_INT, option_name, mnemonic, name_of_color);
1511        AW_cb *cbs   = _callback; // user-own callback
1512
1513        // callback for new choice
1514        XtAddCallback(entry, XmNactivateCallback,
1515                      (XtCallbackProc) AW_variable_update_callback,
1516                      (XtPointer) new VarUpdateInfo(this, NULL, AW_WIDGET_CHOICE_MENU, root->awar(oms->variable_name), var_value, cbs));
1517
1518        option_menu_add_option(p_global->current_option_menu, new AW_widget_value_pair(var_value, entry), default_option);
1519        root->make_sensitive(entry, _at->widget_mask);
1520        this->unset_at_commands();
1521    }
1522}
1523void AW_window::insert_option_internal(AW_label option_name, const char *mnemonic, float var_value, const char *name_of_color, bool default_option) {
1524    AW_option_menu_struct *oms = p_global->current_option_menu;
1525
1526    if (oms->variable_type != AW_FLOAT) {
1527        option_type_mismatch("float");
1528    }
1529    else {
1530        Widget        entry = (Widget)_create_option_entry(AW_FLOAT, option_name, mnemonic, name_of_color);
1531        AW_cb *cbs   = _callback; // user-own callback
1532
1533        // callback for new choice
1534        XtAddCallback(entry, XmNactivateCallback,
1535                      (XtCallbackProc) AW_variable_update_callback,
1536                      (XtPointer) new VarUpdateInfo(this, NULL, AW_WIDGET_CHOICE_MENU, root->awar(oms->variable_name), var_value, cbs));
1537
1538        option_menu_add_option(p_global->current_option_menu, new AW_widget_value_pair(var_value, entry), default_option);
1539        root->make_sensitive(entry, _at->widget_mask);
1540        this->unset_at_commands();
1541    }
1542}
1543
1544void AW_window::insert_option        (AW_label on, const char *mn, const char *vv, const char *noc) { insert_option_internal(on, mn, vv, noc, false); }
1545void AW_window::insert_default_option(AW_label on, const char *mn, const char *vv, const char *noc) { insert_option_internal(on, mn, vv, noc, true); }
1546void AW_window::insert_option        (AW_label on, const char *mn, int vv,         const char *noc) { insert_option_internal(on, mn, vv, noc, false); }
1547void AW_window::insert_default_option(AW_label on, const char *mn, int vv,         const char *noc) { insert_option_internal(on, mn, vv, noc, true); }
1548void AW_window::insert_option        (AW_label on, const char *mn, float vv,       const char *noc) { insert_option_internal(on, mn, vv, noc, false); }
1549void AW_window::insert_default_option(AW_label on, const char *mn, float vv,       const char *noc) { insert_option_internal(on, mn, vv, noc, true); }
1550// (see insert_option_internal for longer parameter names)
1551
1552void AW_window::update_option_menu() {
1553    AW_option_menu_struct *oms = p_global->current_option_menu;
1554    refresh_option_menu(oms);
1555
1556    if (_at->attach_any) aw_attach_widget(oms->label_widget, _at);
1557
1558    short width;
1559    short height;
1560    XtVaGetValues(oms->label_widget, XmNwidth, &width, XmNheight, &height, NULL);
1561    int   width_of_last_widget  = width;
1562    int   height_of_last_widget = height;
1563
1564    if (!_at->to_position_exists) {
1565        if (oms->correct_for_at_center_intern == 0) {   // left aligned
1566            XtVaSetValues(oms->label_widget, XmNx, short(_at->saved_x), NULL);
1567        }
1568        if (oms->correct_for_at_center_intern == 1) {   // middle centered
1569            XtVaSetValues(oms->label_widget, XmNx, short(_at->saved_x - width/2), NULL);
1570            width_of_last_widget = width_of_last_widget / 2;
1571        }
1572        if (oms->correct_for_at_center_intern == 2) {   // right aligned
1573            XtVaSetValues(oms->label_widget, XmNx, short(_at->saved_x - width), NULL);
1574            width_of_last_widget = 0;
1575        }
1576    }
1577           
1578    width_of_last_widget += SPACE_BEHIND_BUTTON;
1579
1580    this->unset_at_commands();
1581    this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1582}
1583
1584void AW_window::refresh_option_menu(AW_option_menu_struct *oms) {
1585    if (get_root()->changer_of_variable != oms->label_widget) {
1586        AW_widget_value_pair *active_choice = oms->first_choice;
1587        {
1588            AW_scalar global_var_value(root->awar(oms->variable_name));
1589            while (active_choice && global_var_value != active_choice->value) {
1590                active_choice = active_choice->next;
1591            }
1592        }
1593
1594        if (!active_choice) active_choice = oms->default_choice;
1595        if (active_choice) XtVaSetValues(oms->label_widget, XmNmenuHistory, active_choice->widget, NULL);
1596
1597    }
1598}
1599
1600// -------------------------------------------------------
1601//      toggle field (actually this are radio buttons)
1602
1603void AW_window::create_toggle_field(const char *var_name, AW_label labeli, const char */*mnemonic*/) {
1604    if (labeli) this->label(labeli);
1605    this->create_toggle_field(var_name);
1606}
1607
1608
1609void AW_window::create_toggle_field(const char *var_name, int orientation) {
1610    // orientation = 0 -> vertical else horizontal layout
1611
1612    Widget label_for_toggle;
1613    Widget toggle_field;
1614
1615    int xoff_for_label           = 0;
1616    int width_of_label           = 0;
1617    int x_for_position_of_option = 0;
1618
1619    const char *tmp_label = "";
1620
1621    if (_at->label_for_inputfield) {
1622        tmp_label = _at->label_for_inputfield;
1623    }
1624
1625    if (_at->correct_for_at_center) {
1626        _at->saved_x = _at->x_for_next_button;
1627        x_for_position_of_option = 10;
1628    }
1629    else {
1630        x_for_position_of_option = _at->x_for_next_button;
1631    }
1632
1633
1634    if (tmp_label) {
1635        int height_of_label;
1636        calculate_label_size(&width_of_label, &height_of_label, true, tmp_label);
1637        // @@@ FIXME: use height_of_label for Y-alignment
1638        // width_of_label = this->calculate_string_width( this->calculate_label_length() );
1639        label_for_toggle = XtVaCreateManagedWidget("label",
1640                                                   xmLabelWidgetClass,
1641                                                   INFO_WIDGET,
1642                                                   XmNx, (int)_at->x_for_next_button,
1643                                                   XmNy, (int)(_at->y_for_next_button) + this->get_root()->y_correction_for_input_labels,
1644                                                   XmNwidth, (int)(width_of_label + 2),
1645                                                   RES_CONVERT(XmNlabelString, tmp_label),
1646                                                   XmNrecomputeSize, false,
1647                                                   XmNalignment, XmALIGNMENT_BEGINNING,
1648                                                   XmNfontList, p_global->fontlist,
1649                                                   NULL);
1650
1651        _at->saved_xoff_for_label = xoff_for_label = width_of_label + 10;
1652
1653        p_w->toggle_label = label_for_toggle;
1654    }
1655    else {
1656        p_w->toggle_label = NULL;
1657        _at->saved_xoff_for_label = 0;
1658    }
1659
1660    {
1661        aw_xargs args(6);
1662        args.add(XmNx,              x_for_position_of_option + xoff_for_label);
1663        args.add(XmNy,              _at->y_for_next_button - 2);
1664        args.add(XmNradioBehavior,  True);
1665        args.add(XmNradioAlwaysOne, True);
1666        args.add(XmNfontList,       (XtArgVal)p_global->fontlist);
1667        args.add(XmNorientation,    orientation ? XmHORIZONTAL : XmVERTICAL);
1668       
1669        toggle_field = XtVaCreateManagedWidget("rowColumn for toggle field", xmRowColumnWidgetClass, (_at->attach_any) ? INFO_FORM : INFO_WIDGET, NULL);
1670
1671        args.assign_to_widget(toggle_field);
1672    }
1673    if (_at->attach_any) {
1674        aw_attach_widget(toggle_field, _at, 300);
1675    }
1676
1677    AW_awar *vs = root->awar(var_name);
1678
1679    p_w->toggle_field = toggle_field;
1680    free((p_w->toggle_field_var_name));
1681    p_w->toggle_field_var_name = strdup(var_name);
1682    p_w->toggle_field_var_type = vs->variable_type;
1683
1684    get_root()->number_of_toggle_fields++;
1685
1686    if (p_global->toggle_field_list) {
1687        p_global->last_toggle_field->next = new AW_toggle_field_struct(get_root()->number_of_toggle_fields, var_name, vs->variable_type, toggle_field, _at->correct_for_at_center);
1688        p_global->last_toggle_field = p_global->last_toggle_field->next;
1689    }
1690    else {
1691        p_global->last_toggle_field = p_global->toggle_field_list = new AW_toggle_field_struct(get_root()->number_of_toggle_fields, var_name, vs->variable_type, toggle_field, _at->correct_for_at_center);
1692    }
1693
1694    vs->tie_widget(get_root()->number_of_toggle_fields, toggle_field, AW_WIDGET_TOGGLE_FIELD, this);
1695    root->make_sensitive(toggle_field, _at->widget_mask);
1696}
1697
1698static Widget _aw_create_toggle_entry(AW_window *aww, Widget toggle_field,
1699                                      const char *label, const char *mnemonic,
1700                                      VarUpdateInfo *awus,
1701                                      AW_widget_value_pair *toggle, bool default_toggle) {
1702    AW_root *root = aww->get_root();
1703
1704    Widget          toggleButton;
1705
1706    toggleButton = XtVaCreateManagedWidget("toggleButton",
1707                                           xmToggleButtonWidgetClass,
1708                                           toggle_field,
1709                                           RES_LABEL_CONVERT_AWW(label, aww),
1710                                           RES_CONVERT(XmNmnemonic, mnemonic),
1711                                           XmNindicatorSize, 16,
1712                                           XmNfontList, p_global->fontlist,
1713
1714                                           NULL);
1715    toggle->widget = toggleButton;
1716    awus->set_widget(toggleButton);
1717    XtAddCallback(toggleButton, XmNvalueChangedCallback,
1718                  (XtCallbackProc) AW_variable_update_callback,
1719                  (XtPointer) awus);
1720    if (default_toggle) {
1721        delete p_global->last_toggle_field->default_toggle;
1722        p_global->last_toggle_field->default_toggle = toggle;
1723    }
1724    else {
1725        if (p_global->last_toggle_field->first_toggle) {
1726            p_global->last_toggle_field->last_toggle->next = toggle;
1727            p_global->last_toggle_field->last_toggle = toggle;
1728        }
1729        else {
1730            p_global->last_toggle_field->last_toggle = toggle;
1731            p_global->last_toggle_field->first_toggle = toggle;
1732        }
1733    }
1734    root->make_sensitive(toggleButton, aww->get_at().widget_mask);
1735
1736    aww->unset_at_commands();
1737    return  toggleButton;
1738}
1739
1740
1741void AW_window::insert_toggle_internal(AW_label toggle_label, const char *mnemonic, const char *var_value, bool default_toggle) {
1742    if (p_w->toggle_field_var_type != AW_STRING) {
1743        toggle_type_mismatch("string");
1744    }
1745    else {
1746        _aw_create_toggle_entry(this, p_w->toggle_field, toggle_label, mnemonic,
1747                                new VarUpdateInfo(this, NULL, AW_WIDGET_TOGGLE_FIELD, root->awar(p_w->toggle_field_var_name), var_value, _callback),
1748                                new AW_widget_value_pair(var_value, 0),
1749                                default_toggle);
1750    }
1751}
1752void AW_window::insert_toggle_internal(AW_label toggle_label, const char *mnemonic, int var_value, bool default_toggle) {
1753    if (p_w->toggle_field_var_type != AW_INT) {
1754        toggle_type_mismatch("int");
1755    }
1756    else {
1757        _aw_create_toggle_entry(this, p_w->toggle_field, toggle_label, mnemonic,
1758                                new VarUpdateInfo(this, NULL, AW_WIDGET_TOGGLE_FIELD, root->awar(p_w->toggle_field_var_name), var_value, _callback),
1759                                new AW_widget_value_pair(var_value, 0),
1760                                default_toggle);
1761    }
1762}
1763void AW_window::insert_toggle_internal(AW_label toggle_label, const char *mnemonic, float var_value, bool default_toggle) {
1764    if (p_w->toggle_field_var_type != AW_FLOAT) {
1765        toggle_type_mismatch("float");
1766    }
1767    else {
1768        _aw_create_toggle_entry(this, p_w->toggle_field, toggle_label, mnemonic,
1769                                new VarUpdateInfo(this, NULL, AW_WIDGET_TOGGLE_FIELD, root->awar(p_w->toggle_field_var_name), var_value, _callback),
1770                                new AW_widget_value_pair(var_value, 0),
1771                                default_toggle);
1772    }
1773}
1774
1775void AW_window::insert_toggle        (AW_label toggle_label, const char *mnemonic, const char *var_value) { insert_toggle_internal(toggle_label, mnemonic, var_value, false); }
1776void AW_window::insert_default_toggle(AW_label toggle_label, const char *mnemonic, const char *var_value) { insert_toggle_internal(toggle_label, mnemonic, var_value, true); }
1777void AW_window::insert_toggle        (AW_label toggle_label, const char *mnemonic, int var_value)           { insert_toggle_internal(toggle_label, mnemonic, var_value, false); }
1778void AW_window::insert_default_toggle(AW_label toggle_label, const char *mnemonic, int var_value)           { insert_toggle_internal(toggle_label, mnemonic, var_value, true); }
1779void AW_window::insert_toggle        (AW_label toggle_label, const char *mnemonic, float var_value)         { insert_toggle_internal(toggle_label, mnemonic, var_value, false); }
1780void AW_window::insert_default_toggle(AW_label toggle_label, const char *mnemonic, float var_value)         { insert_toggle_internal(toggle_label, mnemonic, var_value, true); }
1781
1782void AW_window::update_toggle_field() {
1783    this->refresh_toggle_field(get_root()->number_of_toggle_fields);
1784}
1785
1786
1787void AW_window::refresh_toggle_field(int toggle_field_number) {
1788#if defined(DEBUG)
1789    static int inside_here = 0;
1790    aw_assert(!inside_here);
1791    inside_here++;
1792#endif // DEBUG
1793
1794    AW_toggle_field_struct *toggle_field_list = p_global->toggle_field_list;
1795    {
1796        while (toggle_field_list) {
1797            if (toggle_field_number == toggle_field_list->toggle_field_number) {
1798                break;
1799            }
1800            toggle_field_list = toggle_field_list->next;
1801        }
1802    }
1803
1804    if (toggle_field_list) {
1805        AW_widget_value_pair *active_toggle = toggle_field_list->first_toggle;
1806        {
1807            AW_scalar global_value(root->awar(toggle_field_list->variable_name));
1808            while (active_toggle && active_toggle->value != global_value) {
1809                active_toggle = active_toggle->next;
1810            }
1811            if (!active_toggle) active_toggle = toggle_field_list->default_toggle;
1812        }
1813
1814        // iterate over all toggles including default_toggle and set their state
1815        for (AW_widget_value_pair *toggle = toggle_field_list->first_toggle; toggle;) {
1816            XmToggleButtonSetState(toggle->widget, toggle == active_toggle, False);
1817
1818            if (toggle->next)                                     toggle = toggle->next;
1819            else if (toggle != toggle_field_list->default_toggle) toggle = toggle_field_list->default_toggle;
1820            else                                                  toggle = 0;
1821        }
1822
1823        // @@@ code below should go to update_toggle_field
1824        {
1825            short length;
1826            short height;
1827            XtVaGetValues(p_w->toggle_field, XmNwidth, &length, XmNheight, &height, NULL);
1828            length                += (short)_at->saved_xoff_for_label;
1829
1830            int width_of_last_widget  = length;
1831            int height_of_last_widget = height;
1832
1833            if (toggle_field_list->correct_for_at_center_intern) {
1834                if (toggle_field_list->correct_for_at_center_intern == 1) {   // middle centered
1835                    XtVaSetValues(p_w->toggle_field, XmNx, (short)((short)_at->saved_x - (short)(length/2) + (short)_at->saved_xoff_for_label), NULL);
1836                    if (p_w->toggle_label) {
1837                        XtVaSetValues(p_w->toggle_label, XmNx, (short)((short)_at->saved_x - (short)(length/2)), NULL);
1838                    }
1839                    width_of_last_widget = width_of_last_widget / 2;
1840                }
1841                if (toggle_field_list->correct_for_at_center_intern == 2) {   // right centered
1842                    XtVaSetValues(p_w->toggle_field, XmNx, (short)((short)_at->saved_x - length + (short)_at->saved_xoff_for_label), NULL);
1843                    if (p_w->toggle_label) {
1844                        XtVaSetValues(p_w->toggle_label, XmNx, (short)((short)_at->saved_x - length),    NULL);
1845                    }
1846                    width_of_last_widget = 0;
1847                }
1848            }
1849
1850            this->unset_at_commands();
1851            this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1852        }
1853    }
1854    else {
1855        GBK_terminatef("update_toggle_field: toggle field %i does not exist", toggle_field_number);
1856    }
1857
1858#if defined(DEBUG)
1859    inside_here--;
1860#endif // DEBUG
1861}
Note: See TracBrowser for help on using the repository browser.