source: tags/svn.1.5.4/WINDOW/AW_button.cxx

Last change on this file was 8359, checked in by westram, 13 years ago
  • added 'Never ask again' switch to most modal question dialogs. This is a workaround to make it possible to work with macros where modal questions are used. See also #179
    • added unique IDs to all calls to aw_question / AW_repeated_question::get_answer
    • replaced most calls to aw_popup_ok with aw_message (most of them only worked-around the non-standard way of EDIT4 to show aw_message)
  • added 'Reactivate questions' to all properties menus
  • hardcoded unused default-params from aw_ask_sure, aw_popup_ok + aw_popup_exit
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 102.9 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : AW_button.cxx                                     //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "aw_at.hxx"
12#include "aw_Xm.hxx"
13#include "aw_select.hxx"
14#include "aw_nawar.hxx"
15#include "aw_awar.hxx"
16#include "aw_window_Xm.hxx"
17#include "aw_msg.hxx"
18#include "aw_root.hxx"
19#include "aw_question.hxx"
20
21#include <arb_str.h>
22#include <arb_strbuf.h>
23#include <arb_strarray.h>
24#include <arb_sort.h>
25
26#include <Xm/Frame.h>
27#include <Xm/MenuShell.h>
28#include <Xm/RowColumn.h>
29#include <Xm/ToggleB.h>
30#include <Xm/Label.h>
31#include <Xm/List.h>
32#include <Xm/PushB.h>
33#include <Xm/Text.h>
34#include <Xm/TextF.h>
35#include <Xm/ScrolledW.h>
36
37#include <iostream>
38
39#if defined(DEBUG)
40// #define DUMP_BUTTON_CREATION
41#endif // DEBUG
42
43struct AW_widget_refresh_cb : virtual Noncopyable {
44    AW_widget_refresh_cb(AW_widget_refresh_cb *previous, AW_awar *vs, AW_CL cd1, Widget w, AW_widget_type type, AW_window *awi);
45    ~AW_widget_refresh_cb();
46
47    AW_CL           cd;
48    AW_awar        *awar;
49    Widget          widget;
50    AW_widget_type  widget_type;
51    AW_window      *aw;
52
53    AW_widget_refresh_cb *next;
54};
55
56static void aw_cp_awar_2_widget_cb(AW_root *root, AW_CL cl_widget_refresh_cb) {
57    AW_widget_refresh_cb *widgetlist = (AW_widget_refresh_cb*)cl_widget_refresh_cb;
58    if (widgetlist->widget == root->changer_of_variable) {
59        root->changer_of_variable = 0;
60        root->value_changed = false;
61        return;
62    }
63
64    {
65        char *var_value;
66        var_value = widgetlist->awar->read_as_string();
67
68        // und benachrichtigen der anderen
69        switch (widgetlist->widget_type) {
70
71            case AW_WIDGET_INPUT_FIELD:
72                widgetlist->aw->update_input_field(widgetlist->widget, var_value);
73                break;
74            case AW_WIDGET_TEXT_FIELD:
75                widgetlist->aw->update_text_field(widgetlist->widget, var_value);
76                break;
77            case AW_WIDGET_TOGGLE:
78                widgetlist->aw->update_toggle(widgetlist->widget, var_value, widgetlist->cd);
79                break;
80            case AW_WIDGET_LABEL_FIELD:
81                widgetlist->aw->update_label(widgetlist->widget, var_value);
82                break;
83            case AW_WIDGET_CHOICE_MENU:
84                widgetlist->aw->update_option_menu((AW_option_menu_struct*)widgetlist->cd);
85                break;
86            case AW_WIDGET_TOGGLE_FIELD:
87                widgetlist->aw->update_toggle_field((int)widgetlist->cd);
88                break;
89            case AW_WIDGET_SELECTION_LIST:
90                widgetlist->aw->update_selection_list_intern((AW_selection_list *)widgetlist->cd);
91            default:
92                break;
93        }
94        free(var_value);
95    }
96    root->value_changed = false;     // Maybe value changed is set because Motif calls me
97}
98
99AW_widget_refresh_cb::AW_widget_refresh_cb(AW_widget_refresh_cb *previous, AW_awar *vs, AW_CL cd1, Widget w, AW_widget_type type, AW_window *awi) {
100    cd          = cd1;
101    widget      = w;
102    widget_type = type;
103    awar        = vs;
104    aw          = awi;
105    next        = previous;
106
107    awar->add_callback(aw_cp_awar_2_widget_cb, (AW_CL)this);
108}
109
110AW_widget_refresh_cb::~AW_widget_refresh_cb() {
111    if (next) delete next;
112    awar->remove_callback(aw_cp_awar_2_widget_cb, (AW_CL)this);
113}
114
115void AW_awar::tie_widget(AW_CL cd1, Widget widget, AW_widget_type type, AW_window *aww) {
116    refresh_list = new AW_widget_refresh_cb(refresh_list, this, cd1, widget, type, aww);
117}
118void AW_awar::untie_all_widgets() {
119    delete refresh_list; refresh_list = NULL;
120}
121
122
123class VarUpdateInfo : virtual Noncopyable { // used to refresh single items on change
124    Widget          widget;
125    AW_widget_type  widget_type;
126    AW_awar        *awar;
127    AW_scalar       value;
128    AW_cb_struct   *cbs;
129    void           *id;         // selection id etc ...
130   
131public:
132    VarUpdateInfo(Widget w, AW_widget_type wtype, AW_awar *a, AW_cb_struct *cbs_)
133        : widget(w), widget_type(wtype), awar(a),
134          value(a),
135          cbs(cbs_), id(NULL)
136    {
137    }
138    template<typename T>
139    VarUpdateInfo(Widget w, AW_widget_type wtype, AW_awar *a, T t, AW_cb_struct *cbs_)
140        : widget(w), widget_type(wtype), awar(a),
141          value(t),
142          cbs(cbs_), id(NULL)
143    {
144    }
145
146    void change_from_widget(XtPointer call_data);
147
148    void set_widget(Widget w) { widget = w; }
149    void set_id(void *ID) { id = ID; }
150};
151
152static void AW_variable_update_callback(Widget /*wgt*/, XtPointer variable_update_struct, XtPointer call_data) {
153    VarUpdateInfo *vui = (VarUpdateInfo *) variable_update_struct;
154    aw_assert(vui);
155
156    vui->change_from_widget(call_data);
157}
158
159void VarUpdateInfo::change_from_widget(XtPointer call_data) {
160    GB_ERROR  error = NULL;
161    AW_root  *root  = awar->root;
162
163    if (root->value_changed) {
164        root->changer_of_variable = widget;
165    }
166
167    switch (widget_type) {
168        case AW_WIDGET_INPUT_FIELD:
169        case AW_WIDGET_TEXT_FIELD: {
170            if (!root->value_changed) return;
171
172            char *new_text = XmTextGetString((widget));
173            error          = awar->write_as_string(new_text);
174            XtFree(new_text);
175            break;
176        }
177        case AW_WIDGET_TOGGLE:
178            root->changer_of_variable = 0;
179            error = awar->toggle_toggle();
180            break;
181
182        case AW_WIDGET_TOGGLE_FIELD: {
183            if (XmToggleButtonGetState(widget) == False) break; // no toggle is selected (?)
184            // fall-through
185        }
186        case AW_WIDGET_CHOICE_MENU:
187            error = value.write_to(awar);
188            break;
189
190        case AW_WIDGET_SELECTION_LIST: {
191            char *selected; {
192                XmListCallbackStruct *xml = (XmListCallbackStruct*)call_data;
193                XmStringGetLtoR(xml->item, XmSTRING_DEFAULT_CHARSET, &selected);
194            }
195
196            AW_selection_list       *list  = (AW_selection_list*)id;
197            AW_selection_list_entry *entry = list->list_table;
198
199            while (entry && strcmp(entry->get_displayed(), selected) != 0) {
200                entry = entry->next;
201            }
202
203            if (!entry) {   
204                entry = list->default_select; // use default selection
205                if (!entry) GBK_terminate("no default specified for selection list"); // or die
206            }
207            entry->value.write_to(awar);
208            XtFree(selected);
209            break;
210        }
211        case AW_WIDGET_LABEL_FIELD:
212            break;
213
214        default:
215            GBK_terminatef("Unknown widget type %i in AW_variable_update_callback", widget_type);
216            break;
217    }
218
219    if (error) {
220        root->changer_of_variable = 0;
221        awar->update();
222        aw_message(error);
223    }
224    else {
225        if (root->prvt->recording_macro_file) {
226            fprintf(root->prvt->recording_macro_file, "BIO::remote_awar($gb_main,\"%s\",", root->prvt->application_name_for_macros);
227            GBS_fwrite_string(awar->awar_name, root->prvt->recording_macro_file);
228            fprintf(root->prvt->recording_macro_file, ",");
229
230            char *svalue = awar->read_as_string();
231            GBS_fwrite_string(svalue, root->prvt->recording_macro_file);
232            free(svalue);
233
234            fprintf(root->prvt->recording_macro_file, ");\n");
235        }
236        if (cbs) cbs->run_callback();
237        root->value_changed = false;
238    }
239}
240
241
242static void AW_value_changed_callback(Widget /*wgt*/, XtPointer rooti, XtPointer /*call_data*/) {
243    AW_root *root = (AW_root *)rooti;
244    root->value_changed = true;
245}
246
247static void aw_attach_widget(Widget scrolledWindowText, AW_at *_at, int default_width = -1) {
248    short height = 0;
249    short width = 0;
250    if (!_at->to_position_exists) {
251        XtVaGetValues(scrolledWindowText, XmNheight, &height, XmNwidth, &width, NULL);
252        if (default_width >0) width = default_width;
253
254        switch (_at->correct_for_at_center) {
255            case 0:             // left justified
256                _at->to_position_x      = _at->x_for_next_button + width;
257                break;
258            case 1:             // centered
259                _at->to_position_x      = _at->x_for_next_button + width/2;
260                _at->x_for_next_button -= width/2;
261                break;
262            case 2:             // right justified
263                _at->to_position_x      = _at->x_for_next_button;
264                _at->x_for_next_button -= width;
265                break;
266        }
267        _at->to_position_y = _at->y_for_next_button + height;
268        _at->attach_x      = _at->attach_lx;
269        _at->attach_y      = _at->attach_ly;
270    }
271
272#define MIN_RIGHT_OFFSET  10
273#define MIN_BOTTOM_OFFSET 10
274
275    if (_at->attach_x) {
276        int right_offset = _at->max_x_size - _at->to_position_x;
277        if (right_offset<MIN_RIGHT_OFFSET) {
278            right_offset    = MIN_RIGHT_OFFSET;
279            _at->max_x_size = _at->to_position_x+right_offset;
280        }
281
282        XtVaSetValues(scrolledWindowText,
283                      XmNrightAttachment,     XmATTACH_FORM,
284                      XmNrightOffset,         right_offset,
285                      NULL);
286    }
287    else {
288        XtVaSetValues(scrolledWindowText,
289                      XmNrightAttachment,     XmATTACH_OPPOSITE_FORM,
290                      XmNrightOffset,         -_at->to_position_x,
291                      NULL);
292    }
293    if (_at->attach_lx) {
294        XtVaSetValues(scrolledWindowText,
295                      XmNwidth,               _at->to_position_x - _at->x_for_next_button,
296                      XmNleftAttachment,      XmATTACH_NONE,
297                      NULL);
298    }
299    else {
300        XtVaSetValues(scrolledWindowText,
301                      XmNleftAttachment,      XmATTACH_FORM,
302                      XmNleftOffset,          _at->x_for_next_button,
303                      NULL);
304    }
305
306    if (_at->attach_y) {
307        int bottom_offset = _at->max_y_size - _at->to_position_y;
308        if (bottom_offset<MIN_BOTTOM_OFFSET) {
309            bottom_offset   = MIN_BOTTOM_OFFSET;
310            _at->max_y_size = _at->to_position_y+bottom_offset;
311        }
312
313        XtVaSetValues(scrolledWindowText,
314                      XmNbottomAttachment,    XmATTACH_FORM,
315                      XmNbottomOffset,        bottom_offset,
316                      NULL);
317    }
318    else {
319        XtVaSetValues(scrolledWindowText,
320                      XmNbottomAttachment,    XmATTACH_OPPOSITE_FORM,
321                      XmNbottomOffset,        - _at->to_position_y,
322                      NULL);
323    }
324    if (_at->attach_ly) {
325        XtVaSetValues(scrolledWindowText,
326                      XmNheight,              _at->to_position_y - _at->y_for_next_button,
327                      XmNtopAttachment,       XmATTACH_NONE,
328                      NULL);
329
330    }
331    else {
332        XtVaSetValues(scrolledWindowText,
333                      XmNtopAttachment,       XmATTACH_FORM,
334                      XmNtopOffset,           _at->y_for_next_button,
335                      NULL);
336    }
337}
338
339static char *pixmapPath(const char *pixmapName) {
340    return nulldup(GB_path_in_ARBLIB("pixmaps", pixmapName));
341}
342
343
344#define MAX_LINE_LENGTH 200
345static GB_ERROR detect_bitmap_size(const char *pixmapname, int *width, int *height) {
346    GB_ERROR err = 0;
347
348    *width  = 0;
349    *height = 0;
350
351    char *path = pixmapPath(pixmapname);
352    FILE *in   = fopen(path, "rt");
353    if (in) {
354        const char *subdir = strrchr(pixmapname, '/');
355        char       *name   = strdup(subdir ? subdir+1 : pixmapname);
356        {
357            char *dot       = strrchr(name, '.');
358            if (dot) dot[0] = 0;
359            else  err       = "'.' expected";
360        }
361        int  namelen = strlen(name);
362        char buffer[MAX_LINE_LENGTH];
363        bool done    = false;
364
365        while (!done && !err) {
366            fgets(buffer, MAX_LINE_LENGTH, in);
367            if (strchr(buffer, 0)[-1] != '\n') {
368                err = GBS_global_string("Line too long ('%s')", buffer); // increase MAX_LINE_LENGTH above
369            }
370            else if (strncmp(buffer, "#define", 7) != 0) {
371                done = true;
372            }
373            else {
374                char *name_pos = strstr(buffer+7, name);
375                if (name_pos) {
376                    char *behind = name_pos+namelen;
377                    if (strncmp(behind, "_width ", 7) == 0) *width = atoi(behind+7);
378                    else if (strncmp(behind, "_height ", 8) == 0) *height = atoi(behind+8);
379                }
380            }
381        }
382
383        if (done && ((*width == 0) || (*height == 0))) {
384            if (strstr(buffer, "XPM") != NULL) {
385                fgets(buffer, MAX_LINE_LENGTH, in);
386                fgets(buffer, MAX_LINE_LENGTH, in);
387                char *temp = strtok(buffer+1, " ");
388                *width = atoi(temp);
389                temp = strtok(NULL,  " ");
390                *height = atoi(temp);
391            }
392            else {
393                err = "can't detect size";
394            }
395        }
396
397        free(name);
398        fclose(in);
399    }
400    else {
401        err = "no such file";
402    }
403
404    if (err) {
405        err = GBS_global_string("%s: %s", pixmapname, err);
406    }
407
408#if defined(DUMP_BUTTON_CREATION)
409    printf("Bitmap '%s' has size %i/%i\n", pixmapname, *width, *height);
410#endif // DUMP_BUTTON_CREATION
411
412    free(path);
413    return err;
414}
415#undef MAX_LINE_LENGTH
416
417inline void calculate_textsize(const char *str, int *width, int *height) {
418    int textwidth  = 0;
419    int textheight = 1;
420    int linewidth  = 0;
421
422    for (int p = 0; str[p]; ++p) {
423        if (str[p] == '\n') {
424            if (linewidth>textwidth) textwidth = linewidth;
425
426            linewidth = 0;
427            textheight++;
428        }
429        else {
430            linewidth++;
431        }
432    }
433
434    if (linewidth>textwidth) textwidth = linewidth;
435
436    *width  = textwidth;
437    *height = textheight;
438}
439
440static void calculate_label_size(AW_window *aww, int *width, int *height, bool in_pixel, const char *non_at_label) {
441    // in_pixel == true -> calculate size in pixels
442    // in_pixel == false -> calculate size in characters
443
444    const char *label = non_at_label ? non_at_label : aww->_at->label_for_inputfield;
445    if (label) {
446        calculate_textsize(label, width, height);
447        if (aww->_at->length_of_label_for_inputfield) {
448            *width = aww->_at->length_of_label_for_inputfield;
449        }
450        if (in_pixel) {
451            *width  = aww->calculate_string_width(*width);
452            *height = aww->calculate_string_height(*height, 0);
453        }
454    }
455    else {
456        *width  = 0;
457        *height = 0;
458    }
459}
460
461Widget AW_window::get_last_widget() const {
462    return p_global->get_last_widget();
463}
464
465void aw_detect_text_size(const char *text, size_t& width, size_t& height) {
466    size_t text_width = strcspn(text, "\n");
467
468    if (text[text_width]) {
469        aw_assert(text[text_width] == '\n');
470
471        aw_detect_text_size(text+text_width+1, width, height);
472        if (text_width>width) width = text_width;
473        height++;
474    }
475    else { // EOS
476        width  = text_width;
477        height = 1;
478    }
479}
480
481void AW_window::create_autosize_button(const char *macro_name, AW_label buttonlabel, const  char *mnemonic, unsigned xtraSpace) {
482    aw_assert(buttonlabel[0] != '#');               // use create_button() for graphical buttons!
483
484    AW_awar *is_awar = get_root()->label_is_awar(buttonlabel);
485    size_t   width, height;
486    if (is_awar) {
487        char *content = is_awar->read_as_string();
488        aw_assert(content[0]); /* you need to fill the awar before calling create_autosize_button,
489                                * otherwise size cannot be detected */
490        aw_detect_text_size(content, width, height);
491    }
492    else {
493        aw_detect_text_size(buttonlabel, width, height);
494    }
495
496    int   len               = width+(xtraSpace*2);
497    short length_of_buttons = _at->length_of_buttons;
498    short height_of_buttons = _at->height_of_buttons;
499
500    _at->length_of_buttons = len+1;
501    _at->height_of_buttons = height;
502    create_button(macro_name, buttonlabel, mnemonic);
503    _at->length_of_buttons = length_of_buttons;
504    _at->height_of_buttons = height_of_buttons;
505}
506
507void AW_window::create_button(const char *macro_name, AW_label buttonlabel, const char */*mnemonic*/, const char *color) {
508    // Create a button or text display.
509    //
510    // If a callback is bound via at->callback(), a button is created.
511    // Otherwise a text display is created.
512    //
513    // if buttonlabel starts with '#' the rest of buttonlabel is used as name of bitmap file used for button
514    // if buttonlabel contains a '/' it's interpreted as AWAR name and the button displays the content of the awar
515    // otherwise buttonlabel is interpreted as button label (may contain '\n').
516    //
517    // Note 1: Button width 0 does not work together with labels!
518
519    // Note 2: "color" may be specified for the button background (see TuneOrSetBackground for details)
520
521    TuneOrSetBackground(_at->attach_any ? INFO_FORM : INFO_WIDGET, // set background for buttons / text displays
522                        color,
523                        _callback ? TUNE_BUTTON : 0);
524
525#if defined(DUMP_BUTTON_CREATION)
526    printf("------------------------------ Button '%s'\n", buttonlabel);
527    printf("x_for_next_button=%i y_for_next_button=%i\n", _at->x_for_next_button, _at->y_for_next_button);
528#endif // DUMP_BUTTON_CREATION
529
530    if (_callback && ((long)_callback != 1))
531    {
532        if (macro_name) {
533            _callback->id = GBS_global_string_copy("%s/%s", this->window_defaults_name, macro_name);
534            get_root()->define_remote_command(_callback);
535        }
536        else {
537            _callback->id = 0;
538        }
539    }
540
541#define SPACE_BEHIND_LABEL  10
542#define SPACE_BEHIND_BUTTON 3
543
544#define BUTTON_TEXT_X_PADDING 4
545#define BUTTON_TEXT_Y_PADDING 10
546
547#define BUTTON_GRAPHIC_PADDING 12
548#define FLAT_GRAPHIC_PADDING   4 // for buttons w/o callback
549
550    bool is_graphical_button = buttonlabel[0] == '#';
551
552#if defined(ASSERTION_USED)
553    AW_awar *is_awar = is_graphical_button ? NULL : get_root()->label_is_awar(buttonlabel);
554#endif // ASSERTION_USED
555
556    int width_of_button = -1, height_of_button = -1;
557
558    int width_of_label, height_of_label;
559    calculate_label_size(this, &width_of_label, &height_of_label, true, 0);
560    int width_of_label_and_spacer = _at->label_for_inputfield ? width_of_label+SPACE_BEHIND_LABEL : 0;
561
562    bool let_motif_choose_size  = false;
563
564    if (_at->to_position_exists) { // size has explicitly been specified in xfig -> calculate
565        width_of_button  = _at->to_position_x - _at->x_for_next_button - width_of_label_and_spacer;
566        height_of_button = _at->to_position_y - _at->y_for_next_button;
567    }
568    else if (_at->length_of_buttons) { // button width specified from client code
569        width_of_button  = BUTTON_TEXT_X_PADDING + calculate_string_width(_at->length_of_buttons+1);
570
571        if (!is_graphical_button) {
572            if (_at->height_of_buttons) { // button height specified from client code
573                height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(_at->height_of_buttons, 0);
574            }
575            else {
576                int textwidth, textheight;
577                calculate_textsize(buttonlabel, &textwidth, &textheight);
578                height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(textheight, 0);
579            }
580        }
581        else {
582            height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(1, 0);
583        }
584    }
585    else { // no button_length() specified
586        aw_assert(!is_awar); // please specify button_length() for AWAR button!
587
588        if (is_graphical_button) {
589            int      width, height;
590            GB_ERROR err = detect_bitmap_size(buttonlabel+1, &width, &height);
591
592            if (!err) {
593                int gpadding = _callback ? BUTTON_GRAPHIC_PADDING : FLAT_GRAPHIC_PADDING;
594
595                width_of_button  = width+gpadding;
596                height_of_button = height+gpadding;
597            }
598            else {
599                aw_assert(0);   // oops - failed to detect bitmap size
600                let_motif_choose_size = true;
601            }
602        }
603        else {
604            int textwidth, textheight;
605            calculate_textsize(buttonlabel, &textwidth, &textheight);
606
607            width_of_button  = BUTTON_TEXT_X_PADDING + calculate_string_width(textwidth+1);
608            height_of_button = BUTTON_TEXT_Y_PADDING + calculate_string_height(textheight, 0);
609        }
610    }
611
612    if (!let_motif_choose_size) {
613        if (height_of_button<height_of_label) height_of_button = height_of_label;
614        aw_assert(width_of_button && height_of_button);
615    }
616
617    int x_label  = _at->x_for_next_button;
618    int y_label  = _at->y_for_next_button;
619    int x_button = x_label + width_of_label_and_spacer;
620    int y_button = y_label;
621
622    int org_correct_for_at_center = _at->correct_for_at_center; // store original justification
623    int org_y_for_next_button     = _at->y_for_next_button; // store original y pos (modified while creating label)
624
625    if (!let_motif_choose_size) { // don't correct position of button w/o known size
626        // calculate justification manually
627
628        int width_of_button_and_highlight = width_of_button + (_at->highlight ? 2*(_at->shadow_thickness+1)+1 : 0);
629        int width_of_label_and_button     = width_of_label_and_spacer+width_of_button_and_highlight;
630
631        if (_at->correct_for_at_center) { // not if left justified
632            int shiftback = width_of_label_and_button; // shiftback for right justification
633            if (_at->correct_for_at_center == 1) { // center justification
634                shiftback /= 2;
635            }
636            x_label  -= shiftback;
637            x_button -= shiftback;
638        }
639
640        // we already did the justification by calculating all positions manually, so..
641        _at->correct_for_at_center = 0; // ..from now on act like "left justified"!
642    }
643
644    // correct label Y position
645    if (_callback) {            // only if button is a real 3D-button
646        y_label += (height_of_button-height_of_label)/2;
647    }
648
649    Widget parent_widget = (_at->attach_any) ? INFO_FORM : INFO_WIDGET;
650    Widget tmp_label         = 0;
651
652    if (_at->label_for_inputfield) {
653        _at->x_for_next_button = x_label;
654        _at->y_for_next_button = y_label;
655
656        tmp_label = XtVaCreateManagedWidget("label",
657                                            xmLabelWidgetClass,
658                                            parent_widget,
659                                            XmNwidth, (int)(width_of_label + 2),
660                                            RES_LABEL_CONVERT(_at->label_for_inputfield),
661                                            XmNrecomputeSize, false,
662                                            XmNalignment, XmALIGNMENT_BEGINNING,
663                                            XmNfontList, p_global->fontlist,
664                                            XmNx, (int)(x_label),
665                                            XmNy, (int)(y_label),
666                                            NULL);
667
668        if (_at->attach_any) aw_attach_widget(tmp_label, _at);
669        AW_label_in_awar_list(this, tmp_label, _at->label_for_inputfield);
670    }
671
672    _at->x_for_next_button = x_button;
673    _at->y_for_next_button = y_button;
674
675    Widget fatherwidget = parent_widget; // used as father for button below
676    if (_at->highlight) {
677        if (_at->attach_any) {
678#if defined(DEBUG)
679            printf("Attaching highlighted buttons does not work - "
680                   "highlight ignored for button '%s'!\n", buttonlabel);
681#endif // DEBUG
682            _at->highlight = false;
683        }
684        else {
685            int shadow_offset = _at->shadow_thickness;
686            int x_shadow      = x_button - shadow_offset;
687            int y_shadow      = y_button - shadow_offset;
688
689            fatherwidget = XtVaCreateManagedWidget("draw_area",
690                                                   xmFrameWidgetClass,
691                                                   INFO_WIDGET,
692                                                   XmNx, (int)(x_shadow),
693                                                   XmNy, (int)(y_shadow),
694                                                   XmNshadowType, XmSHADOW_IN,
695                                                   XmNshadowThickness, _at->shadow_thickness,
696                                                   NULL);
697        }
698    }
699
700    Widget  button       = 0;
701    char   *mwidth       = let_motif_choose_size ? 0 : XmNwidth; // 0 means autodetect by motif
702    char   *mheight      = let_motif_choose_size ? 0 : XmNheight;
703
704    if (_callback) {
705        if (_at->attach_any) { // attached button with callback
706            button = XtVaCreateManagedWidget("button",
707                                             xmPushButtonWidgetClass,
708                                             fatherwidget,
709                                             RES_LABEL_CONVERT(buttonlabel),
710                                             XmNx, (int)(x_button),
711                                             XmNy, (int)(y_button),
712                                             XmNshadowThickness, _at->shadow_thickness,
713                                             XmNalignment, XmALIGNMENT_CENTER,
714                                             XmNfontList, p_global->fontlist,
715                                             XmNbackground, _at->background_color,
716                                             mwidth, (int)width_of_button, // may terminate the list
717                                             mheight, (int)height_of_button, // may terminate the list
718                                             NULL);
719            aw_attach_widget(button, _at);
720        }
721        else { // unattached button with callback
722            button = XtVaCreateManagedWidget("label",
723                                             xmPushButtonWidgetClass,
724                                             fatherwidget,
725                                             RES_LABEL_CONVERT(buttonlabel),
726                                             XmNx, (int)(x_button),
727                                             XmNy, (int)(y_button),
728                                             XmNrecomputeSize, false,
729                                             XmNshadowThickness, _at->shadow_thickness,
730                                             XmNalignment, XmALIGNMENT_CENTER,
731                                             XmNfontList, p_global->fontlist,
732                                             XmNbackground, _at->background_color,
733                                             mwidth, (int)width_of_button, // may terminate the list
734                                             mheight, (int)height_of_button, // may terminate the list
735                                             NULL);
736        }
737        AW_label_in_awar_list(this, button, buttonlabel);
738        root->make_sensitive(button, _at->widget_mask);
739    }
740    else { // button w/o callback (flat, not clickable)
741        long alignment = (org_correct_for_at_center == 1) ? XmALIGNMENT_CENTER : XmALIGNMENT_BEGINNING;
742
743        button = XtVaCreateManagedWidget("label",
744                                         xmLabelWidgetClass,
745                                         parent_widget,
746                                         XmNrecomputeSize, false,
747                                         XmNx, (int)(x_button),
748                                         XmNy, (int)(y_button),
749                                         XmNalignment, alignment, // alignment of text inside button
750                                         // XmNalignment, XmALIGNMENT_BEGINNING, // alignment of text inside button
751                                         RES_LABEL_CONVERT(buttonlabel),
752                                         XmNfontList, p_global->fontlist,
753                                         XmNbackground, _at->background_color,
754                                         mwidth, (int)width_of_button, // may terminate the list
755                                         mheight, (int)height_of_button, // may terminate the list
756                                         NULL);
757
758        if (_at->attach_any) aw_attach_widget(button, _at);
759        AW_JUSTIFY_LABEL(button, _at->correct_for_at_center);
760        AW_label_in_awar_list(this, button, buttonlabel);
761    }
762
763    short height = 0;
764    short width  = 0;
765
766    if (_at->to_position_exists) {
767        // size has explicitly been specified in xfig -> calculate
768        height = _at->to_position_y - _at->y_for_next_button;
769        width  = _at->to_position_x - _at->x_for_next_button;
770    }
771
772    {
773        Widget  toRecenter   = 0;
774        int     recenterSize = 0;
775
776        if (!height || !width) {
777            // ask motif for real button size
778            Widget ButOrHigh = _at->highlight ? fatherwidget : button;
779            XtVaGetValues(ButOrHigh, XmNheight, &height, XmNwidth, &width, NULL);
780
781            if (let_motif_choose_size) {
782                if (_at->correct_for_at_center) {
783                    toRecenter   = ButOrHigh;
784                    recenterSize = width;
785                }
786                width = 0;          // ignore the used size (because it may use more than the window size)
787            }
788        }
789
790        if (toRecenter) {
791            int shiftback = 0;
792            switch (_at->correct_for_at_center) {
793                case 1: shiftback = recenterSize/2; break;
794                case 2: shiftback = recenterSize; break;
795            }
796            if (shiftback) {
797                XtVaSetValues(toRecenter, XmNx, x_button-shiftback, NULL);
798            }
799        }
800    }
801
802    _at->correct_for_at_center = org_correct_for_at_center; // restore original justification
803    _at->y_for_next_button     = org_y_for_next_button;
804
805    p_w->toggle_field = button;
806    this->_set_activate_callback((void *)button);
807    this->unset_at_commands();
808    this->increment_at_commands(width+SPACE_BEHIND_BUTTON, height);
809}
810
811void AW_window::dump_at_position(const char *tmp_label) const {
812    printf("%s at x = %i / y = %i\n", tmp_label, _at->x_for_next_button, _at->y_for_next_button);
813}
814
815void AW_window::update_label(Widget widget, const char *var_value) {
816    if (get_root()->changer_of_variable != widget) {
817        XtVaSetValues(widget, RES_CONVERT(XmNlabelString, var_value), NULL);
818    }
819    else {
820        get_root()->changer_of_variable = 0;
821    }
822}
823
824// ----------------------
825//      on/off toggle
826
827struct aw_toggle_data {
828    bool  isTextToggle;
829    char *bitmapOrText[2];
830    int   buttonWidth; // wanted width in characters
831};
832
833void AW_window::update_toggle(Widget widget, const char *var, AW_CL cd_toggle_data) {
834    aw_toggle_data *tdata = (aw_toggle_data*)cd_toggle_data;
835    const char     *text  = tdata->bitmapOrText[(var[0] == '0' || var[0] == 'n') ? 0 : 1];
836
837    if (tdata->isTextToggle) {
838        XtVaSetValues(widget, RES_CONVERT(XmNlabelString, text), NULL);
839    }
840    else {
841        char *path = pixmapPath(text+1);
842        XtVaSetValues(widget, RES_CONVERT(XmNlabelPixmap, path), NULL);
843        free(path);
844    }
845}
846
847void AW_window::create_toggle(const char *var_name, aw_toggle_data *tdata) {
848    AW_cb_struct *cbs = _callback;
849    _callback         = (AW_cb_struct *)1;
850
851    {
852        int old_length_of_buttons = _at->length_of_buttons;
853
854        if (tdata->buttonWidth == 0) {
855            if (tdata->isTextToggle) {
856                int l1 = strlen(tdata->bitmapOrText[0]);
857                int l2 = strlen(tdata->bitmapOrText[1]);
858
859                _at->length_of_buttons = l1>l2 ? l1 : l2; // use longer text for button size
860            }
861            else {
862                _at->length_of_buttons = 0;
863            }
864        }
865        else {
866            _at->length_of_buttons = tdata->buttonWidth;
867        }
868
869        create_button(0, tdata->bitmapOrText[0], 0);
870
871        _at->length_of_buttons = old_length_of_buttons;
872    }
873
874    AW_awar *vs = this->get_root()->awar(var_name);
875    {
876        char *var_value = vs->read_as_string();
877
878        this->update_toggle(p_w->toggle_field, var_value, (AW_CL)tdata);
879        free(var_value);
880    }
881
882    VarUpdateInfo *vui;
883    vui = new VarUpdateInfo(p_w->toggle_field, AW_WIDGET_TOGGLE, vs, cbs);
884
885    XtAddCallback(p_w->toggle_field, XmNactivateCallback,
886                  (XtCallbackProc) AW_variable_update_callback,
887                  (XtPointer) vui);
888
889    vs->tie_widget((AW_CL)tdata, p_w->toggle_field, AW_WIDGET_TOGGLE, this);
890}
891
892
893void AW_window::create_toggle(const char *var_name, const char *no, const char *yes, int buttonWidth) {
894    aw_toggle_data *tdata  = new aw_toggle_data;
895    tdata->isTextToggle    = false;
896
897    aw_assert(no[0] == '#');
898    aw_assert(yes[0] == '#');
899
900    tdata->bitmapOrText[0] = strdup(no);
901    tdata->bitmapOrText[1] = strdup(yes);
902
903    tdata->buttonWidth = buttonWidth;
904
905    create_toggle(var_name, tdata);
906}
907
908void AW_window::create_text_toggle(const char *var_name, const char *noText, const char *yesText, int buttonWidth) {
909    aw_toggle_data *tdata  = new aw_toggle_data;
910    tdata->isTextToggle    = true;
911    tdata->bitmapOrText[0] = strdup(noText);
912    tdata->bitmapOrText[1] = strdup(yesText);
913    tdata->buttonWidth     = buttonWidth;
914
915    create_toggle(var_name, tdata);
916}
917
918
919void AW_window::create_toggle(const char *var_name) {
920    create_toggle(var_name, "#no.bitmap", "#yes.bitmap");
921}
922
923void AW_window::create_inverse_toggle(const char *var_name) {
924    // like create_toggle, but displays inverse value
925    // (i.e. it's checked if value is zero, and unchecked otherwise)
926    create_toggle(var_name, "#yes.bitmap", "#no.bitmap");
927}
928
929// ---------------------
930//      input fields
931
932void AW_window::create_input_field(const char *var_name,   int columns) {
933    Widget         textField              = 0;
934    Widget         tmp_label              = 0;
935    AW_cb_struct  *cbs;
936    VarUpdateInfo *vui;
937    char          *str; 
938    int            x_correcting_for_label = 0;
939
940    if (!columns) columns = _at->length_of_buttons;
941
942    AW_awar *vs = root->awar(var_name);
943    str         = root->awar(var_name)->read_as_string();
944
945    int width_of_input_label, height_of_input_label;
946    calculate_label_size(this, &width_of_input_label, &height_of_input_label, true, 0);
947    // @@@ FIXME: use height_of_input_label for propper Y-adjusting of label
948    // width_of_input_label = this->calculate_string_width( calculate_label_length() );
949
950    int width_of_input = this->calculate_string_width(columns+1) + 9;
951    // calculate width for 1 additional character (input field is not completely used)
952    // + 4 pixel for shadow + 4 unknown missing pixels + 1 add. pixel needed for visible text area
953
954    Widget parentWidget = _at->attach_any ? INFO_FORM : INFO_WIDGET;
955
956    if (_at->label_for_inputfield) {
957        tmp_label = XtVaCreateManagedWidget("label",
958                                            xmLabelWidgetClass,
959                                            parentWidget,
960                                            XmNwidth, (int)(width_of_input_label + 2),
961                                            XmNhighlightThickness, 0,
962                                            RES_CONVERT(XmNlabelString, _at->label_for_inputfield),
963                                            XmNrecomputeSize, false,
964                                            XmNalignment, XmALIGNMENT_BEGINNING,
965                                            XmNfontList, p_global->fontlist,
966                                            (_at->attach_any) ? NULL : XmNx, (int)_at->x_for_next_button,
967                                            XmNy, (int)(_at->y_for_next_button) + root->y_correction_for_input_labels -1,
968                                            NULL);
969        if (_at->attach_any) aw_attach_widget(tmp_label, _at);
970        x_correcting_for_label = width_of_input_label + 10;
971    }
972
973
974    int width_of_last_widget = x_correcting_for_label + width_of_input + 2;
975
976    if (_at->to_position_exists) {
977        width_of_input = _at->to_position_x - _at->x_for_next_button - x_correcting_for_label + 2;
978        width_of_last_widget = _at->to_position_x - _at->x_for_next_button;
979    }
980
981    {
982        TuneBackground(parentWidget, TUNE_INPUT);
983        textField = XtVaCreateManagedWidget("textField",
984                                            xmTextFieldWidgetClass,
985                                            parentWidget,
986                                            XmNwidth, (int)width_of_input,
987                                            XmNrows, 1,
988                                            XmNvalue, str,
989                                            XmNfontList, p_global->fontlist,
990                                            XmNbackground, _at->background_color,
991                                            (_at->attach_any) ? NULL : XmNx, (int)(_at->x_for_next_button + x_correcting_for_label),
992                                            XmNy, (int)(_at->y_for_next_button + 5) - 8,
993                                            NULL);
994        if (_at->attach_any) aw_attach_widget(textField, _at);
995    }
996
997    free(str);
998
999    // user-own callback
1000    cbs = _callback;
1001
1002    // callback for enter
1003    vui = new VarUpdateInfo(textField, AW_WIDGET_INPUT_FIELD, vs, cbs);
1004
1005    XtAddCallback(textField, XmNactivateCallback,
1006                  (XtCallbackProc) AW_variable_update_callback,
1007                  (XtPointer) vui);
1008    if (_d_callback) {
1009        XtAddCallback(textField, XmNactivateCallback,
1010                      (XtCallbackProc) AW_server_callback,
1011                      (XtPointer) _d_callback);
1012        _d_callback->id = GBS_global_string_copy("INPUT:%s", var_name);
1013        get_root()->define_remote_command(_d_callback);
1014    }
1015
1016    // callback for losing focus
1017    XtAddCallback(textField, XmNlosingFocusCallback,
1018                  (XtCallbackProc) AW_variable_update_callback,
1019                  (XtPointer) vui);
1020    // callback for value changed
1021    XtAddCallback(textField, XmNvalueChangedCallback,
1022                  (XtCallbackProc) AW_value_changed_callback,
1023                  (XtPointer) root);
1024
1025    vs->tie_widget(0, textField, AW_WIDGET_INPUT_FIELD, this);
1026    root->make_sensitive(textField, _at->widget_mask);
1027
1028    short height;
1029    XtVaGetValues(textField, XmNheight, &height, NULL);
1030    int height_of_last_widget = height;
1031
1032    if (_at->correct_for_at_center == 1) {   // middle centered
1033        XtVaSetValues(textField, XmNx, ((int)(_at->x_for_next_button + x_correcting_for_label) - (int)(width_of_last_widget/2) + 1), NULL);
1034        if (tmp_label) {
1035            XtVaSetValues(tmp_label, XmNx, ((int)(_at->x_for_next_button) - (int)(width_of_last_widget/2) + 1), NULL);
1036        }
1037        width_of_last_widget = width_of_last_widget / 2;
1038    }
1039    if (_at->correct_for_at_center == 2) {   // right centered
1040        XtVaSetValues(textField, XmNx, (int)(_at->x_for_next_button + x_correcting_for_label - width_of_last_widget + 3), NULL);
1041        if (tmp_label) {
1042            XtVaSetValues(tmp_label, XmNx, (int)(_at->x_for_next_button - width_of_last_widget + 3), NULL);
1043        }
1044        width_of_last_widget = 0;
1045    }
1046    width_of_last_widget -= 2;
1047
1048    this->unset_at_commands();
1049    this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1050
1051}
1052
1053void AW_window::update_input_field(Widget widget, const char *var_value) {
1054    XtVaSetValues(widget, XmNvalue, var_value, NULL);
1055}
1056
1057void AW_window::create_text_field(const char *var_name, int columns, int rows) {
1058    Widget         scrolledWindowText;
1059    Widget         scrolledText;
1060    Widget         tmp_label              = 0;
1061    AW_cb_struct  *cbs;
1062    VarUpdateInfo *vui;
1063    char          *str                    = NULL;
1064    short          width_of_last_widget   = 0;
1065    short          height_of_last_widget  = 0;
1066    int            width_of_text          = 0;
1067    int            height_of_text         = 0;
1068    int            x_correcting_for_label = 0;
1069
1070    AW_awar *vs = root->awar(var_name);
1071    str         = root->awar(var_name)->read_string();
1072
1073    int width_of_text_label, height_of_text_label;
1074    calculate_label_size(this, &width_of_text_label, &height_of_text_label, true, 0);
1075    // @@@ FIXME: use height_of_text_label for propper Y-adjusting of label
1076
1077    // width_of_text_label = this->calculate_string_width( calculate_label_length() );
1078    width_of_text = this->calculate_string_width(columns) + 18;
1079    height_of_text = this->calculate_string_height(rows, rows*4) + 9;
1080
1081
1082    if (_at->label_for_inputfield) {
1083        tmp_label = XtVaCreateManagedWidget("label",
1084                                            xmLabelWidgetClass,
1085                                            INFO_WIDGET,
1086                                            XmNx, (int)_at->x_for_next_button,
1087                                            XmNy, (int)(_at->y_for_next_button) + this->get_root()->y_correction_for_input_labels + 5 - 6,
1088                                            XmNwidth, (int)(width_of_text_label + 2),
1089                                            RES_CONVERT(XmNlabelString, _at->label_for_inputfield),
1090                                            XmNrecomputeSize, false,
1091                                            XmNalignment, XmALIGNMENT_BEGINNING,
1092                                            XmNfontList, p_global->fontlist,
1093                                            NULL);
1094
1095        x_correcting_for_label = width_of_text_label + 10;
1096
1097    }
1098
1099
1100    if (_at->to_position_exists) {
1101        scrolledWindowText = XtVaCreateManagedWidget("scrolledWindowList1",
1102                                                     xmScrolledWindowWidgetClass,
1103                                                     INFO_FORM,
1104                                                     XmNscrollingPolicy, XmAPPLICATION_DEFINED,
1105                                                     XmNvisualPolicy, XmVARIABLE,
1106                                                     XmNscrollBarDisplayPolicy, XmSTATIC,
1107                                                     XmNfontList,          p_global->fontlist,
1108                                                     NULL);
1109        aw_attach_widget(scrolledWindowText, _at);
1110
1111        width_of_text = _at->to_position_x - _at->x_for_next_button - x_correcting_for_label - 18;
1112        if (_at->y_for_next_button < _at->to_position_y - 18) {
1113            height_of_text = _at->to_position_y - _at->y_for_next_button - 18;
1114        }
1115    }
1116    else {
1117        scrolledWindowText = XtVaCreateManagedWidget("scrolledWindowText",
1118                                                     xmScrolledWindowWidgetClass,
1119                                                     INFO_WIDGET,
1120                                                     XmNscrollingPolicy, XmAPPLICATION_DEFINED,
1121                                                     XmNvisualPolicy, XmVARIABLE,
1122                                                     XmNscrollBarDisplayPolicy, XmSTATIC,
1123                                                     XmNx, (int)10,
1124                                                     XmNy, (int)_at->y_for_next_button,
1125                                                     XmNfontList, p_global->fontlist,
1126                                                     NULL);
1127    }
1128
1129    TuneBackground(scrolledWindowText, TUNE_INPUT);
1130    scrolledText = XtVaCreateManagedWidget("scrolledText1",
1131                                           xmTextWidgetClass,
1132                                           scrolledWindowText,
1133                                           XmNeditMode, XmMULTI_LINE_EDIT,
1134                                           XmNvalue, str,
1135                                           XmNscrollLeftSide, false,
1136                                           XmNwidth, (int)width_of_text,
1137                                           XmNheight, (int)height_of_text,
1138                                           XmNfontList, p_global->fontlist,
1139                                           XmNbackground, _at->background_color,
1140                                           NULL);
1141    free(str);
1142
1143    if (!_at->to_position_exists) {
1144        XtVaGetValues(scrolledWindowText,   XmNheight, &height_of_last_widget,
1145                      XmNwidth, &width_of_last_widget, NULL);
1146
1147        width_of_last_widget += (short)x_correcting_for_label;
1148
1149        switch (_at->correct_for_at_center) {
1150            case 0: // left centered
1151                XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + x_correcting_for_label), NULL);
1152                break;
1153
1154            case 1: // middle centered
1155                XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + x_correcting_for_label - (width_of_last_widget/2)), NULL);
1156                if (_at->label_for_inputfield) {
1157                    XtVaSetValues(tmp_label, XmNx, (int)(_at->x_for_next_button - (width_of_last_widget/2)), NULL);
1158                }
1159                width_of_last_widget = width_of_last_widget / 2;
1160                break;
1161
1162            case 2: // right centered
1163                XtVaSetValues(scrolledWindowText, XmNx, (int)(_at->x_for_next_button + x_correcting_for_label - width_of_last_widget),     NULL);
1164                if (_at->label_for_inputfield) {
1165                    XtVaSetValues(tmp_label, XmNx, (int)(_at->x_for_next_button - width_of_last_widget), NULL);
1166                }
1167                width_of_last_widget = 0;
1168                break;
1169        }
1170    }
1171
1172    // user-own callback
1173    cbs = _callback;
1174
1175    // callback for enter
1176    vui = new VarUpdateInfo(scrolledText, AW_WIDGET_TEXT_FIELD, vs, cbs);
1177    XtAddCallback(scrolledText, XmNactivateCallback, (XtCallbackProc) AW_variable_update_callback, (XtPointer) vui);
1178    // callback for losing focus
1179    XtAddCallback(scrolledText, XmNlosingFocusCallback, (XtCallbackProc) AW_variable_update_callback, (XtPointer) vui);
1180    // callback for value changed
1181    XtAddCallback(scrolledText, XmNvalueChangedCallback, (XtCallbackProc) AW_value_changed_callback, (XtPointer) root);
1182
1183    vs->tie_widget(0, scrolledText, AW_WIDGET_TEXT_FIELD, this);
1184    root->make_sensitive(scrolledText, _at->widget_mask);
1185
1186    this->unset_at_commands();
1187    this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1188}
1189
1190
1191void AW_window::update_text_field(Widget widget, const char *var_value) {
1192    XtVaSetValues(widget, XmNvalue, var_value, NULL);
1193}
1194
1195// -----------------------
1196//      selection list
1197
1198
1199AW_selection_list* AW_window::create_selection_list(const char *var_name, const char *tmp_label, const char */*mnemonic*/, int columns, int rows) {
1200    Widget scrolledWindowList;
1201    Widget scrolledList;
1202    Widget l = 0;
1203
1204    VarUpdateInfo *vui;
1205    AW_cb_struct              *cbs;
1206
1207    int width_of_label        = 0;
1208    int height_of_label       = 0;
1209    int width_of_list;
1210    int height_of_list;
1211    int width_of_last_widget  = 0;
1212    int height_of_last_widget = 0;
1213
1214    if (_at->label_for_inputfield) {
1215        tmp_label = _at->label_for_inputfield;
1216    }
1217
1218    AW_awar *vs = 0;
1219    if (var_name) vs = root->awar(var_name);
1220
1221    if (tmp_label) {
1222        calculate_label_size(this, &width_of_label, &height_of_label, true, tmp_label);
1223        // @@@ FIXME: use height_of_label for propper Y-adjusting of label
1224        // width_of_label = this->calculate_string_width( calculate_label_length() );
1225
1226        l = XtVaCreateManagedWidget("label",
1227                                    xmLabelWidgetClass,
1228                                    INFO_WIDGET,
1229                                    XmNx, (int)10,
1230                                    XmNy, (int)(_at->y_for_next_button) + this->get_root()->y_correction_for_input_labels - 1,
1231                                    XmNwidth, (int)(width_of_label + 2),
1232                                    RES_CONVERT(XmNlabelString, tmp_label),
1233                                    XmNrecomputeSize, false,
1234                                    XmNalignment, XmALIGNMENT_BEGINNING,
1235                                    NULL);
1236        width_of_label += 10;
1237    }
1238
1239
1240    width_of_list = this->calculate_string_width(columns) + 9;
1241    height_of_list = this->calculate_string_height(rows, 4*rows) + 9;
1242
1243
1244    if (_at->to_position_exists) {
1245        width_of_list = _at->to_position_x - _at->x_for_next_button - width_of_label - 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",
1250                                                     xmScrolledWindowWidgetClass,
1251                                                     INFO_FORM,
1252                                                     XmNvisualPolicy, XmVARIABLE,
1253                                                     XmNscrollBarDisplayPolicy, XmSTATIC,
1254                                                     XmNshadowThickness, 0,
1255                                                     XmNfontList,          p_global->fontlist,
1256                                                     NULL);
1257        aw_attach_widget(scrolledWindowList, _at);
1258
1259        width_of_last_widget = _at->to_position_x - _at->x_for_next_button;
1260        height_of_last_widget = _at->to_position_y - _at->y_for_next_button;
1261    }
1262    else {
1263        scrolledWindowList = XtVaCreateManagedWidget("scrolledWindowList1",
1264                                                     xmScrolledWindowWidgetClass,
1265                                                     INFO_WIDGET,
1266                                                     XmNscrollingPolicy, XmAPPLICATION_DEFINED,
1267                                                     XmNvisualPolicy, XmVARIABLE,
1268                                                     XmNscrollBarDisplayPolicy, XmSTATIC,
1269                                                     XmNshadowThickness, 0,
1270                                                     XmNx, (int)10,
1271                                                     XmNy, (int)(_at->y_for_next_button),
1272                                                     XmNfontList, p_global->fontlist,
1273                                                     NULL);
1274    }
1275
1276    {
1277        int select_type = XmMULTIPLE_SELECT;
1278        if (vs) select_type = XmSINGLE_SELECT;
1279
1280        TuneBackground(scrolledWindowList, TUNE_INPUT);
1281        scrolledList = XtVaCreateManagedWidget("scrolledList1",
1282                                               xmListWidgetClass,
1283                                               scrolledWindowList,
1284                                               XmNwidth, (int)width_of_list,
1285                                               XmNheight, (int) height_of_list,
1286                                               XmNscrollBarDisplayPolicy, XmSTATIC,
1287                                               XmNselectionPolicy, select_type,
1288                                               XmNlistSizePolicy, XmCONSTANT,
1289                                               XmNfontList, p_global->fontlist,
1290                                               XmNbackground, _at->background_color,
1291                                               NULL);
1292    }
1293
1294    if (!_at->to_position_exists) {
1295        short height;
1296        XtVaGetValues(scrolledList, XmNheight, &height, NULL);
1297        height_of_last_widget = height + 20;
1298        width_of_last_widget = width_of_label + width_of_list + 20;
1299
1300        switch (_at->correct_for_at_center) {
1301            case 3: break;
1302            case 0: // left centered
1303                XtVaSetValues(scrolledWindowList, XmNx, (int)(_at->x_for_next_button + width_of_label), NULL);
1304                if (tmp_label) {
1305                    XtVaSetValues(l, XmNx, (int)(_at->x_for_next_button), NULL);
1306                }
1307                break;
1308
1309            case 1: // middle centered
1310                XtVaSetValues(scrolledWindowList, XmNx, (int)(_at->x_for_next_button - (width_of_last_widget/2) + width_of_label), NULL);
1311                if (tmp_label) {
1312                    XtVaSetValues(l, XmNx, (int)(_at->x_for_next_button - (width_of_last_widget/2)), NULL);
1313                }
1314                width_of_last_widget = width_of_last_widget / 2;
1315                break;
1316
1317            case 2: // right centered
1318                XtVaSetValues(scrolledWindowList, XmNx, (int)(_at->x_for_next_button - width_of_list - 18), NULL);
1319                if (tmp_label) {
1320                    XtVaSetValues(l, XmNx, (int)(_at->x_for_next_button - width_of_last_widget - 18), NULL);
1321                }
1322                width_of_last_widget = 0;
1323        }
1324
1325    }
1326
1327    {
1328        int type = GB_STRING;
1329        if (vs)  type = vs->variable_type;
1330
1331        if (p_global->selection_list) {
1332            p_global->last_selection_list->next = new AW_selection_list(var_name, type, scrolledList);
1333            p_global->last_selection_list = p_global->last_selection_list->next;
1334        }
1335        else {
1336            p_global->last_selection_list = p_global->selection_list = new AW_selection_list(var_name, type, scrolledList);
1337        }
1338    }
1339
1340
1341    // user-own callback
1342    cbs = _callback;
1343
1344    // callback for enter
1345    if (vs) {
1346        vui = new VarUpdateInfo(scrolledList, AW_WIDGET_SELECTION_LIST, vs, cbs);
1347        vui->set_id((void*)p_global->last_selection_list);
1348
1349        XtAddCallback(scrolledList, XmNsingleSelectionCallback,
1350                      (XtCallbackProc) AW_variable_update_callback,
1351                      (XtPointer) vui);
1352
1353        if (_d_callback) {
1354            XtAddCallback(scrolledList, XmNdefaultActionCallback,
1355                          (XtCallbackProc) AW_server_callback,
1356                          (XtPointer) _d_callback);
1357        }
1358        vs->tie_widget((AW_CL)p_global->last_selection_list, scrolledList, AW_WIDGET_SELECTION_LIST, this);
1359        root->make_sensitive(scrolledList, _at->widget_mask);
1360    }
1361
1362    this->unset_at_commands();
1363    this->increment_at_commands(width_of_last_widget, height_of_last_widget);
1364    return p_global->last_selection_list;
1365}
1366
1367AW_selection_list *AW_window::create_multi_selection_list(const char *tmp_label, const char *mnemonic, int columns, int rows) {
1368    return create_selection_list(0, tmp_label, mnemonic, columns, rows);
1369}
1370
1371void AW_window::conc_list(AW_selection_list *from_list, AW_selection_list *to_list) {
1372    // @@@ conc_list is a bad name (it does move the entries)
1373    // @@@ instead of COPYING, it could simply move the entries
1374    AW_selection_list_entry *from_list_table;
1375
1376    from_list_table = from_list->list_table;
1377    while (from_list_table) {
1378        if (from_list->default_select != from_list_table) {
1379            if (! to_list->list_table) {
1380                to_list->last_of_list_table = to_list->list_table = new AW_selection_list_entry(from_list_table->get_displayed(), from_list_table->value.get_string());
1381            }
1382            else {
1383                to_list->last_of_list_table->next = new AW_selection_list_entry(from_list_table->get_displayed(), from_list_table->value.get_string());
1384                to_list->last_of_list_table = to_list->last_of_list_table->next;
1385                to_list->last_of_list_table->next = NULL;
1386            }
1387        }
1388
1389        from_list_table = from_list_table->next;
1390    }
1391
1392    clear_selection_list(from_list);
1393    insert_default_selection(from_list, "", "");
1394}
1395
1396// -----------------------------------------
1397//      iterator through selection list:
1398
1399static AW_selection_list_entry *current_list_table = 0;
1400
1401void AW_window::init_list_entry_iterator(AW_selection_list *selection_list) const {
1402    current_list_table = selection_list->list_table;
1403}
1404
1405void AW_window::iterate_list_entry(int offset) {
1406    while (offset--) {
1407        if (!current_list_table) break;
1408        current_list_table = current_list_table->next;
1409    }
1410}
1411
1412const char *AW_window::get_list_entry_char_value() const {
1413    return current_list_table ? current_list_table->value.get_string() : 0;
1414}
1415
1416const char *AW_window::get_list_entry_displayed() const {
1417    return current_list_table ? current_list_table->get_displayed() : 0;
1418}
1419
1420void AW_window::set_list_entry_char_value(const char *new_char_value) {
1421    aw_assert(current_list_table);
1422    current_list_table->set_value(new_char_value);
1423}
1424
1425void AW_window::set_list_entry_displayed(const char *new_displayed) {
1426    aw_assert(current_list_table);
1427    current_list_table->set_displayed(new_displayed);
1428}
1429
1430void AW_window::set_selection_list_suffix(AW_selection_list *selection_list, const char *suffix) {
1431    char filter[200];
1432    sprintf(filter, "tmp/save_box_sel_%li/filter", (long)selection_list);
1433    get_root()->awar_string(filter, suffix);
1434    sprintf(filter, "tmp/load_box_sel_%li/filter", (long)selection_list);
1435    get_root()->awar_string(filter, suffix);
1436}
1437
1438int AW_window::get_index_of_selected_element(AW_selection_list *selection_list) {
1439    // returns index of element (or index of default)
1440    const char *awar_value = selection_list->get_awar_value(get_root());
1441    return get_index_of_element(selection_list, awar_value);
1442}
1443
1444void AW_window::select_element_at_index(AW_selection_list *selection_list, int wanted_index) {
1445    const char *wanted_value = get_element_at_index(selection_list, wanted_index);
1446
1447    if (!wanted_value) {
1448        wanted_value = selection_list->get_default_value();
1449        if (!wanted_value) wanted_value = "";
1450    }
1451
1452    selection_list->set_awar_value(get_root(), wanted_value);
1453}
1454
1455void AW_window::move_selection(AW_selection_list *selection_list, int offset) {
1456    /*! move selection 'offset' position
1457     *  offset == 1  -> select next element
1458     *  offset == -1 -> select previous element
1459     */
1460   
1461    int index = get_index_of_selected_element(selection_list);
1462    select_element_at_index(selection_list, index+offset);
1463}
1464
1465int AW_window::get_index_of_element(AW_selection_list *selection_list, const char *searched_value) {
1466    /*! get index of an entry in the selection list
1467     * @return 0..n-1 index of matching element (or index of default entry)
1468     */
1469    int element_index = 0;
1470
1471    for (const char *listEntry = selection_list->first_element();
1472         listEntry;
1473         listEntry = selection_list->next_element())
1474    {
1475        if (strcmp(listEntry, searched_value) == 0) break; // found
1476        ++element_index;
1477    }
1478
1479    return element_index;
1480}
1481
1482const char *AW_window::get_element_at_index(AW_selection_list *selection_list, int index) {
1483    // get value of the entry at position 'index' [0..n-1] of the 'selection_list'
1484    // returns NULL if index is out of bounds
1485    const char *element = NULL;
1486
1487    if (index >= 0) {
1488        int         element_index = 0;
1489        const char *listEntry     = selection_list->first_element();
1490
1491        while (listEntry) {
1492            if (element_index == index) {
1493                element = listEntry;
1494                break;
1495            }
1496            ++element_index;
1497            listEntry = selection_list->next_element();
1498        }
1499    }
1500
1501    return element;
1502}
1503
1504#if defined(WARN_TODO)
1505#warning design of delete_selection_from_list is broken - shall use 'associated value' not 'displayed value'!
1506#endif
1507
1508void AW_window::delete_selection_from_list(AW_selection_list *selection_list, const char *disp_string)
1509{
1510    if (selection_list->size() == 1) {   // Letzter Eintrag
1511        clear_selection_list(selection_list);
1512    }
1513
1514    AW_selection_list_entry *list_table;
1515    AW_selection_list_entry *next = NULL;
1516    AW_selection_list_entry *prev = NULL;
1517
1518    for (list_table = selection_list->list_table, next = selection_list->list_table;
1519         list_table;
1520         prev = next, list_table = list_table->next, next = list_table)
1521    {
1522        if (strcmp(disp_string, list_table->get_displayed()) == 0) {
1523            next = list_table->next;
1524
1525            if (prev) prev->next = next;
1526            else selection_list->list_table = next;
1527
1528            if (!list_table->next && prev) selection_list->last_of_list_table = prev;
1529
1530            if (selection_list->default_select == list_table) {
1531                selection_list->default_select = NULL;
1532                insert_default_selection(selection_list, "", "");
1533            }
1534
1535            delete list_table;
1536            return;
1537        }
1538    }
1539}
1540
1541INLINE_ATTRIBUTED(__ATTR__NORETURN, void type_mismatch(const char *triedType, const char *intoWhat)) {
1542    GBK_terminatef("Cannot insert %s into %s which uses a non-%s AWAR", triedType, intoWhat, triedType);
1543}
1544
1545INLINE_ATTRIBUTED(__ATTR__NORETURN, void selection_type_mismatch(const char *triedType)) { type_mismatch(triedType, "selection-list"); }
1546INLINE_ATTRIBUTED(__ATTR__NORETURN, void option_type_mismatch(const char *triedType)) { type_mismatch(triedType, "option-menu"); }
1547INLINE_ATTRIBUTED(__ATTR__NORETURN, void toggle_type_mismatch(const char *triedType)) { type_mismatch(triedType, "toggle"); }
1548
1549void AW_window::insert_selection(AW_selection_list *selection_list, const char *displayed, const char *value) {
1550    if (selection_list->variable_type != AW_STRING) {
1551        selection_type_mismatch("string");
1552        return;
1553    }
1554
1555    if (selection_list->list_table) {
1556        selection_list->last_of_list_table->next = new AW_selection_list_entry(displayed, value);
1557        selection_list->last_of_list_table = selection_list->last_of_list_table->next;
1558        selection_list->last_of_list_table->next = NULL;
1559    }
1560    else {
1561        selection_list->last_of_list_table = selection_list->list_table = new AW_selection_list_entry(displayed, value);
1562    }
1563}
1564
1565
1566void AW_window::insert_default_selection(AW_selection_list *selection_list, const char *displayed, const char *value) {
1567    if (selection_list->variable_type != AW_STRING) {
1568        selection_type_mismatch("string");
1569        return;
1570    }
1571    if (selection_list->default_select) {
1572        delete selection_list->default_select;
1573    }
1574    selection_list->default_select = new AW_selection_list_entry(displayed, value);
1575}
1576
1577#if defined(WARN_TODO)
1578#warning parameter value must be int32_t
1579#endif
1580void AW_window::insert_selection(AW_selection_list *selection_list, const char *displayed, int32_t value) {
1581
1582    if (selection_list->variable_type != AW_INT) {
1583        selection_type_mismatch("int");
1584        return;
1585    }
1586    if (selection_list->list_table) {
1587        selection_list->last_of_list_table->next = new AW_selection_list_entry(displayed, value);
1588        selection_list->last_of_list_table = selection_list->last_of_list_table->next;
1589        selection_list->last_of_list_table->next = NULL;
1590    }
1591    else {
1592        selection_list->last_of_list_table = selection_list->list_table = new AW_selection_list_entry(displayed, value);
1593    }
1594}
1595
1596#if defined(WARN_TODO)
1597#warning parameter value must be int32_t
1598#endif
1599void AW_window::insert_default_selection(AW_selection_list *selection_list, const char *displayed, int32_t value) {
1600    if (selection_list->variable_type != AW_INT) {
1601        selection_type_mismatch("int");
1602        return;
1603    }
1604    if (selection_list->default_select) {
1605        delete selection_list->default_select;
1606    }
1607    selection_list->default_select = new AW_selection_list_entry(displayed, value);
1608}
1609
1610void AW_window::insert_selection(AW_selection_list * selection_list, const char *displayed, void *pointer) {
1611    if (selection_list->variable_type != AW_POINTER) {
1612        selection_type_mismatch("pointer");
1613        return;
1614    }
1615    if (selection_list->list_table) {
1616        selection_list->last_of_list_table->next = new AW_selection_list_entry(displayed, pointer);
1617        selection_list->last_of_list_table = selection_list->last_of_list_table->next;
1618        selection_list->last_of_list_table->next = NULL;
1619    }
1620    else {
1621        selection_list->last_of_list_table = selection_list->list_table = new AW_selection_list_entry(displayed, pointer);
1622    }
1623}
1624
1625void AW_window::insert_default_selection(AW_selection_list * selection_list, const char *displayed, void *pointer) {
1626    if (selection_list->variable_type != AW_POINTER) {
1627        selection_type_mismatch("pointer");
1628        return;
1629    }
1630    if (selection_list->default_select) {
1631        delete selection_list->default_select;
1632    }
1633    selection_list->default_select = new AW_selection_list_entry(displayed, pointer);
1634}
1635
1636void AW_window::clear_selection_list(AW_selection_list *selection_list) {
1637    AW_selection_list_entry *list_table;
1638    AW_selection_list_entry *help;
1639
1640
1641    for (help = selection_list->list_table; help;) {
1642        list_table = help;
1643        help = list_table->next;
1644        delete list_table;
1645    }
1646    if (selection_list->default_select) {
1647        delete selection_list->default_select;
1648    }
1649
1650    selection_list->list_table         = NULL;
1651    selection_list->last_of_list_table = NULL;
1652    selection_list->default_select     = NULL;
1653
1654
1655}
1656
1657inline XmString XmStringCreateSimple_wrapper(const char *text) {
1658    return XmStringCreateSimple((char*)text);
1659}
1660
1661void AW_window::update_selection_list(AW_selection_list * selection_list) {
1662    // Warning:
1663    // update_selection_list() will not set the connected awar to the default value
1664    // if it contains a value which is not associated with a list entry!
1665
1666    size_t count = selection_list->size();
1667    if (selection_list->default_select) count++;
1668
1669    XmString *strtab = new XmString[count];
1670
1671    count = 0;
1672    for (AW_selection_list_entry *lt = selection_list->list_table; lt; lt = lt->next) {
1673        const char *s2 = lt->get_displayed();
1674        if (!strlen(s2)) s2 = "  ";
1675        strtab[count] = XmStringCreateSimple_wrapper(s2);
1676        count++;
1677    }
1678
1679    if (selection_list->default_select) {
1680        const char *s2 = selection_list->default_select->get_displayed();
1681        if (!strlen(s2)) s2 = "  ";
1682        strtab[count] = XmStringCreateSimple_wrapper(s2);
1683        count++;
1684    }
1685    if (!count) {
1686        strtab[count] = XmStringCreateSimple_wrapper("   ");
1687        count ++;
1688    }
1689
1690    XtVaSetValues(selection_list->select_list_widget, XmNitemCount, count, XmNitems, strtab, NULL);
1691
1692    update_selection_list_intern(selection_list);
1693
1694    for (size_t i=0; i<count; i++) XmStringFree(strtab[i]);
1695    delete [] strtab;
1696}
1697
1698void AW_window::init_selection_list_from_array(AW_selection_list *selection_list, const CharPtrArray& entries, const char *defaultEntry) {
1699    // update selection list with contents of NULL-terminated array 'entries'
1700    // 'defaultEntry' is used as default selection
1701    // awar value will be changed to 'defaultEntry' if it does not match any other entry
1702    // Note: This works only with selection lists bound to AW_STRING awars.
1703
1704    aw_assert(defaultEntry);
1705    char *defaultEntryCopy = strdup(defaultEntry); // use a copy (just in case defaultEntry point to a value free'd by clear_selection_list())
1706    bool  defInserted      = false;
1707
1708    clear_selection_list(selection_list);
1709    for (int i = 0; entries[i]; ++i) {
1710        if (!defInserted && strcmp(entries[i], defaultEntryCopy) == 0) {
1711            insert_default_selection(selection_list, defaultEntryCopy, defaultEntryCopy);
1712            defInserted = true;
1713        }
1714        else {
1715            insert_selection(selection_list, entries[i], entries[i]);
1716        }
1717    }
1718    if (!defInserted) insert_default_selection(selection_list, defaultEntryCopy, defaultEntryCopy);
1719    update_selection_list(selection_list);
1720
1721    const char *selected = selection_list->first_selected();
1722    if (selected) get_root()->awar(selection_list->variable_name)->write_string(selected);
1723
1724    free(defaultEntryCopy);
1725}
1726
1727void AW_window::selection_list_to_array(StrArray& array, AW_selection_list *sel_list, bool values) {
1728    /*! read contents of selection list into an array.
1729     * @param values true->read values, false->read displayed strings
1730     * Use GBT_free_names() to free the result.
1731     *
1732     * Note: if 'values' is true, this function only works for string selection lists!
1733     */
1734
1735    size_t count = sel_list->size();
1736    array.reserve(count);
1737   
1738    for (AW_selection_list_entry *lt = sel_list->list_table; lt; lt = lt->next) {
1739        array.put(strdup(values ? lt->value.get_string() : lt->get_displayed()));
1740    }
1741    aw_assert(array.size() == count);
1742}
1743
1744void AW_window::update_selection_list_intern(AW_selection_list *selection_list) {
1745    if (!selection_list->variable_name) return;     // not connected to awar
1746
1747    bool     found = false;
1748    int      pos   = 0;
1749    AW_awar *awar  = root->awar(selection_list->variable_name);
1750
1751    AW_selection_list_entry *lt;
1752
1753    switch (selection_list->variable_type) {
1754        case AW_STRING: {
1755            char *var_value = awar->read_string();
1756            for (lt = selection_list->list_table; lt; lt = lt->next) {
1757                if (strcmp(var_value, lt->value.get_string()) == 0) {
1758                    found = true;
1759                    break;
1760                }
1761                pos++;
1762            }
1763            free(var_value);
1764            break;
1765        }
1766        case AW_INT: {
1767            int var_value = awar->read_int();
1768            for (lt = selection_list->list_table; lt; lt = lt->next) {
1769                if (var_value == lt->value.get_int()) {
1770                    found = true;
1771                    break;
1772                }
1773                pos++;
1774            }
1775            break;
1776        }
1777        case AW_FLOAT: {
1778            float var_value = awar->read_float();
1779            for (lt = selection_list->list_table; lt; lt = lt->next) {
1780                if (var_value == lt->value.get_float()) {
1781                    found = true;
1782                    break;
1783                }
1784                pos++;
1785            }
1786            break;
1787        }
1788        case AW_POINTER: {
1789            void *var_value = awar->read_pointer();
1790            for (lt = selection_list->list_table; lt; lt = lt->next) {
1791                if (var_value == lt->value.get_pointer()) {
1792                    found = true;
1793                    break;
1794                }
1795                pos++;
1796            }
1797            break;
1798        }
1799        default:
1800            aw_assert(0);
1801            GB_warning("Unknown AWAR type");
1802            break;
1803    }
1804
1805    if (found || selection_list->default_select) {
1806        pos++;
1807        int top;
1808        int vis;
1809        XtVaGetValues(selection_list->select_list_widget,
1810                      XmNvisibleItemCount, &vis,
1811                      XmNtopItemPosition, &top,
1812                      NULL);
1813        XmListSelectPos(selection_list->select_list_widget, pos, False);
1814
1815        if (pos < top) {
1816            if (pos > 1) pos --;
1817            XmListSetPos(selection_list->select_list_widget, pos);
1818        }
1819        if (pos >= top + vis) {
1820            XmListSetBottomPos(selection_list->select_list_widget, pos + 1);
1821        }
1822    }
1823    else {
1824        GBK_terminatef("Selection list '%s' has no default selection", selection_list->variable_name);
1825    }
1826}
1827
1828char *AW_window::get_selection_list_contents(AW_selection_list *selection_list, long number_of_lines) {
1829    // number_of_lines == 0     -> print all
1830
1831    AW_selection_list_entry *lt;
1832    GBS_strstruct          *fd = GBS_stropen(10000);
1833
1834    for (lt = selection_list->list_table; lt; lt = lt->next) {
1835        number_of_lines--;
1836        GBS_strcat(fd, lt->get_displayed());
1837        GBS_chrcat(fd, '\n');
1838        if (!number_of_lines) break;
1839    }
1840    return GBS_strclose(fd);
1841}
1842
1843GB_HASH *AW_window::selection_list_to_hash(AW_selection_list *sel_list, bool case_sens) {
1844    // creates a hash (key = value of selection list, value = display string from selection list)
1845
1846    size_t   size = sel_list->size();
1847    GB_HASH *hash = GBS_create_hash(size, case_sens ? GB_MIND_CASE : GB_IGNORE_CASE);
1848
1849    for (AW_selection_list_entry *lt = sel_list->list_table; lt; lt = lt->next) {
1850        GBS_write_hash(hash, lt->value.get_string(), (long)lt->get_displayed());
1851    }
1852
1853    return hash;
1854}
1855
1856static int AW_sort_AW_select_table_struct(const void *t1, const void *t2, void *) {
1857    return strcmp(static_cast<const AW_selection_list_entry*>(t1)->get_displayed(),
1858                  static_cast<const AW_selection_list_entry*>(t2)->get_displayed());
1859}
1860static int AW_sort_AW_select_table_struct_backward(const void *t1, const void *t2, void *) {
1861    return strcmp(static_cast<const AW_selection_list_entry*>(t2)->get_displayed(),
1862                  static_cast<const AW_selection_list_entry*>(t1)->get_displayed());
1863}
1864static int AW_isort_AW_select_table_struct(const void *t1, const void *t2, void *) {
1865    return ARB_stricmp(static_cast<const AW_selection_list_entry*>(t1)->get_displayed(),
1866                       static_cast<const AW_selection_list_entry*>(t2)->get_displayed());
1867}
1868static int AW_isort_AW_select_table_struct_backward(const void *t1, const void *t2, void *) {
1869    return ARB_stricmp(static_cast<const AW_selection_list_entry*>(t2)->get_displayed(),
1870                       static_cast<const AW_selection_list_entry*>(t1)->get_displayed());
1871}
1872
1873AW_selection_list* AW_window::copySelectionList(AW_selection_list *sourceList, AW_selection_list *destinationList) {
1874
1875    if (destinationList) clear_selection_list(destinationList);
1876    else {
1877        printf(" Destination list not initialized!!\n");
1878        return 0;
1879    }
1880
1881    const char *readListItem = sourceList->first_element();
1882
1883    while (readListItem) {
1884        insert_selection(destinationList, readListItem, readListItem);
1885        readListItem = sourceList->next_element();
1886    }
1887
1888    insert_default_selection(destinationList, "END of List", "");
1889    update_selection_list(destinationList);
1890
1891    return destinationList;
1892}
1893
1894
1895void AW_window::sort_selection_list(AW_selection_list * selection_list, int backward, int case_sensitive) {
1896    size_t count = selection_list->size();
1897    if (count) {
1898        AW_selection_list_entry **tables = new AW_selection_list_entry *[count];
1899        count = 0;
1900        for (AW_selection_list_entry *lt = selection_list->list_table; lt; lt = lt->next) {
1901            tables[count++] = lt;
1902        }
1903
1904        gb_compare_function comparator;
1905        if (backward) {
1906            if (case_sensitive) comparator = AW_sort_AW_select_table_struct_backward;
1907            else comparator                = AW_isort_AW_select_table_struct_backward;
1908        }
1909        else {
1910            if (case_sensitive) comparator = AW_sort_AW_select_table_struct;
1911            else comparator                = AW_isort_AW_select_table_struct;
1912        }
1913
1914        GB_sort((void**)tables, 0, count, comparator, 0);
1915
1916        size_t i;
1917        for (i=0; i<count-1; i++) {
1918            tables[i]->next = tables[i+1];
1919        }
1920        tables[i]->next = 0;
1921        selection_list->list_table = tables[0];
1922        selection_list->last_of_list_table = tables[i];
1923
1924        delete [] tables;
1925    }
1926}
1927
1928GB_ERROR AW_window::save_selection_list(AW_selection_list * selection_list, const char *filename, long number_of_lines) {
1929    // number_of_lines == 0     -> print all
1930
1931    GB_ERROR  error = NULL;
1932    FILE     *fd    = fopen(filename, "w");
1933
1934    if (!fd) {
1935        error = GB_IO_error("writing", filename);
1936    }
1937    else {
1938        for (AW_selection_list_entry *lt = selection_list->list_table; lt; lt = lt->next) {
1939            const char *displayed = lt->get_displayed();
1940            const char *sep       = 0;
1941
1942            if (!selection_list->value_equal_display) {
1943                sep = strstr(displayed, "#"); // interpret displayed as 'value#displayed' (old general behavior)
1944            }
1945
1946            if (sep) {
1947                char *disp = strdup(displayed);
1948                disp[sep-displayed] = ','; // replace first '#' with ','  (that's loaded different)
1949                fputs(disp, fd);
1950                free(disp);
1951            }
1952            else {
1953                fputs(displayed, fd); // save plain (no interpretation)
1954            }
1955            int res = fputc('\n', fd);
1956            if (res<0) {
1957                error = GB_IO_error("writing", filename);
1958                break;
1959            }
1960
1961            if (--number_of_lines == 0) break; // number_of_lines == 0 -> write all lines; otherwise write number_of_lines lines
1962        }
1963        fclose(fd);
1964    }
1965    return error;
1966}
1967
1968GB_ERROR AW_window::load_selection_list(AW_selection_list *selection_list, const char *filename) {
1969    char *nl;
1970    char *ko;
1971    char *pl;
1972
1973    this->clear_selection_list(selection_list);
1974    StrArray fnames;
1975    GBS_read_dir(fnames, filename, NULL);
1976
1977    for (int i = 0; fnames[i]; ++i) {
1978        const char *fname = fnames[i];
1979        char       *data  = GB_read_file(fname);
1980        if (!data) {
1981            GB_print_error();
1982            continue;
1983        }
1984
1985        int correct_old_format = -1;
1986
1987        for (pl = data; pl; pl = nl) {
1988            ko = strchr(pl, ','); // look for ','
1989
1990            if (ko) {
1991                if (selection_list->value_equal_display) { // here no comma should occur
1992                    if (correct_old_format == -1) {
1993                        correct_old_format = aw_ask_sure(NULL, GBS_global_string("'%s' seems to be in old selection-list-format. Try to correct?", fname));
1994                    }
1995
1996                    if (correct_old_format == 1) {
1997                        *ko = '#'; // restore (was converted by old-version save)
1998                        ko  = 0; // ignore comma
1999                    }
2000                }
2001            }
2002
2003            if (ko) *(ko++) = 0;
2004            else ko         = pl; // if no comma -> display same as value
2005
2006            while (*ko == ' ' || *ko == '\t') ko++;
2007
2008            nl              = strchr(ko, '\n');
2009            if (nl) *(nl++) = 0;
2010
2011            if (ko[0] && pl[0] != '#') this->insert_selection(selection_list, pl, ko);
2012        }
2013        free(data);
2014    }
2015
2016    this->insert_default_selection(selection_list, "", "");
2017    this->update_selection_list(selection_list);
2018    return 0;
2019}
2020
2021// --------------------------------------------------------------------------------
2022//  Options-Menu
2023// --------------------------------------------------------------------------------
2024
2025AW_option_menu_struct *AW_window::create_option_menu(const char *var_name, AW_label tmp_label, const char *mnemonic) {
2026    Widget optionMenu_shell;
2027    Widget optionMenu;
2028    Widget optionMenu1;
2029    int x_for_position_of_menu;
2030
2031    if (_at->label_for_inputfield) {
2032        tmp_label = _at->label_for_inputfield;
2033    }
2034
2035    if (_at->correct_for_at_center) {
2036        if (tmp_label) {
2037            _at->saved_x = _at->x_for_next_button;
2038            x_for_position_of_menu = 10;
2039        }
2040        else {
2041            _at->saved_x = _at->x_for_next_button;
2042            x_for_position_of_menu = 10;
2043        }
2044    }
2045    else {
2046        if (tmp_label) {
2047            x_for_position_of_menu = _at->x_for_next_button - 3;
2048        }
2049        else {
2050            x_for_position_of_menu = _at->x_for_next_button - 3 - 7;
2051        }
2052    }
2053
2054    optionMenu_shell = XtVaCreatePopupShell ("optionMenu shell",
2055                                             xmMenuShellWidgetClass,
2056                                             INFO_WIDGET,
2057                                             XmNwidth, 1,
2058                                             XmNheight, 1,
2059                                             XmNallowShellResize, true,
2060                                             XmNoverrideRedirect, true,
2061                                             XmNfontList, p_global->fontlist,
2062                                             NULL);
2063
2064    optionMenu = XtVaCreateWidget("optionMenu_p1",
2065                                  xmRowColumnWidgetClass,
2066                                  optionMenu_shell,
2067                                  XmNrowColumnType, XmMENU_PULLDOWN,
2068                                  XmNfontList, p_global->fontlist,
2069                                  NULL);
2070
2071    if (tmp_label) {
2072        char *help_label;
2073        int   width_help_label, height_help_label;
2074        calculate_label_size(this, &width_help_label, &height_help_label, false, tmp_label);
2075        // @@@ FIXME: use height_help_label for Y-alignment
2076
2077#if defined(DUMP_BUTTON_CREATION)
2078        printf("width_help_label=%i label='%s'\n", width_help_label, tmp_label);
2079#endif // DUMP_BUTTON_CREATION
2080
2081        help_label = this->align_string(tmp_label, width_help_label);
2082        if (mnemonic && mnemonic[0] && strchr(tmp_label, mnemonic[0])) {
2083            optionMenu1 = XtVaCreateManagedWidget("optionMenu1",
2084                                                  xmRowColumnWidgetClass,
2085                                                  INFO_WIDGET,
2086                                                  XmNrowColumnType, XmMENU_OPTION,
2087                                                  XmNsubMenuId, optionMenu,
2088                                                  XmNfontList, p_global->fontlist,
2089                                                  XmNx, (int)x_for_position_of_menu,
2090                                                  XmNy, (int)(_at->y_for_next_button - 5),
2091                                                  RES_CONVERT(XmNlabelString, help_label),
2092                                                  RES_CONVERT(XmNmnemonic, mnemonic),
2093                                                  NULL);
2094        }
2095        else {
2096            optionMenu1 = XtVaCreateManagedWidget("optionMenu1",
2097                                                  xmRowColumnWidgetClass,
2098                                                  INFO_WIDGET,
2099                                                  XmNrowColumnType, XmMENU_OPTION,
2100                                                  XmNsubMenuId, optionMenu,
2101                                                  XmNfontList, p_global->fontlist,
2102                                                  XmNx, (int)x_for_position_of_menu,
2103                                                  XmNy, (int)(_at->y_for_next_button - 5),
2104                                                  RES_CONVERT(XmNlabelString, help_label),
2105                                                  NULL);
2106        }
2107        free(help_label);
2108    }
2109    else {
2110        optionMenu1 = XtVaCreateManagedWidget("optionMenu1",
2111                                              xmRowColumnWidgetClass,
2112                                              (_at->attach_any) ? INFO_FORM : INFO_WIDGET,
2113                                              XmNrowColumnType, XmMENU_OPTION,
2114                                              XmNsubMenuId, optionMenu,
2115                                              XmNfontList, p_global->fontlist,
2116                                              XmNx, (int)x_for_position_of_menu,
2117                                              XmNy, (int)(_at->y_for_next_button - 5),
2118                                              RES_CONVERT(XmNlabelString, ""),
2119                                              NULL);
2120        if (_at->attach_any) {
2121            aw_attach_widget(optionMenu1, _at);
2122        }
2123    }
2124
2125#if 0
2126    // setting background color for radio button only does not work.
2127    // works only for label and button together, but that's not what we want.
2128    TuneBackground(optionMenu_shell, TUNE_BUTTON); // set background color for radio button
2129    XtVaSetValues(optionMenu1, // colorizes background and label
2130                  XmNbackground, _at->background_color,
2131                  NULL);
2132#endif
2133
2134    get_root()->number_of_option_menus++;
2135
2136    AW_awar *vs = root->awar(var_name);
2137    {
2138        AW_option_menu_struct *next =
2139            new AW_option_menu_struct(get_root()->number_of_option_menus,
2140                                      var_name,
2141                                      vs->variable_type,
2142                                      optionMenu1,
2143                                      optionMenu,
2144                                      _at->x_for_next_button - 7,
2145                                      _at->y_for_next_button,
2146                                      _at->correct_for_at_center);
2147
2148        if (p_global->option_menu_list) {
2149            p_global->last_option_menu->next = next;
2150            p_global->last_option_menu = p_global->last_option_menu->next;
2151        }
2152        else {
2153            p_global->last_option_menu = p_global->option_menu_list = next;
2154        }
2155    }
2156
2157    p_global->current_option_menu = p_global->last_option_menu;
2158
2159    vs->tie_widget((AW_CL)p_global->current_option_menu, optionMenu, AW_WIDGET_CHOICE_MENU, this);
2160    root->make_sensitive(optionMenu1, _at->widget_mask);
2161
2162    return p_global->current_option_menu;
2163}
2164
2165static void remove_option_from_option_menu(AW_root *aw_root, AW_widget_value_pair *os) {
2166    aw_root->remove_button_from_sens_list(os->widget);
2167    XtDestroyWidget(os->widget);
2168}
2169
2170void AW_window::clear_option_menu(AW_option_menu_struct *oms) {
2171    p_global->current_option_menu = oms; // define as current (for subsequent inserts)
2172
2173    AW_widget_value_pair *next_os;
2174    for (AW_widget_value_pair *os = oms->first_choice; os; os = next_os) {
2175        next_os  = os->next;
2176        os->next = 0;
2177        remove_option_from_option_menu(root, os);
2178        delete os;
2179    }
2180
2181    if (oms->default_choice) {
2182        remove_option_from_option_menu(root, oms->default_choice);
2183        oms->default_choice = 0;
2184    }
2185
2186    oms->first_choice   = 0;
2187    oms->last_choice    = 0;
2188}
2189
2190void *AW_window::_create_option_entry(AW_VARIABLE_TYPE IF_DEBUG(type), const char *name, const char */*mnemonic*/, const char *name_of_color) {
2191    Widget                 entry;
2192    AW_option_menu_struct *oms = p_global->current_option_menu;
2193
2194    aw_assert(oms->variable_type == type); // adding wrong entry type
2195
2196    TuneOrSetBackground(oms->menu_widget, name_of_color, TUNE_BUTTON); // set background color for radio button entries
2197    entry = XtVaCreateManagedWidget("optionMenu_entry",
2198                                    xmPushButtonWidgetClass,
2199                                    oms->menu_widget,
2200                                    RES_LABEL_CONVERT(((char *)name)),
2201                                    XmNfontList, p_global->fontlist,
2202                                    XmNbackground, _at->background_color,
2203                                    NULL);
2204    AW_label_in_awar_list(this, entry, name);
2205    return (void *)entry;
2206}
2207
2208inline void option_menu_add_option(AW_option_menu_struct *oms, AW_widget_value_pair *os, bool default_option) {
2209    if (default_option) {
2210        oms->default_choice = os;
2211    }
2212    else {
2213        if (oms->first_choice) {
2214            oms->last_choice->next = os;
2215            oms->last_choice       = oms->last_choice->next;
2216        }
2217        else {
2218            oms->last_choice = oms->first_choice = os;
2219        }
2220    }
2221}
2222
2223// for string :
2224
2225void AW_window::insert_option_internal(AW_label option_name, const char *mnemonic, const char *var_value, const char *name_of_color, bool default_option) {
2226    AW_option_menu_struct *oms = p_global->current_option_menu;
2227    if (oms->variable_type != AW_STRING) {
2228        option_type_mismatch("string");
2229    }
2230    else {
2231        Widget        entry = (Widget)_create_option_entry(AW_STRING, option_name, mnemonic, name_of_color);
2232        AW_cb_struct *cbs   = _callback; // user-own callback
2233
2234        // callback for new choice
2235        XtAddCallback(entry, XmNactivateCallback,
2236                      (XtCallbackProc) AW_variable_update_callback,
2237                      (XtPointer) new VarUpdateInfo(NULL, AW_WIDGET_CHOICE_MENU, root->awar(oms->variable_name), var_value, cbs));
2238
2239        option_menu_add_option(p_global->current_option_menu, new AW_widget_value_pair(var_value, entry), default_option);
2240        root->make_sensitive(entry, _at->widget_mask);
2241        this->unset_at_commands();
2242    }
2243}
2244void AW_window::insert_option_internal(AW_label option_name, const char *mnemonic, int var_value, const char *name_of_color, bool default_option) {
2245    AW_option_menu_struct *oms = p_global->current_option_menu;
2246
2247    if (oms->variable_type != AW_INT) {
2248        option_type_mismatch("int");
2249    }
2250    else {
2251        Widget        entry = (Widget)_create_option_entry(AW_INT, option_name, mnemonic, name_of_color);
2252        AW_cb_struct *cbs   = _callback; // user-own callback
2253
2254        // callback for new choice
2255        XtAddCallback(entry, XmNactivateCallback,
2256                      (XtCallbackProc) AW_variable_update_callback,
2257                      (XtPointer) new VarUpdateInfo(NULL, AW_WIDGET_CHOICE_MENU, root->awar(oms->variable_name), var_value, cbs));
2258
2259        option_menu_add_option(p_global->current_option_menu, new AW_widget_value_pair(var_value, entry), default_option);
2260        root->make_sensitive(entry, _at->widget_mask);
2261        this->unset_at_commands();
2262    }
2263}
2264void AW_window::insert_option_internal(AW_label option_name, const char *mnemonic, float var_value, const char *name_of_color, bool default_option) {
2265    AW_option_menu_struct *oms = p_global->current_option_menu;
2266
2267    if (oms->variable_type != AW_FLOAT) {
2268        option_type_mismatch("float");
2269    }
2270    else {
2271        Widget        entry = (Widget)_create_option_entry(AW_FLOAT, option_name, mnemonic, name_of_color);
2272        AW_cb_struct *cbs   = _callback; // user-own callback
2273
2274        // callback for new choice
2275        XtAddCallback(entry, XmNactivateCallback,
2276                      (XtCallbackProc) AW_variable_update_callback,
2277                      (XtPointer) new VarUpdateInfo(NULL, AW_WIDGET_CHOICE_MENU, root->awar(oms->variable_name), var_value, cbs));
2278
2279        option_menu_add_option(p_global->current_option_menu, new AW_widget_value_pair(var_value, entry), default_option);
2280        root->make_sensitive(entry, _at->widget_mask);
2281        this->unset_at_commands();
2282    }
2283}
2284
2285void AW_window::insert_option        (AW_label on, const char *mn, const char *vv, const char *noc) { insert_option_internal(on, mn, vv, noc, false); }
2286void AW_window::insert_default_option(AW_label on, const char *mn, const char *vv, const char *noc) { insert_option_internal(on, mn, vv, noc, true); }
2287void AW_window::insert_option        (AW_label on, const char *mn, int vv,         const char *noc) { insert_option_internal(on, mn, vv, noc, false); }
2288void AW_window::insert_default_option(AW_label on, const char *mn, int vv,         const char *noc) { insert_option_internal(on, mn, vv, noc, true); }
2289void AW_window::insert_option        (AW_label on, const char *mn, float vv,       const char *noc) { insert_option_internal(on, mn, vv, noc, false); }
2290void AW_window::insert_default_option(AW_label on, const char *mn, float vv,       const char *noc) { insert_option_internal(on, mn, vv, noc, true); }
2291// (see insert_option_internal for longer parameter names)
2292
2293void AW_window::update_option_menu() {
2294    this->update_option_menu(p_global->current_option_menu);
2295}
2296
2297void AW_window::update_option_menu(AW_option_menu_struct *oms) {
2298    if (get_root()->changer_of_variable != oms->label_widget) {
2299        AW_widget_value_pair *active_choice = oms->first_choice;
2300        {
2301            AW_scalar global_var_value(root->awar(oms->variable_name));
2302            while (active_choice && global_var_value != active_choice->value) {
2303                active_choice = active_choice->next;
2304            }
2305        }
2306
2307        if (!active_choice) active_choice = oms->default_choice;
2308        if (active_choice) XtVaSetValues(oms->label_widget, XmNmenuHistory, active_choice->widget, NULL);
2309
2310        {
2311            short length;
2312            short height;
2313            XtVaGetValues(oms->label_widget, XmNwidth, &length, XmNheight, &height, NULL);
2314            int   width_of_last_widget  = length;
2315            int   height_of_last_widget = height;
2316
2317            if (oms->correct_for_at_center_intern) {
2318                if (oms->correct_for_at_center_intern == 1) {   // middle centered
2319                    XtVaSetValues(oms->label_widget, XmNx, (short)((short)_at->saved_x - (short)(length/2)), NULL);
2320                    width_of_last_widget = width_of_last_widget / 2;
2321                }
2322                if (oms->correct_for_at_center_intern == 2) {   // right centered
2323                    XtVaSetValues(oms->label_widget, XmNx, (short)((short)_at->saved_x - length) + 7, NULL);
2324                    width_of_last_widget = 0;
2325                }
2326            }
2327            width_of_last_widget -= 4;
2328
2329            this->unset_at_commands();
2330            this->increment_at_commands(width_of_last_widget, height_of_last_widget);
2331        }
2332    }
2333}
2334
2335// -------------------------------------------------------
2336//      toggle field (actually this are radio buttons)
2337
2338void AW_window::create_toggle_field(const char *var_name, AW_label labeli, const char */*mnemonic*/) {
2339    if (labeli) this->label(labeli);
2340    this->create_toggle_field(var_name);
2341}
2342
2343
2344void AW_window::create_toggle_field(const char *var_name, int orientation) {
2345    // orientation = 0 -> vertical else horizontal layout
2346
2347    Widget label_for_toggle;
2348    Widget toggle_field;
2349    int x_correcting_for_label = 0;
2350    int width_of_label = 0;
2351    int x_for_position_of_option = 0;
2352    const char *tmp_label = "";
2353    if (_at->label_for_inputfield) {
2354        tmp_label = _at->label_for_inputfield;
2355    }
2356
2357    if (_at->correct_for_at_center) {
2358        _at->saved_x = _at->x_for_next_button;
2359        x_for_position_of_option = 10;
2360    }
2361    else {
2362        x_for_position_of_option = _at->x_for_next_button;
2363    }
2364
2365
2366    if (tmp_label) {
2367        int height_of_label;
2368        calculate_label_size(this, &width_of_label, &height_of_label, true, tmp_label);
2369        // @@@ FIXME: use height_of_label for Y-alignment
2370        // width_of_label = this->calculate_string_width( this->calculate_label_length() );
2371        label_for_toggle = XtVaCreateManagedWidget("label",
2372                                                   xmLabelWidgetClass,
2373                                                   INFO_WIDGET,
2374                                                   XmNx, (int)_at->x_for_next_button,
2375                                                   XmNy, (int)(_at->y_for_next_button) + this->get_root()->y_correction_for_input_labels,
2376                                                   XmNwidth, (int)(width_of_label + 2),
2377                                                   RES_CONVERT(XmNlabelString, tmp_label),
2378                                                   XmNrecomputeSize, false,
2379                                                   XmNalignment, XmALIGNMENT_BEGINNING,
2380                                                   XmNfontList, p_global->fontlist,
2381                                                   NULL);
2382
2383        _at->saved_x_correction_for_label = x_correcting_for_label = width_of_label + 10;
2384
2385        p_w->toggle_label = label_for_toggle;
2386    }
2387    else {
2388        p_w->toggle_label = NULL;
2389        _at->saved_x_correction_for_label = 0;
2390    }
2391
2392    if (orientation) {
2393        toggle_field = XtVaCreateManagedWidget("rowColumn for toggle field",
2394                                               xmRowColumnWidgetClass,
2395                                               (_at->attach_any) ? INFO_FORM : INFO_WIDGET,
2396                                               XmNorientation, XmHORIZONTAL,
2397                                               XmNx, (int)(x_for_position_of_option + x_correcting_for_label),
2398                                               XmNy, (int)(_at->y_for_next_button - 2),
2399                                               XmNradioBehavior, True,
2400                                               XmNradioAlwaysOne, True,
2401                                               XmNfontList, p_global->fontlist,
2402                                               NULL);
2403    }
2404    else {
2405        toggle_field = XtVaCreateManagedWidget("rowColumn for toggle field",
2406                                               xmRowColumnWidgetClass,
2407                                               (_at->attach_any) ? INFO_FORM : INFO_WIDGET,
2408                                               XmNx, (int)(x_for_position_of_option + x_correcting_for_label),
2409                                               XmNy, (int)(_at->y_for_next_button - 2),
2410                                               XmNradioBehavior, True,
2411                                               XmNradioAlwaysOne, True,
2412                                               XmNfontList, p_global->fontlist,
2413                                               NULL);
2414    }
2415    if (_at->attach_any) {
2416        aw_attach_widget(toggle_field, _at, 300);
2417    }
2418
2419    AW_awar *vs = root->awar(var_name);
2420
2421    p_w->toggle_field = toggle_field;
2422    free((p_w->toggle_field_var_name));
2423    p_w->toggle_field_var_name = strdup(var_name);
2424    p_w->toggle_field_var_type = vs->variable_type;
2425
2426    get_root()->number_of_toggle_fields++;
2427
2428    if (p_global->toggle_field_list) {
2429        p_global->last_toggle_field->next = new AW_toggle_field_struct(get_root()->number_of_toggle_fields, var_name, vs->variable_type, toggle_field, _at->correct_for_at_center);
2430        p_global->last_toggle_field = p_global->last_toggle_field->next;
2431    }
2432    else {
2433        p_global->last_toggle_field = p_global->toggle_field_list = new AW_toggle_field_struct(get_root()->number_of_toggle_fields, var_name, vs->variable_type, toggle_field, _at->correct_for_at_center);
2434    }
2435
2436    vs->tie_widget(get_root()->number_of_toggle_fields, toggle_field, AW_WIDGET_TOGGLE_FIELD, this);
2437    root->make_sensitive(toggle_field, _at->widget_mask);
2438}
2439
2440static Widget _aw_create_toggle_entry(AW_window *aww, Widget toggle_field,
2441                                      const char *label, const char *mnemonic,
2442                                      VarUpdateInfo *awus,
2443                                      AW_widget_value_pair *toggle, bool default_toggle) {
2444    AW_root *root = aww->get_root();
2445
2446    Widget          toggleButton;
2447
2448    toggleButton = XtVaCreateManagedWidget("toggleButton",
2449                                           xmToggleButtonWidgetClass,
2450                                           toggle_field,
2451                                           RES_LABEL_CONVERT2(label, aww),
2452                                           RES_CONVERT(XmNmnemonic, mnemonic),
2453                                           XmNindicatorSize, 16,
2454                                           XmNfontList, p_global->fontlist,
2455
2456                                           NULL);
2457    toggle->widget = toggleButton;
2458    awus->set_widget(toggleButton);
2459    XtAddCallback(toggleButton, XmNvalueChangedCallback,
2460                  (XtCallbackProc) AW_variable_update_callback,
2461                  (XtPointer) awus);
2462    if (default_toggle) {
2463        delete p_global->last_toggle_field->default_toggle;
2464        p_global->last_toggle_field->default_toggle = toggle;
2465    }
2466    else {
2467        if (p_global->last_toggle_field->first_toggle) {
2468            p_global->last_toggle_field->last_toggle->next = toggle;
2469            p_global->last_toggle_field->last_toggle = toggle;
2470        }
2471        else {
2472            p_global->last_toggle_field->last_toggle = toggle;
2473            p_global->last_toggle_field->first_toggle = toggle;
2474        }
2475    }
2476    root->make_sensitive(toggleButton, aww->_at->widget_mask);
2477
2478    aww->unset_at_commands();
2479    return  toggleButton;
2480}
2481
2482
2483void AW_window::insert_toggle_internal(AW_label toggle_label, const char *mnemonic, const char *var_value, bool default_toggle) {
2484    if (p_w->toggle_field_var_type != AW_STRING) {
2485        toggle_type_mismatch("string");
2486    }
2487    else {
2488        _aw_create_toggle_entry(this, p_w->toggle_field, toggle_label, mnemonic,
2489                                new VarUpdateInfo(NULL, AW_WIDGET_TOGGLE_FIELD, root->awar(p_w->toggle_field_var_name), var_value, _callback),
2490                                new AW_widget_value_pair(var_value, 0),
2491                                default_toggle);
2492    }
2493}
2494void AW_window::insert_toggle_internal(AW_label toggle_label, const char *mnemonic, int var_value, bool default_toggle) {
2495    if (p_w->toggle_field_var_type != AW_INT) {
2496        toggle_type_mismatch("int");
2497    }
2498    else {
2499        _aw_create_toggle_entry(this, p_w->toggle_field, toggle_label, mnemonic,
2500                                new VarUpdateInfo(NULL, AW_WIDGET_TOGGLE_FIELD, root->awar(p_w->toggle_field_var_name), var_value, _callback),
2501                                new AW_widget_value_pair(var_value, 0),
2502                                default_toggle);
2503    }
2504}
2505void AW_window::insert_toggle_internal(AW_label toggle_label, const char *mnemonic, float var_value, bool default_toggle) {
2506    if (p_w->toggle_field_var_type != AW_FLOAT) {
2507        toggle_type_mismatch("float");
2508    }
2509    else {
2510        _aw_create_toggle_entry(this, p_w->toggle_field, toggle_label, mnemonic,
2511                                new VarUpdateInfo(NULL, AW_WIDGET_TOGGLE_FIELD, root->awar(p_w->toggle_field_var_name), var_value, _callback),
2512                                new AW_widget_value_pair(var_value, 0),
2513                                default_toggle);
2514    }
2515}
2516
2517void AW_window::insert_toggle        (AW_label toggle_label, const char *mnemonic, const char *var_value) { insert_toggle_internal(toggle_label, mnemonic, var_value, false); }
2518void AW_window::insert_default_toggle(AW_label toggle_label, const char *mnemonic, const char *var_value) { insert_toggle_internal(toggle_label, mnemonic, var_value, true); }
2519void AW_window::insert_toggle        (AW_label toggle_label, const char *mnemonic, int var_value)           { insert_toggle_internal(toggle_label, mnemonic, var_value, false); }
2520void AW_window::insert_default_toggle(AW_label toggle_label, const char *mnemonic, int var_value)           { insert_toggle_internal(toggle_label, mnemonic, var_value, true); }
2521void AW_window::insert_toggle        (AW_label toggle_label, const char *mnemonic, float var_value)         { insert_toggle_internal(toggle_label, mnemonic, var_value, false); }
2522void AW_window::insert_default_toggle(AW_label toggle_label, const char *mnemonic, float var_value)         { insert_toggle_internal(toggle_label, mnemonic, var_value, true); }
2523
2524void AW_window::update_toggle_field() {
2525    this->update_toggle_field(get_root()->number_of_toggle_fields);
2526}
2527
2528
2529void AW_window::update_toggle_field(int toggle_field_number) {
2530#if defined(DEBUG)
2531    static int inside_here = 0;
2532    aw_assert(!inside_here);
2533    inside_here++;
2534#endif // DEBUG
2535
2536    AW_toggle_field_struct *toggle_field_list = p_global->toggle_field_list;
2537    {
2538        while (toggle_field_list) {
2539            if (toggle_field_number == toggle_field_list->toggle_field_number) {
2540                break;
2541            }
2542            toggle_field_list = toggle_field_list->next;
2543        }
2544    }
2545
2546    if (toggle_field_list) {
2547        AW_widget_value_pair *active_toggle = toggle_field_list->first_toggle;
2548        {
2549            AW_scalar global_value(root->awar(toggle_field_list->variable_name));
2550            while (active_toggle && active_toggle->value != global_value) {
2551                active_toggle = active_toggle->next;
2552            }
2553            if (!active_toggle) active_toggle = toggle_field_list->default_toggle;
2554        }
2555
2556        // iterate over all toggles including default_toggle and set their state
2557        for (AW_widget_value_pair *toggle = toggle_field_list->first_toggle; toggle;) {
2558            XmToggleButtonSetState(toggle->widget, toggle == active_toggle, False);
2559
2560            if (toggle->next)                                     toggle = toggle->next;
2561            else if (toggle != toggle_field_list->default_toggle) toggle = toggle_field_list->default_toggle;
2562            else                                                  toggle = 0;
2563        }
2564
2565        {
2566            short length;
2567            short height;
2568            XtVaGetValues(p_w->toggle_field, XmNwidth, &length, XmNheight, &height, NULL);
2569            length                += (short)_at->saved_x_correction_for_label;
2570
2571            int width_of_last_widget  = length;
2572            int height_of_last_widget = height;
2573
2574            if (toggle_field_list->correct_for_at_center_intern) {
2575                if (toggle_field_list->correct_for_at_center_intern == 1) {   // middle centered
2576                    XtVaSetValues(p_w->toggle_field, XmNx, (short)((short)_at->saved_x - (short)(length/2) + (short)_at->saved_x_correction_for_label), NULL);
2577                    if (p_w->toggle_label) {
2578                        XtVaSetValues(p_w->toggle_label, XmNx, (short)((short)_at->saved_x - (short)(length/2)), NULL);
2579                    }
2580                    width_of_last_widget = width_of_last_widget / 2;
2581                }
2582                if (toggle_field_list->correct_for_at_center_intern == 2) {   // right centered
2583                    XtVaSetValues(p_w->toggle_field, XmNx, (short)((short)_at->saved_x - length + (short)_at->saved_x_correction_for_label), NULL);
2584                    if (p_w->toggle_label) {
2585                        XtVaSetValues(p_w->toggle_label, XmNx, (short)((short)_at->saved_x - length),    NULL);
2586                    }
2587                    width_of_last_widget = 0;
2588                }
2589            }
2590
2591            this->unset_at_commands();
2592            this->increment_at_commands(width_of_last_widget, height_of_last_widget);
2593        }
2594    }
2595    else {
2596        GBK_terminatef("update_toggle_field: toggle field %i does not exist", toggle_field_number);
2597    }
2598
2599#if defined(DEBUG)
2600    inside_here--;
2601#endif // DEBUG
2602}
Note: See TracBrowser for help on using the repository browser.