source: trunk/WINDOW/AW_button.cxx

Last change on this file was 19245, checked in by westram, 2 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_concat_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) {
379    // in_pixel == true -> calculate size in pixels
380    // in_pixel == false -> calculate size in characters
381
382    const char *label_ = _at->label_for_inputfield;
383    if (label_) {
384        aw_assert(label_[0]); // empty string is not allowed as label!
385
386        calculate_textsize(label_, width, height);
387        if (_at->length_of_label_for_inputfield) {
388            *width = _at->length_of_label_for_inputfield;
389        }
390        if (in_pixel) {
391            *width  = calculate_string_width(*width);
392            *height = calculate_string_height(*height, 0);
393        }
394    }
395    else {
396        *width  = 0;
397        *height = 0;
398    }
399}
400
401Widget AW_window::get_last_widget() const {
402    return p_global->get_last_widget();
403}
404
405void aw_detect_text_size(const char *text, size_t& width, size_t& height) {
406    size_t text_width = strcspn(text, "\n");
407
408    if (text[text_width]) {
409        aw_assert(text[text_width] == '\n');
410
411        aw_detect_text_size(text+text_width+1, width, height);
412        if (text_width>width) width = text_width;
413        height++;
414    }
415    else { // EOS
416        width  = text_width;
417        height = 1;
418    }
419}
420
421void AW_window::create_autosize_button(const char *macro_name, AW_label buttonlabel, const  char *mnemonic, unsigned xtraSpace) {
422    aw_assert(!AW_IS_IMAGEREF(buttonlabel));    // use create_button for graphical buttons!
423    aw_assert(!_at->to_position_exists); // wont work if to-position exists
424
425    AW_awar *is_awar = get_root()->label_is_awar(buttonlabel);
426    size_t   width, height;
427    if (is_awar) {
428        char *content = is_awar->read_as_string();
429        aw_assert(content[0]); /* you need to fill the awar before calling create_autosize_button,
430                                * otherwise size cannot be detected */
431        aw_detect_text_size(content, width, height);
432    }
433    else {
434        aw_detect_text_size(buttonlabel, width, height);
435    }
436
437    int   len               = width+(xtraSpace*2);
438    short length_of_buttons = _at->length_of_buttons;
439    short height_of_buttons = _at->height_of_buttons;
440
441    _at->length_of_buttons = len+1;
442    _at->height_of_buttons = height;
443    create_button(macro_name, buttonlabel, mnemonic);
444    _at->length_of_buttons = length_of_buttons;
445    _at->height_of_buttons = height_of_buttons;
446}
447
448void AW_window::create_button(const char *macro_name, AW_label buttonlabel, const char */*mnemonic*/, const char *color) {
449    // Create a button or text display.
450    //
451    // If a callback is bound via at->callback(), a button is created.
452    // Otherwise a text display is created.
453    //
454    // if buttonlabel starts with '#' the rest of buttonlabel is used as name of pixmap file used for button
455    // if buttonlabel contains a '/' it's interpreted as AWAR name and the button displays the content of the awar
456    // otherwise buttonlabel is interpreted as button label (may contain '\n').
457    //
458    // Note 1: Button width 0 does not work together with labels!
459
460    // Note 2: "color" may be specified for the button background (see TuneOrSetBackground for details)
461
462    TuneOrSetBackground(_at->attach_any ? INFO_FORM : INFO_WIDGET, // set background for buttons / text displays
463                        color,
464                        _callback ? TUNE_BUTTON : 0);
465
466#if defined(DUMP_BUTTON_CREATION)
467    printf("------------------------------ Button '%s'\n", buttonlabel);
468    printf("x_for_next_button=%i y_for_next_button=%i\n", _at->x_for_next_button, _at->y_for_next_button);
469#endif // DUMP_BUTTON_CREATION
470
471    if (_callback && ((long)_callback != 1)) {
472        if (macro_name) {
473            _callback->id = GBS_global_string_copy("%s/%s", this->window_defaults_name, macro_name);
474            get_root()->define_remote_command(_callback);
475        }
476        else {
477            _callback->id = NULp;
478        }
479    }
480#if defined(DEVEL_RALF) && 1
481    else {
482        aw_assert(!macro_name); // please pass NULp for buttons w/o callback
483    }
484#endif
485
486#define SPACE_BEHIND_LABEL  10
487
488#define BUTTON_TEXT_X_PADDING 4
489#define BUTTON_TEXT_Y_PADDING 10
490
491#define BUTTON_GRAPHIC_PADDING 12
492#define FLAT_GRAPHIC_PADDING   4 // for buttons w/o callback
493
494    bool is_graphical_button = AW_IS_IMAGEREF(buttonlabel);
495
496#if defined(ASSERTION_USED)
497    AW_awar *is_awar = is_graphical_button ? NULp : get_root()->label_is_awar(buttonlabel);
498#endif // ASSERTION_USED
499
500    int width_of_button = -1, height_of_button = -1;
501
502    int width_of_label, height_of_label;
503    calculate_label_size(&width_of_label, &height_of_label, true);
504    int width_of_label_and_spacer = _at->label_for_inputfield ? width_of_label+SPACE_BEHIND_LABEL : 0;
505
506    bool let_motif_choose_size  = false;
507
508    if (_at->to_position_exists) { // size has explicitly been specified in xfig -> calculate
509        width_of_button  = _at->to_position_x - _at->x_for_next_button - width_of_label_and_spacer;
510        height_of_button = _at->to_position_y - _at->y_for_next_button;
511    }
512    else if (_at->length_of_buttons) { // button width specified from client code
513        width_of_button  = BUTTON_TEXT_X_PADDING + calculate_string_width(_at->length_of_buttons+1);
514
515        if (!is_graphical_button) {
516            if (_at->height_of_buttons) { // button height specified from client code
517                height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(_at->height_of_buttons, 0);
518            }
519            else {
520                int textwidth, textheight;
521                calculate_textsize(buttonlabel, &textwidth, &textheight);
522                height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(textheight, 0);
523            }
524        }
525        else {
526            height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(1, 0);
527        }
528    }
529    else { // no button_length() specified
530        aw_assert(!is_awar); // please specify button_length() for AWAR button!
531
532        if (is_graphical_button) {
533            int      width, height;
534            GB_ERROR err = detect_bitmap_size(buttonlabel+1, &width, &height);
535
536            if (!err) {
537                int gpadding = _callback ? BUTTON_GRAPHIC_PADDING : FLAT_GRAPHIC_PADDING;
538
539                width_of_button  = width+gpadding;
540                height_of_button = height+gpadding;
541            }
542            else {
543                err = GBS_global_string("button gfx error: %s", err);
544                aw_message(err);
545                let_motif_choose_size = true;
546            }
547        }
548        else {
549            int textwidth, textheight;
550            calculate_textsize(buttonlabel, &textwidth, &textheight);
551
552            width_of_button  = BUTTON_TEXT_X_PADDING + calculate_string_width(textwidth+1);
553            height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(textheight, 0);
554        }
555    }
556
557    if (!let_motif_choose_size) {
558        if (height_of_button<height_of_label) height_of_button = height_of_label;
559        aw_assert(width_of_button && height_of_button);
560    }
561
562    int x_label  = _at->x_for_next_button;
563    int y_label  = _at->y_for_next_button;
564    int x_button = x_label + width_of_label_and_spacer;
565    int y_button = y_label;
566
567    int org_correct_for_at_center = _at->correct_for_at_center; // store original justification
568    int org_y_for_next_button     = _at->y_for_next_button; // store original y pos (modified while creating label)
569
570    if (!let_motif_choose_size) { // don't correct position of button w/o known size
571        // calculate justification manually
572
573        int width_of_button_and_highlight = width_of_button + (_at->highlight ? 2*(_at->shadow_thickness+1)+1 : 0);
574        int width_of_label_and_button     = width_of_label_and_spacer+width_of_button_and_highlight;
575
576        if (_at->correct_for_at_center) { // not if left justified
577            int shiftback = width_of_label_and_button; // shiftback for right justification
578            if (_at->correct_for_at_center == 1) { // center justification
579                shiftback /= 2;
580            }
581            x_label  -= shiftback;
582            x_button -= shiftback;
583        }
584
585        // we already did the justification by calculating all positions manually, so..
586        _at->correct_for_at_center = 0; // ..from now on act like "left justified"!
587    }
588
589    // correct label Y position
590    if (_callback) {            // only if button is a real 3D-button
591        y_label += (height_of_button-height_of_label)/2;
592    }
593
594    Widget parent_widget = (_at->attach_any) ? INFO_FORM : INFO_WIDGET;
595    Widget label_widget  = NULp;
596
597    if (_at->label_for_inputfield) {
598        _at->x_for_next_button = x_label;
599        _at->y_for_next_button = y_label;
600
601        Label clientlabel(_at->label_for_inputfield, this);
602        label_widget = XtVaCreateManagedWidget("label",
603                                               xmLabelWidgetClass,
604                                               parent_widget,
605                                               XmNwidth, (int)(width_of_label + 2),
606                                               RES_LABEL_CONVERT(clientlabel),
607                                               XmNrecomputeSize, false,
608                                               XmNalignment, XmALIGNMENT_BEGINNING,
609                                               XmNfontList, p_global->fontlist,
610                                               XmNx, (int)(x_label),
611                                               XmNy, (int)(y_label),
612                                               NULp);
613
614        if (_at->attach_any) aw_attach_widget(label_widget, _at);
615        AW_label_in_awar_list(this, label_widget, _at->label_for_inputfield);
616    }
617
618    _at->x_for_next_button = x_button;
619    _at->y_for_next_button = y_button;
620
621    Widget fatherwidget = parent_widget; // used as father for button below
622    if (_at->highlight) {
623        if (_at->attach_any) {
624#if defined(DEBUG)
625            printf("Attaching highlighted buttons does not work - "
626                   "highlight ignored for button '%s'!\n", buttonlabel);
627#endif // DEBUG
628            _at->highlight = false;
629        }
630        else {
631            int shadow_offset = _at->shadow_thickness;
632            int x_shadow      = x_button - shadow_offset;
633            int y_shadow      = y_button - shadow_offset;
634
635            fatherwidget = XtVaCreateManagedWidget("draw_area",
636                                                   xmFrameWidgetClass,
637                                                   INFO_WIDGET,
638                                                   XmNx, (int)(x_shadow),
639                                                   XmNy, (int)(y_shadow),
640                                                   XmNshadowType, XmSHADOW_IN,
641                                                   XmNshadowThickness, _at->shadow_thickness,
642                                                   NULp);
643        }
644    }
645
646    Widget button = NULp;
647
648    {
649        aw_xargs args(9);
650        args.add(XmNx, x_button);
651        args.add(XmNy, y_button);
652
653        args.add(XmNfontList,   (XtArgVal)p_global->fontlist);
654        args.add(XmNbackground, _at->background_color);
655
656        if (!let_motif_choose_size) {
657            args.add(XmNwidth,  width_of_button);
658            args.add(XmNheight, height_of_button);
659        }
660
661        Label buttonLabel(buttonlabel, this);
662        if (_callback) {
663            args.add(XmNshadowThickness, _at->shadow_thickness);
664            args.add(XmNalignment,       XmALIGNMENT_CENTER);
665
666            button = XtVaCreateManagedWidget("button", xmPushButtonWidgetClass, fatherwidget, RES_LABEL_CONVERT(buttonLabel), NULp);
667        }
668        else { // button w/o callback; (flat, not clickable)
669            button = XtVaCreateManagedWidget("label", xmLabelWidgetClass, parent_widget, RES_LABEL_CONVERT(buttonLabel), NULp);
670            args.add(XmNalignment, (org_correct_for_at_center == 1) ? XmALIGNMENT_CENTER : XmALIGNMENT_BEGINNING);
671        }
672
673        if (!_at->attach_any || !_callback) args.add(XmNrecomputeSize, false);
674        args.assign_to_widget(button);
675        if (_at->attach_any) aw_attach_widget(button, _at);
676
677        if (_callback) {
678            root->make_sensitive(button, _at->widget_mask);
679        }
680        else {
681            aw_assert(_at->correct_for_at_center == 0);
682            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)
683        }
684
685        AW_label_in_awar_list(this, button, buttonlabel);
686    }
687
688    short height = 0;
689    short width  = 0;
690
691    if (_at->to_position_exists) {
692        // size has explicitly been specified in xfig -> calculate
693        height = _at->to_position_y - _at->y_for_next_button;
694        width  = _at->to_position_x - _at->x_for_next_button;
695    }
696
697    {
698        Widget  toRecenter   = NULp;
699        int     recenterSize = 0;
700
701        if (!height || !width) {
702            // ask motif for real button size
703            Widget ButOrHigh = _at->highlight ? fatherwidget : button;
704            XtVaGetValues(ButOrHigh, XmNheight, &height, XmNwidth, &width, NULp);
705
706            if (let_motif_choose_size) {
707                if (_at->correct_for_at_center) {
708                    toRecenter   = ButOrHigh;
709                    recenterSize = width;
710                }
711                width = 0;          // ignore the used size (because it may use more than the window size)
712            }
713        }
714
715        if (toRecenter) {
716            int shiftback = 0;
717            switch (_at->correct_for_at_center) {
718                case 1: shiftback = recenterSize/2; break;
719                case 2: shiftback = recenterSize; break;
720            }
721            if (shiftback) {
722                XtVaSetValues(toRecenter, XmNx, x_button-shiftback, NULp);
723            }
724        }
725    }
726
727    _at->correct_for_at_center = org_correct_for_at_center; // restore original justification
728    _at->y_for_next_button     = org_y_for_next_button;
729
730    p_w->toggle_field = button;
731    this->_set_activate_callback((void *)button);
732    this->unset_at_commands();
733    this->increment_at_commands(width+SPACE_BEHIND_BUTTON, height);
734}
735
736void AW_window::dump_at_position(const char *tmp_label) const {
737    printf("%s at x = %i / y = %i\n", tmp_label, _at->x_for_next_button, _at->y_for_next_button);
738}
739
740void AW_window::update_label(Widget widget, const char *var_value) {
741    if (get_root()->changer_of_variable != widget) {
742        XtVaSetValues(widget, RES_CONVERT(XmNlabelString, var_value), NULp);
743    }
744    else {
745        get_root()->changer_of_variable = NULp;
746    }
747}
748
749// ----------------------
750//      on/off toggle
751
752struct aw_toggle_data {
753    bool  isTextToggle;
754    char *bitmapOrText[2];
755    int   buttonWidth; // wanted width in characters
756};
757
758void AW_window::update_toggle(Widget widget, const char *var, AW_CL cd_toggle_data) {
759    aw_toggle_data *tdata = (aw_toggle_data*)cd_toggle_data;
760    const char     *text  = tdata->bitmapOrText[(var[0] == '0' || var[0] == 'n') ? 0 : 1];
761
762    if (tdata->isTextToggle) {
763        XtVaSetValues(widget, RES_CONVERT(XmNlabelString, text), NULp);
764    }
765    else {
766        char *path = pixmapPath(text+1);
767        XtVaSetValues(widget, RES_CONVERT(XmNlabelPixmap, path), NULp);
768        free(path);
769    }
770}
771
772void AW_window::create_toggle(const char *var_name, aw_toggle_data *tdata) {
773    AW_cb *cbs = _callback;
774    _callback         = (AW_cb *)1;
775
776    {
777        int old_length_of_buttons = _at->length_of_buttons;
778
779        if (tdata->buttonWidth == 0) {
780            if (tdata->isTextToggle) {
781                int l1 = strlen(tdata->bitmapOrText[0]);
782                int l2 = strlen(tdata->bitmapOrText[1]);
783
784                _at->length_of_buttons = l1>l2 ? l1 : l2; // use longer text for button size
785            }
786            else {
787                _at->length_of_buttons = 0;
788            }
789        }
790        else {
791            _at->length_of_buttons = tdata->buttonWidth;
792        }
793
794        create_button(NULp, tdata->bitmapOrText[0]);
795
796        _at->length_of_buttons = old_length_of_buttons;
797    }
798
799    AW_awar *vs = this->get_root()->awar(var_name);
800    {
801        char *var_value = vs->read_as_string();
802
803        this->update_toggle(p_w->toggle_field, var_value, (AW_CL)tdata);
804        free(var_value);
805    }
806
807    VarUpdateInfo *vui;
808    vui = new VarUpdateInfo(this, p_w->toggle_field, AW_WIDGET_TOGGLE, vs, cbs);
809
810    XtAddCallback(p_w->toggle_field, XmNactivateCallback,
811                  (XtCallbackProc) AW_variable_update_callback,
812                  (XtPointer) vui);
813
814    vs->tie_widget((AW_CL)tdata, p_w->toggle_field, AW_WIDGET_TOGGLE, this);
815}
816
817
818void AW_window::create_toggle(const char *var_name, const char *no, const char *yes, int buttonWidth) {
819    aw_toggle_data *tdata  = new aw_toggle_data;
820    tdata->isTextToggle    = false;
821
822    aw_assert(AW_IS_IMAGEREF(no));
823    aw_assert(AW_IS_IMAGEREF(yes));
824
825    tdata->bitmapOrText[0] = strdup(no);
826    tdata->bitmapOrText[1] = strdup(yes);
827
828    tdata->buttonWidth = buttonWidth;
829
830    create_toggle(var_name, tdata);
831}
832
833void AW_window::create_text_toggle(const char *var_name, const char *noText, const char *yesText, int buttonWidth) {
834    aw_toggle_data *tdata  = new aw_toggle_data;
835    tdata->isTextToggle    = true;
836    tdata->bitmapOrText[0] = strdup(noText);
837    tdata->bitmapOrText[1] = strdup(yesText);
838    tdata->buttonWidth     = buttonWidth;
839
840    create_toggle(var_name, tdata);
841}
842
843
844void AW_window::create_toggle(const char *var_name) {
845    create_toggle(var_name, "#no.xpm", "#yes.xpm");
846}
847
848void AW_window::create_inverse_toggle(const char *var_name) {
849    // like create_toggle, but displays inverse value
850    // (i.e. it's checked if value is zero, and unchecked otherwise)
851    create_toggle(var_name, "#yes.xpm", "#no.xpm");
852}
853
854// ---------------------
855//      input fields
856
857void AW_window::create_input_field(const char *var_name, int columns) {
858    Widget         textField      = NULp;
859    Widget         label_widget   = NULp;
860    AW_cb         *cbs;
861    VarUpdateInfo *vui;
862    char          *str;
863    int            xoff_for_label = 0;
864
865    if (!columns) columns = _at->length_of_buttons;
866
867    AW_awar *vs = root->awar(var_name);
868    str         = root->awar(var_name)->read_as_string();
869
870    int width_of_input_label, height_of_input_label;
871    calculate_label_size(&width_of_input_label, &height_of_input_label, true);
872#if defined(DUMP_BUTTON_CREATION)
873    printf("width_of_input_label=%i height_of_input_label=%i label='%s'\n", width_of_input_label, height_of_input_label, _at->label_for_inputfield);
874#endif // DUMP_BUTTON_CREATION
875
876    int width_of_input = this->calculate_string_width(columns+1) + 9;
877    // calculate width for 1 additional character (input field is not completely used)
878    // + 4 pixel for shadow + 4 unknown missing pixels + 1 add. pixel needed for visible text area
879
880    Widget parentWidget = _at->attach_any ? INFO_FORM : INFO_WIDGET;
881
882    if (_at->label_for_inputfield) {
883        Label clientlabel(_at->label_for_inputfield, this);
884        label_widget = XtVaCreateManagedWidget("label",
885                                            xmLabelWidgetClass,
886                                            parentWidget,
887                                            XmNwidth, (int)(width_of_input_label + 2),
888                                            XmNhighlightThickness, 0,
889                                            RES_LABEL_CONVERT(clientlabel),
890                                            XmNrecomputeSize, false,
891                                            XmNalignment, XmALIGNMENT_BEGINNING,
892                                            XmNfontList, p_global->fontlist,
893                                            (_at->attach_any) ? NULp : XmNx, (int)_at->x_for_next_button,
894                                            XmNy, (int)(_at->y_for_next_button) + 2*root->y_correction_for_input_labels - height_of_input_label/2,
895                                            NULp);
896        if (_at->attach_any) aw_attach_widget(label_widget, _at);
897        xoff_for_label = width_of_input_label + 10;
898    }
899
900
901    int width_of_last_widget = xoff_for_label + width_of_input + 2;
902
903    if (_at->to_position_exists) {
904        width_of_input = _at->to_position_x - _at->x_for_next_button - xoff_for_label + 2;
905        width_of_last_widget = _at->to_position_x - _at->x_for_next_button;
906    }
907
908    {
909        TuneBackground(parentWidget, TUNE_INPUT);
910        textField = XtVaCreateManagedWidget("textField",
911                                            xmTextFieldWidgetClass,
912                                            parentWidget,
913                                            XmNwidth, (int)width_of_input,
914                                            XmNrows, 1,
915                                            XmNvalue, str,
916                                            XmNfontList, p_global->fontlist,
917                                            XmNbackground, _at->background_color,
918                                            (_at->attach_any) ? NULp : XmNx, (int)(_at->x_for_next_button + xoff_for_label),
919                                            XmNy, (int)(_at->y_for_next_button + 5) - 8,
920                                            NULp);
921        if (_at->attach_any) {
922            _at->x_for_next_button += xoff_for_label;
923            aw_attach_widget(textField, _at);
924            _at->x_for_next_button -= xoff_for_label;
925        }
926    }
927
928    free(str);
929
930    // user-own callback
931    cbs = _callback;
932
933    // callback for enter
934    vui = new VarUpdateInfo(this, textField, AW_WIDGET_INPUT_FIELD, vs, cbs);
935
936    XtAddCallback(textField, XmNactivateCallback,
937                  (XtCallbackProc) AW_variable_update_callback,
938                  (XtPointer) vui);
939    if (_d_callback) {
940        XtAddCallback(textField, XmNactivateCallback,
941                      (XtCallbackProc) AW_server_callback,
942                      (XtPointer) _d_callback);
943        _d_callback->id = GBS_global_string_copy("INPUT:%s", var_name);
944        get_root()->define_remote_command(_d_callback);
945    }
946
947    // callback for losing focus
948    XtAddCallback(textField, XmNlosingFocusCallback,
949                  (XtCallbackProc) AW_variable_update_callback,
950                  (XtPointer) vui);
951    // callback for value changed
952    XtAddCallback(textField, XmNvalueChangedCallback,
953                  (XtCallbackProc) AW_value_changed_callback,
954                  (XtPointer) root);
955
956    vs->tie_widget(0, textField, AW_WIDGET_INPUT_FIELD, this);
957    root->make_sensitive(textField, _at->widget_mask);
958
959    short height;
960    XtVaGetValues(textField, XmNheight, &height, NULp);
961    int height_of_last_widget = height;
962
963    if (_at->correct_for_at_center == 1) {   // middle centered
964        XtVaSetValues(textField, XmNx, ((int)(_at->x_for_next_button + xoff_for_label) - (int)(width_of_last_widget/2) + 1), NULp);
965        if (label_widget) {
966            XtVaSetValues(label_widget, XmNx, ((int)(_at->x_for_next_button) - (int)(width_of_last_widget/2) + 1), NULp);
967        }
968        width_of_last_widget = width_of_last_widget / 2;
969    }
970    if (_at->correct_for_at_center == 2) {   // right centered
971        XtVaSetValues(textField, XmNx, (int)(_at->x_for_next_button + xoff_for_label - width_of_last_widget + 3), NULp);
972        if (label_widget) {
973            XtVaSetValues(label_widget, XmNx, (int)(_at->x_for_next_button - width_of_last_widget + 3), NULp);
974        }
975        width_of_last_widget = 0;
976    }
977    width_of_last_widget -= 2;
978
979    this->unset_at_commands();
980    this->increment_at_commands(width_of_last_widget, height_of_last_widget);
981
982}
983
984void AW_window::update_input_field(Widget widget, const char *var_value) {
985    XtVaSetValues(widget, XmNvalue, var_value, NULp);
986}
987
988void AW_window::create_text_field(const char *var_name, int columns, int rows) {
989    Widget         scrolledWindowText;
990    Widget         scrolledText;
991    Widget         label_widget          = NULp;
992    AW_cb         *cbs;
993    VarUpdateInfo *vui;
994    char          *str                   = NULp;
995    short          width_of_last_widget  = 0;
996    short          height_of_last_widget = 0;
997    int            width_of_text         = 0;
998    int            height_of_text        = 0;
999    int            xoff_for_label        = 0;
1000
1001    AW_awar *vs = root->awar(var_name);
1002    str         = root->awar(var_name)->read_string();
1003
1004    int width_of_text_label, height_of_text_label;
1005    calculate_label_size(&width_of_text_label, &height_of_text_label, true);
1006    // @@@ FIXME: use height_of_text_label for propper Y-adjusting of label
1007
1008    // width_of_text_label = this->calculate_string_width( calculate_label_length() );
1009    width_of_text = this->calculate_string_width(columns) + 18;
1010    height_of_text = this->calculate_string_height(rows, rows*4) + 9;
1011
1012
1013    if (_at->label_for_inputfield) {
1014        Label clientlabel(_at->label_for_inputfield, this);
1015        label_widget = XtVaCreateManagedWidget("label",
1016                                               xmLabelWidgetClass,
1017                                               INFO_WIDGET,
1018                                               XmNx, (int)_at->x_for_next_button,
1019                                               XmNy, (int)(_at->y_for_next_button) + this->get_root()->y_correction_for_input_labels + 5 - 6,
1020                                               XmNwidth, (int)(width_of_text_label + 2),
1021                                               RES_LABEL_CONVERT(clientlabel),
1022                                               XmNrecomputeSize, false,
1023                                               XmNalignment, XmALIGNMENT_BEGINNING,
1024                                               XmNfontList, p_global->fontlist,
1025                                               NULp);
1026
1027        xoff_for_label = width_of_text_label + 10;
1028
1029    }
1030
1031    {
1032        aw_xargs args(6);
1033        args.add(XmNscrollingPolicy,        XmAPPLICATION_DEFINED);
1034        args.add(XmNvisualPolicy,           XmVARIABLE);
1035        args.add(XmNscrollBarDisplayPolicy, XmSTATIC);
1036        args.add(XmNfontList,               (XtArgVal)p_global->fontlist);
1037
1038        if (_at->to_position_exists) {
1039            scrolledWindowText = XtVaCreateManagedWidget("scrolledWindowList1", xmScrolledWindowWidgetClass, INFO_FORM, NULp);
1040            args.assign_to_widget(scrolledWindowText);
1041
1042            aw_attach_widget(scrolledWindowText, _at);
1043            width_of_text = _at->to_position_x - _at->x_for_next_button - xoff_for_label - 18;
1044            if (_at->y_for_next_button < _at->to_position_y - 18) {
1045                height_of_text = _at->to_position_y - _at->y_for_next_button - 18;
1046            }
1047        }
1048        else {
1049            scrolledWindowText = XtVaCreateManagedWidget("scrolledWindowText", xmScrolledWindowWidgetClass, INFO_WIDGET, NULp);
1050            args.add(XmNx, 10);
1051            args.add(XmNy, _at->y_for_next_button);
1052            args.assign_to_widget(scrolledWindowText);
1053        }
1054    }
1055
1056    TuneBackground(scrolledWindowText, TUNE_INPUT);
1057    scrolledText = XtVaCreateManagedWidget("scrolledText1",
1058                                           xmTextWidgetClass,
1059                                           scrolledWindowText,
1060                                           XmNeditMode, XmMULTI_LINE_EDIT,
1061                                           XmNvalue, str,
1062                                           XmNscrollLeftSide, false,
1063                                           XmNwidth, (int)width_of_text,
1064                                           XmNheight, (int)height_of_text,
1065                                           XmNfontList, p_global->fontlist,
1066                                           XmNbackground, _at->background_color,
1067                                           NULp);
1068    free(str);
1069
1070    if (!_at->to_position_exists) {
1071        XtVaGetValues(scrolledWindowText,   XmNheight, &height_of_last_widget,
1072                      XmNwidth, &width_of_last_widget, NULp);
1073
1074        width_of_last_widget += (short)xoff_for_label;
1075
1076        switch (_at->correct_for_at_center) {
1077            case 0: // left centered
1078                XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + xoff_for_label), NULp);
1079                break;
1080
1081            case 1: // middle centered
1082                XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + xoff_for_label - (width_of_last_widget/2)), NULp);
1083                if (_at->label_for_inputfield) {
1084                    XtVaSetValues(label_widget, XmNx, (int)(_at->x_for_next_button - (width_of_last_widget/2)), NULp);
1085                }
1086                width_of_last_widget = width_of_last_widget / 2;
1087                break;
1088
1089            case 2: // right centered
1090                XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + xoff_for_label - width_of_last_widget),     NULp);
1091                if (_at->label_for_inputfield) {
1092                    XtVaSetValues(label_widget, XmNx, (int)(_at->x_for_next_button - width_of_last_widget), NULp);
1093                }
1094                width_of_last_widget = 0;
1095                break;
1096        }
1097    }
1098
1099    // user-own callback
1100    cbs = _callback;
1101
1102    // callback for enter
1103    vui = new VarUpdateInfo(this, scrolledText, AW_WIDGET_TEXT_FIELD, vs, cbs);
1104    XtAddCallback(scrolledText, XmNactivateCallback, (XtCallbackProc) AW_variable_update_callback, (XtPointer) vui);
1105    // callback for losing focus
1106    XtAddCallback(scrolledText, XmNlosingFocusCallback, (XtCallbackProc) AW_variable_update_callback, (XtPointer) vui);
1107    // callback for value changed
1108    XtAddCallback(scrolledText, XmNvalueChangedCallback, (XtCallbackProc) AW_value_changed_callback, (XtPointer) root);
1109
1110    vs->tie_widget(0, scrolledText, AW_WIDGET_TEXT_FIELD, this);
1111    root->make_sensitive(scrolledText, _at->widget_mask);
1112
1113    this->unset_at_commands();
1114    this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1115}
1116
1117
1118void AW_window::update_text_field(Widget widget, const char *var_value) {
1119    XtVaSetValues(widget, XmNvalue, var_value, NULp);
1120}
1121
1122static void scalerChanged_cb(Widget scale, XtPointer variable_update_struct, XtPointer call_data) {
1123    XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct*)call_data;
1124    VarUpdateInfo         *vui = (VarUpdateInfo*)variable_update_struct;
1125
1126    bool do_update = true;
1127    if (cbs->reason == XmCR_DRAG) { // still dragging?
1128        double mean_callback_time = vui->get_awar()->mean_callback_time();
1129
1130        const double MAX_DRAGGED_CALLBACK_TIME = 1.0;
1131        if (mean_callback_time>MAX_DRAGGED_CALLBACK_TIME) {
1132            do_update = false; // do not update while dragging, if update callback needs more than 1 second
1133                               // Note that a longer update will happen once!
1134        }
1135    }
1136
1137    if (do_update) {
1138        AW_root::SINGLETON->value_changed = true;
1139        AW_variable_update_callback(scale, variable_update_struct, call_data);
1140    }
1141}
1142
1143void AW_window::create_input_field_with_scaler(const char *awar_name, int textcolumns, int scaler_length, AW_ScalerType scalerType) {
1144    create_input_field(awar_name, textcolumns);
1145
1146    Widget parentWidget = _at->attach_any ? INFO_FORM : INFO_WIDGET;
1147
1148    AW_awar *vs = root->awar(awar_name);
1149    // Note: scaler also "works" if no min/max is defined for awar, but scaling is a bit weird
1150    int scalerValue = calculate_scaler_value(vs, scalerType);
1151
1152    Widget scale = XtVaCreateManagedWidget("scale",
1153                                           xmScaleWidgetClass,
1154                                           parentWidget,
1155                                           XmNx, _at->x_for_next_button,
1156                                           XmNy, _at->y_for_next_button + 4,
1157                                           XmNorientation, XmHORIZONTAL,
1158                                           XmNscaleWidth, scaler_length,
1159                                           XmNshowValue, False,
1160                                           XmNminimum, SCALER_MIN_VALUE,
1161                                           XmNmaximum, SCALER_MAX_VALUE,
1162                                           XmNvalue, scalerValue,
1163                                           NULp);
1164
1165    short width_of_last_widget  = 0;
1166    short height_of_last_widget = 0;
1167
1168    XtVaGetValues(scale,
1169                  XmNheight, &height_of_last_widget,
1170                  XmNwidth, &width_of_last_widget,
1171                  NULp);
1172
1173    AW_cb         *cbs = _callback;
1174    VarUpdateInfo *vui = new VarUpdateInfo(this, scale, AW_WIDGET_SCALER, vs, cbs);
1175    vui->set_scalerType(scalerType);
1176
1177    XtAddCallback(scale, XmNvalueChangedCallback, scalerChanged_cb, (XtPointer)vui);
1178    XtAddCallback(scale, XmNdragCallback,         scalerChanged_cb, (XtPointer)vui);
1179
1180    vs->tie_widget((AW_CL)scalerType, scale, AW_WIDGET_SCALER, this);
1181    root->make_sensitive(scale, _at->widget_mask);
1182
1183    this->unset_at_commands();
1184    this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1185}
1186
1187void AW_window::update_scaler(Widget widget, AW_awar *awar, AW_ScalerType scalerType) {
1188    int scalerVal = calculate_scaler_value(awar, scalerType);
1189    XtVaSetValues(widget, XmNvalue, scalerVal, NULp);
1190}
1191
1192// -----------------------
1193//      selection list
1194
1195
1196static void scroll_sellist(Widget scrolledList, bool upwards) {
1197    int oldPos, visible, items;
1198    XtVaGetValues(scrolledList,
1199                  XmNtopItemPosition, &oldPos,
1200                  XmNvisibleItemCount, &visible,
1201                  XmNitemCount,  &items,
1202                  NULp);
1203
1204    int amount = visible/5;
1205    if (amount<1) amount = 1;
1206    if (upwards) amount = -amount;
1207
1208    int newPos = force_in_range(1, oldPos + amount, items-visible+2);
1209    if (newPos != oldPos) XmListSetPos(scrolledList, newPos);
1210}
1211
1212static void scroll_sellist_up(Widget scrolledList, XEvent*, String*, Cardinal*) { scroll_sellist(scrolledList, true); }
1213static void scroll_sellist_dn(Widget scrolledList, XEvent*, String*, Cardinal*) { scroll_sellist(scrolledList, false); }
1214
1215AW_selection_list* AW_window::create_selection_list(const char *var_name, int columns, int rows) {
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.