source: trunk/SL/SAICALC/saicalc.cxx

Last change on this file was 19365, checked in by westram, 18 months ago
  • string splitters:
    • unittests for GBT_split_string:
      • add tests for dropEmptyTokens.
      • document special behavior for empty string.
    • define enum SplitMode. use enum instead of bool param for GBT_splitNdestroy_string + GBT_split_string.
File size: 45.4 KB
Line 
1// ========================================================= //
2//                                                           //
3//   File      : saicalc.cxx                                 //
4//   Purpose   : SAI calculator (gui)                        //
5//                                                           //
6//   Coded by Ralf Westram (coder@reallysoft.de) in Oct 19   //
7//   http://www.arb-home.de/                                 //
8//                                                           //
9// ========================================================= //
10
11#include "saicalc.h"
12#include "saiop.h"
13
14#include <awt_sel_boxes.hxx>
15#include <awt_config_manager.hxx>
16
17#include <aw_select.hxx>
18#include <aw_awar_defs.hxx>
19#include <aw_awar.hxx>
20#include <aw_root.hxx>
21#include <aw_msg.hxx>
22#include <rootAsWin.h>
23#include <downcast.h>
24#include "calculator.h"
25
26using namespace std;
27
28#define AWAR_SC_BASE           "sai/calc/"
29#define AWAR_SC_TEMP           "tmp/" AWAR_SC_BASE
30#define AWAR_SC_TRANSLATE_BASE AWAR_SC_BASE "translate/"
31#define AWAR_SC_TRANSLATE_TEMP AWAR_SC_TEMP "translate/"
32#define AWAR_SC_MATRIX_BASE    AWAR_SC_BASE "matrix/"
33#define AWAR_SC_MATRIX_TEMP    AWAR_SC_TEMP "matrix/"
34#define AWAR_SC_BOOL_BASE      AWAR_SC_BASE "bool/"
35#define AWAR_SC_BOOL_TEMP      AWAR_SC_TEMP "bool/"
36#define AWAR_SC_ACI_BASE       AWAR_SC_BASE "aci/"
37#define AWAR_SC_ACI_TEMP       AWAR_SC_TEMP "aci/"
38
39#define AWAR_SC_TARGET_SAI      AWAR_SC_BASE "target"
40#define AWAR_SC_SOURCE_SAI_LIST AWAR_SC_BASE "sources" // format = "name1;name2;..."
41#define AWAR_SC_METHOD          AWAR_SC_BASE "method"  // = SaiOperatorType
42#define AWAR_SC_SCOPE           AWAR_SC_BASE "scope"   // = SaiAliScope
43#define AWAR_SC_METHOD_CONFIG   AWAR_SC_TEMP "config"  // mapped to config of currently selected SaiOperatorType
44
45#define AWAR_SC_TRANSLATE_CONFIG   AWAR_SC_TRANSLATE_BASE "config"
46#define AWAR_SC_TRANSLATE_DEFAULT  AWAR_SC_TRANSLATE_TEMP "default"
47#define AWAR_SC_TRANSLATE_IO_TEMPL AWAR_SC_TRANSLATE_TEMP "%c%i"
48
49#define AWAR_SC_MATRIX_CONFIG     AWAR_SC_MATRIX_BASE "config"
50#define AWAR_SC_MATRIX_CELL_TEMPL AWAR_SC_MATRIX_TEMP "m%i_%i"
51
52#define AWAR_SC_BOOL_CONFIG   AWAR_SC_BOOL_BASE "config"
53#define AWAR_SC_BOOL_IN1      AWAR_SC_BOOL_TEMP "in1"
54#define AWAR_SC_BOOL_IN0      AWAR_SC_BOOL_TEMP "in0"
55#define AWAR_SC_BOOL_OP       AWAR_SC_BOOL_TEMP "op"
56#define AWAR_SC_BOOL_OUT1     AWAR_SC_BOOL_TEMP "out1"
57#define AWAR_SC_BOOL_OUT0     AWAR_SC_BOOL_TEMP "out0"
58#define AWAR_SC_BOOL_SEL_RULE AWAR_SC_BOOL_TEMP "selrule"
59#define AWAR_SC_BOOL_RULES    AWAR_SC_BOOL_TEMP "rules"
60
61#define AWAR_SC_ACI_CONFIG AWAR_SC_ACI_BASE "config"
62#define AWAR_SC_ACI        AWAR_SC_ACI_TEMP "aci"
63
64#define TRANSLATION_RULES 10
65
66#define MATRIX_RULES (7+1)      // includes default translation rule
67#define MATRIX_AWARS (MATRIX_RULES+1)
68
69static AWT_config_mapping_def saicalc_config_mapping[] = {
70    { AWAR_SC_TARGET_SAI,      "target" },
71    { AWAR_SC_SOURCE_SAI_LIST, "sources" },
72    { AWAR_SC_METHOD,          "method" },
73    { AWAR_SC_SCOPE,           "scope" },
74    { AWAR_SC_METHOD_CONFIG,   "~config" }, // during restore this has to change after AWAR_SC_METHOD (otherwise we run into spurious errors). Ensured here by alphabetical order!
75
76    { NULp, NULp }
77};
78
79static AWT_predefined_config saicalc_predefined_configs[] = {
80    { "*diff2",         "Compares 2 SAI.\nResult: '-' where equal\n        'x' where different",                                                         "method='0';target='diff';~config='aci=\\'colsplit|compare|plus(1)|translate(\"012\",\"x-x\")\\''" },
81    { "*diff2_ignCase", "Compares 2 SAI (ignoring case).\nResult: '-' where equal \n        'x' where different",                                        "method='0';target='idiff';~config='aci=\\'upper|colsplit|compare|plus(1)|translate(\"012\",\"x-x\")\\''" },
82    { "*count_x",       "Count 'x' in multiple SAI (up to 9).",                                                                                          "method='0';target='x-count';~config='aci=\\'keep(\"x\")|len|translate(\"0\",\"-\")\\''" },
83    { "*sum_up_2",      "Sum up 2 SAI containing digits and gaps\n(raises error if result overflows 9).",                                                "method='0';target='sum';~config='aci=\\'translate(\"-=\",\"00\")|colsplit|plus\\''" },
84    { "*cutByTermini",  "Sai1: termini (containing 'x' in region)\nSai2: any\n=> same as Sai2 at all 'x' in Sai1\n   else same as Sai1 (normally gap).", "method='0';sources='termini';~config='aci=\\'command(\"/^x//\")|head(1)\\''" },
85    { "*invert_binary", "inverts binary SAI\n(works with binary source and/or target)",                                                                  "method='0';~config='aci=\\'translate(\"01\",\"10\")\\''" },
86
87    { NULp, NULp, NULp }
88};
89
90static void sai_seletion_changed_cb(AW_selection *sel_sai, bool /*interactive*/, AW_CL) { // @@@ impl 'interactive'
91    StrArray sainame;
92    sel_sai->get_values(sainame);
93
94    char *sainameList = GBT_join_strings(sainame, ';');
95    AW_root::SINGLETON->awar(AWAR_SC_SOURCE_SAI_LIST)->write_string(sainameList);
96    free(sainameList);
97}
98static void fill_with_source_sais(ConstStrArray& sainame, AW_root *awr) {
99    char *sainameList = awr->awar(AWAR_SC_SOURCE_SAI_LIST)->read_string();
100    GBT_splitNdestroy_string(sainame, sainameList, ';');
101}
102static void source_sai_list_changed_cb(AW_root *awr, AW_selection *sel_sai) {
103    ConstStrArray sainame;
104    fill_with_source_sais(sainame, awr);
105    awt_set_subset_selection_content(sel_sai, sainame);
106}
107
108static const char *awar_translate(bool in, int num) {
109    static SmartCharPtr result; // result is kept until next call of awar_translate()
110    result = GBS_global_string_copy(AWAR_SC_TRANSLATE_IO_TEMPL, in ? 'i' : 'o', num);
111    return &*result;
112}
113
114static AW_window *create_translator_config_window(AW_root *awr) {
115    AW_window_simple *aws = new AW_window_simple;
116
117    aws->init(awr, "SAI_TRANSLATOR", "SAI translator configuration");
118    aws->load_xfig("saitrans.fig");
119
120    aws->auto_space(5, 5);
121    aws->button_length(8);
122
123    aws->at("close");
124    aws->callback(AW_POPDOWN);
125    aws->create_button("CLOSE", "CLOSE", "O");
126
127    aws->callback(makeHelpCallback("saicalc.hlp"));
128    aws->create_button("HELP", "HELP");
129
130    aws->at("target"); int x2 = aws->get_at_xposition();
131    aws->at("source"); int x1 = aws->get_at_xposition();
132
133    for (int i = 0; i<TRANSLATION_RULES; ++i) {
134        aws->at_x(x1);
135        aws->create_input_field(awar_translate(true, i), 15);
136
137        aws->at_x(x2);
138        aws->create_input_field(awar_translate(false, i), 3);
139
140        aws->at_newline();
141    }
142
143    aws->at_x(x1);
144    aws->label("Default:");
145    aws->create_input_field(AWAR_SC_TRANSLATE_DEFAULT, 3);
146
147    aws->window_fit();
148
149    return aws;
150}
151
152
153
154static const char *awar_matrix_cell(int x, int y) {
155    sai_assert(x>=0 && x<MATRIX_AWARS);
156    sai_assert(y>=0 && y<MATRIX_AWARS);
157
158    // meaning of indices:
159    // 0                     = heading
160    // 1                     = default translation
161    // 2 .. (MATRIX_AWARS-1) = translations
162
163    // for unused combinations, this function returns NULp:
164    if ((x == 0 && (y == 0 || y == 1))
165        ||
166        (x == 1 && y == 0))
167    {
168        return NULp;
169    }
170
171    static SmartCharPtr awarName;
172    awarName = GBS_global_string_copy(AWAR_SC_MATRIX_CELL_TEMPL, x, y);
173    return &*awarName;
174}
175
176static void normalize_matrix_cb(AW_window *aww) {
177    // reloading awar from config does always normalize
178    aww->get_root()->awar(AWAR_SC_MATRIX_CONFIG)->touch();
179}
180
181static AW_window *create_matrix_config_window(AW_root *awr) {
182    AW_window_simple *aws = new AW_window_simple;
183
184    aws->init(awr, "SAI_MATRIX_TRANSLATOR", "SAI matrix translator configuration");
185    aws->load_xfig("saimatrix.fig");
186
187    aws->auto_space(5, 5);
188    aws->button_length(8);
189
190    aws->at("close");
191    aws->callback(AW_POPDOWN);
192    aws->create_button("CLOSE", "CLOSE", "O");
193
194    aws->callback(makeHelpCallback("saicalc.hlp"));
195    aws->create_button("HELP", "HELP");
196
197    int xpos[MATRIX_AWARS];
198    int ypos[MATRIX_AWARS];
199    int xcheck, ycheck;
200
201    aws->at("col1"); aws->get_at_position(&xpos[1], &ypos[0]);
202    aws->at("col2"); aws->get_at_position(&xpos[2], &ycheck);
203
204    aws->at("row1"); aws->get_at_position(&xpos[0], &ypos[1]);
205    aws->at("row2"); aws->get_at_position(&xcheck, &ypos[2]);
206
207    // distribute coordinates:
208    {
209        int xdiff = xpos[2]-xpos[1];
210        int ydiff = ypos[2]-ypos[1];
211
212        bool figConsistent = (xpos[0] == xcheck) && (ypos[0] == ycheck) && xdiff>0 && ydiff>0;
213        if (figConsistent) {
214            for (int p = 3; p<MATRIX_AWARS; ++p) {
215                xpos[p] = xpos[p-1] + xdiff;
216                ypos[p] = ypos[p-1] + ydiff;
217            }
218        }
219        else {
220            sai_assert(figConsistent);
221            aw_message("internal error: invalid position values");
222        }
223    }
224
225    // create fields upon awars:
226    for (int x = 0; x<MATRIX_AWARS; ++x) {
227        for (int y = 0; y<MATRIX_AWARS; ++y) {
228            const char *awar_name = awar_matrix_cell(x, y);
229            aws->at(xpos[x], ypos[y]);
230            if (awar_name) {
231                aws->create_input_field(awar_name, 5);
232            }
233        }
234    }
235
236    aws->at_newline();
237    aws->at_x(xpos[0]);
238    aws->callback(normalize_matrix_cb);
239    aws->create_autosize_button("NORMALIZE", "Normalize");
240
241    return aws;
242}
243
244static AW_window *create_aciapp_config_window(AW_root *awr) {
245    AW_window_simple *aws = new AW_window_simple;
246
247    aws->init(awr, "SAI_ACI_CONFIG", "SAI ACI configuration");
248    aws->load_xfig("saiaci.fig");
249
250    aws->auto_space(5, 5);
251    aws->button_length(8);
252
253    aws->at("close");
254    aws->callback(AW_POPDOWN);
255    aws->create_button("CLOSE", "CLOSE", "O");
256
257    aws->callback(makeHelpCallback("saicalc.hlp"));
258    aws->create_button("HELP", "HELP");
259
260    aws->at("aci");
261    aws->create_input_field(AWAR_SC_ACI);
262
263    return aws;
264}
265
266// --------------------------
267//      boolchain config
268
269static const char* const  RULELIST_DELIMITER = "\1";
270static AW_selection_list *boolrule_sellst    = NULp;
271
272static void refill_boolrules_sellist(const ConstStrArray& ruleArray) {
273    // fill selection list from array content:
274    if (boolrule_sellst) {
275        boolrule_sellst->clear();
276        for (int r = 0; ruleArray[r]; ++r) {
277            boolrule_sellst->insert(ruleArray[r], ruleArray[r]);
278        }
279        if (ruleArray.empty()) {
280            boolrule_sellst->insert_default("<no rules defined>", "");
281        }
282        else {
283            boolrule_sellst->insert_default("", "");
284        }
285        boolrule_sellst->update();
286    }
287}
288
289static void update_rulesAwar(AW_root *awr, const CharPtrArray& ruleArray) {
290    // Updates AWAR_SC_BOOL_RULES from rules stored in ruleArray.
291    //
292    // Note: if any of the rules in 'ruleArray' does contain RULELIST_DELIMITER,
293    // the whole update mechanism would not work.
294    // -> workaround: test for and remove delimiter char. warn user.
295
296    bool seenDelimiter = false;
297    for (int i = 0; ruleArray[i] && !seenDelimiter; ++i) {
298        seenDelimiter = strchr(ruleArray[i], RULELIST_DELIMITER[0]);
299    }
300
301    if (seenDelimiter) {
302        // replace all delimiters (into copy of array):
303        StrArray copy;
304        char srt[] = ":?=";
305        srt[1]     = RULELIST_DELIMITER[0];
306
307        for (int i = 0; ruleArray[i]; ++i) {
308            copy.put(GBS_string_eval(ruleArray[i], srt));
309            if (strlen(copy[i]) != strlen(ruleArray[i])) {
310                aw_message(GBS_global_string("Warning: detected delimiter (ASCII %i) in '%s' and removed it.",
311                                             int(RULELIST_DELIMITER[0]), ruleArray[i]));
312            }
313        }
314
315        update_rulesAwar(awr, copy);
316    }
317    else {
318        char *rulelist = GBT_join_strings(ruleArray, RULELIST_DELIMITER[0]);
319        awr->awar(AWAR_SC_BOOL_RULES)->write_string(rulelist);
320        free(rulelist);
321    }
322}
323
324static void fill_boolrules_array_from_AWAR(AW_root *awr, ConstStrArray& ruleArray) {
325    char *rulelist = awr->awar(AWAR_SC_BOOL_RULES)->read_string();
326    GBT_splitNdestroy_string(ruleArray, rulelist, RULELIST_DELIMITER, SPLIT_DROPEMPTY);
327}
328static void refill_boolrules_sellist_from_AWAR(AW_root *awr) {
329    if (boolrule_sellst) {
330        ConstStrArray ruleArray;
331        fill_boolrules_array_from_AWAR(awr, ruleArray);
332        refill_boolrules_sellist(ruleArray);
333    }
334}
335
336static SaiBoolRulePtr build_rule_from_AWARs(AW_root *awr, bool createFirstRule) {
337    // build SaiBoolRule from rule defining awars:
338
339    SaiBoolOp op;
340    if (createFirstRule) {
341        op = SBO_FIRST;
342    }
343    else {
344        op = SaiBoolOp(awr->awar(AWAR_SC_BOOL_OP)->read_int());
345        sai_assert(op != SBO_FIRST);
346    }
347
348    const char *trueChars  = awr->awar(AWAR_SC_BOOL_IN1)->read_char_pntr();
349    const char *falseChars = awr->awar(AWAR_SC_BOOL_IN0)->read_char_pntr();
350
351    bool specifiedChars = trueChars[0]; // if trueChars specified -> define via trueChars
352    // otherwise: define via no chars (or accept all chars as true = empty no chars)
353
354    return new SaiBoolRule(op, specifiedChars, specifiedChars ? trueChars : falseChars);
355}
356
357static void add_boolrule_cb(AW_window *aww) {
358    AW_root *awr = aww->get_root();
359
360    ConstStrArray ruleArray; // split existing rules into array
361    fill_boolrules_array_from_AWAR(awr, ruleArray);
362
363    const bool     first = ruleArray.empty();
364    SaiBoolRulePtr rule  = build_rule_from_AWARs(awr, first);
365
366    ruleArray.put(rule->to_string().c_str()); // insert new rule into array
367    update_rulesAwar(awr, ruleArray);         // write back array to awar (will refresh selection list via callback)
368}
369static void mod_boolrule_cb(AW_window *aww) {
370    int selIdx = boolrule_sellst->get_index_of_selected();
371    if (selIdx>=0) {
372        ConstStrArray  ruleArray; // split existing rules into array
373        AW_root       *awr = aww->get_root();
374
375        fill_boolrules_array_from_AWAR(awr, ruleArray);
376
377        const bool     first = selIdx == 0;
378        SaiBoolRulePtr rule  = build_rule_from_AWARs(awr, first);
379
380        ruleArray.replace(selIdx, rule->to_string().c_str()); // update rule in array
381        update_rulesAwar(awr, ruleArray);                     // write back array to awar (will refresh selection list via callback)
382        boolrule_sellst->select_element_at(selIdx);
383    }
384    else {
385        aw_message("No operation selected to modify.");
386    }
387}
388static void del_boolrule_cb(AW_window *aww) {
389    int selIdx = boolrule_sellst->get_index_of_selected();
390    if (selIdx>=0) {
391        string         replaced;
392        ConstStrArray  ruleArray;
393        AW_root       *awr = aww->get_root();
394
395        fill_boolrules_array_from_AWAR(awr, ruleArray);
396        ruleArray.safe_remove(selIdx);
397        if (selIdx == 0 && !ruleArray.empty()) {
398            // correct 1st rule (has to be SBO_FIRST)
399            ErrorOrSaiBoolRulePtr product = SaiBoolRule::make(ruleArray[0]);
400            if (product.hasError()) { // should be impossible .. just in case.
401                aw_message(product.getError().deliver());
402                return;
403            }
404
405            const SaiBoolRule& rule = *product.getValue();
406            SaiBoolRule        new1st(SBO_FIRST, rule.specifiesTrueChars(), rule.get_chars());
407
408            replaced = new1st.to_string();
409            ruleArray.replace(0, replaced.c_str());
410        }
411        update_rulesAwar(awr, ruleArray);
412
413        boolrule_sellst->select_element_at(selIdx);
414    }
415    else {
416        aw_message("No operation selected to delete.");
417    }
418}
419
420static AW_window *create_boolchain_config_window(AW_root *awr) {
421    AW_window_simple *aws = new AW_window_simple;
422
423    aws->init(awr, "SAI_BOOLCHAIN_CONFIG", "SAI boolchain configuration");
424    aws->load_xfig("saichain.fig");
425
426    aws->auto_space(5, 5);
427    aws->button_length(8);
428
429    aws->at("close");
430    aws->callback(AW_POPDOWN);
431    aws->create_button("CLOSE", "CLOSE", "O");
432
433    aws->callback(makeHelpCallback("saicalc.hlp"));
434    aws->create_button("HELP", "HELP");
435
436    aws->at("trueIn");  aws->create_input_field(AWAR_SC_BOOL_IN1, 5);
437    aws->at("falseIn"); aws->create_input_field(AWAR_SC_BOOL_IN0, 5);
438
439    aws->at("op");
440    aws->create_option_menu(AWAR_SC_BOOL_OP);
441    aws->insert_default_option("AND",  "A", SBO_AND);
442    aws->insert_option        ("OR",   "O", SBO_OR);
443    aws->insert_option        ("XOR",  "X", SBO_XOR);
444    aws->insert_option        ("NAND", "D", SBO_NAND);
445    aws->insert_option        ("NOR",  "N", SBO_NOR);
446    aws->insert_option        ("XNOR", "R", SBO_XNOR);
447    aws->update_option_menu();
448
449    aws->at("trueOut");  aws->create_input_field(AWAR_SC_BOOL_OUT1, 1);
450    aws->at("falseOut"); aws->create_input_field(AWAR_SC_BOOL_OUT0, 1);
451
452    aws->at("rules");
453    boolrule_sellst = aws->create_selection_list(AWAR_SC_BOOL_SEL_RULE);
454    refill_boolrules_sellist_from_AWAR(awr);
455
456    aws->at("add");
457    aws->callback(add_boolrule_cb); aws->create_button("ADD",    "ADD");
458    aws->callback(mod_boolrule_cb); aws->create_button("UPDATE", "UPDATE");
459    aws->callback(del_boolrule_cb); aws->create_button("DELETE", "DELETE");
460
461    return aws;
462}
463
464static void saicalc_edit_method_cb(AW_root *awr, bool forcePopup) {
465    // forcePopup==false -> only popup if another config window was visible
466
467    static AW_window *aww[SAI_OPERATOR_TYPES] = { NULp, NULp, NULp, NULp };
468    static AW_window *aw_visible = NULp;
469
470    SaiOperatorType type = SaiOperatorType(awr->awar(AWAR_SC_METHOD)->read_int());
471
472    sai_assert(int(type) >= 0 && int(type)<SAI_OPERATOR_TYPES);
473
474    // always show one window only (popdown previous before popping up a new one):
475    if (aw_visible && aw_visible != aww[type]) {
476        if (aw_visible->is_shown()) forcePopup = true;
477        aw_visible->hide();
478        aw_visible = NULp;
479    }
480
481    if (!forcePopup) return;
482
483    if (!aww[type]) {
484        AW_window *awe = NULp;
485
486        switch (type) {
487            case SOP_TRANSLATE:
488                awe = create_translator_config_window(awr);
489                break;
490            case SOP_ACI:
491                awe = create_aciapp_config_window(awr);
492                break;
493            case SOP_MATRIX:
494                awe = create_matrix_config_window(awr);
495                break;
496            case SOP_BOOLCHAIN:
497                awe = create_boolchain_config_window(awr);
498                break;
499        }
500
501        if (awe) {
502            aww[type] = awe;
503        }
504        else {
505            aw_message("cannot edit this type of calculation method (yet)");
506        }
507    }
508
509    aw_visible = aww[type];
510    if (aw_visible) {
511        aw_visible->activate();
512    }
513}
514
515static SaiOperatorPtr createOpFromConfigAwar(SaiOperatorType type, AW_awar *awar_config) {
516    // creates an SaiOperator from the config awar
517
518    SaiOperatorPtr         saiOp;
519    const char            *config  = awar_config->read_char_pntr();
520    ErrorOrSaiOperatorPtr  product = SaiOperator::make(type, config);
521
522    if (product.hasError()) {
523        aw_message(GBS_global_string("Failed to load config: %s", product.getError().deliver()));
524    }
525    else {
526        saiOp = product.getValue();
527    }
528    return saiOp;
529}
530
531// --------------------------------------------------------------------------------
532
533static bool in_translate_awar_callback = false;
534
535static void translate_config_changed_cb(AW_root *awr) { // [CFG->AWARS]
536    if (!in_translate_awar_callback) {
537        LocallyModify<bool> avoid_recursion(in_translate_awar_callback, true);
538
539        // parse config
540        SaiOperatorPtr saiOp = createOpFromConfigAwar(SOP_TRANSLATE, awr->awar(AWAR_SC_TRANSLATE_CONFIG));
541        if (saiOp.isSet()) {
542            // reverse generate rules and default char:
543            const SaiTranslator *translator = DOWNCAST(SaiTranslator*, &*saiOp);
544            ConfigMapping        cmap;
545            translator->deduceTranslations(cmap);
546
547            // 1st clear all awars:
548            for (int i = 0; i<TRANSLATION_RULES; ++i) {
549                awr->awar(awar_translate(true, i))->write_string("");
550                awr->awar(awar_translate(false, i))->write_string("");
551            }
552
553            // set specific awars:
554            ConstStrArray keys;
555            cmap.get_entries(keys);
556
557            for (int k = 0; keys[k]; ++k) {
558                const char *value    = cmap.get_entry(keys[k]);
559                bool        accepted = false;
560                if (strncmp(keys[k], "trans", 5) == 0) {
561                    const int num = atoi(keys[k]+5);
562                    if (num>0) {
563                        char firstChar[2] = "x";
564                        firstChar[0]      = value[0];
565
566                        awr->awar(awar_translate(false, num-1))->write_string(firstChar);
567                        awr->awar(awar_translate(true, num-1))->write_string(value+1);
568                        accepted = true;
569                    }
570                }
571                else if (strcmp(keys[k], "default") == 0) {
572                    awr->awar(AWAR_SC_TRANSLATE_DEFAULT)->write_string(value);
573                    accepted = true;
574                }
575                if (!accepted) {
576                    aw_message(GBS_global_string("Failed to deduce translations (invalid key '%s')", keys[k]));
577                }
578            }
579        }
580    }
581}
582
583static void translate_gui_changed_cb(AW_root *awr, bool /*insetChanged*/, int /*num*/) { // [AWARS->OP->CFG]
584    // @@@ implement parameters: use to decide how to resolve conflicts,
585    // @@@ e.g. when a CHAR is added to 'from'-set => CHAR has to be removed from all other 'from'-sets
586
587    if (!in_translate_awar_callback) {
588        LocallyModify<bool> avoid_recursion(in_translate_awar_callback, true);
589
590        // create SaiTranslator from awars:
591        const char    *translate_default = awr->awar(AWAR_SC_TRANSLATE_DEFAULT)->read_char_pntr();
592        SaiTranslator  translator(translate_default[0] ? translate_default[0] : '-');
593        for (int i = 0; i<TRANSLATION_RULES; ++i) {
594            const char *translate_from = awr->awar(awar_translate(true, i))->read_char_pntr();
595            const char *translate_to   = awr->awar(awar_translate(false, i))->read_char_pntr();
596
597            if (translate_from[0] && translate_to[0]) {
598                translator.addTranslation(translate_from, translate_to[0]);
599            }
600        }
601
602        // ask SaiOperator to create config and store in config awar:
603        string cfg = translator.get_config();
604        awr->awar(AWAR_SC_TRANSLATE_CONFIG)->write_string(cfg.c_str());
605    }
606}
607
608// --------------------------------------------------------------------------------
609
610static bool in_matrix_awar_callback = false;
611
612static const char *content_matrix_cell(int x, int y) {
613    const char *awarname = awar_matrix_cell(x, y);
614    if (awarname) return AW_root::SINGLETON->awar(awarname)->read_char_pntr();
615    return NULp;
616}
617
618static SaiOperatorPtr buildColumnTranslatorFromAwars(int x, bool returnDefault) {
619    sai_assert(x>0);
620
621    const char *globalDefTrans  = content_matrix_cell(1, 1);
622    const bool  globalIsDefined = globalDefTrans && globalDefTrans[0];
623
624    const char *defTrans  = content_matrix_cell(x, 1);
625    bool        isDefined = defTrans && defTrans[0];
626
627    char           defResChar = isDefined ? defTrans[0] : (globalIsDefined ? globalDefTrans[0] : '-');
628    SaiTranslator *colTrans   = new SaiTranslator(defResChar);
629
630    for (int y = 2; y<MATRIX_AWARS; ++y) {
631        const char *from      = content_matrix_cell(0, y);
632        const char *cellTrans = content_matrix_cell(x, y);
633
634        if (cellTrans && cellTrans[0]) {
635            if (from && from[0]) {
636                colTrans->addTranslation(from, cellTrans[0]);
637                isDefined = true;
638            }
639        }
640    }
641
642    SaiOperatorPtr colTransPtr(colTrans);
643    if (!isDefined && !returnDefault) { // undefined empty column
644        colTransPtr.setNull(); // return NULp instead
645    }
646
647    sai_assert(implicated(returnDefault, colTransPtr.isSet()));
648    return colTransPtr;
649}
650
651typedef vector<string> StringVector;
652
653struct CompareByLength { bool operator()(const string& s1, const string& s2) const { return s1.length()>s2.length(); } };
654struct CompareAlpha    { bool operator()(const string& s1, const string& s2) const { return s1<s2; } };
655
656static void detectEqualRowsAndColumns(const string& out, StringVector& row, StringVector& col) {
657    bool check_row[255], check_col[255];
658    for (int i = 0; i<255; ++i) {
659        check_row[i] = check_col[i] = true;
660    }
661
662    // search equal columns:
663    for (int x1 = 0; x1<255; ++x1) {
664        if (check_col[x1]) {
665            string c(1, char(x1+1));
666            for (int x2 = x1+1; x2<255; ++x2) {
667                if (check_col[x2]) {
668                    bool equal = true;
669                    for (int y = 0; y<255 && equal; ++y) {
670                        equal = out[y*255+x1] == out[y*255+x2];
671                    }
672                    if (equal) {
673                        c             += char(x2+1);
674                        check_col[x2]  = false;
675                    }
676                }
677            }
678            check_col[x1] = false;
679            col.push_back(c);
680        }
681    }
682
683    // search equal rows:
684    for (int y1 = 0; y1<255; ++y1) {
685        if (check_row[y1]) {
686            string r(1, char(y1+1));
687            for (int y2 = y1+1; y2<255; ++y2) {
688                if (check_row[y2]) {
689                    bool equal = true;
690                    for (int x = 0; x<255 && equal; ++x) {
691                        equal = out[y1*255+x] == out[y2*255+x];
692                    }
693                    if (equal) {
694                        r             += char(y2+1);
695                        check_row[y2]  = false;
696                    }
697                }
698            }
699            check_row[y1] = false;
700            row.push_back(r);
701        }
702    }
703
704    // sort vectors (longest on 1st position, rest alphabetically):
705    sort(row.begin(), row.end(), CompareByLength());
706    sort(col.begin(), col.end(), CompareByLength());
707
708    StringVector::iterator r2nd = row.begin(); ++r2nd;
709    StringVector::iterator c2nd = col.begin(); ++c2nd;
710
711    sort(r2nd, row.end(), CompareAlpha());
712    sort(c2nd, col.end(), CompareAlpha());
713}
714
715static void matrix_config_changed_cb(AW_root *awr) { // [CFG->AWARS]
716    if (!in_matrix_awar_callback) {
717        LocallyModify<bool> avoid_recursion(in_matrix_awar_callback, true);
718
719        // parse config
720        SaiOperatorPtr saiOp = createOpFromConfigAwar(SOP_MATRIX, awr->awar(AWAR_SC_MATRIX_CONFIG));
721        if (saiOp.isSet()) {
722            const SaiMatrixTranslator *matrix = DOWNCAST(SaiMatrixTranslator*, &*saiOp);
723
724            // 1st clear all awars:
725            for (int x = 0; x<MATRIX_AWARS; ++x) {
726                for (int y = 0; y<MATRIX_AWARS; ++y) {
727                    const char *awarname = awar_matrix_cell(x, y);
728                    if (awarname) awr->awar(awarname)->write_string("");
729                }
730            }
731
732            // calculate full matrix by combining all chars:
733            const int MSIZE = 255*255;
734
735            ConstStrArray in;
736            {
737                char *buffer = ARB_alloc<char>(2*(MSIZE+1)); // size for 2 input strings
738                in.set_memblock(buffer);
739
740                char *in1 = buffer;
741                char *in2 = buffer+(MSIZE+1);
742
743                for (int y = 0; y<255; ++y) {
744                    for (int x = 0; x<255; ++x) {
745                        int offset  = y*255+x;
746                        in1[offset] = x+1;
747                        in2[offset] = y+1;
748                    }
749                }
750
751                in1[MSIZE] = 0;
752                in2[MSIZE] = 0;
753
754                in.put(in1);
755                in.put(in2);
756            }
757
758            SaiCalcEnv env(in, NULp);
759
760            ErrorOrString result = matrix->apply(env);
761            if (result.hasError()) {
762                aw_message(result.getError().deliver());
763            }
764            else {
765                string       out = result.getValue();
766                StringVector row, col; // each entry represents equal rows/columns.
767                                       // the chars in each entry refer to the single rows/columns.
768
769                detectEqualRowsAndColumns(out, row, col);
770
771                sai_assert(row.size()<MATRIX_AWARS);
772                sai_assert(col.size()<MATRIX_AWARS);
773
774                // fill awars:
775                for (size_t r = 1; r<row.size(); ++r) { // row headings
776                    const char *awarname = awar_matrix_cell(0, r+1);
777                    sai_assert(awarname);
778                    awr->awar(awarname)->write_string(row[r].c_str());
779                }
780                for (size_t c = 1; c<col.size(); ++c) { // column headings
781                    const char *awarname = awar_matrix_cell(c+1, 0);
782                    sai_assert(awarname);
783                    awr->awar(awarname)->write_string(col[c].c_str());
784                }
785
786                char globalDefault = 0;
787
788                for (size_t c = 0; c<col.size(); ++c) {
789                    int x = col[c][0]-1;
790
791                    char defaultOfColumn = 0;
792
793                    for (size_t r = 0; r<row.size(); ++r) {
794                        int y = row[r][0]-1;
795
796                        if (x>=0 && y>=0) {
797                            char to[] = "x";
798                            to[0]     = out[y*255+x];
799
800                            if (to[0] != globalDefault && to[0] != defaultOfColumn) {
801                                const char *awarname = awar_matrix_cell(c+1, r+1);
802                                sai_assert(awarname);
803                                awr->awar(awarname)->write_string(to);
804                            }
805
806                            if (r == 0) {
807                                defaultOfColumn = to[0];
808                                if (c == 0) globalDefault = to[0];
809                            }
810                        }
811                    }
812                }
813            }
814        }
815    }
816}
817
818static void matrix_gui_changed_cb(AW_root *awr, int /*x*/, int /*y*/) { // [AWARS->OP->CFG]
819    // @@@ implement parameters: use to decide how to resolve conflicts,
820    // @@@ e.g. when a CHAR is added to 'from'-set = > CHAR has to be removed from all other 'from'-sets
821
822    if (!in_matrix_awar_callback) {
823        LocallyModify<bool> avoid_recursion(in_matrix_awar_callback, true);
824
825        // create SaiMatrixTranslator from awars:
826        SaiOperatorPtr columnTranslator = buildColumnTranslatorFromAwars(1, true);
827        sai_assert(columnTranslator.isSet());
828
829        SaiMatrixTranslator matrixTranslator(columnTranslator);
830
831        for (int col = 2; col<MATRIX_AWARS; ++col) {
832            const char *from = content_matrix_cell(col, 0);
833            if (from && from[0]) {
834                columnTranslator = buildColumnTranslatorFromAwars(col, false);
835                if (columnTranslator.isSet()) {
836                    matrixTranslator.addOperator(from, columnTranslator);
837                }
838            }
839        }
840
841        // ask SaiOperator to create config and store in config awar:
842        string cfg = matrixTranslator.get_config();
843        sai_assert(!cfg.empty());
844        awr->awar(AWAR_SC_MATRIX_CONFIG)->write_string(cfg.c_str());
845    }
846}
847
848// --------------------------------------------------------------------------------
849
850static char firstCharOfAwarOrDefault(AW_root *awr, const char *awarname) {
851    /*! read value of awar 'awarname'
852     * return either
853     * - first char of its value or (if empty)
854     * - first char of its default value
855     */
856
857    AW_awar    *awar   = awr->awar(awarname);
858    const char *value  = awar->read_char_pntr();
859    char        result = value[0];
860
861    if (!result) {
862        char     *copyOfValue = awar->read_string();
863        GB_ERROR  error       = awar->reset_to_default();
864        if (!error) {
865            value  = awar->read_char_pntr();
866            result = value[0];
867            sai_assert(result); // you have to define a non-empty default value for this awar!
868        }
869        if (error) {
870            result = '?';
871        }
872        awar->write_string(copyOfValue);
873        free(copyOfValue);
874    }
875
876    return result;
877}
878
879static bool in_boolchain_awar_callback = false;
880
881static void bool_config_changed_cb(AW_root *awr) { // [CFG->AWARS]
882    if (!in_boolchain_awar_callback) {
883        LocallyModify<bool> avoid_recursion(in_boolchain_awar_callback, true);
884
885        // parse config
886        SaiOperatorPtr saiOp = createOpFromConfigAwar(SOP_BOOLCHAIN, awr->awar(AWAR_SC_BOOL_CONFIG));
887        if (saiOp.isSet()) {
888            const SaiBoolchainOperator *boolchain = DOWNCAST(SaiBoolchainOperator*, &*saiOp);
889
890            // retrieve rules from 'boolchain':
891            {
892                size_t         ruleCount = boolchain->count_rules();
893                vector<string> ruleString;
894                ruleString.reserve(ruleCount);
895                ConstStrArray  ruleArray;
896
897                for (size_t r = 0; r<ruleCount; ++r) {
898                    ruleString.push_back(boolchain->getRule(r).to_string());
899                    ruleArray.put(ruleString.back().c_str());
900                }
901
902                update_rulesAwar(awr, ruleArray);
903            }
904            // retrieve output translation from 'boolchain':
905            {
906                char out[2] = "x";
907                out[0]      = boolchain->getOutTrans(false); awr->awar(AWAR_SC_BOOL_OUT0)->write_string(out);
908                out[0]      = boolchain->getOutTrans(true);  awr->awar(AWAR_SC_BOOL_OUT1)->write_string(out);
909            }
910        }
911    }
912}
913
914static void boolchain_gui_changed_cb(AW_root *awr) { // [AWARS->OP->CFG]
915    if (!in_boolchain_awar_callback) {
916        LocallyModify<bool> avoid_recursion(in_boolchain_awar_callback, true);
917
918        // create SaiBoolchainOperator from awars:
919        ConstStrArray ruleArray;
920        fill_boolrules_array_from_AWAR(awr, ruleArray);
921
922        char c0 = firstCharOfAwarOrDefault(awr, AWAR_SC_BOOL_OUT0);
923        char c1 = firstCharOfAwarOrDefault(awr, AWAR_SC_BOOL_OUT1);
924
925        SaiBoolchainOperator boolchainOp(c0, c1);
926
927        ARB_ERROR error;
928        for (size_t r = 0; r<ruleArray.size() && !error; ++r) { // add rules from array to operator
929            ErrorOrSaiBoolRulePtr rule = SaiBoolRule::make(ruleArray[r]);
930            if (rule.hasError()) {
931                error = rule.getError();
932            }
933            else {
934                boolchainOp.addRule(*rule.getValue());
935            }
936        }
937        if (!error) {
938            // ask operator to create config and store in config awar:
939            string cfg = boolchainOp.get_config();
940            awr->awar(AWAR_SC_BOOL_CONFIG)->write_string(cfg.c_str());
941        }
942
943        aw_message_if(error);
944    }
945}
946static void boolchain_rulesAwar_changed_cb(AW_root *awr) {
947    boolchain_gui_changed_cb(awr);
948    refill_boolrules_sellist_from_AWAR(awr);
949}
950
951static bool in_boolchain_inputCharset_awar_callback = false;
952
953static void display_selected_rule_cb(AW_root *awr) {
954    // fill gui awars from selected rule
955
956    const char *selRule = awr->awar(AWAR_SC_BOOL_SEL_RULE)->read_char_pntr();
957    if (selRule && selRule[0]) { // only update awars if rule is nonempty
958        ErrorOrSaiBoolRulePtr product = SaiBoolRule::make(selRule);
959        if (product.hasError()) {
960            aw_message(product.getError().deliver());
961        }
962        else {
963            const SaiBoolRule& rule = *product.getValue();
964
965            SaiBoolOp op = rule.get_op();
966            if (op != SBO_FIRST) { // when 1st rule is selected -> do not change operator type
967                awr->awar(AWAR_SC_BOOL_OP)->write_int(op);
968            }
969
970            const char *trueChars  = "";
971            const char *falseChars = "";
972
973            (rule.specifiesTrueChars() ? trueChars : falseChars) = rule.get_chars();
974
975            LocallyModify<bool> avoid_auto_correction(in_boolchain_inputCharset_awar_callback, true);
976            awr->awar(AWAR_SC_BOOL_IN0)->write_string(falseChars);
977            awr->awar(AWAR_SC_BOOL_IN1)->write_string(trueChars);
978        }
979    }
980}
981
982static void inputCharsetChanged_cb(AW_root *awr, bool defTrue) {
983    if (!in_boolchain_inputCharset_awar_callback) {
984        LocallyModify<bool> avoid_recursion(in_boolchain_inputCharset_awar_callback, true);
985
986        const char *awarname_written = defTrue ? AWAR_SC_BOOL_IN1 : AWAR_SC_BOOL_IN0;
987        const char *awarname_toReset = defTrue ? AWAR_SC_BOOL_IN0 : AWAR_SC_BOOL_IN1;
988
989        if (awr->awar(awarname_written)->read_char_pntr()[0]) { // written awar is not empty
990            awr->awar(awarname_toReset)->write_string("");
991        }
992    }
993}
994
995// --------------------------------------------------------------------------------
996
997static bool in_aci_awar_callback = false;
998
999static void aci_config_changed_cb(AW_root *awr) { // [CFG->AWARS]
1000    if (!in_aci_awar_callback) {
1001        LocallyModify<bool> avoid_recursion(in_aci_awar_callback, true);
1002
1003        SaiOperatorPtr saiOp = createOpFromConfigAwar(SOP_ACI, awr->awar(AWAR_SC_ACI_CONFIG));
1004        if (saiOp.isSet()) {
1005            const SaiAciApplicator *aciOp = DOWNCAST(SaiAciApplicator*, &*saiOp);
1006            // set specific awars:
1007            awr->awar(AWAR_SC_ACI)->write_string(aciOp->get_aci().c_str());
1008        }
1009    }
1010}
1011static void aci_gui_changed_cb(AW_root *awr) { // [AWARS->OP->CFG]
1012    if (!in_aci_awar_callback) {
1013        LocallyModify<bool> avoid_recursion(in_aci_awar_callback, true);
1014
1015        // create SaiAciApplicator from awars:
1016        const char       *aci = awr->awar(AWAR_SC_ACI)->read_char_pntr();
1017        SaiAciApplicator  aciOp(aci);
1018
1019        // ask SaiOperator to create config and store in config awar:
1020        string cfg = aciOp.get_config();
1021        awr->awar(AWAR_SC_ACI_CONFIG)->write_string(cfg.c_str());
1022    }
1023}
1024
1025// --------------------------------------------------------------------------------
1026
1027static void calc_method_changed_cb(AW_root *awr) {
1028    SaiOperatorType type = SaiOperatorType(awr->awar(AWAR_SC_METHOD)->read_int());
1029
1030    saicalc_edit_method_cb(awr, false); // switch config window (if any is shown)
1031
1032    // map AWAR_SC_METHOD_CONFIG to type-specific awar:
1033    const char *currCfg = NULp;
1034    switch (type) {
1035        case SOP_ACI:
1036            currCfg = AWAR_SC_ACI_CONFIG;
1037            break;
1038        case SOP_MATRIX:
1039            currCfg = AWAR_SC_MATRIX_CONFIG;
1040            break;
1041        case SOP_BOOLCHAIN:
1042            currCfg = AWAR_SC_BOOL_CONFIG;
1043            break;
1044        case SOP_TRANSLATE:
1045            currCfg = AWAR_SC_TRANSLATE_CONFIG;
1046            break;
1047    }
1048
1049    AW_awar *awar_cfg          = awr->awar(AWAR_SC_METHOD_CONFIG);
1050    AW_awar *awar_specific_cfg = currCfg ? awr->awar_no_error(currCfg) : NULp;
1051
1052    if (awar_specific_cfg) {
1053        awar_cfg->map(awar_specific_cfg);
1054        awar_specific_cfg->touch(); // force reinit of temporary config awars (needed once for each method after startup)
1055    }
1056    else {
1057        awar_cfg->unmap();
1058    }
1059}
1060
1061static void calculate_sai_cb(AW_window *aww, GBDATA *gb_main) {
1062    AW_root         *awr   = aww->get_root();
1063    SaiOperatorType  type  = SaiOperatorType(awr->awar(AWAR_SC_METHOD)->read_int());
1064    SaiAliScope      scope = SaiAliScope(awr->awar(AWAR_SC_SCOPE)->read_int());
1065    SaiOperatorPtr   saiOp = createOpFromConfigAwar(type, awr->awar(AWAR_SC_METHOD_CONFIG));
1066
1067    if (saiOp.isSet()) { // otherwise createOpFromConfigAwar did show error message
1068        const char    *targetSaiName = awr->awar(AWAR_SC_TARGET_SAI)->read_char_pntr();
1069        ConstStrArray  inputSaiName;
1070        fill_with_source_sais(inputSaiName, awr);
1071
1072        SaiCalculator calculator(gb_main, inputSaiName, *saiOp, targetSaiName, scope);
1073        if (calculator.hasError()) {
1074            aw_message(calculator.getError().deliver());
1075        }
1076    }
1077}
1078
1079static void use_selected_as_target_cb(AW_window *aww) {
1080    AW_root *awr = aww->get_root();
1081    awr->awar(AWAR_SC_TARGET_SAI)->write_string(awr->awar(AWAR_SAI_NAME)->read_char_pntr());
1082}
1083
1084static void SAI_init_calculator_awars(AW_root *awr) {
1085    awr->awar_string(AWAR_SC_TARGET_SAI,      "", AW_ROOT_DEFAULT);
1086    awr->awar_string(AWAR_SC_SOURCE_SAI_LIST, "", AW_ROOT_DEFAULT);
1087    awr->awar_string(AWAR_SC_METHOD_CONFIG,   "", AW_ROOT_DEFAULT); // no callback needed. only mapped to type-specific configs.
1088
1089    awr->awar_int(AWAR_SC_METHOD, SOP_TRANSLATE, AW_ROOT_DEFAULT)->add_callback(calc_method_changed_cb);
1090    awr->awar_int(AWAR_SC_SCOPE,  SAS_SELECTED,  AW_ROOT_DEFAULT);
1091
1092    // init translator awars:
1093    for (int i = 0; i<TRANSLATION_RULES; ++i) {
1094        awr->awar_string(awar_translate(true,  i), "", AW_ROOT_DEFAULT)->add_callback(makeRootCallback(translate_gui_changed_cb, true,  i));
1095        awr->awar_string(awar_translate(false, i), "", AW_ROOT_DEFAULT)->add_callback(makeRootCallback(translate_gui_changed_cb, false, i));
1096    }
1097    awr->awar_string(AWAR_SC_TRANSLATE_DEFAULT, "-", AW_ROOT_DEFAULT)->add_callback(makeRootCallback(translate_gui_changed_cb, false, -1));
1098
1099    // init matrix awars:
1100    for (int x = 0; x<MATRIX_AWARS; ++x) {
1101        for (int y = 0; y<MATRIX_AWARS; ++y) {
1102            const char *awar_name = awar_matrix_cell(x, y);
1103            if (awar_name) {
1104                awr->awar_string(awar_name, "", AW_ROOT_DEFAULT)->add_callback(makeRootCallback(matrix_gui_changed_cb, x,  y));
1105            }
1106        }
1107    }
1108
1109    // init boolchain awars:
1110    awr->awar_string(AWAR_SC_BOOL_IN0, "", AW_ROOT_DEFAULT)->add_callback(makeRootCallback(inputCharsetChanged_cb, false));
1111    awr->awar_string(AWAR_SC_BOOL_IN1, "", AW_ROOT_DEFAULT)->add_callback(makeRootCallback(inputCharsetChanged_cb, true));
1112
1113    awr->awar_int(AWAR_SC_BOOL_OP, SBO_AND, AW_ROOT_DEFAULT);
1114
1115    awr->awar_string(AWAR_SC_BOOL_OUT0,     "-", AW_ROOT_DEFAULT)->add_callback(boolchain_gui_changed_cb);
1116    awr->awar_string(AWAR_SC_BOOL_OUT1,     "x", AW_ROOT_DEFAULT)->add_callback(boolchain_gui_changed_cb);
1117    awr->awar_string(AWAR_SC_BOOL_RULES,    "",  AW_ROOT_DEFAULT)->add_callback(boolchain_rulesAwar_changed_cb);
1118    awr->awar_string(AWAR_SC_BOOL_SEL_RULE, "",  AW_ROOT_DEFAULT)->add_callback(display_selected_rule_cb);
1119
1120    // init aci awars:
1121    awr->awar_string(AWAR_SC_ACI, "", AW_ROOT_DEFAULT)->add_callback(aci_gui_changed_cb);
1122
1123    // config awars:
1124    // (to update the default values of the following awars, do the following (for each calculator method):
1125    // * edit the configuration of the method (change some awar into its default value) => config-awar gets updated from other awars
1126    // * store a managed config
1127    // * edit that config and copy the value of "~config" to the corresponding default below
1128    //   (backslashes have to be escaped!)
1129    // )
1130    awr->awar_string(AWAR_SC_TRANSLATE_CONFIG, "default='-'",                                                AW_ROOT_DEFAULT)->add_callback(translate_config_changed_cb);
1131    awr->awar_string(AWAR_SC_MATRIX_CONFIG,    "col0='default=\\'-\\'';columns='1';first='default=\\'A\\''", AW_ROOT_DEFAULT)->add_callback(matrix_config_changed_cb);
1132    awr->awar_string(AWAR_SC_BOOL_CONFIG,      "out='-x';rules='0'",                                         AW_ROOT_DEFAULT)->add_callback(bool_config_changed_cb);
1133    awr->awar_string(AWAR_SC_ACI_CONFIG,       "aci=''",                                                     AW_ROOT_DEFAULT)->add_callback(aci_config_changed_cb);
1134
1135    calc_method_changed_cb(awr); // call once to initialize mapping
1136}
1137
1138void SAI_popup_calculator_window(AW_window *awp, GBDATA *gb_main) {
1139    static AW_window *aww = NULp;
1140
1141    if (!aww) {
1142        AW_window_simple *aws = new AW_window_simple;
1143
1144        AW_root *awr = awp->get_root();
1145        SAI_init_calculator_awars(awr);
1146
1147        aws->init(awr, "SAI_CALC", "SAI calculator");
1148        aws->load_xfig("saicalc.fig");
1149
1150        aws->button_length(8);
1151
1152        aws->at("close");
1153        aws->callback(AW_POPDOWN);
1154        aws->create_button("CLOSE", "CLOSE", "O");
1155
1156        aws->at("help");
1157        aws->callback(makeHelpCallback("saicalc.hlp"));
1158        aws->create_button("HELP", "HELP");
1159
1160        aws->at("avail");
1161        AW_awar      *awar_source_sai = awr->awar(AWAR_SC_SOURCE_SAI_LIST);
1162        SmartCharPtr  source_sai_list = awar_source_sai->read_string(); // temp. save value that was stored in properties (awt_create_subset_selection_list will reset awar content)
1163
1164        AW_DB_selection *all_SAI      = awt_create_SAI_selection_list(gb_main, aws, AWAR_SAI_NAME);
1165        AW_selection    *selected_SAI = awt_create_subset_selection_list(aws, all_SAI->get_sellist(), "source", "add", "sort", true, sai_seletion_changed_cb);
1166
1167        aws->at("target");
1168        aws->create_input_field(AWAR_SC_TARGET_SAI);
1169
1170        aws->at("overwrite");
1171        aws->callback(use_selected_as_target_cb);
1172        aws->create_button("OVERWRITE", "Overwrite");
1173
1174        aws->at("scope");
1175        aws->create_option_menu(AWAR_SC_SCOPE);
1176        aws->insert_default_option("Selected alignment",  "S", SAS_SELECTED);
1177        aws->insert_option        ("Existing alignments", "E", SAS_ALL);
1178        aws->insert_option        ("Common alignments",   "C", SAS_COMMON);
1179        aws->insert_option        ("Target alignments",   "C", SAS_TARGET);
1180        aws->update_option_menu();
1181
1182        aws->at("cfg");
1183        AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "saicalc", saicalc_config_mapping, NULp, saicalc_predefined_configs);
1184
1185        aws->at("method");
1186        aws->create_option_menu(AWAR_SC_METHOD);
1187        aws->insert_default_option(SaiOperator::type_name(SOP_TRANSLATE), "T", SOP_TRANSLATE);
1188        aws->insert_option        (SaiOperator::type_name(SOP_MATRIX), "M", SOP_MATRIX);
1189        aws->insert_option        (SaiOperator::type_name(SOP_BOOLCHAIN),   "B", SOP_BOOLCHAIN);
1190        aws->insert_option        (SaiOperator::type_name(SOP_ACI),      "A", SOP_ACI);
1191        aws->update_option_menu();
1192
1193        aws->at("edmeth");
1194        aws->callback(RootAsWindowCallback::reuse(makeRootCallback(saicalc_edit_method_cb, true)));
1195        aws->create_button("EDIT", "EDIT");
1196
1197        aws->at("calc");
1198        aws->callback(makeWindowCallback(calculate_sai_cb, gb_main));
1199        aws->highlight();
1200        aws->create_autosize_button("CALC", "Calculate");
1201
1202        // @@@ add way to view result (e.g. link to SAI manager?)
1203
1204
1205        awar_source_sai->add_callback(makeRootCallback(source_sai_list_changed_cb, selected_SAI));
1206        awar_source_sai->write_string(&*source_sai_list); // refill list of selected source awars
1207
1208        aww = aws;
1209    }
1210
1211    aww->activate();
1212}
1213
1214
Note: See TracBrowser for help on using the repository browser.