/
ParamsHelper.h
1072 lines (932 loc) · 37.2 KB
/
ParamsHelper.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/****************************************************************************
* Copyright (c) 2017 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
****************************************************************************/
#ifndef PARAMS_HELPER_H
#define PARAMS_HELPER_H
/** \page ParamPage Parameter helper macros
* \ingroup PATH
* Collections of macros for managing groups of parameters.
*
* \section Motivation
*
* For an application like FreeCAD, there are often cases where the same set of
* parameters are referred in dozons of different places. The macros here is
* designed to help managing those parameters, so that you can define groups of
* parameters once, and refer them everywhere in groups with simple macro calls for
* all kinds of purposes. Any changing, adding and removing of parameters in the
* group become much easier. And by everywhere, I mean \ref ParamCommon
* "class definition, implementation", \ref ParamProperty "document object properties",
* \ref ParamPy "python c++ classes", and even \ref ParamDoc "doc string",
* pretty much everything except the python code, which although not implemented
* yet, is in fact also possible to be done using C preprocessor (No one says C
* preprocessor must produce C code :). It is also possible (not implemented
* yet) to use macros to generate python wrapper class instead of using
* FreeCAD's current xml python export.
*
* \section Debugging
*
* Extensive use of macros has one noticeable disadvantage, though. If some thing
* goes wrong, the compiler error message is kind of cryptic. If so, first
* double check your macro definition of the parameter is correctly, not missing
* or having extra parathesis or comma. Then, you can use the CMake
* intermediate file target to get the preprocessor output for checking. For
* example, for a file located at \c src/Mod/Path/App/Area.cpp,
* \code{.sh}
* cd <your_build_dir>/src/Mod/Path/App
* make Area.cpp.i
* \endcode
*
* The preprocessed intermediate output will be at,
* \code{.sh}
* <your_build_dir>/src/Mod/Path/App.CMakeFiles/Path.dir/Area.cpp.i
* \endcode
*
* \section Introduction of Boost.Preprocessor
*
* The macros here make heavy use of the awesome
* [Boost.Preprocessor](http://www.boost.org/libs/preprocessor/) (short for
* Boost.PP). Here are is a brief introduction on Boost.PP concept in order to
* explain why this marco library is designed the way it is.
*
* In Boost.PP, a sequence is defined as,
* \code{.sh}
* (a)(b)(c)...
* \endcode
*
* A sequence cannot be empty. Thus, \c () is not a sequence. And also those
* <tt>a, b, c</tt> here cannot directly contain <tt>,</tt>. These restriction
* is due to the fact that <tt>( ) ,</tt> are among those very few special
* characters recognized by the preprocssor. \c a can itself be a sequence or
* other Boost.PP types, so by right, our parameter can be defined as something
* like
* \code{.sh}
* ((type)(name)(default)...)
* \endcode
*
* A bit awkward to write. So another Boost.PP type is chosen, tuple, to define
* each individual parameter. A tuple is defined as
* \code{.sh}
* (a,b,c ...)
* \endcode
*
* This is why the parameter definition requires a double parathesis, as shown
* in the following section.
*
* \section Library Overview
*
* In this macro library, a parameter is defined using a tuple inside a sequence,
* \code{.sh}
* ((<type>, <arg>, <name>, <default>, <doc>, <seq>, <info>))
* \endcode
*
* - \c type is the type of the parameter. Currently only five types of
* parameters are defined, <tt>short, long, double, bool, enum, enum2</tt>.
* \enum2 type is the same as \enum with additional information to be able to
* map to a user defined C enum type. To add more types, search this file for
* keyword \a _short, and supply all relevant macros. It's quite trivial
* actually.
*
* - \c arg is the argument name. It is intended to be used as function argument.
* By convention, the name shall be all small cases, but that's not required.
* This \c arg can be repurposed, if the parameter is not going to be used as
* function argument. The #AREA_PARAMS_CAREA parameters repurposed this field
* to CArea internal setting variables to implement save, apply and restore
* function using CAreaConfig class.
*
* - \c name is normally a %CamelCase name which are used as member variable and
* property name. Because of this, make sure the names are unique to avoid
* conflicts.
*
* - \c default is the default value of this parameter. Right now, you must
* supply a default value. Boost.PP has trouble dealing with empty values.
* Remember that a sequence cannot be empty. Neither can tuple. Only array,
* something like <tt>(0,())</tt> for an empty array. It is awkward to write,
* and didn't add much functionality I want, hence the restriction of
* non-empty defaults here.
*
* - \c doc is a string to describe the variable.
*
* - \c seq \anchor ParamSeq. Right now this field is used by \c enum and
* \c enum2 type parameter to define its enumerations. As the name suggests,
* it must be a sequence. It is not a tuple because looping through tuple is
* not as easy as sequence. Other type of parameter do not need to have this
* field
*
* - \c info is used to provide the supplimentery information for \c enum2 type
* of parameter, which can be converted to a user defined enum type by
* #PARAM_ENUM_CONVERT. \c info must be a tuple, with the user defined enum
* type as the first element, and a prefix as the second element. For \c enum2
* type of parameter, this field is mandatory.
*
* The common usage is that you define a macro of a group of parameters. And use
* the macro helper here to do operation on each parameter in the group. See
* AreaParams.h file for an example of parameter definitions.
*
* Area.h, Area.cpp, FeatureArea.h, FeatureArea.cpp for usage of variouse macros.
*
* See struct AreaDoc for an example of doc string generation.
*
* Each field of the parameter can be referred to with various
* \ref ParamAccessor "various accessor macros", and can be easily
* \ref ParamStringizer "stringified".
*
* \anchor ParamField You can also use #PARAM_FIELD(_field,_param) to refer to
* each field, where \a _field is one of <tt>TYPE, ARG, NAME, DEF, DOC, or SEQ</tt>.
* And #PARAM_FIELD_STR to stringify.
*
* Here \a _param is the parameter definition described above in the form of a
* Boost.PP tuple, and is usually supplied by various \ref ParamLooper "looper macros"
*
* You can of course directly use various Boost.PP sequence looper to pass
* additional arguments to the operation macro. See #PARAM_PY_DICT_SET_VALUE for
* an example of using tuple, and the more complex example #PARAM_ENUM_CONVERT
*
* Note that when generating comma separated list, the first and last comma are
* conveniently omitted, so that the macros can be mixed with others intuitively
*/
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq/seq.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/pop_front.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/logical/not.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/tuple/enum.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/comparison/greater.hpp>
/** \defgroup ParamHelper Parameters helper macros
* \ingroup PATH
* Collections of macros for managing groups of parameters */
/**
* \defgroup ParamAccessor Field accessors
* To abstract parameter field details
* \ingroup ParamHelper
* @{
*/
#define PARAM_ITYPE 0
#define PARAM_IARG 1
#define PARAM_INAME 2
#define PARAM_IDEF 3
#define PARAM_IDOC 4
#define PARAM_ISEQ 5
#define PARAM_IPROP 5
#define PARAM_IINFO 6
#define PARAM_FIELD(_idx,_param) BOOST_PP_TUPLE_ELEM(PARAM_I##_idx,_param)
#define PARAM_FTYPE(_param) PARAM_FIELD(TYPE,_param)
#define PARAM_FARG(_param) PARAM_FIELD(ARG,_param)
#define PARAM_FNAME(_param) PARAM_FIELD(NAME,_param)
#define PARAM_FDEF(_param) PARAM_FIELD(DEF,_param)
#define PARAM_FDOC(_param) PARAM_FIELD(DOC,_param)
#define PARAM_FSEQ(_param) PARAM_FIELD(SEQ,_param)
#define PARAM_FPROP(_param) PARAM_FIELD(PROP,_param)
#define PARAM_FINFO(_param) PARAM_FIELD(INFO,_param)
#define PARAM_FENUM_TYPE(_param) BOOST_PP_TUPLE_ELEM(0,PARAM_FINFO(_param))
#define PARAM_FENUM_PREFIX(_param) BOOST_PP_TUPLE_ELEM(1,PARAM_FINFO(_param))
/** @} */
/**
* \defgroup ParamStringizer Field stringizers
* \ingroup ParamHelper
* @{ */
#define PARAM_FIELD_STR(_idx,_param) \
BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(PARAM_I##_idx,_param))
#define PARAM_FTYPE_STR(_param) PARAM_FIELD_STR(TYPE,_param)
#define PARAM_FARG_STR(_param) PARAM_FIELD_STR(ARG,_param)
#define PARAM_FNAME_STR(_param) PARAM_FIELD_STR(NAME,_param)
#define PARAM_FDEF_STR(_param) PARAM_FIELD_STR(DEF,_param)
/** @} */
/** Helper for #PARAM_FSEQ_STR */
#define PARAM_FSEQ_STR_(_i,_elem) \
BOOST_PP_COMMA_IF(_i) BOOST_PP_STRINGIZE(_elem)
/** \c SEQ stringizer will stringify each element separately
*
* Expands to:
* #seq[0], #seq[1] ...
* \ingroup ParamHelper
*/
#define PARAM_FSEQ_STR(_param) \
PARAM_FOREACH_I(PARAM_FSEQ_STR_,PARAM_FSEQ(_param))
/** \defgroup ParamLooper Looper macros
* Macros for looping through sequence to parameters
* \ingroup ParamHelper
*/
/** Helper for #PARAM_FOREACH */
#define PARAM_FOREACH_(_,_op,_param) _op(_param)
/** Apply macro \a _op to each parameter in sequence \a _seq
*
* Operation macro \a _op should be defined as,
* \code
* _op(_param)
* \endcode
* \ingroup ParamLooper
*/
#define PARAM_FOREACH(_op,_seq) \
BOOST_PP_SEQ_FOR_EACH(PARAM_FOREACH_,_op,_seq)
/** Helper for #PARAM_FOREACH_I */
#define PARAM_FOREACH_I_(_,_op,_i,_param) _op(_i,_param)
/** Apply macro \a _op to each parameter in sequence \a _seq with additional index
*
* Operation macro \a _op should be defined as,
* \code
* _op(_i,_param)
* \endcode
* \ingroup ParamLooper
* */
#define PARAM_FOREACH_I(_op,_seq) \
BOOST_PP_SEQ_FOR_EACH_I(PARAM_FOREACH_I_,_op,_seq)
/** Helper for #PARAM_TYPED_FOREACH */
#define PARAM_TYPED_FOREACH_(_1,_op,_param) \
PARAM_TYPED(_op,_param)(_param)
/** Type depended macro construction
*
* Convert macro \a _op to \a _op##\<type\>. Note that it only converts the
* macro name, not contsucts a macro call. To expand to a macro call, simply
* \code
* PARAM_TYPED(_op,_param)(_param)
* \endcode
* \ingroup ParamLooper
*/
#define PARAM_TYPED(_op,_param) \
BOOST_PP_CAT(_op,PARAM_FTYPE(_param))
/** Apply type dependent macro call to a sequence of parameters
*
* \a _op will be converted to \a _op##\<type\> for each parameter
* \ingroup ParamLooper
*/
#define PARAM_TYPED_FOREACH(_op,_seq) \
BOOST_PP_SEQ_FOR_EACH(PARAM_TYPED_FOREACH_,_op,_seq)
/** \defgroup ParamCommon Common helpers
* \ingroup ParamHelper
*/
#define PARAM_TYPE_short short
#define PARAM_TYPE_long long
#define PARAM_TYPE_double double
#define PARAM_TYPE_bool bool
#define PARAM_TYPE_enum short
#define PARAM_TYPE_enum2 short
/** Obtain parameter type
*
* The main purpose is to alias enum type to short
* \ingroup ParamCommon
*/
#define PARAM_TYPE(_param) \
PARAM_TYPED(PARAM_TYPE_,_param)
/** Helper for #PARAM_DECLARE */
#define PARAM_DECLARE_(_1,_src,_param) \
PARAM_TYPE(_param) _src(_param);
/**
* Declares parameters using the given field as name
*
* \arg \c _src: \anchor ParamSrc Macro to generate source variable. The
* signature must be <tt>_src(_param)<\tt>, where \c _param is the tuple
* defining the parameter. You pass any of the \ref ParamAccessor "parameter
* accessors" to directly access the field. Or, supply your own macro to append
* any prefix as you like. For example:
* \code{.unparsed}
* #define MY_SRC(_param) BOOST_PP_CAT(my,PARAM_FNAME(_param))
* ->
* my##<name>
* \endcode
*
* Expands to:
* \code{.unparsed}
* type1 _src(_param1);type2 _src(_param2); ...
* \endcode
* \ingroup ParamCommon
*/
#define PARAM_DECLARE(_src,_seq) \
BOOST_PP_SEQ_FOR_EACH(PARAM_DECLARE_,_src,_seq)
/** Helper for #PARAM_DECLARE_INIT */
#define PARAM_DECLARE_INIT_(_1,_src,_param) \
PARAM_TYPE(_param) _src(_param) = PARAM_FDEF(_param);
/**
* Declares parameters with initialization to default using the given field as
* name
*
* \arg \c _src: macro to generate source field. See \ref ParamSrc "here" for
* more details
*
* Expands to:
* \code{.unparsed}
* type1 _src(_param1)=_def1;type2 _src(_param2)=_def2; ...
* \endcode
* \ingroup ParamCommon
*/
#define PARAM_DECLARE_INIT(_src,_seq) \
BOOST_PP_SEQ_FOR_EACH(PARAM_DECLARE_INIT_,_src,_seq)
#define PARAM_ENUM_DECLARE_enum_(_1,_name,_i,_elem) \
BOOST_PP_COMMA_IF(_i) BOOST_PP_CAT(_name,_elem)
#define PARAM_ENUM_DECLARE_enum(_param) \
enum {BOOST_PP_SEQ_FOR_EACH_I(PARAM_ENUM_DECLARE_enum_,PARAM_FNAME(_param),PARAM_FSEQ(_param))};
#define PARAM_ENUM_DECLARE_short(_param)
#define PARAM_ENUM_DECLARE_long(_param)
#define PARAM_ENUM_DECLARE_double(_param)
#define PARAM_ENUM_DECLARE_bool(_param)
#define PARAM_ENUM_DECLARE_enum2 PARAM_ENUM_DECLARE_enum
/** \defgroup ParamEnumHelper Enum convert helpers
* \ingroup ParamCommon
*/
/** Make anonymous \c enum type
*
* Make anonymous \c enum type for \c enum type parameters in \a _seq. All other
* types are ignored. The enum member is prefixed with \a _name. Expand to:
* \code{.unparsed}
* enum {_name1##_seq1[0], _name1##_seq1[1] ...};
* enum {_name2##_seq2[0], _name2##_seq2[1] ...};
* ...
* \endcode
* \ingroup ParamEnumHelper*/
#define PARAM_ENUM_DECLARE(_seq) \
PARAM_TYPED_FOREACH(PARAM_ENUM_DECLARE_,_seq)
/** \addgroup ParamEnumHelper Enum convert helpers
* @{ */
#define PARAM_ENUM_CONVERT_short(...)
#define PARAM_ENUM_CONVERT_long(...)
#define PARAM_ENUM_CONVERT_double(...)
#define PARAM_ENUM_CONVERT_bool(...)
#define PARAM_ENUM_CONVERT_enum(...)
#define PARAM_ENUM_CONVERT_enum2 PARAM_ENUM_CONVERT_SINGLE
#define PARAM_ENUM_CONVERT_enum_(_dst,_name,_prefix,_elem) \
case BOOST_PP_CAT(_name,_elem):\
_dst = BOOST_PP_CAT(_prefix,_elem);\
break;
#define PARAM_ENUM_CONVERT__(_1,_args,_i,_elem) \
PARAM_ENUM_CONVERT_enum_(BOOST_PP_TUPLE_ELEM(0,_args),\
BOOST_PP_TUPLE_ELEM(1,_args),\
BOOST_PP_TUPLE_ELEM(2,_args),\
_elem);
#define PARAM_ENUM_CONVERT_(_1,_args,_param) \
PARAM_TYPED(PARAM_ENUM_CONVERT_,_param)(BOOST_PP_TUPLE_ELEM(0,_args),\
BOOST_PP_TUPLE_ELEM(1,_args),\
BOOST_PP_TUPLE_ELEM(2,_args),\
_param)
/** Convert single enum parameter value into user defined enum type
*
* This macro is used by #PARAM_ENUM_CONVERT to convert each parameter, but
* you can use it directly for a single parameter. Check #PARAM_NUM_CONVERT
* for more detail. Make sure the outer parathesis of \c _param is stripped,
* i.e. not double but single parathesis
*/
#define PARAM_ENUM_CONVERT_SINGLE(_src,_dst,_default,_param) \
PARAM_FENUM_TYPE(_param) _dst(_param);\
switch(_src(_param)) {\
BOOST_PP_SEQ_FOR_EACH_I(PARAM_ENUM_CONVERT__,\
(_dst(_param),PARAM_FNAME(_param),PARAM_FENUM_PREFIX(_param)),PARAM_FSEQ(_param))\
default: \
_default(_param);\
}
/** Default handling in #PARAM_ENUM_CONVERT and #PARAM_ENUM_CHECK*/
#define PARAM_ENUM_EXCEPT(_param) \
throw Base::ValueError("invalid value for enum " PARAM_FNAME_STR(_param))
/** @} */
/* Convert ParamHelper defined enum type to user defined ones
*
* This assumes the user defined enum type is given in \ref ParamSeq "seq_type"
* of the parameter definition, and it has the same postfix as the ones
* specified in \ref ParamSeq "seq" member of the parameter definition. See
* \ref ParamEnumHelper "here" for implementations
*
* \ingroup ParamEnumHelper
*
* \arg \c _src: Macro to generate source variable. The signature must be
* <tt>_src(_param)<\tt>, where \c _param is the tuple defining the parameter.
* You pass any of the \ref ParamAccessor "parameter accessors" to directly
* access the field. Or, supply your own macro to append any prefix as you
* like.
* \arg \c _dst: Same as above.
* \arg \c _default: A macro to call for invalid value. Signature should be
* <tt>_default(_param)<\tt>, where \c _param is the parameter definition. You
* can use #PARAM_ENUM_EXCEPT to throw Base::ValueError exception in FreeCAD
* \arg \c _seq: Parameter sequence
*
* For example, with the following parameter definition
* \code{.unparsed}
* #define MY_PARAM_TEST \
* ((enum,test1,Test1,0,"it's a test",(Foo)(Bar),(MyEnum1,myEnum1)) \
* ((enum,test2,Test2,0,"it's a test",(Foo)(Bar),(MyEnum2,myEnum2)))
*
* #define MY_DST(_param) BOOST_PP_CAT(my,PARAM_FNAME(_param))
* \code{.unparsed}
*
* calling
* \code{.unparsed}
* PARAM_ENUM_CONVERT(PARAM_FNAME,MY_DST,My,PARAM_ENUM_EXCEP,MY_PARAM_TEST)
* \code{.unparsed}
*
* expands to
* \code{.unparsed}
* MyEnum1 myTest1;
* switch(Test1) {
* case Test1Foo:
* myTest1 = myEnum1Foo;
* break;
* case Test1Bar:
* myTest1 = myEnum1Bar;
* break;
* default:
* throw Base::ValueError("invalid value for enum Test1");
* }
* MyEnum2 myTest2;
* switch(Test2) {
* case Test1Foo:
* myTest2 = myEnum2Foo;
* break;
* case Test2Bar:
* myTest2 = myEnum2Bar;
* break;
* default:
* throw Base::ValueError("invalid value for enum Test2");
* }
* \endcode
*
* The above code assumes you've already defined \a Test1 and \a Test2 some
* where as the source variable.
*/
#define PARAM_ENUM_CONVERT(_src,_dst,_default,_seq) \
BOOST_PP_SEQ_FOR_EACH(PARAM_ENUM_CONVERT_,(_src,_dst,_default),_seq)
#define PARAM_ENUM_CHECK_short(...)
#define PARAM_ENUM_CHECK_long(...)
#define PARAM_ENUM_CHECK_double(...)
#define PARAM_ENUM_CHECK_bool(...)
#define PARAM_ENUM_CHECK_enum PARAM_ENUM_CHECK_SINGLE
#define PARAM_ENUM_CHECK_enum2 PARAM_ENUM_CHECK_SINGLE
#define PARAM_ENUM_CHECK_enum_(_1,_name,_i,_elem) \
case BOOST_PP_CAT(_name,_elem): break;
#define PARAM_ENUM_CHECK_(_1,_args,_param) \
PARAM_TYPED(PARAM_ENUM_CHECK_,_param)(BOOST_PP_TUPLE_ELEM(0,_args),\
BOOST_PP_TUPLE_ELEM(1,_args),\
_param)
#define PARAM_ENUM_CHECK_SINGLE(_src,_default,_param) \
switch(_src(_param)) {\
BOOST_PP_SEQ_FOR_EACH_I(PARAM_ENUM_CHECK_enum_,\
PARAM_FNAME(_param),PARAM_FSEQ(_param))\
default: \
_default(_param);\
}
/* Validate enum type parameters
*
* This macro validates the value a variable of enum type parameters. See
* similar macro #PARAM_ENUM_CONVERT for detail usage.
*
* \ingroup ParamEnumHelper
*
* \arg \c _src: Macro to generate source variable. The signature must be
* <tt>_src(_param)<\tt>, where \c _param is the tuple defining the parameter.
* You pass any of the \ref ParamAccessor "parameter accessors" to directly
* access the field. Or, supply your own macro to append any prefix as you
* like.
*
* \arg \c _default: A macro to call for invalid value. Signature should be
* <tt>_default(_param)<\tt>, where \c _param is the parameter definition. You
* can use #PARAM_ENUM_EXCEPT to throw Base::ValueError exception in FreeCAD
*
* \arg \c _seq: Parameter sequence
*/
#define PARAM_ENUM_CHECK(_src,_default,_seq) \
BOOST_PP_SEQ_FOR_EACH(PARAM_ENUM_CHECK_,(_src,_default),_seq)
#define PARAM_ENUM_STRING_DECLARE_short(...)
#define PARAM_ENUM_STRING_DECLARE_long(...)
#define PARAM_ENUM_STRING_DECLARE_double(...)
#define PARAM_ENUM_STRING_DECLARE_bool(...)
#define PARAM_ENUM_STRING_DECLARE_enum2 PARAM_ENUM_STRING_DECLARE_enum
/** Helper for #PARAM_ENUM_STRING_DECLARE */
#define PARAM_ENUM_STRING_DECLARE_enum(_prefix,_param) \
BOOST_PP_CAT(_prefix,PARAM_FNAME(_param))[] = {PARAM_FSEQ_STR(_param),NULL};
/** Helper for #PARAM_ENUM_STRING_DECLARE */
#define PARAM_ENUM_STRING_DECLARE_(_1,_prefix,_param) \
PARAM_TYPED(PARAM_ENUM_STRING_DECLARE_,_param)(_prefix,_param)
/** Make \c enum string list
*
* Roughly translated:
* \code{.unparsed}
* _prefix##_name1[] = {#seq1[0], #seq1[1], ...,NULL};
* _prefix##_name2[] = {#seq2[0], #seq2[1], ...,NULL};
* ...
* \endcode
* Example usage:
* PARAM_ENUM_STRING_DECLARE(static const char *Enum, MyParamsSeq)
* \ingroup ParamEnumHelper
*/
#define PARAM_ENUM_STRING_DECLARE(_prefix,_seq) \
BOOST_PP_SEQ_FOR_EACH(PARAM_ENUM_STRING_DECLARE_,_prefix,_seq)
/** Helper for #PARAM_INIT */
#define PARAM_INIT_(_,_src,_i,_param) \
BOOST_PP_COMMA_IF(_i) _src(_param)(PARAM_FDEF(_param))
/** Constructor initialization
*
* \arg \c _src: macro to generate source field. See \ref ParamSrc "here" for
* more details
*
* Expand to,
* \code{.unparsed}
* _src(_param1)(def1), _src(_param1)(def2)...
* \endcode
* \ingroup ParamCommon
*/
#define PARAM_INIT(_src,_seq) \
BOOST_PP_SEQ_FOR_EACH_I(PARAM_INIT_,_src,_seq)
/** Helper for #PARAM_OP */
#define PARAM_OP_(_,_args,_param) \
BOOST_PP_TUPLE_ELEM(0,_args)(_param) BOOST_PP_TUPLE_ELEM(1,_args) \
BOOST_PP_TUPLE_ELEM(2,_args)(_param);
/** Perform operation on two instance of each parameter in a sequence
*
* \arg \c _src: Macro to generate source variable. The signature must be
* <tt>_src(_param)<\tt>, where \c _param is the tuple defining the parameter.
* You pass any of the \ref ParamAccessor "parameter accessors" to directly
* access the field. Or, supply your own macro to append any prefix as you
* like.
* \arg \c _op: a boolean operator
* \arg \c _dst: Same as \c _src above.
*
* Expands to:
* \code{.unparsed}
* _src(_param1) _op _src(_param2);
* \endcode
*
* \ingroup ParamCommon
*/
#define PARAM_OP(_src,_op,_dst,_seq) \
BOOST_PP_SEQ_FOR_EACH(PARAM_COPY_,(_src,_op,_dst),_seq)
/** Helper for #PARAM_ARGS_DEF */
#define PARAM_ARGS_DEF_(_,_src,_i,_param) \
BOOST_PP_COMMA_IF(_i) PARAM_TYPE(_param) _src(_param)=PARAM_FDEF(_param)
/** Declare the parameters as function argument list with defaults.
*
* \arg \c _src: macro to generate source field. See \ref ParamSrc "here" for
* more details
*
* Expand to:
* \code{.unparsed}
* type1 _src(_param1)=def1, type2 _src(_param1)=def2 ...
* \endcode
* \ingroup ParamCommon
*/
#define PARAM_ARGS_DEF(_src,_seq) \
BOOST_PP_SEQ_FOR_EACH_I(PARAM_ARGS_DEF_,_src,_seq)
/** Helper for #PARAM_ARGS */
#define PARAM_ARGS_(_,_src,_i,_param) \
BOOST_PP_COMMA_IF(_i) PARAM_TYPE(_param) _src(_param)
/** Declare the parameters as function argument list without defaults.
*
* \arg \c _src: macro to generate source field. See \ref ParamSrc "here" for
* more details
*
* Expand to:
* \code{.unparsed}
* type1 _src(_param1), type2 _src(_param2) ...
* \endcode
* \ingroup ParamCommon
*/
#define PARAM_ARGS(_src,_seq) \
BOOST_PP_SEQ_FOR_EACH_I(PARAM_ARGS_,_src,_seq)
/** \defgroup ParamPy Python helper
* Helper macros for Python bindings
* \ingroup ParamHelper
*/
/** \defgroup ParamDoc Python doc helper
* Generate argument doc string for Python
* \ingroup ParamPy
*/
/** Helper for #PARAM_PY_DOC_enum */
#define PARAM_PY_DOC_enum_(_i,_elem) \
BOOST_PP_IF(_i,","," ") #_i "=" #_elem
/** Generate doc for an enum parameter */
#define PARAM_PY_DOC_enum(_field,_param) \
"\n* " PARAM_FIELD_STR(_field,_param) "(" PARAM_FDEF_STR(_param)"):" \
PARAM_FOREACH_I(PARAM_PY_DOC_enum_, PARAM_FSEQ(_param)) ". " \
PARAM_FDOC(_param) "\n"
/* Generate doc for other type of parameter */
#define PARAM_PY_DOC_short(_field,_param) \
"\n* " PARAM_FIELD_STR(_field,_param) "(" PARAM_FDEF_STR(_param)"): " \
PARAM_FDOC(_param) "\n"
#define PARAM_PY_DOC_long PARAM_PY_DOC_short
#define PARAM_PY_DOC_double PARAM_PY_DOC_short
#define PARAM_PY_DOC_bool PARAM_PY_DOC_short
#define PARAM_PY_DOC_enum2 PARAM_PY_DOC_enum
#define PARAM_PY_DOC_(_,_field,_param) \
PARAM_TYPED(PARAM_PY_DOC_,_param)(_field,_param)
/* Generate document of a sequence of parameters
* \ingroup ParamDoc
*/
#define PARAM_PY_DOC(_field,_seq) \
BOOST_PP_SEQ_FOR_EACH(PARAM_PY_DOC_,_field,_seq)
/** Helper for #PARAM_PY_ARGS_DOC */
#define PARAM_PY_ARGS_DOC_(_,_field,_i,_param) \
BOOST_PP_IF(_i,", "," ") PARAM_FIELD_STR(_field,_param) "=" PARAM_FDEF_STR(_param)
/** Generate argument list string
* \arg \c _field: specifies the \ref ParamField "field" to use as name
*
* Expand to a single string:
* \code{.unparsed}
* "_field1=_def1,_field2=_def2 ..."
* \endcode
*
* \ingroup ParamDoc
*/
#define PARAM_PY_ARGS_DOC(_field,_seq) \
BOOST_PP_SEQ_FOR_EACH_I(PARAM_PY_ARGS_DOC_,_field,_seq)
/** Helper for #PARAM_FIELDS */
#define PARAM_FIELDS_(_1,_src,_i,_param) \
BOOST_PP_COMMA_IF(_i) _src(_param)
/** Expand to a list of the given field in the parameter sequence
*
* \arg \c _src: macro to generate source field. See \ref ParamSrc "here" for
* more details
*
* For example, PARAM_FIELDS(PARAM_FARG, _seq) expands to:
* \code{.unparsed}
* arg1,arg2 ...
* \endcode
* \ingroup ParamCommon ParamPy
*/
#define PARAM_FIELDS(_src,_seq) \
BOOST_PP_SEQ_FOR_EACH_I(PARAM_FIELDS_,_src,_seq)
#define PARAM_PY_CAST_short(_v) (_v)
#define PARAM_PY_CAST_long(_v) (_v)
#define PARAM_PY_CAST_double(_v) (_v)
#define PARAM_PY_CAST_bool(_v) ((_v)?Py_True:Py_False)
#define PARAM_PY_CAST_enum(_v) (_v)
#define PARAM_PY_CAST_enum2(_v) (_v)
#define PARAM_CAST_PY_short(_v) (_v)
#define PARAM_CAST_PY_long(_v) (_v)
#define PARAM_CAST_PY_double(_v) (_v)
#define PARAM_CAST_PY_bool(_v) (PyObject_IsTrue(_v)?true:false)
#define PARAM_CAST_PY_enum(_v) (_v)
#define PARAM_CAST_PY_enum2(_v) (_v)
/** Helper for #PARAM_PY_FIELDS */
#define PARAM_PY_FIELDS_(_1,_src,_i,_param) \
BOOST_PP_COMMA_IF(_i) PARAM_TYPED(PARAM_CAST_PY_,_param)(_src(_param))
/** Expand to a comma separated list of the given field in the sequence
*
* \arg \c _src: macro to generate source field. See \ref ParamSrc "here" for
* more details
*
* The field will be casted from python C to C type
* \ingroup ParamCommon ParamPy
*/
#define PARAM_PY_FIELDS(_src,_seq) \
BOOST_PP_SEQ_FOR_EACH_I(PARAM_PY_FIELDS_,_src,_seq)
/** Helper for #PARAM_FIELD_STRINGS */
#define PARAM_FIELD_STRINGS_(_1,_field,_i,_param) \
BOOST_PP_COMMA_IF(_i) PARAM_FIELD_STR(_field,_param)
/** Expand to a list of stringified fields
* \ingroup ParamStringizer ParamPy
*/
#define PARAM_FIELD_STRINGS(_field,_seq) \
BOOST_PP_SEQ_FOR_EACH_I(PARAM_FIELD_STRINGS_,_field,_seq)
#define PARAM_PYARG_short "h"
#define PARAM_PYARG_long "l"
#define PARAM_PYARG_double "d"
#define PARAM_PYARG_bool "O"
#define PARAM_PYARG_enum "h"
#define PARAM_PYARG_enum2 "h"
/** Helper for #PARAM_PY_KWDS */
#define PARAM_PY_KWDS_(_param) \
PARAM_TYPED(PARAM_PYARG_,_param)
/** Generate a format string for kewords based argument
* \ingroup ParamPy
*/
#define PARAM_PY_KWDS(_seq) \
PARAM_FOREACH(PARAM_PY_KWDS_,_seq)
#define PARAM_PY_TYPE_short short
#define PARAM_PY_TYPE_long long
#define PARAM_PY_TYPE_double double
#define PARAM_PY_TYPE_bool PyObject*
#define PARAM_PY_TYPE_enum short
#define PARAM_PY_TYPE_enum2 short
/** Helper for #PARAM_PY_DECLARE */
#define PARAM_PY_DECLARE_(_1,_src,_param) \
PARAM_TYPED(PARAM_PY_TYPE_,_param) _src(_param);
/** Declare field variables for Python C type without initialization
* \ingroup ParamPy
*/
#define PARAM_PY_DECLARE(_src,_seq) \
BOOST_PP_SEQ_FOR_EACH(PARAM_PY_DECLARE_,_src,_seq)
#define PARAM_PY_INIT_short(_v) _v
#define PARAM_PY_INIT_long(_v) _v
#define PARAM_PY_INIT_double(_v) _v
#define PARAM_PY_INIT_bool(_v) ((_v)?Py_True:Py_False)
#define PARAM_PY_INIT_enum(_v) _v
#define PARAM_PY_INIT_enum2(_v) _v
/** Helper for #PARAM_PY_DECLARE_INIT */
#define PARAM_PY_DECLARE_INIT_(_1,_src,_param) \
PARAM_TYPED(PARAM_PY_TYPE_,_param) _src(_param) = \
PARAM_TYPED(PARAM_PY_INIT_,_param)(PARAM_FDEF(_param));
/** Declare field variables of Python c type with initialization to default
* \ingroup ParamPy
*/
#define PARAM_PY_DECLARE_INIT(_src,_seq) \
BOOST_PP_SEQ_FOR_EACH(PARAM_PY_DECLARE_INIT_,_src,_seq)
/** Helper for #PARAM_REF */
#define PARAM_REF_(_1,_src,_i,_param) \
BOOST_PP_COMMA_IF(_i) &_src(_param)
/** Generate a list of field references
*
* \arg \c _src: macro to generate source field. See \ref ParamSrc "here" for
*
* more details
* Expand to:
* \code{.unparsed}
* &_src(_param1), &_src(_param1) ...
* \endcode
* \ingroup ParamPy
*/
#define PARAM_REF(_src,_seq) \
BOOST_PP_SEQ_FOR_EACH_I(PARAM_REF_,_src,_seq)
#if PY_MAJOR_VERSION < 3
#define PARAM_CAST_PYOBJ_short(_v) PyInt_FromLong(_v)
#define PARAM_CAST_PYOBJ_long(_v) PyInt_FromLong(_v)
#else
#define PARAM_CAST_PYOBJ_short(_v) PyLong_FromLong(_v)
#define PARAM_CAST_PYOBJ_long(_v) PyLong_FromLong(_v)
#endif
#define PARAM_CAST_PYOBJ_double(_v) PyFloat_FromDouble(_v)
#define PARAM_CAST_PYOBJ_bool(_v) ((_v)?Py_True:Py_False)
#define PARAM_CAST_PYOBJ_enum PARAM_CAST_PYOBJ_short
#define PARAM_CAST_PYOBJ_enum2 PARAM_CAST_PYOBJ_short
/** Stringize field to a Python string
* \ingroup ParamPy ParamStringizer
*/
#if PY_MAJOR_VERSION < 3
#define PARAM_PY_STR(_field,_param) \
PyString_FromString(PARAM_FIELD_STR(_field,_param))
#else
#define PARAM_PY_STR(_field,_param) \
PyUnicode_FromString(PARAM_FIELD_STR(_field,_param))
#endif
/** Helper for #PARAM_PY_DICT_SET_VALUE */
#define PARAM_PY_DICT_SET_VALUE_(_1,_args,_param) \
PyDict_SetItem(BOOST_PP_TUPLE_ELEM(0,_args), \
PARAM_PY_STR(BOOST_PP_TUPLE_ELEM(1,_args),_param),\
PARAM_TYPED(PARAM_CAST_PYOBJ_,_param)(\
BOOST_PP_TUPLE_ELEM(2,_args)(_param)));
/** Populate a Python dict with a structure variable
*
* \arg \c _dict: the Python dictionary object
* \arg \c _field: specifies the \ref ParamField "field" to use as key
* \arg \c _src: macro to generate source field. See \ref ParamSrc "here" for
* more details
*
* Roughly translated to:
* \code{.unparsed}
* PyDict_SetItem(_dict,#_field1,_src(_param));
* PyDict_SetItem(_dict,#_field2,_src(_param));
* ...
* \endcode
* \ingroup ParamPy
*/
#define PARAM_PY_DICT_SET_VALUE(_dict,_field,_src,_seq) \
BOOST_PP_SEQ_FOR_EACH(PARAM_PY_DICT_SET_VALUE_,(_dict,_field,_src),_seq)
#define PARAM_PY_DICT_DOC_enum_(_i,_elem) \
BOOST_PP_IF(_i,","," ") #_i "=" #_elem
/** Generate doc for an enum parameter */
#define PARAM_PY_DICT_DOC_enum(_param) \
"(" PARAM_FDEF_STR(_param) ") - " \
PARAM_FOREACH_I(PARAM_PY_DOC_enum_, PARAM_FSEQ(_param)) ".\n" \
PARAM_FDOC(_param) "\n"
/* Generate doc for other type of parameter */
#define PARAM_PY_DICT_DOC_(_param) \
"(" PARAM_FDEF_STR(_param) ") - " PARAM_FDOC(_param) "\n"
#define PARAM_PY_DICT_DOC_short PARAM_PY_DICT_DOC_
#define PARAM_PY_DICT_DOC_long PARAM_PY_DICT_DOC_
#define PARAM_PY_DICT_DOC_double PARAM_PY_DICT_DOC_
#define PARAM_PY_DICT_DOC_bool PARAM_PY_DICT_DOC_
#define PARAM_PY_DICT_DOC_enum2 PARAM_PY_DICT_DOC_enum
/** Helper for #PARAM_PY_DICT_SET_DOC */
#if PY_MAJOR_VERSION < 3
#define PARAM_PY_DICT_SET_DOC_(_1,_args,_param) \
PyDict_SetItem(BOOST_PP_TUPLE_ELEM(0,_args), \
PARAM_PY_STR(BOOST_PP_TUPLE_ELEM(1,_args),_param),\
PyString_FromString(PARAM_TYPED(PARAM_PY_DICT_DOC_,_param)(_param)));
#else
#define PARAM_PY_DICT_SET_DOC_(_1,_args,_param) \
PyDict_SetItem(BOOST_PP_TUPLE_ELEM(0,_args), \
PARAM_PY_STR(BOOST_PP_TUPLE_ELEM(1,_args),_param),\
PyUnicode_FromString(PARAM_TYPED(PARAM_PY_DICT_DOC_,_param)(_param)));
#endif
/** Populate a Python dict with the doc field of the parameter sequence
*
* \arg \c _dict: the Python dictionary object
* \arg \c _field: specifies the \ref ParamField "field" to use as key
*
* Roughly translated to:
* \code{.unparsed}
* PyDict_SetItem(_dict,#_field1,doc1);
* PyDict_SetItem(_dict,#_field1,doc2);
* ...
* \endcode
* \ingroup ParamDoc
*/
#define PARAM_PY_DICT_SET_DOC(_dict,_field,_seq) \
BOOST_PP_SEQ_FOR_EACH(PARAM_PY_DICT_SET_DOC_,(_dict,_field),_seq)
/** \defgroup ParamProperty Property Macros
* Helper macros for FreeCAD properties
* \ingroup ParamHelper
* @{*/
#define PARAM_PROP_bool(_param) App::PropertyBool PARAM_FNAME(_param)
#define PARAM_PROP_double(_param) PARAM_FPROP(_param) PARAM_FNAME(_param)
#define PARAM_PROP_short(_param) App::PropertyInteger PARAM_FNAME(_param)
#define PARAM_PROP_long(_param) App::PropertyInteger PARAM_FNAME(_param)
#define PARAM_PROP_enum(_param) App::PropertyEnumeration PARAM_FNAME(_param)
#define PARAM_PROP_enum2(_param) App::PropertyEnumeration PARAM_FNAME(_param)
/** @} */
/** Helper for #PARAM_PROP_DECLARE */
#define PARAM_PROP_DECLARE_(_param) \
PARAM_TYPED(PARAM_PROP_,_param)(_param);
/** Declare FreeCAD properties
* \ingroup ParamProperty
*/
#define PARAM_PROP_DECLARE(_seq) \
PARAM_FOREACH(PARAM_PROP_DECLARE_,_seq)
/** Replace FreeCAD #ADD_PROPERTY_TYPE to fix singifying macro */
#define PARAM_ADD_PROPERTY_TYPE(_prop_, _defaultval_, _group_,_type_,_Docu_) \
do { \
this->_prop_.setValue _defaultval_;\
this->_prop_.setContainer(this); \
propertyData.addProperty(static_cast<App::PropertyContainer*>(this), BOOST_PP_STRINGIZE(_prop_), &this->_prop_, (_group_),(_type_),(_Docu_)); \
} while (0)
/** Generic property adding */
#define PARAM_PROP_ADD_(_group,_param) \
PARAM_ADD_PROPERTY_TYPE(PARAM_FNAME(_param), (PARAM_FDEF(_param)),\
_group,App::Prop_None,PARAM_FDOC(_param));
#define PARAM_PROP_ADD_short PARAM_PROP_ADD_
#define PARAM_PROP_ADD_long PARAM_PROP_ADD_
#define PARAM_PROP_ADD_double PARAM_PROP_ADD_