source: tags/ms_r16q3/WINDOW/AW_button.cxx

Last change on this file was 15279, checked in by westram, 8 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 51.0 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_select.hxx"
13#include "aw_awar.hxx"
14#include "aw_window_Xm.hxx"
15#include "aw_msg.hxx"
16#include "aw_root.hxx"
17#include "aw_xargs.hxx"
18#include "aw_varupdate.hxx"
19
20#include <arb_algo.h>
21#include <ad_cb.h>
22
23#include <Xm/Frame.h>
24#include <Xm/ToggleB.h>
25#include <Xm/Label.h>
26#include <Xm/List.h>
27#include <Xm/PushB.h>
28#include <Xm/Text.h>
29#include <Xm/TextF.h>
30#include <Xm/ScrolledW.h>
31#include <Xm/Scale.h>
32
33void AW_variable_update_callback(Widget /*wgt*/, XtPointer variable_update_struct, XtPointer call_data) {
34    VarUpdateInfo *vui = (VarUpdateInfo *) variable_update_struct;
35    aw_assert(vui);
36
37    vui->change_from_widget(call_data);
38}
39
40struct TrackedAwarChange {
41    AW_awar *awar;
42    bool     changed;
43
44    TrackedAwarChange(AW_awar *awar_) : awar(awar_), changed(false) {}
45};
46
47static void track_awar_change_cb(GBDATA *IF_ASSERTION_USED(gbd), TrackedAwarChange *tac, GB_CB_TYPE IF_ASSERTION_USED(cb_type)) {
48    aw_assert(cb_type == GB_CB_CHANGED);
49    aw_assert(tac->awar->gb_var == gbd);
50    tac->changed = true;
51}
52
53#define SCALER_MIN_VALUE 0
54#define SCALER_MAX_VALUE 1000
55
56static int calculate_scaler_value(AW_awar *awar, AW_ScalerType scalerType) {
57    float modAwarRel  = AW_ScalerTransformer(scalerType).awar2scaler(awar);
58    int   scalerValue = SCALER_MIN_VALUE + modAwarRel * (SCALER_MAX_VALUE-SCALER_MIN_VALUE);
59
60    return scalerValue;
61}
62
63static void write_scalervalue_to_awar(int scalerVal, AW_awar *awar, AW_ScalerType scalerType) {
64    float scaleRel = scalerVal/double(SCALER_MAX_VALUE-SCALER_MIN_VALUE);
65    aw_assert(scaleRel>=0.0 && scaleRel<=1.0);
66
67    float aval = AW_ScalerTransformer(scalerType).scaler2awar(scaleRel, awar);
68
69    switch (awar->variable_type) {
70        case AW_FLOAT:
71            awar->write_float(aval);
72            break;
73
74        case AW_INT:
75            awar->write_int(aval);
76            break;
77
78        default:
79            GBK_terminatef("Unsupported awar type %i in write_scalervalue_to_awar", int(awar->variable_type));
80            break;
81    }
82}
83
84void VarUpdateInfo::change_from_widget(XtPointer call_data) {
85    AW_cb::useraction_init();
86   
87    GB_ERROR  error = NULL;
88    AW_root  *root  = awar->root;
89
90    if (root->value_changed) {
91        root->changer_of_variable = widget;
92    }
93
94    TrackedAwarChange tac(awar);
95    if (root->is_tracking()) {
96        // add a callback which writes macro-code (BEFORE any other callback happens; last added, first calledback)
97        GB_transaction ta(awar->gb_var);
98        GB_add_callback(awar->gb_var, GB_CB_CHANGED, makeDatabaseCallback(track_awar_change_cb, &tac));
99    }
100
101    bool run_cb = true;
102    switch (widget_type) {
103        case AW_WIDGET_INPUT_FIELD:
104        case AW_WIDGET_TEXT_FIELD:
105            if (!root->value_changed) {
106                run_cb = false;
107            }
108            else {
109                char *new_text = XmTextGetString((widget));
110                error          = awar->write_as_string(new_text);
111                XtFree(new_text);
112            }
113            break;
114
115        case AW_WIDGET_TOGGLE:
116            root->changer_of_variable = 0;
117            error = awar->toggle_toggle();
118            break;
119
120        case AW_WIDGET_TOGGLE_FIELD:
121            if (XmToggleButtonGetState(widget) == False) break; // no toggle is selected (?)
122            // fall-through
123        case AW_WIDGET_CHOICE_MENU:
124            error = value.write_to(awar);
125            break;
126
127        case AW_WIDGET_SELECTION_LIST: {
128            char *selected; {
129                XmListCallbackStruct *xml = (XmListCallbackStruct*)call_data;
130                XmStringGetLtoR(xml->item, XmSTRING_DEFAULT_CHARSET, &selected);
131            }
132
133            AW_selection_list_entry *entry = ts.sellist->list_table;
134            while (entry && strcmp(entry->get_displayed(), selected) != 0) {
135                entry = entry->next;
136            }
137
138            if (!entry) {   
139                entry = ts.sellist->default_select; // use default selection
140                if (!entry) GBK_terminate("no default specified for selection list"); // or die
141            }
142            entry->value.write_to(awar);
143            XtFree(selected);
144            break;
145        }
146
147        case AW_WIDGET_LABEL_FIELD:
148            break;
149
150        case AW_WIDGET_SCALER: {
151            XmScaleCallbackStruct *xms = (XmScaleCallbackStruct*)call_data;
152            write_scalervalue_to_awar(xms->value, awar, ts.scalerType);
153            break;
154        }
155        default:
156            GBK_terminatef("Unknown widget type %i in AW_variable_update_callback", widget_type);
157            break;
158    }
159
160    if (root->is_tracking()) {
161        {
162            GB_transaction ta(awar->gb_var);
163            GB_remove_callback(awar->gb_var, GB_CB_CHANGED, makeDatabaseCallback(track_awar_change_cb, &tac));
164        }
165        if (tac.changed) {
166            root->track_awar_change(awar);
167        }
168    }
169
170    if (error) {
171        root->changer_of_variable = 0;
172        awar->update();
173        aw_message(error);
174    }
175    else {
176        if (cbs && run_cb) cbs->run_callbacks(); // @@@ generally unwanted callback (see #559)
177        root->value_changed = false;
178
179        aw_message_if(GB_incur_error()); // show error exported by awar-change-callback
180    }
181
182    AW_cb::useraction_done(aw_parent);
183}
184
185
186static void AW_value_changed_callback(Widget /*wgt*/, XtPointer rooti, XtPointer /*call_data*/) {
187    AW_root *root = (AW_root *)rooti;
188    root->value_changed = true;
189}
190
191void aw_attach_widget(Widget w, AW_at *_at, int default_width) {
192    short height = 0;
193    short width = 0;
194    if (!_at->to_position_exists) {
195        XtVaGetValues(w, XmNheight, &height, XmNwidth, &width, NULL);
196        if (default_width >0) width = default_width;
197
198        switch (_at->correct_for_at_center) {
199            case 0:             // left justified
200                _at->to_position_x      = _at->x_for_next_button + width;
201                break;
202            case 1:             // centered
203                _at->to_position_x      = _at->x_for_next_button + width/2;
204                _at->x_for_next_button -= width/2;
205                break;
206            case 2:             // right justified
207                _at->to_position_x      = _at->x_for_next_button;
208                _at->x_for_next_button -= width;
209                break;
210        }
211        _at->to_position_y = _at->y_for_next_button + height;
212        _at->attach_x      = _at->attach_lx;
213        _at->attach_y      = _at->attach_ly;
214    }
215
216#define MIN_RIGHT_OFFSET  10
217#define MIN_BOTTOM_OFFSET 10
218
219    aw_xargs args(4*2);
220
221    if (_at->attach_x) {
222        int right_offset = _at->max_x_size - _at->to_position_x;
223        if (right_offset<MIN_RIGHT_OFFSET) {
224            right_offset    = MIN_RIGHT_OFFSET;
225            _at->max_x_size = _at->to_position_x+right_offset;
226        }
227
228        args.add(XmNrightAttachment, XmATTACH_FORM);
229        args.add(XmNrightOffset,     right_offset);
230    }
231    else {
232        args.add(XmNrightAttachment, XmATTACH_OPPOSITE_FORM);
233        args.add(XmNrightOffset,     -_at->to_position_x);
234    }
235
236    if (_at->attach_lx) {
237        args.add(XmNleftAttachment, XmATTACH_NONE);
238        args.add(XmNwidth,          _at->to_position_x - _at->x_for_next_button);
239    }
240    else {
241        args.add(XmNleftAttachment, XmATTACH_FORM);
242        args.add(XmNleftOffset,     _at->x_for_next_button);
243    }
244
245    if (_at->attach_y) {
246        int bottom_offset = _at->max_y_size - _at->to_position_y;
247        if (bottom_offset<MIN_BOTTOM_OFFSET) {
248            bottom_offset   = MIN_BOTTOM_OFFSET;
249            _at->max_y_size = _at->to_position_y+bottom_offset;
250        }
251
252        args.add(XmNbottomAttachment, XmATTACH_FORM);
253        args.add(XmNbottomOffset,     bottom_offset);
254    }
255    else {
256        args.add(XmNbottomAttachment, XmATTACH_OPPOSITE_FORM);
257        args.add(XmNbottomOffset,     - _at->to_position_y);
258    }
259    if (_at->attach_ly) {
260        args.add(XmNtopAttachment, XmATTACH_NONE);
261        args.add(XmNheight,        _at->to_position_y - _at->y_for_next_button);
262    }
263    else {
264        args.add(XmNtopAttachment, XmATTACH_FORM);
265        args.add(XmNtopOffset,     _at->y_for_next_button);
266    }
267
268    args.assign_to_widget(w);
269}
270
271const char *AW_get_pixmapPath(const char *pixmapName) {
272    // const char *pixmapsDir = "pixmaps"; // normal pixmaps (as used in gtk branch)
273    const char *pixmapsDir = "motifHack/pixmaps"; // see ../lib/motifHack/README
274
275    return GB_path_in_ARBLIB(pixmapsDir, pixmapName);
276}
277
278static char *pixmapPath(const char *pixmapName) {
279    return nulldup(AW_get_pixmapPath(pixmapName));
280}
281
282
283#define MAX_LINE_LENGTH 200
284__ATTR__USERESULT static GB_ERROR detect_bitmap_size(const char *pixmapname, int *width, int *height) {
285    GB_ERROR err = 0;
286
287    *width  = 0;
288    *height = 0;
289
290    char *path = pixmapPath(pixmapname);
291    FILE *in   = fopen(path, "rt");
292    if (in) {
293        const char *subdir = strrchr(pixmapname, '/');
294        char       *name   = strdup(subdir ? subdir+1 : pixmapname);
295        {
296            char *dot       = strrchr(name, '.');
297            if (dot) dot[0] = 0;
298            else  err       = "'.' expected";
299        }
300        int  namelen = strlen(name);
301        char buffer[MAX_LINE_LENGTH];
302        bool done    = false;
303
304        while (!done && !err) {
305            if (!fgets(buffer, MAX_LINE_LENGTH, in)) {
306                err = GB_IO_error("reading", pixmapname);
307            }
308            else if (strchr(buffer, 0)[-1] != '\n') {
309                err = GBS_global_string("Line too long ('%s')", buffer); // increase MAX_LINE_LENGTH above
310            }
311            else if (strncmp(buffer, "#define", 7) != 0) {
312                done = true;
313            }
314            else {
315                char *name_pos = strstr(buffer+7, name);
316                if (name_pos) {
317                    char *behind = name_pos+namelen;
318                    if (strncmp(behind, "_width ", 7) == 0) *width = atoi(behind+7);
319                    else if (strncmp(behind, "_height ", 8) == 0) *height = atoi(behind+8);
320                }
321            }
322        }
323
324        if (done && ((*width == 0) || (*height == 0))) {
325            if (strstr(buffer, "XPM") != NULL) {
326                if (!fgets(buffer, MAX_LINE_LENGTH, in) || !fgets(buffer, MAX_LINE_LENGTH, in)) {
327                    err = GB_IO_error("reading", pixmapname);
328                }
329                else {
330                    char *temp = strtok(buffer+1, " ");
331                    *width     = atoi(temp);
332                    temp       = strtok(NULL,  " ");
333                    *height    = atoi(temp);
334                }
335            }
336            else {
337                err = "can't detect size";
338            }
339        }
340
341        free(name);
342        fclose(in);
343    }
344    else {
345        err = "no such file";
346    }
347
348    if (err) {
349        err = GBS_global_string("%s: %s", pixmapname, err);
350    }
351
352#if defined(DUMP_BUTTON_CREATION)
353    printf("Bitmap '%s' has size %i/%i\n", pixmapname, *width, *height);
354#endif // DUMP_BUTTON_CREATION
355
356    free(path);
357    return err;
358}
359#undef MAX_LINE_LENGTH
360
361inline void calculate_textsize(const char *str, int *width, int *height) {
362    int textwidth  = 0;
363    int textheight = 1;
364    int linewidth  = 0;
365
366    for (int p = 0; str[p]; ++p) {
367        if (str[p] == '\n') {
368            if (linewidth>textwidth) textwidth = linewidth;
369
370            linewidth = 0;
371            textheight++;
372        }
373        else {
374            linewidth++;
375        }
376    }
377
378    if (linewidth>textwidth) textwidth = linewidth;
379
380    *width  = textwidth;
381    *height = textheight;
382}
383
384void AW_window::calculate_label_size(int *width, int *height, bool in_pixel, const char *non_at_label) {
385    // in_pixel == true -> calculate size in pixels
386    // in_pixel == false -> calculate size in characters
387
388    const char *label_ = non_at_label ? non_at_label : _at->label_for_inputfield;
389    if (label_) {
390        calculate_textsize(label_, width, height);
391        if (_at->length_of_label_for_inputfield) {
392            *width = _at->length_of_label_for_inputfield;
393        }
394        if (in_pixel) {
395            *width  = calculate_string_width(*width);
396            *height = calculate_string_height(*height, 0);
397        }
398    }
399    else {
400        *width  = 0;
401        *height = 0;
402    }
403}
404
405Widget AW_window::get_last_widget() const {
406    return p_global->get_last_widget();
407}
408
409void aw_detect_text_size(const char *text, size_t& width, size_t& height) {
410    size_t text_width = strcspn(text, "\n");
411
412    if (text[text_width]) {
413        aw_assert(text[text_width] == '\n');
414
415        aw_detect_text_size(text+text_width+1, width, height);
416        if (text_width>width) width = text_width;
417        height++;
418    }
419    else { // EOS
420        width  = text_width;
421        height = 1;
422    }
423}
424
425void AW_window::create_autosize_button(const char *macro_name, AW_label buttonlabel, const  char *mnemonic, unsigned xtraSpace) {
426    aw_assert(!AW_IS_IMAGEREF(buttonlabel));    // use create_button for graphical buttons!
427    aw_assert(!_at->to_position_exists); // wont work if to-position exists
428
429    AW_awar *is_awar = get_root()->label_is_awar(buttonlabel);
430    size_t   width, height;
431    if (is_awar) {
432        char *content = is_awar->read_as_string();
433        aw_assert(content[0]); /* you need to fill the awar before calling create_autosize_button,
434                                * otherwise size cannot be detected */
435        aw_detect_text_size(content, width, height);
436    }
437    else {
438        aw_detect_text_size(buttonlabel, width, height);
439    }
440
441    int   len               = width+(xtraSpace*2);
442    short length_of_buttons = _at->length_of_buttons;
443    short height_of_buttons = _at->height_of_buttons;
444
445    _at->length_of_buttons = len+1;
446    _at->height_of_buttons = height;
447    create_button(macro_name, buttonlabel, mnemonic);
448    _at->length_of_buttons = length_of_buttons;
449    _at->height_of_buttons = height_of_buttons;
450}
451
452void AW_window::create_button(const char *macro_name, AW_label buttonlabel, const char */*mnemonic*/, const char *color) {
453    // Create a button or text display.
454    //
455    // If a callback is bound via at->callback(), a button is created.
456    // Otherwise a text display is created.
457    //
458    // if buttonlabel starts with '#' the rest of buttonlabel is used as name of pixmap file used for button
459    // if buttonlabel contains a '/' it's interpreted as AWAR name and the button displays the content of the awar
460    // otherwise buttonlabel is interpreted as button label (may contain '\n').
461    //
462    // Note 1: Button width 0 does not work together with labels!
463
464    // Note 2: "color" may be specified for the button background (see TuneOrSetBackground for details)
465
466    TuneOrSetBackground(_at->attach_any ? INFO_FORM : INFO_WIDGET, // set background for buttons / text displays
467                        color,
468                        _callback ? TUNE_BUTTON : 0);
469
470#if defined(DUMP_BUTTON_CREATION)
471    printf("------------------------------ Button '%s'\n", buttonlabel);
472    printf("x_for_next_button=%i y_for_next_button=%i\n", _at->x_for_next_button, _at->y_for_next_button);
473#endif // DUMP_BUTTON_CREATION
474
475    if (_callback && ((long)_callback != 1))
476    {
477        if (macro_name) {
478            _callback->id = GBS_global_string_copy("%s/%s", this->window_defaults_name, macro_name);
479            get_root()->define_remote_command(_callback);
480        }
481        else {
482            _callback->id = 0;
483        }
484    }
485#if defined(DEVEL_RALF) && 1
486    else {
487        aw_assert(!macro_name); // please pass NULL for buttons w/o callback
488    }
489#endif
490
491#define SPACE_BEHIND_LABEL  10
492
493#define BUTTON_TEXT_X_PADDING 4
494#define BUTTON_TEXT_Y_PADDING 10
495
496#define BUTTON_GRAPHIC_PADDING 12
497#define FLAT_GRAPHIC_PADDING   4 // for buttons w/o callback
498
499    bool is_graphical_button = AW_IS_IMAGEREF(buttonlabel);
500
501#if defined(ASSERTION_USED)
502    AW_awar *is_awar = is_graphical_button ? NULL : get_root()->label_is_awar(buttonlabel);
503#endif // ASSERTION_USED
504
505    int width_of_button = -1, height_of_button = -1;
506
507    int width_of_label, height_of_label;
508    calculate_label_size(&width_of_label, &height_of_label, true, 0);
509    int width_of_label_and_spacer = _at->label_for_inputfield ? width_of_label+SPACE_BEHIND_LABEL : 0;
510
511    bool let_motif_choose_size  = false;
512
513    if (_at->to_position_exists) { // size has explicitly been specified in xfig -> calculate
514        width_of_button  = _at->to_position_x - _at->x_for_next_button - width_of_label_and_spacer;
515        height_of_button = _at->to_position_y - _at->y_for_next_button;
516    }
517    else if (_at->length_of_buttons) { // button width specified from client code
518        width_of_button  = BUTTON_TEXT_X_PADDING + calculate_string_width(_at->length_of_buttons+1);
519
520        if (!is_graphical_button) {
521            if (_at->height_of_buttons) { // button height specified from client code
522                height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(_at->height_of_buttons, 0);
523            }
524            else {
525                int textwidth, textheight;
526                calculate_textsize(buttonlabel, &textwidth, &textheight);
527                height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(textheight, 0);
528            }
529        }
530        else {
531            height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(1, 0);
532        }
533    }
534    else { // no button_length() specified
535        aw_assert(!is_awar); // please specify button_length() for AWAR button!
536
537        if (is_graphical_button) {
538            int      width, height;
539            GB_ERROR err = detect_bitmap_size(buttonlabel+1, &width, &height);
540
541            if (!err) {
542                int gpadding = _callback ? BUTTON_GRAPHIC_PADDING : FLAT_GRAPHIC_PADDING;
543
544                width_of_button  = width+gpadding;
545                height_of_button = height+gpadding;
546            }
547            else {
548                err = GBS_global_string("button gfx error: %s", err);
549                aw_message(err);
550                let_motif_choose_size = true;
551            }
552        }
553        else {
554            int textwidth, textheight;
555            calculate_textsize(buttonlabel, &textwidth, &textheight);
556
557            width_of_button  = BUTTON_TEXT_X_PADDING + calculate_string_width(textwidth+1);
558            height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(textheight, 0);
559        }
560    }
561
562    if (!let_motif_choose_size) {
563        if (height_of_button<height_of_label) height_of_button = height_of_label;
564        aw_assert(width_of_button && height_of_button);
565    }
566
567    int x_label  = _at->x_for_next_button;
568    int y_label  = _at->y_for_next_button;
569    int x_button = x_label + width_of_label_and_spacer;
570    int y_button = y_label;
571
572    int org_correct_for_at_center = _at->correct_for_at_center; // store original justification
573    int org_y_for_next_button     = _at->y_for_next_button; // store original y pos (modified while creating label)
574
575    if (!let_motif_choose_size) { // don't correct position of button w/o known size
576        // calculate justification manually
577
578        int width_of_button_and_highlight = width_of_button + (_at->highlight ? 2*(_at->shadow_thickness+1)+1 : 0);
579        int width_of_label_and_button     = width_of_label_and_spacer+width_of_button_and_highlight;
580
581        if (_at->correct_for_at_center) { // not if left justified
582            int shiftback = width_of_label_and_button; // shiftback for right justification
583            if (_at->correct_for_at_center == 1) { // center justification
584                shiftback /= 2;
585            }
586            x_label  -= shiftback;
587            x_button -= shiftback;
588        }
589
590        // we already did the justification by calculating all positions manually, so..
591        _at->correct_for_at_center = 0; // ..from now on act like "left justified"!
592    }
593
594    // correct label Y position
595    if (_callback) {            // only if button is a real 3D-button
596        y_label += (height_of_button-height_of_label)/2;
597    }
598
599    Widget parent_widget = (_at->attach_any) ? INFO_FORM : INFO_WIDGET;
600    Widget tmp_label         = 0;
601
602    if (_at->label_for_inputfield) {
603        _at->x_for_next_button = x_label;
604        _at->y_for_next_button = y_label;
605
606        Label clientlabel(_at->label_for_inputfield, this);
607        tmp_label = XtVaCreateManagedWidget("label",
608                                            xmLabelWidgetClass,
609                                            parent_widget,
610                                            XmNwidth, (int)(width_of_label + 2),
611                                            RES_LABEL_CONVERT(clientlabel),
612                                            XmNrecomputeSize, false,
613                                            XmNalignment, XmALIGNMENT_BEGINNING,
614                                            XmNfontList, p_global->fontlist,
615                                            XmNx, (int)(x_label),
616                                            XmNy, (int)(y_label),
617                                            NULL);
618
619        if (_at->attach_any) aw_attach_widget(tmp_label, _at);
620        AW_label_in_awar_list(this, tmp_label, _at->label_for_inputfield);
621    }
622
623    _at->x_for_next_button = x_button;
624    _at->y_for_next_button = y_button;
625
626    Widget fatherwidget = parent_widget; // used as father for button below
627    if (_at->highlight) {
628        if (_at->attach_any) {
629#if defined(DEBUG)
630            printf("Attaching highlighted buttons does not work - "
631                   "highlight ignored for button '%s'!\n", buttonlabel);
632#endif // DEBUG
633            _at->highlight = false;
634        }
635        else {
636            int shadow_offset = _at->shadow_thickness;
637            int x_shadow      = x_button - shadow_offset;
638            int y_shadow      = y_button - shadow_offset;
639
640            fatherwidget = XtVaCreateManagedWidget("draw_area",
641                                                   xmFrameWidgetClass,
642                                                   INFO_WIDGET,
643                                                   XmNx, (int)(x_shadow),
644                                                   XmNy, (int)(y_shadow),
645                                                   XmNshadowType, XmSHADOW_IN,
646                                                   XmNshadowThickness, _at->shadow_thickness,
647                                                   NULL);
648        }
649    }
650
651    Widget button = 0;
652
653    {
654        aw_xargs args(9);
655        args.add(XmNx, x_button);
656        args.add(XmNy, y_button);
657
658        args.add(XmNfontList,   (XtArgVal)p_global->fontlist);
659        args.add(XmNbackground, _at->background_color);
660
661        if (!let_motif_choose_size) {
662            args.add(XmNwidth,  width_of_button);
663            args.add(XmNheight, height_of_button);
664        }
665
666        Label buttonLabel(buttonlabel, this);
667        if (_callback) {
668            args.add(XmNshadowThickness, _at->shadow_thickness);
669            args.add(XmNalignment,       XmALIGNMENT_CENTER);
670
671            button = XtVaCreateManagedWidget("button", xmPushButtonWidgetClass, fatherwidget, RES_LABEL_CONVERT(buttonLabel), NULL);
672        }
673        else { // button w/o callback; (flat, not clickable)
674            button = XtVaCreateManagedWidget("label", xmLabelWidgetClass, parent_widget, RES_LABEL_CONVERT(buttonLabel), NULL);
675            args.add(XmNalignment, (org_correct_for_at_center == 1) ? XmALIGNMENT_CENTER : XmALIGNMENT_BEGINNING);
676        }
677
678        if (!_at->attach_any || !_callback) args.add(XmNrecomputeSize, false);
679        args.assign_to_widget(button);
680        if (_at->attach_any) aw_attach_widget(button, _at);
681
682        if (_callback) {
683            root->make_sensitive(button, _at->widget_mask);
684        }
685        else {
686            aw_assert(_at->correct_for_at_center == 0);
687            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)
688        }
689
690        AW_label_in_awar_list(this, button, buttonlabel);
691    }
692
693    short height = 0;
694    short width  = 0;
695
696    if (_at->to_position_exists) {
697        // size has explicitly been specified in xfig -> calculate
698        height = _at->to_position_y - _at->y_for_next_button;
699        width  = _at->to_position_x - _at->x_for_next_button;
700    }
701
702    {
703        Widget  toRecenter   = 0;
704        int     recenterSize = 0;
705
706        if (!height || !width) {
707            // ask motif for real button size
708            Widget ButOrHigh = _at->highlight ? fatherwidget : button;
709            XtVaGetValues(ButOrHigh, XmNheight, &height, XmNwidth, &width, NULL);
710
711            if (let_motif_choose_size) {
712                if (_at->correct_for_at_center) {
713                    toRecenter   = ButOrHigh;
714                    recenterSize = width;
715                }
716                width = 0;          // ignore the used size (because it may use more than the window size)
717            }
718        }
719
720        if (toRecenter) {
721            int shiftback = 0;
722            switch (_at->correct_for_at_center) {
723                case 1: shiftback = recenterSize/2; break;
724                case 2: shiftback = recenterSize; break;
725            }
726            if (shiftback) {
727                XtVaSetValues(toRecenter, XmNx, x_button-shiftback, NULL);
728            }
729        }
730    }
731
732    _at->correct_for_at_center = org_correct_for_at_center; // restore original justification
733    _at->y_for_next_button     = org_y_for_next_button;
734
735    p_w->toggle_field = button;
736    this->_set_activate_callback((void *)button);
737    this->unset_at_commands();
738    this->increment_at_commands(width+SPACE_BEHIND_BUTTON, height);
739}
740
741void AW_window::dump_at_position(const char *tmp_label) const {
742    printf("%s at x = %i / y = %i\n", tmp_label, _at->x_for_next_button, _at->y_for_next_button);
743}
744
745void AW_window::update_label(Widget widget, const char *var_value) {
746    if (get_root()->changer_of_variable != widget) {
747        XtVaSetValues(widget, RES_CONVERT(XmNlabelString, var_value), NULL);
748    }
749    else {
750        get_root()->changer_of_variable = 0;
751    }
752}
753
754// ----------------------
755//      on/off toggle
756
757struct aw_toggle_data {
758    bool  isTextToggle;
759    char *bitmapOrText[2];
760    int   buttonWidth; // wanted width in characters
761};
762
763void AW_window::update_toggle(Widget widget, const char *var, AW_CL cd_toggle_data) {
764    aw_toggle_data *tdata = (aw_toggle_data*)cd_toggle_data;
765    const char     *text  = tdata->bitmapOrText[(var[0] == '0' || var[0] == 'n') ? 0 : 1];
766
767    if (tdata->isTextToggle) {
768        XtVaSetValues(widget, RES_CONVERT(XmNlabelString, text), NULL);
769    }
770    else {
771        char *path = pixmapPath(text+1);
772        XtVaSetValues(widget, RES_CONVERT(XmNlabelPixmap, path), NULL);
773        free(path);
774    }
775}
776
777void AW_window::create_toggle(const char *var_name, aw_toggle_data *tdata) {
778    AW_cb *cbs = _callback;
779    _callback         = (AW_cb *)1;
780
781    {
782        int old_length_of_buttons = _at->length_of_buttons;
783
784        if (tdata->buttonWidth == 0) {
785            if (tdata->isTextToggle) {
786                int l1 = strlen(tdata->bitmapOrText[0]);
787                int l2 = strlen(tdata->bitmapOrText[1]);
788
789                _at->length_of_buttons = l1>l2 ? l1 : l2; // use longer text for button size
790            }
791            else {
792                _at->length_of_buttons = 0;
793            }
794        }
795        else {
796            _at->length_of_buttons = tdata->buttonWidth;
797        }
798
799        create_button(0, tdata->bitmapOrText[0], 0);
800
801        _at->length_of_buttons = old_length_of_buttons;
802    }
803
804    AW_awar *vs = this->get_root()->awar(var_name);
805    {
806        char *var_value = vs->read_as_string();
807
808        this->update_toggle(p_w->toggle_field, var_value, (AW_CL)tdata);
809        free(var_value);
810    }
811
812    VarUpdateInfo *vui;
813    vui = new VarUpdateInfo(this, p_w->toggle_field, AW_WIDGET_TOGGLE, vs, cbs);
814
815    XtAddCallback(p_w->toggle_field, XmNactivateCallback,
816                  (XtCallbackProc) AW_variable_update_callback,
817                  (XtPointer) vui);
818
819    vs->tie_widget((AW_CL)tdata, p_w->toggle_field, AW_WIDGET_TOGGLE, this);
820}
821
822
823void AW_window::create_toggle(const char *var_name, const char *no, const char *yes, int buttonWidth) {
824    aw_toggle_data *tdata  = new aw_toggle_data;
825    tdata->isTextToggle    = false;
826
827    aw_assert(AW_IS_IMAGEREF(no));
828    aw_assert(AW_IS_IMAGEREF(yes));
829
830    tdata->bitmapOrText[0] = strdup(no);
831    tdata->bitmapOrText[1] = strdup(yes);
832
833    tdata->buttonWidth = buttonWidth;
834
835    create_toggle(var_name, tdata);
836}
837
838void AW_window::create_text_toggle(const char *var_name, const char *noText, const char *yesText, int buttonWidth) {
839    aw_toggle_data *tdata  = new aw_toggle_data;
840    tdata->isTextToggle    = true;
841    tdata->bitmapOrText[0] = strdup(noText);
842    tdata->bitmapOrText[1] = strdup(yesText);
843    tdata->buttonWidth     = buttonWidth;
844
845    create_toggle(var_name, tdata);
846}
847
848
849void AW_window::create_toggle(const char *var_name) {
850    create_toggle(var_name, "#no.xpm", "#yes.xpm");
851}
852
853void AW_window::create_inverse_toggle(const char *var_name) {
854    // like create_toggle, but displays inverse value
855    // (i.e. it's checked if value is zero, and unchecked otherwise)
856    create_toggle(var_name, "#yes.xpm", "#no.xpm");
857}
858
859// ---------------------
860//      input fields
861
862void AW_window::create_input_field(const char *var_name,   int columns) {
863    Widget         textField      = 0;
864    Widget         tmp_label      = 0;
865    AW_cb  *cbs;
866    VarUpdateInfo *vui;
867    char          *str;
868    int            xoff_for_label = 0;
869
870    if (!columns) columns = _at->length_of_buttons;
871
872    AW_awar *vs = root->awar(var_name);
873    str         = root->awar(var_name)->read_as_string();
874
875    int width_of_input_label, height_of_input_label;
876    calculate_label_size(&width_of_input_label, &height_of_input_label, true, 0);
877    // @@@ FIXME: use height_of_input_label for propper Y-adjusting of label
878    // width_of_input_label = this->calculate_string_width( calculate_label_length() );
879
880    int width_of_input = this->calculate_string_width(columns+1) + 9;
881    // calculate width for 1 additional character (input field is not completely used)
882    // + 4 pixel for shadow + 4 unknown missing pixels + 1 add. pixel needed for visible text area
883
884    Widget parentWidget = _at->attach_any ? INFO_FORM : INFO_WIDGET;
885
886    if (_at->label_for_inputfield) {
887        Label clientlabel(_at->label_for_inputfield, this);
888        tmp_label = XtVaCreateManagedWidget("label",
889                                            xmLabelWidgetClass,
890                                            parentWidget,
891                                            XmNwidth, (int)(width_of_input_label + 2),
892                                            XmNhighlightThickness, 0,
893                                            RES_LABEL_CONVERT(clientlabel),
894                                            XmNrecomputeSize, false,
895                                            XmNalignment, XmALIGNMENT_BEGINNING,
896                                            XmNfontList, p_global->fontlist,
897                                            (_at->attach_any) ? NULL : XmNx, (int)_at->x_for_next_button,
898                                            XmNy, (int)(_at->y_for_next_button) + root->y_correction_for_input_labels -1,
899                                            NULL);
900        if (_at->attach_any) aw_attach_widget(tmp_label, _at);
901        xoff_for_label = width_of_input_label + 10;
902    }
903
904
905    int width_of_last_widget = xoff_for_label + width_of_input + 2;
906
907    if (_at->to_position_exists) {
908        width_of_input = _at->to_position_x - _at->x_for_next_button - xoff_for_label + 2;
909        width_of_last_widget = _at->to_position_x - _at->x_for_next_button;
910    }
911
912    {
913        TuneBackground(parentWidget, TUNE_INPUT);
914        textField = XtVaCreateManagedWidget("textField",
915                                            xmTextFieldWidgetClass,
916                                            parentWidget,
917                                            XmNwidth, (int)width_of_input,
918                                            XmNrows, 1,
919                                            XmNvalue, str,
920                                            XmNfontList, p_global->fontlist,
921                                            XmNbackground, _at->background_color,
922                                            (_at->attach_any) ? NULL : XmNx, (int)(_at->x_for_next_button + xoff_for_label),
923                                            XmNy, (int)(_at->y_for_next_button + 5) - 8,
924                                            NULL);
925        if (_at->attach_any) {
926            _at->x_for_next_button += xoff_for_label;
927            aw_attach_widget(textField, _at);
928            _at->x_for_next_button -= xoff_for_label;
929        }
930    }
931
932    free(str);
933
934    // user-own callback
935    cbs = _callback;
936
937    // callback for enter
938    vui = new VarUpdateInfo(this, textField, AW_WIDGET_INPUT_FIELD, vs, cbs);
939
940    XtAddCallback(textField, XmNactivateCallback,
941                  (XtCallbackProc) AW_variable_update_callback,
942                  (XtPointer) vui);
943    if (_d_callback) {
944        XtAddCallback(textField, XmNactivateCallback,
945                      (XtCallbackProc) AW_server_callback,
946                      (XtPointer) _d_callback);
947        _d_callback->id = GBS_global_string_copy("INPUT:%s", var_name);
948        get_root()->define_remote_command(_d_callback);
949    }
950
951    // callback for losing focus
952    XtAddCallback(textField, XmNlosingFocusCallback,
953                  (XtCallbackProc) AW_variable_update_callback,
954                  (XtPointer) vui);
955    // callback for value changed
956    XtAddCallback(textField, XmNvalueChangedCallback,
957                  (XtCallbackProc) AW_value_changed_callback,
958                  (XtPointer) root);
959
960    vs->tie_widget(0, textField, AW_WIDGET_INPUT_FIELD, this);
961    root->make_sensitive(textField, _at->widget_mask);
962
963    short height;
964    XtVaGetValues(textField, XmNheight, &height, NULL);
965    int height_of_last_widget = height;
966
967    if (_at->correct_for_at_center == 1) {   // middle centered
968        XtVaSetValues(textField, XmNx, ((int)(_at->x_for_next_button + xoff_for_label) - (int)(width_of_last_widget/2) + 1), NULL);
969        if (tmp_label) {
970            XtVaSetValues(tmp_label, XmNx, ((int)(_at->x_for_next_button) - (int)(width_of_last_widget/2) + 1), NULL);
971        }
972        width_of_last_widget = width_of_last_widget / 2;
973    }
974    if (_at->correct_for_at_center == 2) {   // right centered
975        XtVaSetValues(textField, XmNx, (int)(_at->x_for_next_button + xoff_for_label - width_of_last_widget + 3), NULL);
976        if (tmp_label) {
977            XtVaSetValues(tmp_label, XmNx, (int)(_at->x_for_next_button - width_of_last_widget + 3), NULL);
978        }
979        width_of_last_widget = 0;
980    }
981    width_of_last_widget -= 2;
982
983    this->unset_at_commands();
984    this->increment_at_commands(width_of_last_widget, height_of_last_widget);
985
986}
987
988void AW_window::update_input_field(Widget widget, const char *var_value) {
989    XtVaSetValues(widget, XmNvalue, var_value, NULL);
990}
991
992void AW_window::create_text_field(const char *var_name, int columns, int rows) {
993    Widget         scrolledWindowText;
994    Widget         scrolledText;
995    Widget         tmp_label             = 0;
996    AW_cb         *cbs;
997    VarUpdateInfo *vui;
998    char          *str                   = NULL;
999    short          width_of_last_widget  = 0;
1000    short          height_of_last_widget = 0;
1001    int            width_of_text         = 0;
1002    int            height_of_text        = 0;
1003    int            xoff_for_label        = 0;
1004
1005    AW_awar *vs = root->awar(var_name);
1006    str         = root->awar(var_name)->read_string();
1007
1008    int width_of_text_label, height_of_text_label;
1009    calculate_label_size(&width_of_text_label, &height_of_text_label, true, 0);
1010    // @@@ FIXME: use height_of_text_label for propper Y-adjusting of label
1011
1012    // width_of_text_label = this->calculate_string_width( calculate_label_length() );
1013    width_of_text = this->calculate_string_width(columns) + 18;
1014    height_of_text = this->calculate_string_height(rows, rows*4) + 9;
1015
1016
1017    if (_at->label_for_inputfield) {
1018        Label clientlabel(_at->label_for_inputfield, this);
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(clientlabel),
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
1126static void scalerChanged_cb(Widget scale, XtPointer variable_update_struct, XtPointer call_data) {
1127    XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct*)call_data;
1128    VarUpdateInfo         *vui = (VarUpdateInfo*)variable_update_struct;
1129
1130    bool do_update = true;
1131    if (cbs->reason == XmCR_DRAG) { // still dragging?
1132        double mean_callback_time = vui->get_awar()->mean_callback_time();
1133
1134        const double MAX_DRAGGED_CALLBACK_TIME = 1.0;
1135        if (mean_callback_time>MAX_DRAGGED_CALLBACK_TIME) {
1136            do_update = false; // do not update while dragging, if update callback needs more than 1 second
1137                               // Note that a longer update will happen once!
1138        }
1139    }
1140
1141    if (do_update) {
1142        AW_root::SINGLETON->value_changed = true;
1143        AW_variable_update_callback(scale, variable_update_struct, call_data);
1144    }
1145}
1146
1147void AW_window::create_input_field_with_scaler(const char *awar_name, int textcolumns, int scaler_length, AW_ScalerType scalerType) {
1148    create_input_field(awar_name, textcolumns);
1149
1150    Widget parentWidget = _at->attach_any ? INFO_FORM : INFO_WIDGET;
1151
1152    AW_awar *vs = root->awar(awar_name);
1153    // Note: scaler also "works" if no min/max is defined for awar, but scaling is a bit weird
1154    int scalerValue = calculate_scaler_value(vs, scalerType);
1155
1156    Widget scale = XtVaCreateManagedWidget("scale",
1157                                           xmScaleWidgetClass,
1158                                           parentWidget,
1159                                           XmNx, _at->x_for_next_button,
1160                                           XmNy, _at->y_for_next_button + 4,
1161                                           XmNorientation, XmHORIZONTAL,
1162                                           XmNscaleWidth, scaler_length,
1163                                           XmNshowValue, False,
1164                                           XmNminimum, SCALER_MIN_VALUE,
1165                                           XmNmaximum, SCALER_MAX_VALUE,
1166                                           XmNvalue, scalerValue,
1167                                           NULL);
1168
1169    short width_of_last_widget  = 0;
1170    short height_of_last_widget = 0;
1171
1172    XtVaGetValues(scale,
1173                  XmNheight, &height_of_last_widget,
1174                  XmNwidth, &width_of_last_widget,
1175                  NULL);
1176
1177    AW_cb         *cbs = _callback;
1178    VarUpdateInfo *vui = new VarUpdateInfo(this, scale, AW_WIDGET_SCALER, vs, cbs);
1179    vui->set_scalerType(scalerType);
1180
1181    XtAddCallback(scale, XmNvalueChangedCallback, scalerChanged_cb, (XtPointer)vui);
1182    XtAddCallback(scale, XmNdragCallback,         scalerChanged_cb, (XtPointer)vui);
1183
1184    vs->tie_widget((AW_CL)scalerType, scale, AW_WIDGET_SCALER, this);
1185    root->make_sensitive(scale, _at->widget_mask);
1186
1187    this->unset_at_commands();
1188    this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1189}
1190
1191void AW_window::update_scaler(Widget widget, AW_awar *awar, AW_ScalerType scalerType) {
1192    int scalerVal = calculate_scaler_value(awar, scalerType);
1193    XtVaSetValues(widget, XmNvalue, scalerVal, NULL);
1194}
1195
1196// -----------------------
1197//      selection list
1198
1199
1200static void scroll_sellist(Widget scrolledList, bool upwards) {
1201    int oldPos, visible, items;
1202    XtVaGetValues(scrolledList,
1203                  XmNtopItemPosition, &oldPos,
1204                  XmNvisibleItemCount, &visible,
1205                  XmNitemCount,  &items, 
1206                  NULL);
1207
1208    int amount = visible/5;
1209    if (amount<1) amount = 1;
1210    if (upwards) amount = -amount;
1211
1212    int newPos = force_in_range(1, oldPos + amount, items-visible+2);
1213    if (newPos != oldPos) XmListSetPos(scrolledList, newPos);
1214}
1215
1216static void scroll_sellist_up(Widget scrolledList, XEvent*, String*, Cardinal*) { scroll_sellist(scrolledList, true); }
1217static void scroll_sellist_dn(Widget scrolledList, XEvent*, String*, Cardinal*) { scroll_sellist(scrolledList, false); }
1218
1219AW_selection_list* AW_window::create_selection_list(const char *var_name, int columns, int rows, bool /*fallback2default*/) {
1220    // Note: fallback2default has no meaning in motif-version (always acts like 'false', i.e. never does fallback)
1221    // see also .@create_option_menu
1222
1223    Widget         scrolledWindowList; // @@@ fix locals
1224    Widget         scrolledList;
1225    VarUpdateInfo *vui;
1226    AW_cb         *cbs;
1227
1228    int width_of_list;
1229    int height_of_list;
1230    int width_of_last_widget  = 0;
1231    int height_of_last_widget = 0;
1232
1233    aw_assert(!_at->label_for_inputfield); // labels have no effect for selection lists
1234
1235    AW_awar *vs = 0;
1236
1237    aw_assert(var_name); // @@@ case where var_name == NULL is relict from multi-selection-list (not used; removed)
1238
1239    if (var_name) vs = root->awar(var_name);
1240
1241    width_of_list  = this->calculate_string_width(columns) + 9;
1242    height_of_list = this->calculate_string_height(rows, 4*rows) + 9;
1243
1244    {
1245        aw_xargs args(7);
1246        args.add(XmNvisualPolicy,           XmVARIABLE);
1247        args.add(XmNscrollBarDisplayPolicy, XmSTATIC);
1248        args.add(XmNshadowThickness,        0);
1249        args.add(XmNfontList,               (XtArgVal)p_global->fontlist);
1250
1251        if (_at->to_position_exists) {
1252            width_of_list = _at->to_position_x - _at->x_for_next_button - 18;
1253            if (_at->y_for_next_button  < _at->to_position_y - 18) {
1254                height_of_list = _at->to_position_y - _at->y_for_next_button - 18;
1255            }
1256            scrolledWindowList = XtVaCreateManagedWidget("scrolledWindowList1", xmScrolledWindowWidgetClass, INFO_FORM, NULL);
1257
1258            args.assign_to_widget(scrolledWindowList);
1259            aw_attach_widget(scrolledWindowList, _at);
1260
1261            width_of_last_widget = _at->to_position_x - _at->x_for_next_button;
1262            height_of_last_widget = _at->to_position_y - _at->y_for_next_button;
1263        }
1264        else {
1265            scrolledWindowList = XtVaCreateManagedWidget("scrolledWindowList1", xmScrolledWindowWidgetClass, INFO_WIDGET, NULL);
1266
1267            args.add(XmNscrollingPolicy, XmAPPLICATION_DEFINED);
1268            args.add(XmNx, 10);
1269            args.add(XmNy, _at->y_for_next_button);
1270            args.assign_to_widget(scrolledWindowList);
1271        }
1272    }
1273
1274    {
1275        int select_type = XmMULTIPLE_SELECT;
1276        if (vs) select_type = XmBROWSE_SELECT;
1277
1278        TuneBackground(scrolledWindowList, TUNE_INPUT);
1279        scrolledList = XtVaCreateManagedWidget("scrolledList1",
1280                                               xmListWidgetClass,
1281                                               scrolledWindowList,
1282                                               XmNwidth, (int)width_of_list,
1283                                               XmNheight, (int) height_of_list,
1284                                               XmNscrollBarDisplayPolicy, XmSTATIC,
1285                                               XmNselectionPolicy, select_type,
1286                                               XmNlistSizePolicy, XmCONSTANT,
1287                                               XmNfontList, p_global->fontlist,
1288                                               XmNbackground, _at->background_color,
1289                                               NULL);
1290
1291        static bool actionsAdded = false;
1292        if (!actionsAdded) {
1293            struct _XtActionsRec actions[2] = {
1294                {(char*)"scroll_sellist_up", scroll_sellist_up},
1295                {(char*)"scroll_sellist_dn", scroll_sellist_dn}
1296            };
1297
1298            XtAppAddActions(p_global->context, actions, 2);
1299        }
1300
1301        XtTranslations translations = XtParseTranslationTable(
1302            "<Btn4Down>:scroll_sellist_up()\n"
1303            "<Btn5Down>:scroll_sellist_dn()\n"
1304            );
1305        XtAugmentTranslations(scrolledList, translations);
1306    }
1307
1308    if (!_at->to_position_exists) {
1309        short height;
1310        XtVaGetValues(scrolledList, XmNheight, &height, NULL);
1311        height_of_last_widget = height + 20;
1312        width_of_last_widget  = width_of_list + 20;
1313
1314        switch (_at->correct_for_at_center) {
1315            case 3: break;
1316            case 0: // left aligned
1317                XtVaSetValues(scrolledWindowList, XmNx, (int)(_at->x_for_next_button), NULL);
1318                break;
1319
1320            case 1: // center aligned
1321                XtVaSetValues(scrolledWindowList, XmNx, (int)(_at->x_for_next_button - (width_of_last_widget/2)), NULL);
1322                width_of_last_widget = width_of_last_widget / 2;
1323                break;
1324
1325            case 2: // right aligned
1326                XtVaSetValues(scrolledWindowList, XmNx, (int)(_at->x_for_next_button - width_of_list - 18), NULL);
1327                width_of_last_widget = 0;
1328                break;
1329        }
1330
1331    }
1332
1333    {
1334        int type = GB_STRING;
1335        if (vs)  type = vs->variable_type;
1336
1337        if (p_global->selection_list) {
1338            p_global->last_selection_list->next = new AW_selection_list(var_name, type, scrolledList);
1339            p_global->last_selection_list = p_global->last_selection_list->next;
1340        }
1341        else {
1342            p_global->last_selection_list = p_global->selection_list = new AW_selection_list(var_name, type, scrolledList);
1343        }
1344    }
1345
1346
1347    // user-own callback
1348    cbs = _callback; // @@@ generally unwanted (see #559)
1349
1350    // callback for enter
1351    if (vs) {
1352        vui = new VarUpdateInfo(this, scrolledList, AW_WIDGET_SELECTION_LIST, vs, cbs);
1353        vui->set_sellist(p_global->last_selection_list);
1354
1355        XtAddCallback(scrolledList, XmNbrowseSelectionCallback,
1356                      (XtCallbackProc) AW_variable_update_callback,
1357                      (XtPointer) vui);
1358
1359        if (_d_callback) {
1360            XtAddCallback(scrolledList, XmNdefaultActionCallback,
1361                          (XtCallbackProc) AW_server_callback,
1362                          (XtPointer) _d_callback);
1363        }
1364        vs->tie_widget((AW_CL)p_global->last_selection_list, scrolledList, AW_WIDGET_SELECTION_LIST, this);
1365        root->make_sensitive(scrolledList, _at->widget_mask);
1366    }
1367
1368    this->unset_at_commands();
1369    this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1370    return p_global->last_selection_list;
1371}
1372
Note: See TracBrowser for help on using the repository browser.