source: branches/stable/WINDOW/AW_button.cxx

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