// Copyright (c) CNES 2008 // // This software is part of CelestLab, a CNES toolbox for Scilab // // This software is governed by the CeCILL license under French law and // abiding by the rules of distribution of free software. You can use, // modify and/ or redistribute the software under the terms of the CeCILL // license as circulated by CEA, CNRS and INRIA at the following URL // 'http://www.cecill.info'. function [varargout] = CL_inputParam(desc) // Simple user-friendly GUI for the input of parameters // // Calling Sequence // varargout = CL_inputParam(desc) // // Description // // //

CL_inputParam in an interface to x_mdialog for an enhanced input of parameters. It should be used // in conjunction with CL_defparam.

//

Enhancements include the management of units and the validation of the values (that may belong to // a set of accepted values or that can be checked using some arbitrary scilab expressions). // Any scilab expression is a valid value for CL_inputParam.

//

The number of output arguments is normally n, n being the number of parameter descriptions.

//

An additional argument may be passed. Returned values for this argument are: %t (the 'OK' button // has been pressed), and %f (the 'Cancel' button has been pressed). If only n output parameters are // present, an error is generated if the 'cancel' button has been pressed. This error may be caught // by try...catch.

//
//
// // Parameters // desc: List of parameter structures. Use CL_defParam to initialize each structure. // varargout: Output variables (1 for each parameter structure + 1 optional 'OK' output variable). The parameter values in the varargout list are given in 'internal' units. // // Authors // CNES - DCT/SB (AL) // // See also // CL_defParam // // Examples // desc=list(.. // CL_defParam("param 1", val=1000, units=['m', 'km'], valid='$x > 0'),.. // CL_defParam("param 2", val=[2,4,6], units=['Z'], valid='$x < 10', dim=[1,3]),.. // CL_defParam("param 3", val=[1,2,3,4,5,6,7,8], dim=-1, accv=1:10).. // ); // [v1, v2, v3] = CL_inputParam(desc) // error if "cancel" pressed // [v1, v2, v3, OK] = CL_inputParam(desc) // no error if "cancel" pressed // // Declarations: // Code: lhs = argn(1); if (lhs < length(desc) | lhs > length(desc)+1 ) CL__error("Wrong number of output arguments"); end // convert to string function [str] = toString(values) // convert double to string (format: %.15g) function [s] = String(x) N = size(x, "*"); if (N == 0) s = ""; elseif (N == 1) s = sprintf("%.15g", x); else s = emptystr(x); for k = 1 : N s(k) = sprintf("%.15g", x(k)); end end endfunction if (typeof(values) == 'string') str = strcat(values, " "); // add quotes around values elseif (size(values, "*") > 1) // try to pack the values using ":". NB: the order is not changed step = unique(values(2:$) - values(1:$-1)); if (length(step) == 1 & length(values) >= 5 & find(round(values) <> values) == [] & step == 1) str = String(values(1)) + " : " + String(values($)); elseif (length(step) == 1 & length(values) >= 5 & find(round(values) <> values) == [] & step * (values($) - values(1)) > 0) str = String(values(1)) + " : " + String(step) + " : " + String(values($)); else str = strcat(String(values), " "); end else str = strcat(String(values), " "); end endfunction // ajoute des quotes (OK seulement pour type string) function [val] = Quote(val) val = "''" + val + "''"; endfunction // --------------------- // prepare vectors (text + value) for x_mdialog // -> input unit added to text // -> value converted to input unit // --------------------- tab_text = []; tab_cval = []; n = length(desc); // nb of parameters for i=1:n par = desc(i); // parameter structure text = par.text; if (par.units(2) <> []) text = text + " [" + par.units(2) + "]"; end val = par.val; if (par.typ == "r" & par.unitf <> []) val = val / par.unitf; end cval = toString(val); // convert to string tab_text = [tab_text, text]; tab_cval = [tab_cval, cval]; end for i=1:n varargout(i) = []; end if (lhs == n+1) varargout(n+1) = %t; end // --------------------- // loop on x_mdialog until OK or cancel // --------------------- OK = %f; while (~OK) OK = %t; // remove t, f, T, F from values // (because are interpreted as booleans by x_mdialog) tab_cval = stripblanks(tab_cval, %t); I = find(tab_cval == "t" | tab_cval == "f" | tab_cval == "T" | tab_cval == "F"); if (I <> []) tab_cval(I) = tab_cval(I) + " ?"; end tab = x_mdialog("Parameters", tab_text, tab_cval); if (tab == []) OK = %f; break; end // --------------------- // evaluate values and identifier // --------------------- err = list(0, ""); lstval = list(); // list of values for all parameters for i=1:n par = desc(i); // description lstval(i) = []; // default value // add quotes if not real // NB: for string: considered as 1 string sctab(i) = tab(i); if (par.typ <> "r") sctab(i) = Quote(sctab(i)); end sctab(i) = '[' + sctab(i) + ']'; // add '[ ]' even if scalar // evaluates the expression execstr_status = execstr("X = " + sctab(i) + ";", "errcatch"); if (execstr_status <> 0 | (typeof(X) <> "constant" & typeof(X) <> "string")) OK = %f; err = list(i, "=> Expression ''" + tab(i) + "'' cannot be evaluated"); break; end // OK => update lstval(i) lstval(i) = X; // check dimensions dim = size(lstval(i)); // only rows accepted with correct number of values if (OK & dim <> [] & par.typ <> "cal") if (dim(1) > 1 | (par.dim <> -1 & (dim(2) < par.dim(1) | dim(2) > par.dim($)))) OK = %f; err = list(i, "=> wrong dimension or number of values"); end end // initializes identifier for later validity checking if (OK & par.id <> []) execstr_status = execstr(par.id + '=' + sctab(i), "errcatch"); if (execstr_status <> 0) OK = %f; err = list(i, "=> unable to set value to id (" + par.id + ")"); end end end // --------------------- // check types // --------------------- for i=1:n if (~OK) break; end par = desc(i); // checks real type if (OK & par.typ == "r") if (lstval(i) <> [] & typeof(lstval(i)) <> "constant") OK = %f; err = list(i, "=> Not a real number" ); break; end end // checks calendar format if (OK & par.typ == "cal") val = CL_dat_str2cal(lstval(i)); if (find(isnan(val)) <> []) OK = %f; err = list(i, "=> Not a calendar date" ); break; end end end // --------------------- // check validity conditions // --------------------- // check validity conditions (after all identifiers have been initialized) for i=1:n if (~OK) break; end par = desc(i); // check values if 'accv' defined if (OK & ~isempty(par.accv)) vout = setdiff(lstval(i), par.accv); // values not in par.accv if ~isempty(vout) err = list(i, "=> value not in set of possible values"); OK = %f end end // execute "valid" code // for vectors: the code applies to each component if (OK & par.valid <> []) $x = evstr(sctab(i)); if (par.dim == 1) try OK = evstr(par.valid); catch OK = %f; end else I = []; try execstr("I=find(~(" + par.valid + "))"); catch OK = %f; end if (OK & ~isempty(I) & length(lstval(i)) > 0) OK = %f end end if (~OK) err = list(i, "=> validity condition ( " + par.valid + " ) not met" ); end end end // --------------------- // end : print err msg if any // --------------------- if (~OK) num = err(1); msg = ["Parameter ''" + tab_text(num) + "'' : invalid value", err(2)]; msg = strsubst(msg, '<', '<'); msg = strsubst(msg, '>', '>'); messagebox(msg, "modal"); for i=1:n tab_cval(i) = tab(i); end end end if (~OK) if (lhs == n+1) varargout(n+1) = %f; else CL__error("Cancelled!"); end else for i=1:n par = desc(i); if (par.typ == "r" & par.unitf <> []) lstval(i) = lstval(i) * par.unitf; end varargout(i) = lstval(i); end end endfunction