summaryrefslogtreecommitdiffstats
path: root/kig
diff options
context:
space:
mode:
Diffstat (limited to 'kig')
-rw-r--r--kig/AUTHORS1
-rw-r--r--kig/COPYING339
-rw-r--r--kig/ChangeLog1600
-rw-r--r--kig/DESIGN275
-rw-r--r--kig/FEATURES44
-rw-r--r--kig/Makefile.am58
-rw-r--r--kig/README.Developers46
-rw-r--r--kig/README.boost-python1.30-gcc3.219
-rw-r--r--kig/README.in9
-rw-r--r--kig/TODO157
-rw-r--r--kig/VERSION.in1
-rw-r--r--kig/boost-python1.30-gcc3.2.patch13
-rw-r--r--kig/configure.in.bot40
-rw-r--r--kig/configure.in.in251
-rw-r--r--kig/data/Makefile.am3
-rw-r--r--kig/data/tips57
-rw-r--r--kig/examples/Makefile.am11
-rw-r--r--kig/examples/cubic-locus.kig91
-rw-r--r--kig/examples/ellipse.kig29
-rw-r--r--kig/examples/figure_angle.fgeo30
-rw-r--r--kig/examples/figure_manyobjects.fgeo72
-rw-r--r--kig/examples/fregier.kigt61
-rw-r--r--kig/examples/locustest.kig116
-rw-r--r--kig/examples/parabolaBDF.kigt28
-rw-r--r--kig/examples/session_alotofthings.fgeo162
-rw-r--r--kig/examples/sine-curve.kig55
-rw-r--r--kig/examples/sine-curve.pngbin0 -> 49486 bytes
-rw-r--r--kig/examples/trifolium-of-delongchamps.kig163
-rw-r--r--kig/filters/Makefile.am38
-rw-r--r--kig/filters/cabri-filter.cc577
-rw-r--r--kig/filters/cabri-filter.h55
-rw-r--r--kig/filters/drgeo-filter-chooser.cc65
-rw-r--r--kig/filters/drgeo-filter-chooser.h41
-rw-r--r--kig/filters/drgeo-filter-chooserbase.ui140
-rw-r--r--kig/filters/drgeo-filter-status.txt50
-rw-r--r--kig/filters/drgeo-filter.cc809
-rw-r--r--kig/filters/drgeo-filter.h46
-rw-r--r--kig/filters/exporter.cc624
-rw-r--r--kig/filters/exporter.h102
-rw-r--r--kig/filters/filter.cc114
-rw-r--r--kig/filters/filter.h96
-rw-r--r--kig/filters/filters-common.cc39
-rw-r--r--kig/filters/filters-common.h30
-rw-r--r--kig/filters/imageexporteroptions.cc57
-rw-r--r--kig/filters/imageexporteroptions.h45
-rw-r--r--kig/filters/imageexporteroptionsbase.ui152
-rw-r--r--kig/filters/kgeo-filter.cc374
-rw-r--r--kig/filters/kgeo-filter.h55
-rw-r--r--kig/filters/kgeo-resource.h204
-rw-r--r--kig/filters/kseg-defs.h301
-rw-r--r--kig/filters/kseg-filter-status.txt41
-rw-r--r--kig/filters/kseg-filter.cc679
-rw-r--r--kig/filters/kseg-filter.h42
-rw-r--r--kig/filters/latexexporter.cc608
-rw-r--r--kig/filters/latexexporter.h41
-rw-r--r--kig/filters/latexexporteroptions.ui69
-rw-r--r--kig/filters/native-filter.cc747
-rw-r--r--kig/filters/native-filter.h66
-rw-r--r--kig/filters/svgexporter.cc111
-rw-r--r--kig/filters/svgexporter.h41
-rw-r--r--kig/filters/svgexporteroptions.ui61
-rw-r--r--kig/filters/tests/circleBCP.FIG24
-rw-r--r--kig/filters/tests/constrainedPoint.FIG24
-rw-r--r--kig/filters/tests/cubiclineintersect.kig105
-rw-r--r--kig/filters/tests/intersectandasymptotestest.kig111
-rw-r--r--kig/filters/tests/intersection-test.segbin0 -> 484 bytes
-rw-r--r--kig/filters/tests/invisibleLine.FIG32
-rw-r--r--kig/filters/tests/lineBTP.FIG24
-rw-r--r--kig/filters/tests/linebyonepoint.FIG20
-rw-r--r--kig/filters/tests/locus.fgeo2
-rw-r--r--kig/filters/tests/lotsOfObjects.FIG148
-rw-r--r--kig/filters/tests/python-script.kig29
-rw-r--r--kig/filters/tests/radicallinestest.kig85
-rw-r--r--kig/filters/tests/stylestest.kig27
-rw-r--r--kig/filters/tests/test.kgeo145
-rw-r--r--kig/filters/tests/test.segbin0 -> 576 bytes
-rw-r--r--kig/filters/tests/testalotofeverything.kig174
-rw-r--r--kig/filters/tests/testlocuswithinvalidpoints.kig177
-rw-r--r--kig/filters/tests/testnames.kig62
-rw-r--r--kig/filters/tests/testtest.kig66
-rw-r--r--kig/filters/tests/transform-test.segbin0 -> 672 bytes
-rw-r--r--kig/filters/tests/transformlocustest.kig82
-rw-r--r--kig/gencontributors.sh9
-rw-r--r--kig/generate_todo_inc.pl26
-rw-r--r--kig/icons/Makefile.am2
-rw-r--r--kig/icons/hi16-action-kig_xfig.pngbin0 -> 788 bytes
-rw-r--r--kig/icons/hi22-action-angle.pngbin0 -> 1038 bytes
-rw-r--r--kig/icons/hi22-action-angle_bisector.pngbin0 -> 1079 bytes
-rw-r--r--kig/icons/hi22-action-angle_size.pngbin0 -> 956 bytes
-rw-r--r--kig/icons/hi22-action-arc.pngbin0 -> 713 bytes
-rw-r--r--kig/icons/hi22-action-arc_center.pngbin0 -> 844 bytes
-rw-r--r--kig/icons/hi22-action-areaCircle.pngbin0 -> 778 bytes
-rw-r--r--kig/icons/hi22-action-attacher.pngbin0 -> 855 bytes
-rw-r--r--kig/icons/hi22-action-baseCircle.pngbin0 -> 628 bytes
-rw-r--r--kig/icons/hi22-action-bisection.pngbin0 -> 656 bytes
-rw-r--r--kig/icons/hi22-action-centerofcurvature.pngbin0 -> 875 bytes
-rw-r--r--kig/icons/hi22-action-centralsymmetry.pngbin0 -> 892 bytes
-rw-r--r--kig/icons/hi22-action-circlebcl.pngbin0 -> 1086 bytes
-rw-r--r--kig/icons/hi22-action-circlebcp.pngbin0 -> 675 bytes
-rw-r--r--kig/icons/hi22-action-circlebpd.pngbin0 -> 653 bytes
-rw-r--r--kig/icons/hi22-action-circlebps.pngbin0 -> 660 bytes
-rw-r--r--kig/icons/hi22-action-circlebtp.pngbin0 -> 996 bytes
-rw-r--r--kig/icons/hi22-action-circlelineintersection.pngbin0 -> 1082 bytes
-rw-r--r--kig/icons/hi22-action-circumference.pngbin0 -> 757 bytes
-rw-r--r--kig/icons/hi22-action-conicasymptotes.pngbin0 -> 857 bytes
-rw-r--r--kig/icons/hi22-action-conicb5p.pngbin0 -> 1033 bytes
-rw-r--r--kig/icons/hi22-action-coniclineintersection.pngbin0 -> 1144 bytes
-rw-r--r--kig/icons/hi22-action-conicsradicalline.pngbin0 -> 1344 bytes
-rw-r--r--kig/icons/hi22-action-convexhull.pngbin0 -> 1204 bytes
-rw-r--r--kig/icons/hi22-action-curvelineintersection.pngbin0 -> 788 bytes
-rw-r--r--kig/icons/hi22-action-directrix.pngbin0 -> 775 bytes
-rw-r--r--kig/icons/hi22-action-distance.pngbin0 -> 467 bytes
-rw-r--r--kig/icons/hi22-action-ellipsebffp.pngbin0 -> 957 bytes
-rw-r--r--kig/icons/hi22-action-en.pngbin0 -> 381 bytes
-rw-r--r--kig/icons/hi22-action-equilateralhyperbolab4p.pngbin0 -> 944 bytes
-rw-r--r--kig/icons/hi22-action-equitriangle.pngbin0 -> 796 bytes
-rw-r--r--kig/icons/hi22-action-genericaffinity.pngbin0 -> 1098 bytes
-rw-r--r--kig/icons/hi22-action-genericprojectivity.pngbin0 -> 1195 bytes
-rw-r--r--kig/icons/hi22-action-halflinebyvector.pngbin0 -> 1009 bytes
-rw-r--r--kig/icons/hi22-action-harmonichomology.pngbin0 -> 925 bytes
-rw-r--r--kig/icons/hi22-action-hexagonbcv.pngbin0 -> 884 bytes
-rw-r--r--kig/icons/hi22-action-hyperbolabffp.pngbin0 -> 1015 bytes
-rw-r--r--kig/icons/hi22-action-intersection.pngbin0 -> 838 bytes
-rw-r--r--kig/icons/hi22-action-inversion.pngbin0 -> 1095 bytes
-rw-r--r--kig/icons/hi22-action-kig_polygon.pngbin0 -> 1068 bytes
-rw-r--r--kig/icons/hi22-action-kig_text.pngbin0 -> 753 bytes
-rw-r--r--kig/icons/hi22-action-line.pngbin0 -> 480 bytes
-rw-r--r--kig/icons/hi22-action-linebyvector.pngbin0 -> 963 bytes
-rw-r--r--kig/icons/hi22-action-locus.pngbin0 -> 1047 bytes
-rw-r--r--kig/icons/hi22-action-mirrorpoint.pngbin0 -> 496 bytes
-rw-r--r--kig/icons/hi22-action-move.pngbin0 -> 907 bytes
-rw-r--r--kig/icons/hi22-action-paint.pngbin0 -> 824 bytes
-rw-r--r--kig/icons/hi22-action-parabolabtp.pngbin0 -> 946 bytes
-rw-r--r--kig/icons/hi22-action-parallel.pngbin0 -> 897 bytes
-rw-r--r--kig/icons/hi22-action-perpendicular.pngbin0 -> 795 bytes
-rw-r--r--kig/icons/hi22-action-point.pngbin0 -> 257 bytes
-rw-r--r--kig/icons/hi22-action-pointOnLine.pngbin0 -> 557 bytes
-rw-r--r--kig/icons/hi22-action-pointxy.pngbin0 -> 564 bytes
-rw-r--r--kig/icons/hi22-action-polygonsides.pngbin0 -> 842 bytes
-rw-r--r--kig/icons/hi22-action-polygonvertices.pngbin0 -> 1124 bytes
-rw-r--r--kig/icons/hi22-action-python.pngbin0 -> 1169 bytes
-rw-r--r--kig/icons/hi22-action-radicalline.pngbin0 -> 1180 bytes
-rw-r--r--kig/icons/hi22-action-ray.pngbin0 -> 554 bytes
-rw-r--r--kig/icons/hi22-action-rotation.pngbin0 -> 1036 bytes
-rw-r--r--kig/icons/hi22-action-scale.pngbin0 -> 1103 bytes
-rw-r--r--kig/icons/hi22-action-segment.pngbin0 -> 646 bytes
-rw-r--r--kig/icons/hi22-action-segment_midpoint.pngbin0 -> 704 bytes
-rw-r--r--kig/icons/hi22-action-segmentaxis.pngbin0 -> 950 bytes
-rw-r--r--kig/icons/hi22-action-similitude.pngbin0 -> 1166 bytes
-rw-r--r--kig/icons/hi22-action-sizer.pngbin0 -> 700 bytes
-rw-r--r--kig/icons/hi22-action-slope.pngbin0 -> 560 bytes
-rw-r--r--kig/icons/hi22-action-square.pngbin0 -> 578 bytes
-rw-r--r--kig/icons/hi22-action-stretch.pngbin0 -> 1183 bytes
-rw-r--r--kig/icons/hi22-action-tangent.pngbin0 -> 843 bytes
-rw-r--r--kig/icons/hi22-action-test.pngbin0 -> 599 bytes
-rw-r--r--kig/icons/hi22-action-testcollinear.pngbin0 -> 950 bytes
-rw-r--r--kig/icons/hi22-action-testcontains.pngbin0 -> 845 bytes
-rw-r--r--kig/icons/hi22-action-testdistance.pngbin0 -> 1157 bytes
-rw-r--r--kig/icons/hi22-action-testorthogonal.pngbin0 -> 1051 bytes
-rw-r--r--kig/icons/hi22-action-testparallel.pngbin0 -> 1059 bytes
-rw-r--r--kig/icons/hi22-action-translation.pngbin0 -> 872 bytes
-rw-r--r--kig/icons/hi22-action-triangle.pngbin0 -> 908 bytes
-rw-r--r--kig/icons/hi22-action-vector.pngbin0 -> 683 bytes
-rw-r--r--kig/icons/hi22-action-vectordifference.pngbin0 -> 1054 bytes
-rw-r--r--kig/icons/hi22-action-vectorsum.pngbin0 -> 1115 bytes
-rw-r--r--kig/icons/hi22-action-view_fit_to_page.pngbin0 -> 475 bytes
-rw-r--r--kig/icons/hi22-action-w.pngbin0 -> 558 bytes
-rw-r--r--kig/icons/hi32-action-angle.pngbin0 -> 1646 bytes
-rw-r--r--kig/icons/hi32-action-angle_bisector.pngbin0 -> 1807 bytes
-rw-r--r--kig/icons/hi32-action-angle_size.pngbin0 -> 1559 bytes
-rw-r--r--kig/icons/hi32-action-arc.pngbin0 -> 1128 bytes
-rw-r--r--kig/icons/hi32-action-arc_center.pngbin0 -> 1351 bytes
-rw-r--r--kig/icons/hi32-action-areaCircle.pngbin0 -> 1174 bytes
-rw-r--r--kig/icons/hi32-action-attacher.pngbin0 -> 1376 bytes
-rw-r--r--kig/icons/hi32-action-baseCircle.pngbin0 -> 1019 bytes
-rw-r--r--kig/icons/hi32-action-bisection.pngbin0 -> 1048 bytes
-rw-r--r--kig/icons/hi32-action-centerofcurvature.pngbin0 -> 1378 bytes
-rw-r--r--kig/icons/hi32-action-centralsymmetry.pngbin0 -> 1330 bytes
-rw-r--r--kig/icons/hi32-action-circlebcl.pngbin0 -> 1314 bytes
-rw-r--r--kig/icons/hi32-action-circlebcp.pngbin0 -> 1116 bytes
-rw-r--r--kig/icons/hi32-action-circlebpd.pngbin0 -> 1049 bytes
-rw-r--r--kig/icons/hi32-action-circlebps.pngbin0 -> 1047 bytes
-rw-r--r--kig/icons/hi32-action-circlebtp.pngbin0 -> 1530 bytes
-rw-r--r--kig/icons/hi32-action-circlelineintersection.pngbin0 -> 1738 bytes
-rw-r--r--kig/icons/hi32-action-circumference.pngbin0 -> 1202 bytes
-rw-r--r--kig/icons/hi32-action-conicasymptotes.pngbin0 -> 1199 bytes
-rw-r--r--kig/icons/hi32-action-conicb5p.pngbin0 -> 1585 bytes
-rw-r--r--kig/icons/hi32-action-coniclineintersection.pngbin0 -> 1693 bytes
-rw-r--r--kig/icons/hi32-action-conicsradicalline.pngbin0 -> 2189 bytes
-rw-r--r--kig/icons/hi32-action-convexhull.pngbin0 -> 1836 bytes
-rw-r--r--kig/icons/hi32-action-curvelineintersection.pngbin0 -> 1276 bytes
-rw-r--r--kig/icons/hi32-action-directrix.pngbin0 -> 1174 bytes
-rw-r--r--kig/icons/hi32-action-distance.pngbin0 -> 787 bytes
-rw-r--r--kig/icons/hi32-action-ellipsebffp.pngbin0 -> 1448 bytes
-rw-r--r--kig/icons/hi32-action-en.pngbin0 -> 444 bytes
-rw-r--r--kig/icons/hi32-action-equilateralhyperbolab4p.pngbin0 -> 1222 bytes
-rw-r--r--kig/icons/hi32-action-equitriangle.pngbin0 -> 1192 bytes
-rw-r--r--kig/icons/hi32-action-genericaffinity.pngbin0 -> 1764 bytes
-rw-r--r--kig/icons/hi32-action-genericprojectivity.pngbin0 -> 1965 bytes
-rw-r--r--kig/icons/hi32-action-halflinebyvector.pngbin0 -> 1499 bytes
-rw-r--r--kig/icons/hi32-action-harmonichomology.pngbin0 -> 1423 bytes
-rw-r--r--kig/icons/hi32-action-hexagonbcv.pngbin0 -> 1429 bytes
-rw-r--r--kig/icons/hi32-action-hyperbolabffp.pngbin0 -> 1690 bytes
-rw-r--r--kig/icons/hi32-action-intersection.pngbin0 -> 1330 bytes
-rw-r--r--kig/icons/hi32-action-inversion.pngbin0 -> 1514 bytes
-rw-r--r--kig/icons/hi32-action-kig_polygon.pngbin0 -> 1636 bytes
-rw-r--r--kig/icons/hi32-action-kig_text.pngbin0 -> 1063 bytes
-rw-r--r--kig/icons/hi32-action-line.pngbin0 -> 715 bytes
-rw-r--r--kig/icons/hi32-action-linebyvector.pngbin0 -> 1394 bytes
-rw-r--r--kig/icons/hi32-action-locus.pngbin0 -> 1643 bytes
-rw-r--r--kig/icons/hi32-action-mirrorpoint.pngbin0 -> 875 bytes
-rw-r--r--kig/icons/hi32-action-move.pngbin0 -> 938 bytes
-rw-r--r--kig/icons/hi32-action-paint.pngbin0 -> 1303 bytes
-rw-r--r--kig/icons/hi32-action-parabolabtp.pngbin0 -> 1399 bytes
-rw-r--r--kig/icons/hi32-action-parallel.pngbin0 -> 1250 bytes
-rw-r--r--kig/icons/hi32-action-perpendicular.pngbin0 -> 1221 bytes
-rw-r--r--kig/icons/hi32-action-point.pngbin0 -> 385 bytes
-rw-r--r--kig/icons/hi32-action-pointOnLine.pngbin0 -> 858 bytes
-rw-r--r--kig/icons/hi32-action-pointxy.pngbin0 -> 793 bytes
-rw-r--r--kig/icons/hi32-action-polygonsides.pngbin0 -> 1204 bytes
-rw-r--r--kig/icons/hi32-action-polygonvertices.pngbin0 -> 1797 bytes
-rw-r--r--kig/icons/hi32-action-python.pngbin0 -> 2003 bytes
-rw-r--r--kig/icons/hi32-action-radicalline.pngbin0 -> 1676 bytes
-rw-r--r--kig/icons/hi32-action-ray.pngbin0 -> 821 bytes
-rw-r--r--kig/icons/hi32-action-rotation.pngbin0 -> 1640 bytes
-rw-r--r--kig/icons/hi32-action-scale.pngbin0 -> 1785 bytes
-rw-r--r--kig/icons/hi32-action-segment.pngbin0 -> 942 bytes
-rw-r--r--kig/icons/hi32-action-segment_midpoint.pngbin0 -> 1064 bytes
-rw-r--r--kig/icons/hi32-action-segmentaxis.pngbin0 -> 1407 bytes
-rw-r--r--kig/icons/hi32-action-similitude.pngbin0 -> 1730 bytes
-rw-r--r--kig/icons/hi32-action-sizer.pngbin0 -> 779 bytes
-rw-r--r--kig/icons/hi32-action-slope.pngbin0 -> 772 bytes
-rw-r--r--kig/icons/hi32-action-square.pngbin0 -> 843 bytes
-rw-r--r--kig/icons/hi32-action-stretch.pngbin0 -> 2020 bytes
-rw-r--r--kig/icons/hi32-action-tangent.pngbin0 -> 1308 bytes
-rw-r--r--kig/icons/hi32-action-test.pngbin0 -> 855 bytes
-rw-r--r--kig/icons/hi32-action-testcollinear.pngbin0 -> 1543 bytes
-rw-r--r--kig/icons/hi32-action-testcontains.pngbin0 -> 1344 bytes
-rw-r--r--kig/icons/hi32-action-testdistance.pngbin0 -> 1771 bytes
-rw-r--r--kig/icons/hi32-action-testorthogonal.pngbin0 -> 1577 bytes
-rw-r--r--kig/icons/hi32-action-testparallel.pngbin0 -> 1591 bytes
-rw-r--r--kig/icons/hi32-action-translation.pngbin0 -> 1266 bytes
-rw-r--r--kig/icons/hi32-action-triangle.pngbin0 -> 1324 bytes
-rw-r--r--kig/icons/hi32-action-vector.pngbin0 -> 1011 bytes
-rw-r--r--kig/icons/hi32-action-vectordifference.pngbin0 -> 1710 bytes
-rw-r--r--kig/icons/hi32-action-vectorsum.pngbin0 -> 1741 bytes
-rw-r--r--kig/icons/hi32-action-w.pngbin0 -> 714 bytes
-rw-r--r--kig/icons/hisc-action-angle.svgzbin0 -> 2190 bytes
-rw-r--r--kig/icons/hisc-action-angle_bisector.svgzbin0 -> 2268 bytes
-rw-r--r--kig/icons/hisc-action-angle_size.svgzbin0 -> 2085 bytes
-rw-r--r--kig/icons/hisc-action-arc.svgzbin0 -> 2013 bytes
-rw-r--r--kig/icons/hisc-action-arc_center.svgzbin0 -> 2125 bytes
-rw-r--r--kig/icons/hisc-action-areaCircle.svgzbin0 -> 2069 bytes
-rw-r--r--kig/icons/hisc-action-attacher.svgzbin0 -> 1777 bytes
-rw-r--r--kig/icons/hisc-action-baseCircle.svgzbin0 -> 1580 bytes
-rw-r--r--kig/icons/hisc-action-bisection.svgzbin0 -> 1528 bytes
-rw-r--r--kig/icons/hisc-action-centerofcurvature.svgzbin0 -> 1686 bytes
-rw-r--r--kig/icons/hisc-action-centralsymmetry.svgzbin0 -> 1777 bytes
-rw-r--r--kig/icons/hisc-action-circlebcl.svgzbin0 -> 1664 bytes
-rw-r--r--kig/icons/hisc-action-circlebcp.svgzbin0 -> 1718 bytes
-rw-r--r--kig/icons/hisc-action-circlebpd.svgzbin0 -> 1578 bytes
-rw-r--r--kig/icons/hisc-action-circlebps.svgzbin0 -> 1578 bytes
-rw-r--r--kig/icons/hisc-action-circlebtp.svgzbin0 -> 1953 bytes
-rw-r--r--kig/icons/hisc-action-circlelineintersection.svgzbin0 -> 1988 bytes
-rw-r--r--kig/icons/hisc-action-circumference.svgzbin0 -> 1908 bytes
-rw-r--r--kig/icons/hisc-action-conicasymptotes.svgzbin0 -> 1500 bytes
-rw-r--r--kig/icons/hisc-action-conicb5p.svgzbin0 -> 2224 bytes
-rw-r--r--kig/icons/hisc-action-coniclineintersection.svgzbin0 -> 1986 bytes
-rw-r--r--kig/icons/hisc-action-conicsradicalline.svgzbin0 -> 1835 bytes
-rw-r--r--kig/icons/hisc-action-convexhull.svgzbin0 -> 1961 bytes
-rw-r--r--kig/icons/hisc-action-curvelineintersection.svgzbin0 -> 1721 bytes
-rw-r--r--kig/icons/hisc-action-directrix.svgzbin0 -> 1484 bytes
-rw-r--r--kig/icons/hisc-action-distance.svgzbin0 -> 1495 bytes
-rw-r--r--kig/icons/hisc-action-ellipsebffp.svgzbin0 -> 1927 bytes
-rw-r--r--kig/icons/hisc-action-en.svgzbin0 -> 1710 bytes
-rw-r--r--kig/icons/hisc-action-equilateralhyperbolab4p.svgzbin0 -> 2237 bytes
-rw-r--r--kig/icons/hisc-action-equitriangle.svgzbin0 -> 1662 bytes
-rw-r--r--kig/icons/hisc-action-genericaffinity.svgzbin0 -> 2188 bytes
-rw-r--r--kig/icons/hisc-action-genericprojectivity.svgzbin0 -> 2933 bytes
-rw-r--r--kig/icons/hisc-action-halflinebyvector.svgzbin0 -> 2050 bytes
-rw-r--r--kig/icons/hisc-action-harmonichomology.svgzbin0 -> 1725 bytes
-rw-r--r--kig/icons/hisc-action-hexagonbcv.svgzbin0 -> 1655 bytes
-rw-r--r--kig/icons/hisc-action-hyperbolabffp.svgzbin0 -> 2023 bytes
-rw-r--r--kig/icons/hisc-action-intersection.svgzbin0 -> 1634 bytes
-rw-r--r--kig/icons/hisc-action-inversion.svgzbin0 -> 1724 bytes
-rw-r--r--kig/icons/hisc-action-kig_polygon.svgzbin0 -> 1871 bytes
-rw-r--r--kig/icons/hisc-action-kig_text.svgzbin0 -> 2938 bytes
-rw-r--r--kig/icons/hisc-action-line.svgzbin0 -> 1253 bytes
-rw-r--r--kig/icons/hisc-action-linebyvector.svgzbin0 -> 1883 bytes
-rw-r--r--kig/icons/hisc-action-locus.svgzbin0 -> 1919 bytes
-rw-r--r--kig/icons/hisc-action-mirrorpoint.svgzbin0 -> 1615 bytes
-rw-r--r--kig/icons/hisc-action-move.svgzbin0 -> 1509 bytes
-rw-r--r--kig/icons/hisc-action-paint.svgzbin0 -> 2050 bytes
-rw-r--r--kig/icons/hisc-action-parabolabtp.svgzbin0 -> 1690 bytes
-rw-r--r--kig/icons/hisc-action-parallel.svgzbin0 -> 1556 bytes
-rw-r--r--kig/icons/hisc-action-perpendicular.svgzbin0 -> 1693 bytes
-rw-r--r--kig/icons/hisc-action-point.svgzbin0 -> 1409 bytes
-rw-r--r--kig/icons/hisc-action-pointOnLine.svgzbin0 -> 1528 bytes
-rw-r--r--kig/icons/hisc-action-pointxy.svgzbin0 -> 1859 bytes
-rw-r--r--kig/icons/hisc-action-polygonsides.svgzbin0 -> 1350 bytes
-rw-r--r--kig/icons/hisc-action-polygonvertices.svgzbin0 -> 1895 bytes
-rw-r--r--kig/icons/hisc-action-python.svgzbin0 -> 18560 bytes
-rw-r--r--kig/icons/hisc-action-radicalline.svgzbin0 -> 1597 bytes
-rw-r--r--kig/icons/hisc-action-ray.svgzbin0 -> 1509 bytes
-rw-r--r--kig/icons/hisc-action-rotation.svgzbin0 -> 2186 bytes
-rw-r--r--kig/icons/hisc-action-scale.svgzbin0 -> 1626 bytes
-rw-r--r--kig/icons/hisc-action-segment.svgzbin0 -> 1682 bytes
-rw-r--r--kig/icons/hisc-action-segment_midpoint.svgzbin0 -> 1849 bytes
-rw-r--r--kig/icons/hisc-action-segmentaxis.svgzbin0 -> 1795 bytes
-rw-r--r--kig/icons/hisc-action-similitude.svgzbin0 -> 1929 bytes
-rw-r--r--kig/icons/hisc-action-sizer.svgzbin0 -> 1614 bytes
-rw-r--r--kig/icons/hisc-action-slope.svgzbin0 -> 1385 bytes
-rw-r--r--kig/icons/hisc-action-square.svgzbin0 -> 1557 bytes
-rw-r--r--kig/icons/hisc-action-stretch.svgzbin0 -> 1700 bytes
-rw-r--r--kig/icons/hisc-action-tangent.svgzbin0 -> 1484 bytes
-rw-r--r--kig/icons/hisc-action-test.svgzbin0 -> 2716 bytes
-rw-r--r--kig/icons/hisc-action-testcollinear.svgzbin0 -> 2740 bytes
-rw-r--r--kig/icons/hisc-action-testcontains.svgzbin0 -> 2824 bytes
-rw-r--r--kig/icons/hisc-action-testdistance.svgzbin0 -> 3429 bytes
-rw-r--r--kig/icons/hisc-action-testorthogonal.svgzbin0 -> 2657 bytes
-rw-r--r--kig/icons/hisc-action-testparallel.svgzbin0 -> 2483 bytes
-rw-r--r--kig/icons/hisc-action-translation.svgzbin0 -> 1863 bytes
-rw-r--r--kig/icons/hisc-action-triangle.svgzbin0 -> 1739 bytes
-rw-r--r--kig/icons/hisc-action-vector.svgzbin0 -> 1878 bytes
-rw-r--r--kig/icons/hisc-action-vectordifference.svgzbin0 -> 2339 bytes
-rw-r--r--kig/icons/hisc-action-vectorsum.svgzbin0 -> 2151 bytes
-rw-r--r--kig/icons/hisc-action-w.svgzbin0 -> 1419 bytes
-rw-r--r--kig/kfile/Makefile.am24
-rw-r--r--kig/kfile/kfile_drgeo.cpp99
-rw-r--r--kig/kfile/kfile_drgeo.desktop55
-rw-r--r--kig/kfile/kfile_drgeo.h41
-rw-r--r--kig/kfile/kfile_kig.cpp153
-rw-r--r--kig/kfile/kfile_kig.desktop54
-rw-r--r--kig/kfile/kfile_kig.h41
-rw-r--r--kig/kig.lsm.in18
-rw-r--r--kig/kig/Makefile.am53
-rw-r--r--kig/kig/aboutdata.h89
-rw-r--r--kig/kig/hi128-app-kig.pngbin0 -> 11501 bytes
-rw-r--r--kig/kig/hi16-app-kig.pngbin0 -> 777 bytes
-rw-r--r--kig/kig/hi22-app-kig.pngbin0 -> 1210 bytes
-rw-r--r--kig/kig/hi32-app-kig.pngbin0 -> 1848 bytes
-rw-r--r--kig/kig/hi48-app-kig.pngbin0 -> 3042 bytes
-rw-r--r--kig/kig/hi64-app-kig.pngbin0 -> 4472 bytes
-rw-r--r--kig/kig/hisc-app-kig.svgzbin0 -> 3640 bytes
-rw-r--r--kig/kig/kig.cpp308
-rw-r--r--kig/kig/kig.desktop121
-rw-r--r--kig/kig/kig.h148
-rw-r--r--kig/kig/kig_commands.cpp398
-rw-r--r--kig/kig/kig_commands.h217
-rw-r--r--kig/kig/kig_document.cc200
-rw-r--r--kig/kig/kig_document.h137
-rw-r--r--kig/kig/kig_iface.cpp31
-rw-r--r--kig/kig/kig_iface.h37
-rw-r--r--kig/kig/kig_part.cpp1041
-rw-r--r--kig/kig/kig_part.desktop16
-rw-r--r--kig/kig/kig_part.h257
-rw-r--r--kig/kig/kig_view.cpp593
-rw-r--r--kig/kig/kig_view.h274
-rw-r--r--kig/kig/kigpartui.rc288
-rw-r--r--kig/kig/kigui.rc40
-rw-r--r--kig/kig/main.cpp144
-rw-r--r--kig/macros/Makefile.am11
-rw-r--r--kig/macros/circle_by_center_and_line.kigt31
-rw-r--r--kig/macros/circle_by_point_and_diameter.kigt36
-rw-r--r--kig/macros/circle_by_point_and_segment.kigt26
-rw-r--r--kig/macros/equitriangle.kigt32
-rw-r--r--kig/macros/evolute.kigt28
-rw-r--r--kig/macros/osculating_circle.kigt27
-rw-r--r--kig/macros/segment_axis.kigt25
-rw-r--r--kig/macros/square.kigt44
-rw-r--r--kig/macros/vector_difference.kigt31
-rw-r--r--kig/mimetypes/Makefile.am8
-rw-r--r--kig/mimetypes/cabri.magic1
-rw-r--r--kig/mimetypes/cr128-mime-kig_doc.pngbin0 -> 10668 bytes
-rw-r--r--kig/mimetypes/cr16-mime-kig_doc.pngbin0 -> 751 bytes
-rw-r--r--kig/mimetypes/cr22-mime-kig_doc.pngbin0 -> 1106 bytes
-rw-r--r--kig/mimetypes/cr32-mime-kig_doc.pngbin0 -> 1783 bytes
-rw-r--r--kig/mimetypes/cr48-mime-kig_doc.pngbin0 -> 2984 bytes
-rw-r--r--kig/mimetypes/cr64-mime-kig_doc.pngbin0 -> 4248 bytes
-rw-r--r--kig/mimetypes/crsc-mime-kig_doc.svgzbin0 -> 21007 bytes
-rw-r--r--kig/mimetypes/drgeo.magic1
-rw-r--r--kig/mimetypes/x-cabri.desktop67
-rw-r--r--kig/mimetypes/x-drgeo.desktop62
-rw-r--r--kig/mimetypes/x-kgeo.desktop69
-rw-r--r--kig/mimetypes/x-kig.desktop69
-rw-r--r--kig/mimetypes/x-kseg.desktop68
-rw-r--r--kig/misc/Makefile.am50
-rw-r--r--kig/misc/argsparser.cpp267
-rw-r--r--kig/misc/argsparser.h187
-rw-r--r--kig/misc/boost_intrusive_pointer.hpp256
-rw-r--r--kig/misc/builtin_stuff.cc596
-rw-r--r--kig/misc/builtin_stuff.h23
-rw-r--r--kig/misc/calcpaths.cc303
-rw-r--r--kig/misc/calcpaths.h88
-rw-r--r--kig/misc/common.cpp520
-rw-r--r--kig/misc/common.h291
-rw-r--r--kig/misc/conic-common.cpp888
-rw-r--r--kig/misc/conic-common.h278
-rw-r--r--kig/misc/coordinate.cpp184
-rw-r--r--kig/misc/coordinate.h169
-rw-r--r--kig/misc/coordinate_system.cpp720
-rw-r--r--kig/misc/coordinate_system.h134
-rw-r--r--kig/misc/cubic-common.cc527
-rw-r--r--kig/misc/cubic-common.h120
-rw-r--r--kig/misc/goniometry.cc137
-rw-r--r--kig/misc/goniometry.h72
-rw-r--r--kig/misc/guiaction.cc367
-rw-r--r--kig/misc/guiaction.h174
-rw-r--r--kig/misc/kigfiledialog.cc81
-rw-r--r--kig/misc/kigfiledialog.h77
-rw-r--r--kig/misc/kiginputdialog.cc283
-rw-r--r--kig/misc/kiginputdialog.h123
-rw-r--r--kig/misc/kignumerics.cpp389
-rw-r--r--kig/misc/kignumerics.h47
-rw-r--r--kig/misc/kigpainter.cpp953
-rw-r--r--kig/misc/kigpainter.h291
-rw-r--r--kig/misc/kigtransform.cpp810
-rw-r--r--kig/misc/kigtransform.h190
-rw-r--r--kig/misc/lists.cc389
-rw-r--r--kig/misc/lists.h170
-rw-r--r--kig/misc/object_constructor.cc609
-rw-r--r--kig/misc/object_constructor.h396
-rw-r--r--kig/misc/object_hierarchy.cc774
-rw-r--r--kig/misc/object_hierarchy.h111
-rw-r--r--kig/misc/rect.cc308
-rw-r--r--kig/misc/rect.h140
-rw-r--r--kig/misc/screeninfo.cc92
-rw-r--r--kig/misc/screeninfo.h57
-rw-r--r--kig/misc/special_constructors.cc1628
-rw-r--r--kig/misc/special_constructors.h320
-rw-r--r--kig/modes/Makefile.am39
-rw-r--r--kig/modes/base_mode.cc160
-rw-r--r--kig/modes/base_mode.h64
-rw-r--r--kig/modes/construct_mode.cc572
-rw-r--r--kig/modes/construct_mode.h154
-rw-r--r--kig/modes/dragrectmode.cc180
-rw-r--r--kig/modes/dragrectmode.h104
-rw-r--r--kig/modes/edittype.cc107
-rw-r--r--kig/modes/edittype.h48
-rw-r--r--kig/modes/edittypebase.ui287
-rw-r--r--kig/modes/label.cc589
-rw-r--r--kig/modes/label.h129
-rw-r--r--kig/modes/linkslabel.cpp134
-rw-r--r--kig/modes/linkslabel.h85
-rw-r--r--kig/modes/macro.cc245
-rw-r--r--kig/modes/macro.h68
-rw-r--r--kig/modes/macrowizard.cc90
-rw-r--r--kig/modes/macrowizard.h43
-rw-r--r--kig/modes/macrowizardbase.ui188
-rw-r--r--kig/modes/mode.cc133
-rw-r--r--kig/modes/mode.h91
-rw-r--r--kig/modes/moving.cc245
-rw-r--r--kig/modes/moving.h101
-rw-r--r--kig/modes/normal.cc306
-rw-r--r--kig/modes/normal.h74
-rw-r--r--kig/modes/popup.cc1200
-rw-r--r--kig/modes/popup.h153
-rw-r--r--kig/modes/textlabelwizard.cc95
-rw-r--r--kig/modes/textlabelwizard.h46
-rw-r--r--kig/modes/textlabelwizardbase.ui113
-rw-r--r--kig/modes/typesdialog.cpp282
-rw-r--r--kig/modes/typesdialog.h70
-rw-r--r--kig/modes/typesdialogbase.ui337
-rw-r--r--kig/objects/Makefile.am81
-rw-r--r--kig/objects/angle_type.cc208
-rw-r--r--kig/objects/angle_type.h50
-rw-r--r--kig/objects/arc_type.cc199
-rw-r--r--kig/objects/arc_type.h64
-rw-r--r--kig/objects/base_type.cc112
-rw-r--r--kig/objects/base_type.h57
-rw-r--r--kig/objects/bogus_imp.cc388
-rw-r--r--kig/objects/bogus_imp.h281
-rw-r--r--kig/objects/centerofcurvature_type.cc304
-rw-r--r--kig/objects/centerofcurvature_type.h68
-rw-r--r--kig/objects/circle_imp.cc356
-rw-r--r--kig/objects/circle_imp.h125
-rw-r--r--kig/objects/circle_type.cc181
-rw-r--r--kig/objects/circle_type.h69
-rw-r--r--kig/objects/common.cc43
-rw-r--r--kig/objects/common.h107
-rw-r--r--kig/objects/conic_imp.cc385
-rw-r--r--kig/objects/conic_imp.h157
-rw-r--r--kig/objects/conic_types.cc689
-rw-r--r--kig/objects/conic_types.h184
-rw-r--r--kig/objects/cubic_imp.cc437
-rw-r--r--kig/objects/cubic_imp.h81
-rw-r--r--kig/objects/cubic_type.cc185
-rw-r--r--kig/objects/cubic_type.h56
-rw-r--r--kig/objects/curve_imp.cc41
-rw-r--r--kig/objects/curve_imp.h62
-rw-r--r--kig/objects/intersection_types.cc338
-rw-r--r--kig/objects/intersection_types.h105
-rw-r--r--kig/objects/inversion_type.cc412
-rw-r--r--kig/objects/inversion_type.h86
-rw-r--r--kig/objects/line_imp.cc571
-rw-r--r--kig/objects/line_imp.h215
-rw-r--r--kig/objects/line_type.cc334
-rw-r--r--kig/objects/line_type.h110
-rw-r--r--kig/objects/locus_imp.cc397
-rw-r--r--kig/objects/locus_imp.h96
-rw-r--r--kig/objects/object_calcer.cc323
-rw-r--r--kig/objects/object_calcer.h301
-rw-r--r--kig/objects/object_drawer.cc204
-rw-r--r--kig/objects/object_drawer.h146
-rw-r--r--kig/objects/object_factory.cc369
-rw-r--r--kig/objects/object_factory.h145
-rw-r--r--kig/objects/object_holder.cc164
-rw-r--r--kig/objects/object_holder.h145
-rw-r--r--kig/objects/object_imp.cc308
-rw-r--r--kig/objects/object_imp.h360
-rw-r--r--kig/objects/object_imp_factory.cc510
-rw-r--r--kig/objects/object_imp_factory.h40
-rw-r--r--kig/objects/object_type.cc125
-rw-r--r--kig/objects/object_type.h130
-rw-r--r--kig/objects/object_type_factory.cc148
-rw-r--r--kig/objects/object_type_factory.h40
-rw-r--r--kig/objects/other_imp.cc710
-rw-r--r--kig/objects/other_imp.h243
-rw-r--r--kig/objects/other_type.cc189
-rw-r--r--kig/objects/other_type.h61
-rw-r--r--kig/objects/point_imp.cc223
-rw-r--r--kig/objects/point_imp.h91
-rw-r--r--kig/objects/point_type.cc665
-rw-r--r--kig/objects/point_type.h159
-rw-r--r--kig/objects/polygon_imp.cc550
-rw-r--r--kig/objects/polygon_imp.h94
-rw-r--r--kig/objects/polygon_type.cc669
-rw-r--r--kig/objects/polygon_type.h139
-rw-r--r--kig/objects/special_calcers.cc84
-rw-r--r--kig/objects/special_calcers.h38
-rw-r--r--kig/objects/tangent_type.cc285
-rw-r--r--kig/objects/tangent_type.h83
-rw-r--r--kig/objects/tests_type.cc382
-rw-r--r--kig/objects/tests_type.h111
-rw-r--r--kig/objects/text_imp.cc173
-rw-r--r--kig/objects/text_imp.h70
-rw-r--r--kig/objects/text_type.cc215
-rw-r--r--kig/objects/text_type.h55
-rw-r--r--kig/objects/transform_types.cc874
-rw-r--r--kig/objects/transform_types.h243
-rw-r--r--kig/objects/vector_type.cc100
-rw-r--r--kig/objects/vector_type.h45
-rw-r--r--kig/package-kig.sh.in28
-rw-r--r--kig/pykig/API.txt182
-rw-r--r--kig/pykig/Makefile.am1
-rw-r--r--kig/pykig/VERSION1
-rw-r--r--kig/pykig/changelog.txt64
-rw-r--r--kig/pykig/pykig.pth2
-rwxr-xr-xkig/pykig/pykig.py824
-rw-r--r--kig/scripting/Makefile.am22
-rw-r--r--kig/scripting/newscriptwizard.cc234
-rw-r--r--kig/scripting/newscriptwizard.h72
-rw-r--r--kig/scripting/newscriptwizardbase.ui81
-rw-r--r--kig/scripting/python-kig.xml289
-rw-r--r--kig/scripting/python-scripting-api-dox-mainpage.dox26
-rw-r--r--kig/scripting/python_scripter.cc578
-rw-r--r--kig/scripting/python_scripter.h69
-rw-r--r--kig/scripting/python_type.cc195
-rw-r--r--kig/scripting/python_type.h63
-rw-r--r--kig/scripting/script-common.cc95
-rw-r--r--kig/scripting/script-common.h61
-rw-r--r--kig/scripting/script_mode.cc362
-rw-r--r--kig/scripting/script_mode.h119
563 files changed, 59270 insertions, 0 deletions
diff --git a/kig/AUTHORS b/kig/AUTHORS
new file mode 100644
index 00000000..9f44cc84
--- /dev/null
+++ b/kig/AUTHORS
@@ -0,0 +1 @@
+Kig developers <kde-edu-devel@kde.org>
diff --git a/kig/COPYING b/kig/COPYING
new file mode 100644
index 00000000..0b84a43f
--- /dev/null
+++ b/kig/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/kig/ChangeLog b/kig/ChangeLog
new file mode 100644
index 00000000..ec8d6042
--- /dev/null
+++ b/kig/ChangeLog
@@ -0,0 +1,1600 @@
+2005-09-29 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * Fix drawing of arcs with very small angle (patch by
+ F. Pasquarelli).
+
+2005-09-27 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * Imported PyKig, and made install as a binary script.
+
+2005-09-16 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Move a text label by (2,2), so the attached ones should be less
+ sticky to the "parent" object.
+
+2005-09-08 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Fix two bugs, patch by Maurizio Paolini.
+
+2005-09-02 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Slightly change in the text when asking for the results of a
+ macro: tell the user that a macro can construct more than one
+ object per time.
+
+2005-08-25 Inge Wallin <inge@lysator.liu.se>
+
+ * Fix bug 111452: Code violates C++ spec with improper const and
+ iterator declarations.
+
+2005-08-15 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Bump the version to 0.10.5 (I don't think to have enough stuff
+ to have a 0.11 version - at least at the moment).
+
+ * Small changes in the credits, putting me as maintainer.
+
+ * Small update in the TODO.
+
+ * Avoid setting empty captions in the KigFileDialog.
+
+ * Update a bit one tip.
+
+ * Add apidox comments for two classes.
+
+2005-07-30 Pino Toscano <toscano.pino@tiscali.it>
+
+ * With the help of the kde-usability team, I've refactored the Kig
+ exporter dialogs. These new ones are more usable than the previous
+ ones, more simply and more maintainable. This could make us
+ closing bug #101072.
+
+2005-07-25 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Apidox improvements.
+
+2005-07-24 Pino Toscano <toscano.pino@tiscali.it>
+
+ * More apidox fixes.
+
+2005-07-23 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Apidox fixes.
+
+2005-07-06 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Apidox improvements.
+
+2005-06-24 Pino Toscano <toscano.pino@tiscali.it>
+
+ * When making the template fo a new script, give as args names the
+ names of the related objects, if they have one, as suggested by
+ Daniel Moyne. Otherwise, will be used argn as usual.
+
+2005-06-20 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Moved the EditAngleSize dialog to the KigInputDialog class.
+
+ * Handle Return and Escape as key shortcuts to respectively accept
+ or reject a KigInputDialog.
+
+2005-06-19 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Creating a new class, KigInputDialog. This new class is much
+ like KInputDialog, but it fits better Kig purpouses. At the moment
+ it has two methods to get one or two coordinates, made in a
+ cleaner way than the former ZoomArea class and
+ CoordinateSystem::getCoordFromUser(). Using it instead of the
+ former class/method listed above. This way we can construct a
+ custom input dialog accepting also markup text, allowing us to
+ give instructions much clear when we want the user insert a
+ coordinate, fixing also the bug #100007.
+
+2005-06-16 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Re-enable the "snap" to points in construct mode.
+
+2005-06-14 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Give to the user the possbility to select which element popup a
+ menu for.
+
+2005-06-01 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Small changes to make the port to Qt4 less intrusive.
+
+2005-05-25 Pino Toscano <toscano.pino@tiscali.it>
+
+ * The kfile_kig displays also whether the file is compressed or
+ not.
+
+2005-05-21 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Created a new system to select - in normal mode - one object
+ among some: using Shift (or Control) + LMB the user can select the
+ object he/she desire through a popup menu. This new system is
+ applyed also to to mouse hover/left click in construct mode, to
+ select one object if we have more than one valid object. This,
+ plus a search among the object under the mouse, allow the fixing
+ of bug #99870.
+
+ * Added a "tip of day" to inform the user of the possibility to
+ select any object from an object stack under the cursor.
+
+ * Give a different behaviour for Shift and Control keys in normal
+ mode: Shift make appear a popup to choose an object from the
+ object stack under the cursor; Control keep the selection.
+
+2005-05-19 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Give to the kfile_kig the ability to read info from compressed
+ files.
+
+2005-05-15 Danny Allen <dannya40uk@yahoo.co.uk>
+
+ * Added my new action icons for Kig, with SVG sources, changed
+ icons to "hi*" naming conventions.
+
+2005-05-14 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Created a new system to select - in normal mode - one object
+ among some: using Shift (or Control) + LMB the user can select the
+ object he/she desire through a popup menu. This new system is
+ applyed also to to mouse hover/left click in construct mode, to
+ select one object if we have more than one valid object. This,
+ plus a search among the object under the mouse, allow the fixing
+ of bug #99870.
+
+ * Added a "tip of day" to inform the user of the possibility to
+ select any object from an object stack under the cursor.
+
+2005-05-07 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Using three standard action in our popup menu instead of
+ creating new actions "from scratch". Removing the Toggle
+ fullscreen action created by hand, fixes also an ugly bug that
+ happened when choosing Toggle fullscreen from the popup to exit
+ from fullscreen.
+
+2005-05-06 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Made Kig standard names for its icons, so artists can theme them
+ in their icon themes. Some files needed obviously changes.
+
+2005-04-30 Pino Toscano <toscano.pino@tiscali.it>
+
+ * When selecting a custom color for one object, put the old object
+ color as selected color in the Color dialog.
+
+2005-04-28 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Other work on Cabri filter: can read styles and translations.
+
+2005-04-27 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Some work also on Cabri filter: fixed a color, and imported four
+ objects.
+
+2005-04-25 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Almost rewritten a core part of the KSeg import filter: some
+ object are handled in a more correct way than before (thus less
+ crashes, but some crashes still occurs with locuses). As a result,
+ some objects can be imported correctly now.
+
+2005-04-20 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Give to the KSeg filter the ability to import names (called
+ labels) of objects. This is not so perfect, because we need to
+ decode better the read object label.
+
+ * Fix intersection points loading in KSeg filter.
+
+2005-04-16 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Fixing a small issue when saving a file with no name set. The
+ name wasn't empty, but it contained a temp file. Luckly m_bTemp
+ stores whether using a temp file. This could fix bug #98142.
+
+2005-04-15 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Correct size for some menu item icons, as reported by Danny
+ Allen.
+
+ * Better handling of unexistant types found when loading a
+ document.
+
+ * Corrected two strings, thanks to Danny Allen.
+
+ * Use KStdGuiItem in more places than before.
+
+2005-04-14 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Committing fix for bug #100292. The new code makes the
+ ObjectHierarchy construction from QDomElement more safe than
+ before; the new "static constructor" and
+ ObjectImpFactory::deserialize() can report an error in case of.
+
+ * As a result of the fix, less assert() asre used in
+ deserialization code.
+
+2005-02-21 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Again, bump the version number to 0.10.
+
+2005-02-10 Dominique Devriese <devriese@kde.org>
+
+ * The rest of a fix for bug #98517. The problem was that
+ namecalcer's weren't being saved if they weren't shown on the
+ document. This fixes the previous fix to not crash on faulty
+ documents, but give a proper parser error. This should
+ permanently fix #98517.
+
+ * Fix this ChangeLog to document the previous fix for #98517.
+
+2005-02-07 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * Bug fix: new algorithm for calcPath in calcpath.cc; the
+ previous had exponential complexity for some examples
+
+2005-02-03 Dominique Devriese <devriese@kde.org>
+
+ * Add a nice new locus example: trifolium-of-delongchamps.kig
+
+2005-02-03 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Bump the version number to 0.9.1.
+
+2005-01-31 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * added point/line/circle inversion with respect to a given
+ circle.
+
+2005-01-26 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * added many constructions related to polygons:
+ sides, center of mass, winding number, convexity
+ test, convex hull.
+
+ * changes in construct_mode (and in a few other
+ places) to allow the construction with a "cursor"
+ point that gives information on the constructed
+ object, but should not be inserted as argument.
+ This is used for a better interactive construction
+ of regular polygons
+
+2005-01-20 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * new "attaching" style for labels to objects, based on the
+ new RelativePointType. This type is a point located at a
+ relative position with respect to a given attachPoint()
+ associated to the ObjectImp. It depends on three arguments:
+ the object to which the position is relative and two DoubleImp
+ givin the x and y displacement. Now use for angles and
+ polygons.
+
+2005-01-18 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * now the construction of a generic affinity and a generic
+ projectivity (defined by the image of 3 or 4 points) takes
+ advantage of the existence of polygon.
+
+2005-01-15 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * new PolygonBNPType corresponding to a polygon with a
+ generic number of vertices. It is constructed by selecting
+ the vertices and ending up selecting the first vertex again.
+
+ * the new ObjectConstructor::isAlreadySelectedOK method is a
+ technical addition, it returns false for all normal objects
+ (meaning that duplicated arguments are not acceptable). This
+ is introduced in order to implement the construction of
+ polygons "a la Drgeo".
+
+2005-01-12 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Created a new KigPainter::drawArea() to draw and fill closed
+ areas. This new functions differs from drawPolygon, because the
+ old one is used to draw only polygons, while the new one is used
+ to draw all the other closed and filled areases.
+
+ * Adapted our CoordinateSystem's to use the new drawArea to draw
+ the axis arrows.
+
+2005-01-09 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * new action to construct the vertices of a polygon
+
+ * new action to construct a generic triangle (as a polygon) given
+ its vertices
+
+2004-12-30 Dominique Devriese <devriese@kde.org>
+
+ * Fix for a bug where a name calcer wasn't saved if it was only
+ referred to from the object it is the namecalcer for, and not by
+ its own objectholder. This commit makes sure that no more such
+ files are generated, and that kig no longer crashes on such
+ files. Thanks to Pino Toscano for help in fixing this. (#98517)
+
+2004-12-28 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * polygons are filled; no boundary drawn
+
+ * fixed a problem when trasforming a segment with
+ a projective (nonaffine) transformation; in certain
+ cases the result is invalid (no longer a segment)
+
+ * fixed a bug in similitude transformation as suggested by
+ Pino Toscano (#85171)
+
+2004-12-27 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Fix bug #95637: Scrolling does not work during construction of
+ a new object
+
+2004-12-24 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Kig can now save and open compressed files with extension
+ .kigz. This format is a gzip compressed tarball.
+
+2004-12-14 Pino Toscano <toscano.pino@tiscali.it>
+
+ * More tooltips and "what's this" to some dialog.
+
+ * No more file name in every file.
+
+ * More control on macro name: when loading from file, if a macro
+ has no name, we'll assign it a bogus one (like "Unnamed macro
+ #id"). Furthermore, we ensure that the user don't set an empty
+ name for a macro in the Edit Types Dialog.
+
+ * Other misc changes.
+
+2004-11-09 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Made kig.dektop and kig_part.desktop more compliant to
+ freedesktop.org's desktop entry specifications.
+
+ * Introduced PolygonImp, a new ObjectImp to handle all the types
+ of polygons (both generic and regular ones). Modified PoligonType
+ and PoligonBCVConstructor to use the new PolygonImp. Adapted also
+ the ObjectImpVisitor to visit PolygonImp.
+
+ * Improved the LatexExporter to export PolygonImp's.
+
+ * Fixed a crash that occurs when selecting (during a text label
+ construction) the property "Name" for an object with no
+ name(calcer) set.
+
+ * Other misc changes.
+
+2004-11-08 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * Scaling and stretching can be defined using two segments to
+ obtain the scaling ratio (as the ratio of their length). Added in
+ the Transformations menu, not in the Transformations toolbar,
+ which is crowded enough already :-)
+
+2004-11-06 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * Added osculating circle and evolute of a curve as a
+ builtin macros (based upon the center of curvature).
+
+2004-10-27 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Add all the constructible regular polygons actions to
+ kigpartui.rc.
+
+ * Remove the call to KAboutData::setTranslator in kig/aboutdata.h,
+ since Scripty generate automatically the two strings.
+
+2004-10-24 Dominique Devriese <devriese@kde.org>
+
+ * Added a few new icons from Bart Van Hove bartvanhove _at_ skynet _dot_ be
+
+2004-10-23 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * Added construction of the center of curvature of a curve
+ at a point. It works for conics, cubics and locuses.
+ However a special hack was necessary to make it possible to
+ construct the locus of the center of curvatures starting from
+ a locus. Indeed there are problems associated to the getParam
+ function of a locus, which now returns a result with a too large
+ error. Simply reducing the "epsilon" in "LocusImp::getParamofmin"
+ is not feasible since it would degrade the overall response time.
+ However it is quite frequent that the LocusImp::getParam is called
+ right after a LocusImp::getPoint, although at a quite different
+ level, and on curves that are physically the same, but internally
+ different. Since the two functions are inverse one of the other
+ we simply cache the value of "param" in getPoint and try to use
+ the cached value when doing the getParam: if the resulting point
+ is equal to the argument of getParam we win, otherwise we proceed
+ along the lengthy minimization process.
+ A nice example of the involute (locus of centers of curvature)
+ of a curve can be retrieved from
+ "www.dmf.unicatt.it/~paolini/kig/cicloide.kig"
+ The getParam function however requires adjustment: right now the
+ internal test whether a point lies on a locus miserably fails
+ even if we test it on the moving point used to construct the
+ locus :-(
+
+2004-10-13 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * Added construction of the tangent to a locus
+
+2004-10-11 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * Added PoligonBCVType for regular poligons with n sides
+ given the center and a vertex.
+
+ * Transport of Measure is generalized to allow both
+ segments and arcs to provide a length and both a line
+ or a circle with a point on it as the target of the
+ transport.
+
+2004-10-09 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Add a CircleByCenterAndDiameter object, to construct a circle
+ using a point as center and the length of a segment as diameter.
+
+ * A new SVG exporter to make SVG documents starting form Kig
+ documents.
+
+2004-10-08 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * Added the construction of the center of curvature for
+ conics and cubics. It works similarly to the construction
+ of the tangent and the arguments are a curve (conic or cubic)
+ and a point on in. Using the center of curvature it is
+ straightforward to construct the osculating circle or the
+ evolute.
+
+2004-09-13 Pino Toscano <toscano.pino@tiscali.it>
+
+ * The script code editor now can use the Kate KTextEditor, and
+ consequently we can use its interfaces to do some various thing,
+ like the syntax highlight of the code. Moreover if the
+ KTextEditor::Document could not be created, will be used a
+ standard KTextEdit as the code editor.
+
+ * Some i18n fixes.
+
+2004-09-10 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * Now it's possible to construct the tanget to a cubic.
+
+2004-09-05 Pino Toscano <toscano.pino@tiscali.it>
+
+ * A new LaTex exporter.
+
+ * Add a new little system to handle script's properties like
+ icon, template code and stuff related to script type.
+
+ * Now any change in the Types Dialog is applied when the users
+ click OK. If Cancel is pressed, any change is lost, even types
+ addition/deletion. This is done by saving the types when Types
+ Dialog is started.
+
+ * Now the user can choose Start->Python Script from the popup
+ menu to start a new Python script with the selected objects as
+ arguments. If there are no objects selected, the Script Wizard
+ starts as usual.
+
+ * Add the main Kig icons with size 22 and 64.
+
+ * The KSeg filter can import bisector lines.
+
+ * Add a new tip.
+
+2004-09-02 Dominique Devriese <devriese@kde.org>
+
+ * Commit David Vignoni's new kig_doc icon
+
+2004-09-01 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Implement Vector difference as internal macro.
+
+ * The Type list has a popup menu to edit, delete and export types.
+
+ * Small changes to Script Wizard UI.
+
+ * kfile_kig read also the compatibility version.
+
+2004-07-21 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Make a text label not "pasted" to its point by adding a
+ "padding" ( 2 pixels every side ).
+
+ * Now the code editor in the Script Wizard uses KDE global fixed
+ font.
+
+2004-07-20 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Implement arc-line intersection in KSeg filter.
+
+ * Add support in KGeo filter for constrained points and info
+ about the presence of grid and axes.
+
+ * Little fix in Cabri filter.
+
+ * Fixed a crash in the Types dialog.
+
+2004-07-18 Dominique Devriese <devriese@kde.org>
+
+ * Introduce the concept of a CompatibilityVersion. Kig now saves
+ its files with a compatibility version of 0.7.0, indicating that
+ the file format has stayed more or less the same since 0.7, and
+ that an app able to open documents created by Kig 0.7 should
+ normally not have much problems with this version's files ( apart
+ from some new document types, but those are handled separately
+ anyway ). On loading, Kig now first checks the compatibility
+ version, and falls back to the real version only if the previous
+ is not available. The CompatibilityVersion will change only on
+ major file format changes, unlike the normal Version.
+
+ * Move the version back to 0.9, because Kig really isn't in a 1.0
+ state yet. Some problems need addressing first. It took me some
+ time to realise, but calling this release 1.0 would not do credit
+ to the program's long-term potential.
+
+2004-07-13 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Move AngleType from other_type.* into angle_type.*.
+
+ * Add a new HalfAngleType object, which returns only an angle
+ smaller than 180 degrees. This is useful for Dr. Geo angles,
+ which are always smaller than 180 degrees.
+
+ * Activate and improve Cabri filter.
+
+ * Some improvements in the Types dialog.
+
+ * A new magic file for application/x-cabri.
+
+ * Add CubicCartesianData and Cubic to Python Scripting API.
+
+ * Some fixes in Dr. Geo filter: implement Bordeaux colour; fix
+ intersection params; Kig shows the name of every point; ignore
+ Dr. Geo block to UI.
+
+ * Improved the generation of pot catalogs.
+
+ * Now it's possible to construct the tangent to a conic or an
+ arc.
+
+ * Add a select statement to show a message in the statusbar for
+ PropertyObjectConstructor, and use this to show an info text
+ while constructing an angle bisector.
+
+ * A new type to calc the difference between two vectors.
+
+ * ObjectFactory::sensiblePointCalcer can construct line-line
+ intersections.
+
+ * Fix a bug that occurs when Kig draw a line that has the same
+ coordinates in its LineData class.
+
+ * Activate Help button in the Script Wizard.
+
+ * Some little improvements.
+
+2004-07-03 Dominique Devriese <devriese@kde.org>
+
+ * Make the type edit dialog appear when the edit button is
+ pressed, not when the user clicks on a type.
+
+2004-06-29 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Some fixes related to the Kig version change.
+
+ * Some fixes in the Dr. Geo filter.
+
+ * Fixed a small bug that leads to display "Select the point" when
+ I reset the name of an object after setting it.
+
+ * i18n fixes in kfile_kig.
+
+2004-06-29 Dominique Devriese <devriese@kde.org>
+
+ * Change the version to 1.0
+
+2004-06-26 Pino Toscano <toscano.pino@tiscali.it>
+
+ * A new property "Angle" for arcs.
+
+ * Many improvements in the Dr. Geo filter.
+
+2004-06-15 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Add info about whether grid and axes are shown to the kig kfile
+ thing.
+
+ * Now the coordinate system toggleaction is correctly updated
+ when the coordinate system is changed in another way.
+
+ * Disable the page selection in the print dialog.
+
+2004-06-14 Dominique Devriese <devriese@kde.org>
+
+ * Change some more functions that still pass "bool valid&"s around
+ to using Coordinate::valid().
+
+2004-06-14 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Add "Tips Of Day" feature.
+
+ * A new tab in the Print dialog allow the user to choose whether
+ to print grid and/or axes.
+
+ * Add arc-line intersection type.
+
+2004-06-13 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Add the possibility to attach a label ( and a point, of
+ course :) ) to a vector. This because now VectorImp inherits
+ CurveImp.
+
+ * Make types modifiable through types dialog. The system is not
+ complete, because at the moment there is no way to update the UI.
+
+ * The user now can choose manually the zoom area.
+
+ * Get rid of the Invisible coordinate system; now there are two
+ actions ( Show Grid and Show Axes ) to show/hide grid and axes
+ separately. I think this is a better way: the Invisible coordinate
+ system did not allow to work with polar coordinates and no grid.
+
+2004-06-11 Dominique Devriese <devriese@kde.org>
+
+ * Some improvements by me to Pino's object names code. Mostly,
+ this includes cleaning the design a bit, and adding support for
+ the names in some places.
+
+2004-05-31 Dominique Devriese <devriese@kde.org>
+
+ * Fix some memory leaks found by valgrind.
+
+2004-05-30 Dominique Devriese <devriese@kde.org>
+
+ * implement usetexts and select statements for builtin macro's
+
+ * Show a text in the statusbar describing what we want the user to
+ select, in ConstructMode.
+
+ * Add an example of a cubic constructed as a locus.
+
+ * Clean the status bar text on time in ConstructMode and
+ TestConstructMode.
+
+ * Make SetCoordinateSystemAction into a KSelectAction, so the user
+ can see what kind of coordinate system he's currently using.
+
+ * Some tuning of the UI: move Transformations and Tests menu into
+ the Objects menu because the menubar was getting too crowded.
+
+2004-05-29 Dominique Devriese <devriese@kde.org>
+
+ * Fix a crash related to a locus containing some invalid points,
+ and added the offending test file in filters/tests.
+
+ * Fix some --enable-final problems in the filters/ directory.
+
+2004-05-28 Dominique Devriese <devriese@kde.org>
+
+ * Add a test file "testalotofeverything.kig"
+
+ * Add a Similitude transformation.
+
+ * Add a VectorEqualityTestType.
+
+2004-05-27 Dominique Devriese <devriese@kde.org>
+
+ * Fix so that Kig saves its window settings on exit.
+
+2004-05-24 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Add the possibility to give a name to every object. The name is
+ displayed when moving mouse over the object, like "Select this
+ line (AB)" or choosing the object which attach another object to.
+ For now there is no label with title displayed with the object.
+
+ * Make the Vector Sum of two vectors starting at an arbitrary
+ point.
+
+2004-05-23 Dominique Devriese <devriese@kde.org>
+
+ * replace the custom configureShortcuts code with the standard KDE
+ one if the user is running HEAD.
+
+2004-05-18 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Move ArcBTPType from other_type.* into arc_type.*.
+
+ * Add two new types, ArcBCPA ( Arc By Center, starting Point and
+ Angle ) and CircleBCL ( Circle By Center and Line - via macro ).
+
+ * Now every submenu in the RMB menu can have an own icon.
+
+ * Add a menu icon for every ExportAction.
+
+ * Various little improvements
+
+2004-05-18 Dominique Devriese <devriese@kde.org>
+
+ * Add a --convert-to-native command line option, which converts
+ the given file to the native Kig file format ( without a GUI ).
+
+ * Split up KigDocument into KigPart and KigDocument
+
+2004-05-15 Dominique Devriese <devriese@kde.org>
+
+ * Intersecting with a segment only gives points that really are on
+ the segment, and an InvalidImp in other cases.
+
+2004-05-12 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Now circles can display their equation in the form
+ "( x - x0 )^2 + ( y - y0 )^2 = r^2".
+
+ * Add Doxygen comments for AngleImp, VectorImp and ArcImp
+ classes, to make them documented in scripting-api documentation.
+
+ * Add a Copy action to text labels to copy their text ( with
+ substitutions already made ) into the clipboard.
+
+ * Add two little kfile plugins: kfile_kig and kfile_drgeo.
+
+ * Various little improvements
+
+2004-05-11 Dominique Devriese <devriese@kde.org>
+
+ * Rename the two Transformation::scaling functions to
+ scalingOverPoint and scalingOverLine, and export them to python.
+
+ * Fix a crash reported by Maurizio: when debugging is enabled, and
+ one attempts to move an object of a type that inherits
+ ObjectABType, and depends on a non-movable object.
+
+2004-05-03 Dominique Devriese <devriese@kde.org>
+
+ * Add a DrGeo test file using a locus
+
+2004-05-03 Pino Toscano <toscano.pino@tiscali.it>
+
+ * More work on Dr. Geo filter: now locuses should work, fix object
+ visibility.
+
+2004-04-30 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Add line and half-line by vector.
+
+ * More work on Dr. Geo filter to support some types of On_curve
+ points.
+
+2004-04-30 Dominique Devriese <devriese@kde.org>
+
+ * properly generate python error output for compile errors.
+
+ * make touch screens work by placing a mouseMoved call aboove
+ every mouseClicked call.
+
+2004-04-28 Dominique Devriese <devriese@kde.org>
+
+ * change the Qt CapStyle used for drawing locuses, conics and
+ lines to FlatCap, which gives better results with large line
+ widths.
+
+ * Add two line styles: DashDotLine and DashDotDotLine
+
+ * Remove the KigPainter::drawConic and KigPainter::drawCubic
+ functions. Conics and cubics are now drawn with the generic
+ KigPainter::drawCurve function. The performance penalty is not
+ noticable for me, and I haven't been able to quantify it in any
+ way, so I assume it negligible. Cubics and conics drawing now
+ correctly takes line styles into account.
+
+2004-04-27 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Implement styles and visibility for KSeg filter.
+
+2004-04-27 Dominique Devriese <devriese@kde.org>
+
+ * Make locuses work with the line styles, by drawing them with
+ drawPolyline instead of drawing the individual segments ourselves.
+ Thanks to Maurizio for the ideas and the help.
+
+ * Fix a stupid bug in the last commit which caused Kig to crash on
+ older Kig files.
+
+ * Make it possible to switch the radical lines of a conic that are
+ shown.
+
+2004-04-24 Dominique Devriese <devriese@kde.org>
+
+ * Add a vector sum object.
+
+ * Move VectorType from other_type.* into vector_type.*.
+
+ * Fix a bug where some objects were not preliminarily drawn
+ correctly.
+
+2004-04-23 Dominique Devriese <devriese@kde.org>
+
+ * Add a segment-midpoint icon from Julien Narboux
+ <Julien.Narboux@inria.fr>.
+
+ * Implement a scheme that automatically instantiates the singleton
+ ObjectType's. Now, the ObjectType constructor now adds itself to
+ ObjectTypeFactory, so that we cannot forget to do it. This fixes
+ loading of files containing property test objects.
+
+ * Remove the old code that removed $appdata/kig-types/*.kigt on
+ exit, as it's not necessary anymore.
+
+2004-04-22 Dominique Devriese <devriese@kde.org>
+
+ * Add a "opposite vector" property to VectorImp.
+
+2004-04-21 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Add a SameDistanceType, to check whether a point have the same
+ distance from a second point and from a third point.
+
+2004-04-21 Dominique Devriese <devriese@kde.org>
+
+ * Fix tooltips to not contain "&&" instead of "&" ( closes: 78411 ).
+
+2004-04-20 Dominique Devriese <devriese@kde.org>
+
+ * Various i18n'able string fixes.
+
+ * Add some documentation to the functions in misc/conic-common.h
+
+ * Rename "Cubic" to "Cubic Curve", as discussed with Maurizio
+ Paolini and Jaap Woldringh.
+
+ * Save and load line and point styles in the native format. Most
+ of the code comes from Pino.
+
+2004-04-19 Pino Toscano <toscano.pino@tiscali.it>
+
+ * More work in Dr. Geo filter.
+
+ * A new cool (I hope :) ) icon for Python Script.
+
+ * Some various improvements.
+
+2004-04-17 Dominique Devriese <devriese@kde.org>
+
+ * Fix the calculation of the rectangle containing the entire
+ document ( which is used for centering on the document ), to take
+ into account non-point objects. This is accomplished by adding a
+ surroundingRect function to ObjectImp, and by implementing it
+ properly for all objects that can have such a thing.
+
+2004-04-15 Pino Toscano <toscano.pino@tiscali.it>
+
+ * More work in Dr. Geo filter: add a new object and simplifying a
+ bit his internal structure.
+
+ * Kig now ask the user what to do when he/she tries to save to
+ a file in another format than Kig's own.
+
+ * Improve Python scripting's API: add vectors, angles and arcs.
+
+ * Add i18n for TestConstructor's.
+
+ * Improved NewScriptAction class to support, without other
+ changes, other scripting languages.
+
+ * Some little here-and-there improvements
+
+2004-04-11 Dominique Devriese <devriese@kde.org>
+
+ * Improve Kig embedded in Konqueror experience: make translations
+ and icons work by using the correct instanceName(), and using the
+ iconLoader we get from our KInstance instead of from KGlobal ( so
+ that the kig specific dirs are checked for icons as well ).
+
+2004-04-10 Dominique Devriese <devriese@kde.org>
+
+ * Enable the DrGeo input filter.
+
+2004-04-10 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Improved angle size editing, making possible choosing between
+ degrees, radians and gradians.
+
+ * More work in Dr. Geo filter.
+
+ * Some improvements in Goniometry class
+
+2004-04-08 Pino Toscano <toscano.pino@tiscali.it>
+
+ * More work on types dialog: a new dialog will allow to edit
+ types that now work in read-only mode.
+
+ * Add a 'cross' style for points.
+
+ * Some very minor work in Dr. Geo filter.
+
+ * Add a new simple class to easily work with goniometric
+ measures, and adapt Kig to use this class.
+
+ * Some #include fixes
+
+2004-04-05 Pino Toscano <toscano.pino@tiscali.it>
+
+ * A new look for type list in the type dialog: a listview instead
+ of a listbox that should make easier editing a type.
+
+2004-04-04 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Now Kig can save icon information of every macro.
+
+ * Some work on types dialog: icon of every type is now visible,
+ and made a sort of skeleton to modify type's data.
+
+ * Made buttons of some dialogs like other KDE dialogs ones (with
+ icons and correct alignment).
+
+ * Kig now ask the user when exporting type(s) to an already
+ existant file.
+
+ * Some i18n fixes
+
+2004-04-02 Dominique Devriese <devriese@kde.org>
+
+ * Implement the point-on-curve checking. The code should work,
+ but the objects using it cannot be built yet.
+
+2004-03-28 Dominique Devriese <devriese@kde.org>
+
+ * Add some non-functional code for point-on-curve checking.
+
+2004-03-28 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Add point styles
+
+ * Some i18n fixes
+
+ * More work on the DrGeo import filter
+
+2004-03-27 Dominique Devriese <devriese@kde.org>
+
+ * Apply a patch by Albert Astals Cid <tsdgeos@terra.es> that gives
+ focus to the text input on first opening the text dialog.
+ Closes:78409.
+
+ * Fix a translation issue with internal macro's.
+
+ * Make a TextImp transformable by simply transforming its
+ location, and showing the text label in that location again
+ (Closes: 78407 ).
+
+2004-03-26 Pino Toscano <toscano.pino@tiscali.it>
+
+ * Implemented a popup menu submenu for changing the line style of
+ an object.
+
+ * Various i18n fixes
+
+2004-03-15 Dominique Devriese <devriese@kde.org>
+
+ * misc/coordinate_system.cpp: add a simple "Invisible" Coordinate
+ system, showing no axes or grid at all.
+
+2004-03-10 Dominique Devriese <devriese@kde.org>
+
+ * Don't mess up the order of given objects in a macro
+ construction.
+
+2004-03-09 Dominique Devriese <devriese@kde.org>
+
+ * Fix the macro system to reject macro's where not all of the
+ given objects are used.
+
+ * Fix the macro system to properly check whether the final objects
+ depend on the given objects, and fix a problem with the wrong
+ object being selected as the final object in some rare cases.
+
+2004-03-06 Dominique Devriese <devriese@kde.org>
+
+ * Incorporate a patch by Pino Toscano adding some unfinished work
+ on a Dr.Geo import filter. It's not finished yet, and also not
+ visible in the UI yet.
+
+ * Fix the ObjectHierarchy::resultDoesNotDependOnGiven() function
+ to do something much less stupid than before. It still only
+ checks if one of the result objects does not depend on the given
+ objects, it needs to be changed to properly check whether all the
+ result objects depend on the given objects.
+
+ * Fix the ObjectHierarchy class to generate a correct hierarchy
+ when a result object depends on another object that does not
+ depend on the given objects.
+
+2004-02-24 Dominique Devriese <devriese@kde.org>
+
+ * Make the tests stuff generate a proper text label with
+ property calcers instead of a normal calcer as rest arguments.
+
+ * Make the configure.in.in stuff properly detect python on RH
+ -> many thanks to Maurizio for helping me with this.
+
+ * Fix some problems with the useText, that were introduced with
+ the new tests stuff.
+
+2004-02-23 Dominique Devriese <devriese@kde.org>
+
+ * Add a ContainsTestType, testing whether a given point is on a
+ given curve.
+
+2004-02-17 Dominique Devriese <devriese@kde.org>
+
+ * Add the possibility to give an item a custom color in the
+ popup dialog.
+
+2004-02-16 Dominique Devriese <devriese@kde.org>
+
+ * make the usetext in TestConstructMode also appear for all other
+ arguments than the last one
+
+2004-02-15 Dominique Devriese <devriese@kde.org>
+
+ * Add code by Maurizio Paolini, and some adaptations of his code
+ by me for supporting property tests like "are these two lines
+ parallel ?"
+
+ * update the aboutdata: Maurizio Paolini did not only help with
+ math intensive code, and Franco Pasquarelli did some very
+ important work in the locus code.
+
+2004-02-14 Dominique Devriese <devriese@kde.org>
+
+ * Fix a bug waiting to pop up in construct_mode.cc, where you
+ select the same object twice.
+
+ * Add documentation about the locus and textlabel design to the
+ DESIGN document.
+
+2004-02-10 Dominique Devriese <devriese@kde.org>
+
+ * Fix a bug which caused Kig to crash on moving a text label by
+ removing a wrong assertion in objects/object_calcer.cc
+
+2004-02-09 Dominique Devriese <devriese@kde.org>
+
+ * Replace the line-line-intersection algorithm with a much simpler
+ one by Maurizio Paolini
+
+ * Add three new transformations by Maurizio Paolini
+
+ * Remove people-to-inform-about-kig-releases as no further
+ separate releases are planned.
+
+2004-02-08 Dominique Devriese <devriese@kde.org>
+
+ * Fix a bug reported by Maurizio Paolini: don't crash on getting
+ the arguments for a locus in the wrong order.
+
+2004-01-21 Dominique Devriese <devriese@kde.org>
+
+ * replace my own autoconf code in configure.in.in for checking for
+ boost.python and python by some macro's by Ben Burton which
+ additionally check whether the python and boost.python combination
+ found is sane. They're also generally cleaner and such.
+
+ * clean up configure.in.bot a bit
+
+2004-01-20 Dominique Devriese <devriese@kde.org>
+
+ * Add a new internal "Segment Axis" type, implemented as a macro.
+
+2004-01-18 Dominique Devriese <devriese@kde.org>
+
+ * bump the version number to 0.7.1
+
+2003-12-16 Dominique Devriese <devriese@kde.org>
+
+ * Fix the scrolling for horizontal scrolling using the alt button
+ or a horizontal scroll wheel.
+
+2003-12-15 Dominique Devriese <devriese@kde.org>
+
+ * Another try at fixing the ArgsParser parsing order. I think
+ I've tried most problematic cases, and they all seem to work
+ properly. Let's pray for the best ;)
+
+2003-12-10 Dominique Devriese <devriese@kde.org>
+
+ * Fix a crash when using a macro having the moving point of a
+ locus as its argument, reported by Marco Zoso.
+
+2003-11-14 Dominique Devriese <devriese@kde.org>
+
+ * Fix two crashes in TextLabelRedefineMode.
+
+2003-11-10 Dominique Devriese <devriese@kde.org>
+
+ * bump the version number to 0.6.1
+
+ * Fix bugs #67671 and #67694
+
+2003-10-22 Dominique Devriese <devriese@kde.org>
+
+ * Improve the errors given by the "New Script Wizard", by making
+ it get a proper error description from the python interpreter.
+
+ * fix the ArgsParser parsing order, properly this time..
+
+2003-10-20 Dominique Devriese <devriese@kde.org>
+
+ * Work on the Cabri import filter, so that it actually becomes
+ usable for some easier files..
+
+ * Improve the errors given by the "New Script Wizard", by making
+ it get a proper error description from the python interpreter.
+
+2003-10-09 Dominique Devriese <devriese@kde.org>
+
+ * Add a lot of documentation to the new classes.
+
+ * Fix the moving system again, it now only redraws exactly those
+ objects that need to be redrawn. E.g. when a constrained point
+ was moved, before it was assumed that all of its parents, and
+ their children would move, whereas in reality, a constrained point
+ does not move the curve it is constrained to. This is now taken
+ into account for. This much optimizes the case where we move the
+ constrained point in examples/sine-curve.kig.
+
+ * Added a DESIGN document, documenting the Kig object system
+ design. I think that is rather finished now, and it's probably
+ about time to try and make some other people than myself get it ;)
+
+ * Remove support for the ancient pre-0.4 file format that we still
+ supported opening. If you still have old files around using it,
+ you should convert them to the new format, by opening them with a
+ Kig version between 0.4 to 0.6, and re-saving them. Maintaining
+ compatibility with these old files doesn't seem very useful,
+ because I don't think there are many files in this format
+ available, and therefore I didn't think it was worth the trouble
+ of porting the code to the new object system.
+
+ * Introduce a new file format that matches the new object system
+ better. Files in the old format can still be opened seamlessly.
+
+ * Add undo/redo support for changing visible aspects of an object
+ ( size, color, shown state ). In the new system, this was as easy
+ as replacing the ObjectDrawer of an ObjectHolder with another one.
+
+ * Another ( hopefully the last ) major change to the object
+ system. Decouple the link between how an object is calced and how
+ it is drawn. We now have a hierarchy structure of ObjectCalcer's
+ describing various objects and their interrelations. On top of
+ that, there are the ObjectHolder's, which hold a link to an
+ ObjectCalcer from the hierarchy, and keep an ObjectDrawer
+ describing how to draw it. The document only keeps a list of
+ ObjectHolder's, nothing else..
+
+ * make the New Script Wizard give an error when the script does
+ not generate a valid ObjectImp.
+
+ * fix some issues with the escaping of an & in a translatable
+ string in an xml file
+
+ * fix the generation of the pot translation template file
+
+ * fix a problem with the order of arguments in ScalingOverLineType
+ causing a test file to not be loaded correctly..
+
+ * update some test files to the new ( post-0.4 ) kig file format.
+
+ * add ( sometimes placeholder ) icons for the remaining actions
+ that missed icons ( thanks to Maurizio Paolini )
+
+2003-09-08 Dominique Devriese <devriese@kde.org>
+
+ * Fix a bug that prevented Kig from opening its own files,
+ rejecting them because they were of the 0.6.0 version, which Kig
+ could not open.. I'm backporting this into Kig 0.6.0 and
+ informing the packager..
+
+ * clean up: Objects now store their parents in order, so that no
+ parsing has to be done in the calc() function.. Also some more
+ modifications making that function a bit simpler are included.
+ Specifically, ArgsParser now does the checking of the arguments,
+ instead of every single calc function doing it itself..
+
+2003-09-02 Dominique Devriese <devriese@kde.org>
+
+ * rename ArgparserObjectType to ArgsParserObjectType
+
+ * remove ArgsChecker class, and rename ArgParser to ArgsParser
+
+2003-09-02 Dominique Devriese <devriese@kde.org>
+
+ * branch off Kig 0.6.0
+
+2003-09-01 Dominique Devriese <devriese@kde.org>
+
+ * only move an object if its parents are not yet moving.. This
+ fixes bug #63250.
+
+ * remove the defective operator| and operator& implementations for
+ the Objects class
+
+2003-08-31 Dominique Devriese <devriese@kde.org>
+
+ * make the Kig Python Scripting API docs only available online.
+ It's too much trouble to generate them during the build process,
+ and I can't add a hard build-time dependency on doxygen anyway...
+
+ * keep the Kig version number in a central place, so that it can
+ easily be changed. Use some autoconf magic to fill it in in the
+ other places..
+
+2003-08-25 Dominique Devriese <devriese@kde.org>
+
+ * update the configure.in.* files and remove
+ README.boost-python1.30-gcc3.2 and boost-python1.30-gcc3.2.patch
+ because distributing a Boost.Python patch with Kig is really
+ stupid, and because the Debian packagers have already applied the
+ patch in their version of Boost.Python, and so should the other
+ distro's. Seems I need to thank Ben Burton for suggesting to the
+ Debian packagers to apply the patch.
+
+ * fix a wrong "lib not found error" in configure.in.in by removing
+ -pedantic from CXXFLAGS while trying to compile.
+
+2003-08-15 Dominique Devriese <devriese@kde.org>
+
+ * improve the inline documentation in order to improve the doxygen
+ generated docs for the python scripting API.
+
+2003-08-03 Dominique Devriese <devriese@kde.org>
+
+ * give Transformation::apply better semantics
+
+2003-07-27 Dominique Devriese <devriese@kde.org>
+
+ * add a warning to configure.in.bot about how Boost.Python 1.30
+ together with GCC 3.2+ is a bad combination, along with a patch.
+
+ * add documentation about attaching text labels and locuses to the
+ index.docbook file
+
+2003-07-23 Dominique Devriese <devriese@kde.org>
+
+ * add a nifty python scripting example that shows the graph of a
+ sine curve, but can in fact be used to show any function's graph
+ you would come up with. It uses python scripting and the locus
+ facility in a clever way to do this. In fact, I stole the idea
+ from something I saw Hilaire Fernandes do with the Dr.Genius guile
+ scripting on a presentation at FOSDEM. Kig - of course ;) - does
+ it way cooler.. :)
+
+ * add support for using the python math package in Kig python
+ scripts, by importing it from PythonScripter's ctor, and by making
+ Kig load its part library with RTLD_GLOBAL, to eliminate a problem
+ which caused python to not be able to load its math dll..
+
+2003-07-20 Dominique Devriese <devriese@kde.org>
+
+ * add support for attached text labels.
+
+2003-07-17 Dominique Devriese <devriese@kde.org>
+
+ * fix the "conversion from const char* to char*" problem in
+ python_scripter.cc. This introduces a small, harmless memory leak
+ because of how the python libs work..
+
+2003-07-16 Dominique Devriese <devriese@kde.org>
+
+ * add documentation about installing the python dev libs to
+ configure.in.bot
+
+ * adapt some infrastructure regarding text labels to be able to
+ work with labels that get their location from an invisible Point
+ object. This will ease the adding of support for attached text
+ labels..
+
+2003-07-12 Dominique Devriese <devriese@kde.org>
+
+ * prevent a crash when kig cannot find its library. It now just
+ complains and exits properly.
+
+2003-07-03 Dominique Devriese <devriese@kde.org>
+
+ * add Python scripting support. Rather large addition, involving
+ a lot of autoconf and automake magic..
+
+ * make snapToGrid work for PolarCoordinateSystem
+
+ * make shift -> snap to grid work in PointConstructionMode and
+ normal Construction Mode too..
+
+ * add the concept of cache objects, which cannot be stored, in
+ order to support a python compiled script ObjectImp..
+
+2003-07-02 Dominique Devriese <devriese@kde.org>
+
+ * sanitize the ObjectImp inherits() system. It now uses static
+ objects instead of enum values, this also eliminates some ugly
+ functions in ObjectImp, and allows for more flexible addition of
+ new ObjectImp types..
+
+ * fix a memory leak in KigDocument, which did not delete its
+ KCommandHistory..
+
+ * fix some use of uninitialised value in dragrectmode, which
+ caused the dragrect to not work at random times
+
+ * fix the clearing of the selection when the user clicks on an
+ empty point..
+
+2003-06-27 Dominique Devriese <devriese@kde.org>
+
+ * implement helpSlot() in ManageTypesDialog..
+
+ * add a "Set Coordinate System" menu to the Settings menu..
+
+ * make shift snap to grid in moving mode, and rework the moving
+ API to something a bit saner in the process..
+
+2003-06-25 Dominique Devriese <devriese@kde.org>
+
+ * add undo support for various view actions like zoom in, zoom
+ out, recenter screen, select screen rect etc. Check out the
+ comment in the function KigWidget::slotZoomIn() in
+ kig/kig_view.cpp for why I implemented this even though it isn't
+ really "correct".
+
+2003-06-24 Dominique Devriese <devriese@kde.org>
+
+ * fix a crash bug reported by Pino Toscano, that occurs because
+ TextLabelRedefineMode was not yet updated to the new
+ reference-counting Object's stuff..
+
+2003-06-21 Dominique Devriese <devriese@kde.org>
+
+ * Implement Select all, Unselect all and Invert selection.
+
+
+2003-06-20 Dominique Devriese <devriese@kde.org>
+
+ * fix this bug:"17) Add the possiblity, by pressing Esc, to stop
+ the selection, even of the area to be shown."
+
+ * add an icon for Arc's center property, this fixes: "12) Why
+ don't you use baseCircle.png as icon to show/construct the center
+ of a circle and (why not?) an arc?"
+
+ * fix: a text label constructed using "add text label" from an
+ object popup wasn't properly calced after construction..
+
+ * fix this bug: "2) Add the possibility to set shortcut for all
+ the actions & objects (For examples: Ctrl+P to construct a point,
+ Ctrl+R to start a reflection, and so on...).", and add some
+ default accels too ( "p" for point, "s" for segment etc. ( note :
+ no control key ).
+
+ * fix this bug: "3) When I select a segment, in his popup there are
+ two same entry in Construct submenu, called Mid point an
+ Midpoint. Why?" as reported by Pino Toscano
+
+
+2003-06-11 Dominique Devriese <devriese@kde.org>
+
+ * move transformations to their own menu entry, thanks to Pino
+ Toscano
+
+ * move angle stuff to their own objects submenu, and toolbar,
+ thanks to Pino Toscano
+
+ * update the images in the docs, thanks to Pino Toscano
+
+2003-06-04 Dominique Devriese <devriese@kde.org>
+
+ * show an appropriate error when trying to open an non-existing
+ file..
+
+ * clean up the object parent-child relation mechanism. Rather
+ large code cleanup, that simplifies a lot of code.. Needed a
+ backwards-compatible file format extension. This commit now also
+ adds proper treatment of internal objects, because it no longer
+ relies on the inherently wrong isInternal() hack, but features The
+ Correct Fix(tm).
+
+2003-06-03 Dominique Devriese <devriese@kde.org>
+
+ * bugfix: show default icons for actions that don't have any.. (
+ fixes bug #59283 )
+
+ * release Kig 0.5.1
+
+2003-05-30 Dominique Devriese <devriese@kde.org>
+
+ * Add an option to select the part of the screen that should be
+ shown by dragging a rect..
+
+2003-05-28 Dominique Devriese <devriese@kde.org>
+
+ * fix warnings when compiling with --disable-debug
+
+2003-05-26 Dominique Devriese <devriese@kde.org>
+
+ * fix a crash bug for a weird cubic situation
+
+2003-05-25 Dominique Devriese <devriese@kde.org>
+
+ * implement another of Stephan Binner's suggestions: in the set
+ coordinate system popup, show a checked mark next to the
+ current coordinate system..
+
+ * fix a bug that caused the "circle by center and point" type to
+ not be visible..
+
+2003-05-24 Dominique Devriese <devriese@kde.org>
+
+ * when the user tries to construct a macro that constructs an
+ object from its children, warn him instead of
+ crashing... Thanks to Stephan Binner for the bug report
+
+ * improve the export to image dialog, as suggested by Stephan Binner
+
+2003-05-23 Dominique Devriese <devriese@kde.org>
+
+ * remove some obsolete code and clean some older code up..
+
+2003-05-22 Dominique Devriese <devriese@kde.org>
+
+ * add simple printing support using the fantastic KDE-Print lib
+
+2003-05-21 Dominique Devriese <devriese@kde.org>
+
+ * fix the full screen mode, to use the correct shortcut for
+ starting and stopping it, and use QWidget::showFullScreen, instead
+ of creating a full screen pseudo-dialog etc.
+
+ * "branch off" release 0.5, and update the version strings etc.
+
+2003-05-17 Dominique Devriese <devriese@kde.org>
+
+ * add a toolbar icon ( i.e. GUIAction ) for constructing an angle
+ bisector..
+
+2003-05-15 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * take advantage of the new invalid coordinate when creating circles
+ and arcs through three aligned points
+
+2003-05-13 Dominique Devriese <devriese@kde.org>
+
+ * fix compilation with --enable-final
+
+2003-05-12 Dominique Devriese <devriese@kde.org>
+
+ * fix a crash bug for macro's involving PropertyImp
+
+ * update the AboutData: upgrade some people to authors, and add
+ credit for some more people..
+
+ * add an angle bisector property
+
+2003-05-10 Dominique Devriese <devriese@kde.org>
+
+ * fix the transformation types for cases where the object being
+ transformed is the same as one of the arguments that the
+ transformation needs.. E.g. right-click on a
+ point->transform->reflect over a point works properly
+ point->transform->now..
+
+2003-05-09 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * the drawLocus is now changed to function as a generic drawCurve.
+ The changes are very little, and the locusCalcPoint is no
+ longer necessary. It seems that performance is not affected
+ significantly. The drawCubic is not used any longer; it is
+ still there in kigpainter, but can be purged as soon as
+ no problems arise with the new setup. The generic drawCurve
+ is used in place of drawCubic.
+
+2003-05-08 Dominique Devriese <devriese@kde.org>
+
+ * add support for quite some more types to the kseg import filter
+
+2003-05-08 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * fixed drawing problem while building a cubic by 9 points. The
+ problem was located in calcCubicRoot when the degree is
+ less than 3
+
+2003-05-08 Dominique Devriese <devriese@kde.org>
+
+ * add some properties to the arc object
+
+ * organise the filters directory more sanely
+
+ * fix for deleting: remove deleted objects from their children, so
+ they don't appear in saved files
+
+2003-05-07 Dominique Devriese <devriese@kde.org>
+
+ * more undo support: redefining text labels and points is undoable
+ now..
+
+ * small undo stuff cleanup
+
+2003-05-06 Dominique Devriese <devriese@kde.org>
+
+ * fix the change text action for text labels to reuse the label
+ construction dialog. this makes it support multi-line
+ labels, and changing the parameters
+
+2003-05-05 Dominique Devriese <devriese@kde.org>
+
+ * add zoom in/out icons to the document popup menu
+
+2003-05-03 Dominique Devriese <devriese@kde.org>
+
+ * add support for multiline text labels.. still needs some
+ further work..
+
+ * add a set size action to the angle type
+
+ * change the angle size icon..
+
+2003-05-03 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ * add transformation support for arcs..
+
+2003-05-02 Dominique Devriese <devriese@kde.org>
+
+ * add undo support for changing the coordinate system
+
+ * generalize the undo support from the moving mode, and add undo
+ support for many of the object specific actions..
+
+2003-05-01 Dominique Devriese <devriese@kde.org>
+
+ * perfect the grid..
+
+ * fix useless error output on startup
+
+ * add scroll bars to the full screen mode
+
+ * add zoom actions to the document popup
+
+ * add a change text action to text labels
+
+2003-04-28 Dominique Devriese <devriese@kde.org>
+
+ * add undo support for moving
+
+ * add a full screen mode
+
+2003-04-27 Dominique Devriese <devriese@kde.org>
+
+ * some PolarCoords improvements
+
+ * show a popup menu when the user clicks on the document, and allow
+ him to change the coordinate system..
+
+2003-04-26 Dominique Devriese <devriese@kde.org>
+
+ * added property icons
+
+2003-04-22 Dominique Devriese <devriese@kde.org>
+
+ * fix the move dependencies..
+
+2003-04-19 Dominique Devriese <devriese@kde.org>
+
+ * Add KSeg file format support
+
+ * Start using the ChangeLog for versions after 0.4.1 ;)
+
+ma feb 11 00:12:52 CET 2002 - Dominique Devriese <devriese@kde.org>
+
+ * Initial Creation
diff --git a/kig/DESIGN b/kig/DESIGN
new file mode 100644
index 00000000..fd887779
--- /dev/null
+++ b/kig/DESIGN
@@ -0,0 +1,275 @@
+EXPLANATION OF THE KIG DESIGN
+=============================
+
+1. Object system
+----------------
+
+The Kig Object System is a design I'm particularly proud of. It
+started out pretty basic, but has undergone some major revisions, that
+have proven very succesful. Currently, I have just made one more
+major change, and I think this will be the last majore change to it
+for quite some time to come. That's also why I'm writing this
+explanation for other developers.
+
+
+
+1.1 ObjectImp's: Basic objects.
+
+An ObjectImp represents the current state of an object in Kig. It
+keeps information about what type of object it is ( e.g. a line, a
+point, a circle etc. ), and its exact data ( e.g. the center and
+radius of the circle ). It is *not* in any way aware of how the
+object was calculated from its parents (e.g. is this a line that is
+constructed as the parallel of another line, or as the line going
+through two given points ? ) or how it is drawn on the window (
+e.g. the thickness of the line, its color etc. ).
+
+There is also the notion of BogusImp's in Kig. These are special
+kinds of ObjectImp's that *only* hold data. They do not represent any
+real object that can be drawn on a window. Their use is *only* in
+holding data for other objects to use. Examples are StringImp,
+IntImp, ConicImp etc.
+
+There are a lot of ObjectImp's in Kig, most of them are in files
+called *_imp.h and *_imp.cc or *_imp.cpp in the objects subdirectory.
+Examples are PointImp, LineImp, ConicImp, CircleImp, CubicImp,
+AngleImp etc.
+
+There is also the concept of ObjectImpType's. These identify a kind
+of ObjectImp. They carry information about the inheritance among the
+different ObjectImp types, and some strings identifying them. You can
+get hold of the ObjectImpType of a certain ObjectImp by using its
+type() method, you can also get hold of them by name using
+ObjectImpFactory.
+
+
+1.2 ObjectCalcer's: calculating ObjectImp's from other ObjectImp's
+
+An ObjectCalcer is an object that represents an algorithm for
+calculating an ObjectImp from other ObjectImp's. It is also a node in
+the dependency graph of a certain document. E.g. a LineImp can be
+calculated from the two PointImp's it has to go through; every time
+either of them moves, this calculation is redone. In this case, there
+would be an ObjectCalcer that keeps a reference to its two parents (
+the ObjectCalcer's representing the points ), and that will calculate
+its ObjectImp value every time it is asked to do so ( i.e. every time
+one of its parents moves.. ).
+
+Because of the complex relations that ObjectCalcer's hold to other
+ObjectCalcer's and to other classes, they have been made
+reference-counted. This means that they keep a count internally of
+how much times a pointer to them is held. If this count reaches 0,
+this means that nobody needs them anymore, and they delete themselves.
+E.g. an ObjectCalcer always keeps a reference to its parents, to
+ensure that those aren't deleted before it is deleted.
+
+In the inheritance graph of a document, the lowermost objects keep
+references to their parents and those keep reference to their parents,
+so that all of the top of the graph is kept alive. Of course, someone
+needs to keep a reference to the bottommost objects in the graph,
+because otherwise, the entire graph would be deleted. As we will see
+later, an external class ( ObjectHolder ) keeps a reference to the
+ObjectCalcer's that the user is aware of. Thus, the reference
+counting system makes sure that all the objects that the user knows
+about, and all of their ancestors are kept alive, and the others die.
+At the end of the program, this reference is released, and all the
+objects are deleted.
+
+A special case of an ObjectCalcer is the ObjectConstCalcer. This is
+an ObjectCalcer that has no parents, and only holds some data. The
+data is held as an ObjectImp of some type, and it will remain
+constant, and no calculation needs to be done to get it, it is just
+returned every time it is needed.
+
+Other ObjectCalcer's are ObjectPropertyCalcer and ObjectTypeCalcer.
+ObjectTypeCalcer is a ObjectCalcer that calculates an object according
+to what a ObjectType object specifies. It basically forwards all
+calculations to that object ( check below ). An ObjectPropertyCalcer
+gets data from a property of a certain object. In fact, ObjectImp's
+can specify property's ( e.g. properties of a circle are its radius,
+its circumference, its center etc. An angle has its bisector as a
+LineImp property ), and they are returned as ObjectImp's of an
+appropriate type. The ObjectPropertyCalcer just gets one of the
+properties of a certain ObjectImp and stores it.
+
+
+1.3 ObjectType's: a specification of how to calculate an object.
+
+An ObjectType represents a certain algorithm to calculate an ObjectImp
+from other ObjectImp's. Unlike an ObjectCalcer, it does not
+participate in the inheritance graph, and there is only one
+instantiation of each type of ObjectType. An ObjectTypeCalcer is an
+ObjectCalcer that keeps a pointer to a certain ObjectType, and
+forwards all requests it gets to its ObjectType. It's very normal
+that multiple ObjectTypeCalcer's share the same ObjectType.
+
+There are very much ObjectType's in Kig, check out all of the files
+that end in *_type.* or *_types.* in the objects subdirectory of the
+Kig source code.
+
+
+1.4 ObjectHolder's: a link from the document to the hierarchy
+
+An ObjectHolder represents an object as it is known to the document.
+It keeps a pointer to an ObjectCalcer, where it gets its data ( the
+ObjectImp that the ObjectCalcer holds ) from. It also holds
+information about how to draw this ObjectImp on the window, by keeping
+a pointer to an ObjectDrawer ( see below ). In its draw method, it
+gets the ObjectImp from the ObjectCalcer, and passes it to the
+ObjectDrawer, asking it to draw the ObjectImp on the window.
+
+The document ( check the KigDocument class ) holds a list of these
+ObjectHolder's. This is its only link with the ObjectCalcer
+dependency graph. An ObjectHolder keeps a reference to its ObjectCalcer.
+
+
+1.5 ObjectDrawer: An intelligent struct keeping some data about how to
+ draw an ObjectImp on screen.
+
+An ObjectDrawer is used by an ObjectHolder to keep information about
+how to draw an ObjectImp on the window. It is really nothing more
+than a struct with some convenience methods. It does not have any
+virtual methods, or have any complex semantics. It keeps information
+like the thickness of an object, its color, and whether or not it is
+hidden.
+
+
+2. Interesting Issues
+---------------------
+
+Here, I explain some parts of the design that may at first look
+difficult to understand. This part assumes you have read the above.
+
+
+2.1 Text labels
+
+Text labels in Kig are designed in a pretty flexible
+way. I will explain all the classes involved.
+
+2.1.1 TextImp
+
+First of all, there is the TextImp class. It is an ObjectImp (
+cf. supra ), and thus represents a piece of text that can be drawn on
+the document. It contains a QString ( the text to be shown ), a
+coordinate ( the location to draw it ), and a boolean saying whether a
+frame should be drawn around it. As with all ObjectImp's, it does not
+contain any code for calculating it, or how it behaves on user input.
+Most of this is handled by the TextType class.
+
+2.1.2 TextType
+
+The TextType class is an implementation of an ObjectType. It contains
+code specifying how to calculate a TextImp from its parents, and for
+how it behaves on user input. A text object has at least three
+parents, and can handle any number of optional arguments. The three
+mandatory arguments are an int, which is set to 1 or 0 depending on
+whether the label needs a surrounding box, a PointImp, containing the
+location of the text label, and a string containing the text of the
+label. The text can contain tokens like '%1', '%2' etc. Every
+additional argument is used to replace the lowest-numbered of those
+tokens, with its string representation. The function
+ObjectImp::fillInNextEscape is used for this.
+
+For example, if a TextType has the following parents:
+a IntImp with value 0
+a PointImp with value (0,0)
+a String with value "This segment is %1 units long."
+a DoubleImp with value 3.9
+
+This would result in a string being drawn at the coordinate (0,0),
+with no surrounding box, and showing the text "This segment is 3.9
+units long.".
+
+All this gives labels in Kig a lot of flexibility.
+
+2.2 Locuses
+
+Locuses are a mathematical concept that has been modelled in Kig.
+Loosely defined, a locus is the mathematical shape defined by the set
+of points that a certain point moves through while another point is
+moved over its constraints. This can be used to define mathematical
+objects like conics, and various other things. It has been modelled
+in Kig in the most flexible way I can imagine, and I must say that I'm
+proud of this design.
+
+2.2.1 Constrained points
+
+In the implementation of this, we use the concept of constrained
+points. This is a point that is attached to a certain curve. It is
+implemented in Kig by the ConstrainedPointType, which takes a CurveImp
+and a DoubleImp as parents and calculates a Point from these by using
+the CurveImp::getPoint function.
+
+2.2.2 The Implementation
+
+When a Locus is constructed by the user, Kig receives two points, at
+least one of which is a Constrained point, and the other one somehow
+depends on the first. This is checked before trying to construct a
+Locus, and the user is not allowed to try to construct locuses from
+other sorts of points.
+
+Next, Kig takes a look at the ObjectCalcer hierarchy. We look at the
+smallest part of the hierarchy that contains all paths from the first
+point to the second point. We then determine all objects that are not
+*on* one of those paths ( meaning that they are not calculated from
+the first point, or another object that is on one of those paths ),
+but that are parents of one or more objects that are on those paths.
+I call this set of objects the "side of the path" sometimes in the
+code. The function that finds them is called sideOfTreePath.
+
+Next, an ObjectHierarchy object is constructed, which stores the way
+to calculate the second point from the first point and the objects
+from the previous paragraph.
+
+An object is then constructed that has as parent the curve parent that
+the first point is constrained to, the HierarchyImp containing the
+ObjectHierarchy from the previous paragraph, and all the objects from
+the "side of the tree". This new object is an ObjectTypeCalcer with
+the LocusType as its type. In its calc() function, it calculates a
+LocusImp by taking the objecthierarchy and substituting all the
+current values of the objects from the "side of the path", resulting
+in an ObjectHierarchy that takes one PointImp and calculates another
+PointImp from that. The LocusImp then contains the new
+ObjectHierarchy and the current value of the curve that the first
+point is constrained to. In the drawing function of this LocusImp,
+points on the curve are calculated, and then the hierarchy is used to
+calculated from those points the location of the second point. A
+dynamic feedback algorithm, which has been written with a lot of help
+from the mathematician "Franco Pasquarelli" is used to determine which
+of the points on the curve should be used.
+
+2.2.3 The Rationale
+
+The above explanation may seem very complicated, but I am very much
+convinced that this *is* the proper way to handle locuses. I will
+here try explain why I think it is superior to the much simpler
+implementation that is used by much other programs.
+
+The basic alternative implementation involves just keeping a pointer
+to the first and second point in the locus object, and when the locus
+is drawn, the first point is moved over all its possible locations,
+the second point is calculated, and a point is drawn at its new
+location.
+
+The reason I think that this is a bad implementation is that it is not
+possible to model the real dependency relations properly in this
+scheme. For example, the locus object would then be made dependent on
+the constrained point. This is wrong because when the constrained
+point moves within the limits of the curve constraining it, the locus
+does by definition not change. Also, if the constrained point is
+redefined so that it is no longer constrained to any curve, this is a
+major problem, because it would invalidate the locus. Another point
+is that in practice, the locus depends on more objects than its
+parents alone. This is not a good thing, because it makes it
+impossible to optimise drawing of the objects, using the information
+about which objects depend on which others, because this information
+is invalid.
+
+The reason we need to calculate the "side of the path" above is that,
+together with the curve that the first point is constrained to, these
+are the objects that the locus is really dependent on.
+
+The current Kig system correctly models all dependency relations to
+the extent possible, while keeping a correct implementation.
+
+
diff --git a/kig/FEATURES b/kig/FEATURES
new file mode 100644
index 00000000..012f49f1
--- /dev/null
+++ b/kig/FEATURES
@@ -0,0 +1,44 @@
+FEATURES
+here are some nice Kig features i'd like to show off :)
+- More than 40 various nice objects: from the easiest ones ( points ),
+ up to lines, circles, conics, cubics, and more. See the Objects
+ menu...
+- Macros: the power of constructing new objects using the builtin
+ ones. If you want to try, open macrotest.kig, then click the
+ button to the left of the fullscreen button, select the three
+ corners of the triangle, then click the button again, click the
+ circle, click the button again, type in a name. Then check out the
+ new type with the other circle types. You can't really see the
+ difference between built-in types and macro's
+- I've given quite some attention to making Kig as intuitive to use as
+ possible. It has various unique features like the nice RMB menu's,
+ the intuitive construction mode, etc.
+- is a KPart: try opening macrotest.kig from konqueror, if it doesn't
+ work yet, open your kcontrol, then go to "File Browsing"->"File
+ Associations", click add, group:"application", name:"x-kig", open
+ the "embedding" tab page for the new type, click "add", find
+ "KigPart" (if you installed Kig correctly (did you get the
+ "--prefix" on your configure right?) , it should be there), and add
+ it. then try opening macrotest.kig again
+- Kig supports various file formats... See the filters directory.
+ Currently Kig has read-write support for native files ( which is an
+ imho clean xml format ) and for the older version of the Kig file
+ format; read support for KGeo, KSeg and, partially, for Dr. Geo
+ and Cabri files. This is an area where we plan working on...
+- Kig can export a document in several formats: the most common are
+ images, and you can choose among the types supported by Qt and KDE.
+ Moreover, the other supported formats are: XFig files, and SVG and
+ LaTeX documents. These are useful since not all other programs
+ support Kig files yet... ;)
+- Kig is very compatible with the program it was intended to replace,
+ KGeo. It supports all of its Object types and most of its file
+ format...
+- There is a very flexible mechanism for supporting TextLabels with
+ variable parts.. Check out the text label wizard for more
+ explanation...
+- nice support for Locuses, inspired by KSeg's version of this. Check
+ the documentation and examples/locustest.kig for more info..
+- flexible transformation facility
+
+PLANNED FEATURES
+For a list of planned features, check out the TODO file.
diff --git a/kig/Makefile.am b/kig/Makefile.am
new file mode 100644
index 00000000..b2483db0
--- /dev/null
+++ b/kig/Makefile.am
@@ -0,0 +1,58 @@
+if KIG_COMPILE_PYTHON_SCRIPTING
+scriptingdir = scripting
+scriptinglib = scripting/libscripting.la
+else
+scriptingdir =
+scriptinglib =
+endif
+
+SUBDIRS = \
+ objects \
+ misc \
+ modes \
+ icons \
+ filters \
+ examples \
+ kig \
+ mimetypes \
+ macros \
+ kfile \
+ data \
+ pykig \
+ $(scriptingdir)
+
+kde_module_LTLIBRARIES = libkigpart.la
+libkigpart_la_SOURCES = dummy.cpp
+libkigpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+libkigpart_la_LIBADD = $(LIB_KPARTS) \
+ misc/libmisc.la objects/libobjects.la filters/libfilters.la \
+ modes/libmodes.la kig/libkigparttemp.la $(scriptinglib)
+
+messages: rc.cpp
+ rm -f tips.cpp
+ $(EXTRACTRC) */*.rc >> rc.cpp
+ $(EXTRACTRC) */*.ui >> rc.cpp
+ (cd data && $(PREPARETIPS) > ../tips.cpp)
+ for file in macros/*.kigt; do \
+ cat "$$file" | grep '<Name>' | sed -e 's/^ *<Name>\([^<]*\)<\/Name>/i18n( "\1" );/' | sed -e 's/&amp;/\&/g' >> rc.cpp; \
+ cat "$$file" | grep '<Description>' | sed -e 's/^ *<Description>\([^<]*\)<\/Description>/i18n( "\1" );/' | sed -e 's/&amp;/\&/g' >> rc.cpp; \
+ cat "$$file" | grep '<UseText>' | sed -e 's/^ *<UseText>\([^<]*\)<\/UseText>/i18n( "\1" );/' | sed -e 's/&amp;/\&/g' >> rc.cpp; \
+ cat "$$file" | grep '<SelectStatement>' | sed -e 's/^ *<SelectStatement>\([^<]*\)<\/SelectStatement>/i18n( "\1" );/' | sed -e 's/&amp;/\&/g' >> rc.cpp; \
+ done
+ $(XGETTEXT) tips.cpp rc.cpp filters/*.h kig/*.h misc/*.h modes/*.h objects/*.h scripting/*.h */*.cc kig/*.cpp misc/*.cpp modes/*.cpp -o $(podir)/kig.pot
+ $(XGETTEXT) kfile/kfile_drgeo.cpp kfile/kfile_drgeo.h -o $(podir)/kfile_drgeo.pot
+ $(XGETTEXT) kfile/kfile_kig.cpp kfile/kfile_kig.h -o $(podir)/kfile_kig.pot
+
+CLEANFILES = dummy.cpp
+
+dummy.cpp:
+ touch dummy.cpp
+
+TAGS:
+ find -name '*.cc' -o -name '*.cpp' -o -name '*.h' | etags -
+
+# Want to do the scripting part separately, but
+# include everything else.
+DOXYGEN_EXCLUDE = python-scripting-api-dox-mainpage.dox
+DOXYGEN_SET_RECURSIVE = YES
+include ../admin/Doxyfile.am
diff --git a/kig/README.Developers b/kig/README.Developers
new file mode 100644
index 00000000..753533e4
--- /dev/null
+++ b/kig/README.Developers
@@ -0,0 +1,46 @@
+Hi, here are some things that might not be immediately clear :
+
+- There are different source dirs ( kig, objects, misc, filters and
+ modes ) ( just in case this wasn't clear.. )
+
+- for testing code, i don't really know how you're supposed to do this with
+ kparts, so i just do a "make install" every time, and then simply run the
+ program, you prolly want to do "./configure --enable-debug=full
+ --prefix=/usr/local/kde3" (meanwhile, i found out, the solution is in a
+ developer faq on developer.kde.org
+ (http://developer.kde.org/documentation/other/developer-faq.html#q67.1)
+
+- There is some documentation about the design in the file DESIGN
+
+- if you want to contribute, your work is more than welcome, no matter where
+ you want to help: translation, coding, art, just send us a mail at
+ kde-edu-devel@kde.org (preferably before you start, so you won't be
+ doing unnecessary work or something like that), if you have cvs access,
+ you can of course always commit to cvs
+
+HISTORY
+
+I started Kig because we were using "Cabri" in school, a proprietary
+windows-only app. When I started looking for free alternatives that ran on
+linux, i found two: KGeo and KSeg. Both had features and limitations, KSeg
+had most features, but was ugly. Furthermore, it was qt-only, which did
+allow it to run on windows too, but made it not fit into kde. KGeo was
+fully KDE, but didn't have all the features that KSeg had.
+
+I first wanted to merge both together, but the code was rather incompatible,
+so I wanted to simply extend KGeo. Since I was planning to make it a kpart
+app, i started with "kapptemplate --kpart-app", and then started coding. I
+was first planning to use lots of code from both kgeo and kseg, but i ended
+up recoding everything since in many cases it was faster than porting stuff,
+and i wanted to change rather much in the code.
+
+I did get much inspiration from the source of both programs, and i used some
+source and many pictures from KGeo, I would therefore want to thank both
+developers for their work.
+
+I also want to thank everyone who contributed something to Kig or to
+free software in general.
+
+Cheers,
+
+The Kig Developers
diff --git a/kig/README.boost-python1.30-gcc3.2 b/kig/README.boost-python1.30-gcc3.2
new file mode 100644
index 00000000..cafda75e
--- /dev/null
+++ b/kig/README.boost-python1.30-gcc3.2
@@ -0,0 +1,19 @@
+There is a bug in Boost.Python version 1.30 when compiled with GCC
+3.2. This causes an error on compiling. It is a known problem, and
+due to the stricter typename checking in more recent GCC versions.
+The new Boost.Python version will contain a fix for this problem, but
+it might take some more months for this version to become available,
+and some distributions ( including Debian, not including Red Hat ( at
+this time, 22-9-2003, at least ) ). In the mean time, I have included
+a patch to the boost.python headers in the Kig distribution that fixes
+this problem. It is called boost-python1.30-gcc3.2.patch, and should
+be applied in the following way.
+
+Open a console window, and go to the directory containing the
+Boost.Python headers. This will most likely be called something like
+"/usr/include/boost/python/". Then execute the following commands (
+before giving these commands, replace "/dir/to/kig/distribution/" by
+the directory where you put the downloaded kig distribution ):
+
+cd object
+patch make_ptr_instance.hpp < /dir/to/kig/distribution/boost-python1.30-gcc3.2.patch
diff --git a/kig/README.in b/kig/README.in
new file mode 100644
index 00000000..692e03c3
--- /dev/null
+++ b/kig/README.in
@@ -0,0 +1,9 @@
+Kig v@KIGVERSION@
+Kig developers <kde-edu-devel@kde.org>
+----------------------------------------------------------------------
+Kig: KDE Interactive Geometry
+Kig is a program for use in math classes in high school, to allow
+students to interactively explore geometric concepts. For more
+information: check out the documentation ( open "help:/kig" in
+konqueror...)
+
diff --git a/kig/TODO b/kig/TODO
new file mode 100644
index 00000000..8acd9949
--- /dev/null
+++ b/kig/TODO
@@ -0,0 +1,157 @@
+* bugs
+
+- There is a pretty strange bug in kig when you use the accel keys.
+ Open Kig, type p to start constructing a point. Click somewhere to
+ construct one. Now click p again, and press escape to cancel the
+ construction. It will not work, and you will have to construct as
+ many points as times you pressed escape ( or perhaps the times you
+ pressed esc square or sth like that ). Anyway, this is due to how
+ Kig works with some strange Qt event loop stuff to make its modes
+ work, along with a strange way in kaccel of working. I have a
+ patch against kdecore/kaccel.cpp that should fix it, but the real
+ fix is to get rid of the entire event loop stuff and think of a
+ better way to manage all this. pino: seems pressing the stop button
+ n times, where n are the times you pressed escape, cancel all the
+ constructions, so the problem is the behaviour of escape.
+
+- The polar coordinate system blocks Kig when zooming. Select the
+ polar coordinate system, use the Select shown area tool ( or your
+ favorite zooming tool ) and select a specific part of the document.
+ Smaller parts of the document cause bigger problems. pino: this is
+ due to the polar grid: try to make zoom if there is no grid.
+
+* I/O: filters, exporters, ...
+
+- add other command line options, like:<br />
+ -e, --export-to FORMAT file.kig => Kig will export file.kig ( or any
+ other supported format ) into file.ext ( even more than one file ).
+ The output format depends on the FORMAT string. domi: this is more
+ difficult, because the export plugins require extra parameters.
+ E.g. the ImageExporter needs an image size etc.
+
+- filters: more input filters; improve the existent ones ( see
+ filters/*-filter-status.txt ); add the possibility to ignore errors
+ on loading
+
+- "export to *": add stuff like java applets, kmplot documents, etc...
+
+* objects
+
+- Two new transformations: projection on a line, orthogonally and
+ according to a given direction. As a mathematician, I'm supposed to
+ have a grudge against these, as they don't fit the definition for
+ affine transformations ( the matrix has to be regular ) ;), but I
+ suppose high-school students may find them useful. However,they
+ would give rather useless results for e.g. lines ( all curves are
+ almost always projected on a line, segment or ray that you wouldn't
+ see because it's equal to the line we project upon ). It would be
+ useful for points though.
+
+- make DoubleImp a "visible" object with uses like Dr. Geo numeric
+ values.
+
+- Provide some nice stuff for differential geometry: velocity vector
+ of a curve, curvature vector, osculating parabole. Most of this is
+ not too difficult to implement, but very cool :)
+
+- create a formula label to display math formulas in the document, and
+ allow for importing from/exporting to other formula formats such as
+ KFormula, OOFormula and MathML.
+
+- other types of fillable shapes, like arc sector, arc segment...
+
+- defined integrals, as a particular case of filled shapes.
+
+- improve *a lot* the transformation support for cubics.
+
+* GUI
+
+- make stuff from RMB menu's accessible from other places as well.
+
+- Add the possibility to select, via new dialog, one or more types of
+ object.
+
+- add a magnifying glass/zoom window to magnify "on-the-fly" a part of
+ the document.
+
+- improve the KTextEditor interface in the script code wizard.
+
+- make the dialogs not pop up over the main window.
+
+- add QTooltip and QWhatsThis to the widgets in the various dialogs
+ (export dialogs, types dialog, ...)
+
+* core
+
+- When selecting an argument of a certain type, maybe we should check
+ whether the required arguments are really there, before telling the
+ user to select them. Then we could give an error telling the user
+ to first construct the other objects. An exception should be made
+ for points of course.
+
+- Add the possibility to attach text label also to angles.
+
+- add the possibility to transform more than one object at one time,
+ using the popup menu. For example, I select two circles, I choose
+ Transform->Translate form the RMB menu and then Kig should ask me for
+ a vector to use to translate all the selected objects.
+
+- add support for work with other measure units (cm, inches, etc...)
+ than just pixels...
+
+- extend ObjectFactory::sensiblePointCalcer to also construct
+ intersection points of stuff... (pino: done for lines)
+
+- when moving an object that wants to move its parents, try to check if
+ it is itself not an indirect child of one of the parents it is
+ trying to move, and forbid the move in that case, as it will lead
+ to chaotic behaviour. I am not sure if this is really well
+ possible, but I have to look at it.
+
+- add intersection types: arc-arc; arc-conic; arc-cubic; conic-cubic;
+ cubic-cubic; locus-other object.
+
+- rework the ObjectConstructor and GUIAction stuff into something more
+ general, and more clean. See the comment for
+ ObjectConstructor::constructMode().
+
+- figure out a way to allow the user to enable and disable certain
+ features. E.g. I have been asked to allow the user to limit himself
+ to compass-ruler constructions..
+
+- add another viewmode ( which would be completely orthogonal to the
+ KigMode concept ), where you can more clearly see the dependencies
+ in a figure. Something with colours, numberings, and/or a tree-like
+ text representation of the dependencies..
+
+* scripting
+
+- Python scripting: export cubics for real, improve existing API.
+
+- make the scripting system work more like the macro system. Make it
+ a way to define new object types that can be reused more than once,
+ instead of making it just a way to add *one* object.
+
+- support for more scripting languages than just Python.
+
+* other
+
+- document mathematical i18n strings, so that the translators have a
+ clue about how to translate them !
+
+- write cabri-filter-status.txt.
+
+- add "Tools": easy tools designed for geometry, like Angle converter and
+ so on...
+
+- save a "session", i.e.: record how a document is moved, and save it to
+ e.g. a flash file or something like that.
+
+- koffice support ?
+
+* future ?
+
+- there should be a way to link a figure to a (html?) file containing
+ exercises. Teachers would be able to create exercises for Kig.
+ I'm thinking of doing this with HTML (& KHTML) + scripting ( but
+ this is _distant_ future.. )
diff --git a/kig/VERSION.in b/kig/VERSION.in
new file mode 100644
index 00000000..1a7e468b
--- /dev/null
+++ b/kig/VERSION.in
@@ -0,0 +1 @@
+Kig v@KIGVERSION@
diff --git a/kig/boost-python1.30-gcc3.2.patch b/kig/boost-python1.30-gcc3.2.patch
new file mode 100644
index 00000000..5b87a2b3
--- /dev/null
+++ b/kig/boost-python1.30-gcc3.2.patch
@@ -0,0 +1,13 @@
+Only in python/converter: as_to_python_function.hpp~
+diff -u -r python-old/object/make_ptr_instance.hpp python/object/make_ptr_instance.hpp
+--- python-old/object/make_ptr_instance.hpp 2003-04-22 14:35:28.000000000 +0200
++++ python/object/make_ptr_instance.hpp 2003-06-28 15:09:05.000000000 +0200
+@@ -34,7 +34,7 @@
+ template <class U>
+ static inline PyTypeObject* get_class_object_impl(U const volatile* p)
+ {
+- PyTypeObject* derived = get_derived_class_object(is_polymorphic<U>::type(), p);
++ PyTypeObject* derived = get_derived_class_object(typename is_polymorphic<U>::type(), p);
+ if (derived)
+ return derived;
+ return converter::registered<T>::converters.get_class_object();
diff --git a/kig/configure.in.bot b/kig/configure.in.bot
new file mode 100644
index 00000000..a1e0bbde
--- /dev/null
+++ b/kig/configure.in.bot
@@ -0,0 +1,40 @@
+if test x$kig_warn_about_disabling_python = xyes; then
+ cat << EOF
+
+Kig Python scripting support has been disabled, because you
+are missing the necessary headers and/or libraries.
+In order to use Kig Python scripting, you need to have
+Python installed, along with its development package ( e.g.
+libpython-dev ), and also the Boost.Python library, along with
+its development package ( e.g. libboost-python-dev ).
+
+Kig will continue to function without Python scripting support,
+but you will not be able to created Python scripted objects, or
+load Kig files that use them.
+
+Installing the libraries:
+The python development libraries themselves are almost certainly
+packaged by your favourite distribution. Look for a package name
+like libpython-dev, with possibly a version number inserted
+somewhere in the name.. For the Boost.Python libs, check this
+documentation: "http://boost.org/more/download.html" and
+"http://boost.org/more/download.html#Installation" or look for
+a package like libboost-python-dev or libboost-dev..
+EOF
+fi
+
+if test "x$kig_enable_python_scripting" = "xyes"; then
+ # tell users about the Boost.Python 1.30 + GCC 3.2+ problem and patch.
+ cat << EOF
+
+Kig WARNING
+===========
+There is a problem using unpatched Boost.Python 1.30 in combination
+with GCC 3.2 and above. In some distributions, like Debian sarge,
+this problem has been fixed, but in other distributions, the problem
+may still be there. If you encounter problems while compiling Kig,
+then you should try to re-run configure with the option
+"--disable-kig-python-scripting". This may fix the compilation, but
+you will not be able to use the Kig Python Scripting.
+EOF
+fi
diff --git a/kig/configure.in.in b/kig/configure.in.in
new file mode 100644
index 00000000..fa4cd0c7
--- /dev/null
+++ b/kig/configure.in.in
@@ -0,0 +1,251 @@
+kig_version=0.10.7
+
+kde_save_LIBS=$LIBS
+LIBS="$LIBS -lm"
+KDE_CHECK_FUNC_EXT(trunc)
+LIBS="$kde_save_LIBS"
+
+KDE_LANG_CPLUSPLUS
+
+# this variable is set to true if we need to warn the user that Python
+# scripting support has been disabled due to missing headers or libs
+# or whatever.. It's not set if the user explicitly disabled python
+# scripting ( "./configure --disable-kig-python-scripting" ). We
+# complain about this at the end of the ./configure script. Check out
+# configure.in.bot for the code..
+kig_warn_about_disabling_python="no"
+
+# this var is set to yes if we want to compile python scripting, and to
+# no otherwise
+kig_enable_python_scripting="yes"
+
+# this var is set to no if we want to disable support for compressed files
+# (for compatibility reasons with kde 3.1)
+kig_enable_compressed_files="yes"
+
+AC_DEFUN([KIG_PYTHON_NOT_FOUND], [
+ AC_MSG_WARN(
+ [[Kig needs the Python and Boost.Python libraries and their headers \
+installed for its Python scripting support. One of both was not \
+found, or the versions were incompatible, and Python scripting will be disabled.]] );
+ kig_warn_about_disabling_python="yes"
+ kig_enable_python_scripting="no" ] )
+
+AC_ARG_ENABLE( kig-python-scripting,
+ [ --disable-kig-python-scripting Disable Kig Python Scripting support],
+ [ kig_enable_python_scripting=$enableval ],
+ [ kig_enable_python_scripting=yes] )
+
+AC_ARG_ENABLE( kig-compressed-files,
+ [ --disable-kig-compressed-files Disable Kig Compressed Files support],
+ [ kig_enable_compressed_files=$enableval ],
+ [ kig_enable_compressed_files=yes] )
+
+dnl domi: we use some macro's by Ben Burton from the Regina program,
+dnl to check for the availability of a good python+boost.python
+dnl combination. They are included here, the end is marked at the
+dnl bottom. I have changed it only by removing some macro's, and by
+dnl making the other call KIG_PYTHON_NOT_FOUND instead of
+dnl REGINA_DO_NOT_COMPILE, and REGINA_WARN_*.
+dnl
+dnl Regina - A Normal Surface Theory Calculator
+dnl Configure Script Macros
+dnl
+dnl Copyright (c) 2002-2003, Ben Burton
+dnl For further details contact Ben Burton (bab@debian.org).
+dnl
+dnl This file is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU General Public License as
+dnl published by the Free Software Foundation; either version 2 of the
+dnl License, or (at your option) any later version.
+dnl
+dnl This file is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public
+dnl License along with this program; if not, write to the Free
+dnl Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+dnl MA 02110-1301, USA.
+dnl
+dnl Note that this copyright notice applies only to macros beginning
+dnl with REGINA_. Other macros found in acinclude.m4 have been taken
+dnl from external sources; these macros are stored in separate files
+dnl in the admin/ subdirectory and copyright notices can be found in
+dnl these separate files (and in the comments provided with the macros
+dnl themselves).
+dnl
+
+dnl -----------------------------------------------------------------
+dnl
+dnl Macros written for Regina
+dnl
+dnl -----------------------------------------------------------------
+
+dnl
+dnl REGINA_LIB_BOOST_PYTHON(TARGET-LIST, REQUIRED-BY)
+dnl
+dnl Checks for a usable boost.python installation.
+dnl Issues a warning and adds <TARGET-LIST> (which may consist of
+dnl several targets) to $DO_NOT_COMPILE if boost.python is missing.
+dnl
+dnl AC_SUBST()s the following variables:
+dnl
+dnl BOOST_PYTHON_INCLUDES: The compiler flags required for
+dnl building against boost.python,
+dnl including flags for building against
+dnl python itself.
+dnl BOOST_PYTHON_LIBS: The linker flags required for building
+dnl against boost.python.
+dnl PYTHON_LIBS: The linker flags required for building against
+dnl python itself.
+dnl
+dnl AC_DEFINE()s the following variables:
+dnl
+dnl HAVE_BOOST_PYTHON: Defined as 1 if we have a usable boost.python
+dnl installation, or remains undefined otherwise.
+dnl
+dnl Example: REGINA_LIB_BOOST_PYTHON(PYTHON, [the Python interface])
+dnl
+AC_DEFUN([REGINA_LIB_BOOST_PYTHON], [
+ AC_LANG_PUSH(C++)
+ KDE_CHECK_HEADERS([boost/shared_ptr.hpp], [
+ __regina_py_save_cxxflags="$CXXFLAGS"
+ __regina_py_save_ldflags="$LDFLAGS"
+ __regina_py_save_libs="$LIBS"
+ __regina_py_ok=0
+ for pyver in python python2.5 python2.4 python2.3 python2.2; do
+ for incdir in "/usr/include/$pyver" "/usr/local/include/$pyver" \
+ "/usr/$pyver/include" "/usr/local/$pyver/include" \
+ "$prefix/include/$pyver" "$prefix/$pyver/include"; do
+ CXXFLAGS="$__regina_py_save_cxxflags -I$incdir"
+ LDFLAGS="$__regina_py_save_ldflags -shared"
+
+ # Check for python includes.
+ AC_TRY_COMPILE([
+ #include <Python.h>
+ ], [
+ PyObject obj;
+ ], [
+ # Check for compatibility with boost.python.
+ AC_MSG_CHECKING([for boost.python with $incdir/Python.h])
+ AC_TRY_COMPILE([
+ #include <boost/python.hpp>
+ const char* greet() { return "Hello world!"; }
+ BOOST_PYTHON_MODULE(hello) { boost::python::def("greet", greet); }
+ ], [
+ /* No main body. */
+ ], [
+ AC_MSG_RESULT([yes])
+
+ # Check for -lpython.
+ for pylib in "$pyver" python python2.3 python2.2; do
+ for pylibdir in "/usr/lib" "/usr/local/lib" "/usr/lib/$pyver/config" \
+ "/usr/local/lib/$pyver/config"; do
+ for extralibs in "" "-lpthread -lm -lutil -ldl"; do
+ AC_MSG_CHECKING([for $pylibdir/lib$pylib and $extralibs with $incdir/Python.h])
+ LDFLAGS="$__regina_py_save_ldflags -L$pylibdir"
+ LIBS="-l$pylib $extralibs"
+ AC_TRY_LINK([
+ #include <Python.h>
+ ], [
+ Py_Initialize(); Py_Finalize();
+ ], [
+ AC_MSG_RESULT([yes])
+ for bplib in "-lboost_python-mt" "-lboost_python-gcc-mt-1_32" "-lboost_python-gcc-mt-1_31" "-lboost_python-gcc-mt" "-lboost_python"; do
+ AC_MSG_CHECKING([compilation of a boost.python program with $bplib])
+ LDFLAGS="$__regina_py_save_ldflags -L$pylibdir"
+ LIBS="-l$pylib $bplib $extralibs"
+ AC_TRY_LINK([
+ #include <boost/python.hpp>
+ const char* greet() { return "Hello world!"; }
+ BOOST_PYTHON_MODULE(hello) { boost::python::def("greet", greet); }
+ ], [
+ /* No main body. */
+ ], [
+ AC_MSG_RESULT([yes])
+ # And we're done!
+ BOOST_PYTHON_INCLUDES="-I$incdir"
+ BOOST_PYTHON_LIBS="$bplib"
+ PYTHON_LIBS="-l$pylib $extralibs"
+ PYTHON_LDFLAGS="-L$pylibdir"
+ __regina_py_ok=1
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+ if test "$__regina_py_ok" = "1"; then break; fi
+ done
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+ if test "$__regina_py_ok" = "1"; then break; fi
+ done
+ if test "$__regina_py_ok" = "1"; then break; fi
+ done
+ if test "$__regina_py_ok" = "1"; then break; fi
+ done
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+ ])
+ if test "$__regina_py_ok" = "1"; then break; fi
+ done
+ if test "$__regina_py_ok" = "1"; then break; fi
+ done
+
+ CXXFLAGS="$__regina_py_save_cxxflags"
+ LDFLAGS="$__regina_py_save_ldflags"
+ LIBS="$__regina_py_save_libs"
+
+ if test "$__regina_py_ok" = "1"; then
+ AC_DEFINE(HAVE_BOOST_PYTHON, 1,
+ [Define to 1 if you have a usable boost.python installation.])
+ else
+ BOOST_PYTHON_INCLUDES=
+ BOOST_PYTHON_LIBS=
+ KIG_PYTHON_NOT_FOUND
+ fi
+ ], [
+ KIG_PYTHON_NOT_FOUND
+ ])
+ AC_LANG_POP(C++)
+ AC_SUBST(BOOST_PYTHON_INCLUDES)
+ AC_SUBST(BOOST_PYTHON_LIBS)
+ AC_SUBST(PYTHON_LDFLAGS)
+ AC_SUBST(PYTHON_LIBS)
+])
+
+dnl This is the end of the macro's copied from Ben Burton's Regina
+dnl program.
+
+if test "x$kig_enable_python_scripting" != xno; then
+ kig_enable_python_scripting="yes" # either yes or no..
+
+ kig_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS=`echo $CXXFLAGS | sed -e 's/-fno-exceptions//g'`
+ REGINA_LIB_BOOST_PYTHON( PYTHON, Kig Python Scripting )
+ CXXFLAGS="$kig_save_CXXFLAGS"
+fi
+
+if test "x$kig_enable_python_scripting" != xno; then
+ AC_DEFINE( KIG_ENABLE_PYTHON_SCRIPTING, 1, [Defined if Kig Python scripting is enabled] )
+fi
+
+AM_CONDITIONAL(KIG_COMPILE_PYTHON_SCRIPTING, test x$kig_enable_python_scripting != xno)
+
+if test "x$kig_enable_compressed_files" = xno; then
+ CXXFLAGS="$CXXFLAGS -DKIG_NO_COMPRESSED_FILES"
+fi
+
+AC_SUBST( KIGVERSION, $kig_version )
+AC_DEFINE_UNQUOTED( KIGVERSION, "$kig_version", [The current Kig version as a string] )
+
+KDE_CHECK_HEADERS([ieeefp.h])
+
+# apparently the KDE build system wants to see "dnl AC_OUTPUT( ... )",
+# not a normal AC_OUTPUT
+dnl AC_OUTPUT( kig/kig.lsm )
+dnl AC_OUTPUT( kig/README )
+dnl AC_OUTPUT( kig/package-kig.sh )
+dnl AC_OUTPUT( kig/VERSION )
diff --git a/kig/data/Makefile.am b/kig/data/Makefile.am
new file mode 100644
index 00000000..9ba0da28
--- /dev/null
+++ b/kig/data/Makefile.am
@@ -0,0 +1,3 @@
+appdatadir = $(kde_datadir)/kig
+
+appdata_DATA = tips
diff --git a/kig/data/tips b/kig/data/tips
new file mode 100644
index 00000000..e50f386f
--- /dev/null
+++ b/kig/data/tips
@@ -0,0 +1,57 @@
+<tip category="Kig">
+<html>
+<p>One of the most powerful tools in Kig are the menus that you can
+enter by right-clicking on an object, or on some empty space in the
+document. You can use them to give objects names, change their colors
+and line styles, and lots of other interesting things.</p>
+</html>
+</tip>
+
+<tip category="Kig">
+<html>
+<p>You can construct new points without using the menu or the toolbar, simply
+clicking somewhere on the Kig document with the <em>middle mouse
+button</em>.</p>
+</html>
+</tip>
+
+<tip category="Kig">
+<html>
+<p>Kig can open several file formats: its files (<code>.kig</code> files),
+<em>KGeo</em> files, <em>KSeg</em> files, and, partially, <em>Dr. Geo</em>
+and <em>Cabri&#8482;</em> files.</p>
+</html>
+</tip>
+
+<tip category="Kig">
+<html>
+<p>Kig has more than 40 objects and 10 transformations you can construct and use
+in your documents: open the <em>Objects</em> menu to see them all.</p>
+</html>
+</tip>
+
+<tip category="Kig">
+<html>
+<p>You can use the selected objects to start the construction of an object
+which requires the selected objects as arguments. For example, if you have two
+points selected, you can choose <em>Start->Circle by Three Points</em> from the
+popup menu to start constructing a circle by three points.</p>
+</html>
+</tip>
+
+<tip category="Kig">
+<html>
+<p>Kig can extends its object set using external macros. You can find some
+interesting macro on Kig website:
+<a href="http://edu.kde.org/kig">http://edu.kde.org/kig</a>.</p>
+</html>
+</tip>
+
+<tip category="Kig">
+<html>
+<p>If you have more than one object under the mouse, and you want to select any
+of them, you can click with the <em>left mouse button</em>, while holding the
+<em>Shift</em> key, to get a list of the objects under the mouse cursor which
+you can then select from.</p>
+</html>
+</tip>
diff --git a/kig/examples/Makefile.am b/kig/examples/Makefile.am
new file mode 100644
index 00000000..095f1a85
--- /dev/null
+++ b/kig/examples/Makefile.am
@@ -0,0 +1,11 @@
+noinst_DATA= \
+ cubic-locus.kig \
+ ellipse.kig \
+ figure_angle.fgeo \
+ figure_manyobjects.fgeo \
+ fregier.kigt \
+ locustest.kig \
+ parabolaBDF.kigt \
+ session_alotofthings.fgeo \
+ sine-curve.kig \
+ sine-curve.png
diff --git a/kig/examples/cubic-locus.kig b/kig/examples/cubic-locus.kig
new file mode 100644
index 00000000..92d3cd20
--- /dev/null
+++ b/kig/examples/cubic-locus.kig
@@ -0,0 +1,91 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.7.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Hierarchy>
+ <Data type="double" id="1" >-2.27219</Data>
+ <Data type="int" id="2" >1</Data>
+ <Data type="double" id="3" >1.98431</Data>
+ <Data type="double" id="4" >1.90809</Data>
+ <Data type="double" id="5" >2.0933</Data>
+ <Data type="double" id="6" >-2.09014</Data>
+ <Data type="double" id="7" >-1.85202</Data>
+ <Data type="double" id="8" >1.53769</Data>
+ <Data type="hierarchy" id="9" >
+ <input requirement="point" id="1" />
+ <input requirement="point" id="2" />
+ <input requirement="point" id="3" />
+ <input requirement="int" id="4" />
+ <intermediate action="calc" type="CircleBCP" id="5" >
+ <arg>2</arg>
+ <arg>1</arg>
+ </intermediate>
+ <intermediate action="calc" type="RayAB" id="6" >
+ <arg>3</arg>
+ <arg>1</arg>
+ </intermediate>
+ <result action="calc" type="ConicLineIntersection" id="7" >
+ <arg>5</arg>
+ <arg>6</arg>
+ <arg>4</arg>
+ </result>
+ </Data>
+ <Data type="double" id="10" >3.70405</Data>
+ <Data type="double" id="11" >0.738799</Data>
+ <Object type="FixedPoint" id="12" >
+ <Parent id="3" />
+ <Parent id="5" />
+ </Object>
+ <Object type="FixedPoint" id="13" >
+ <Parent id="6" />
+ <Parent id="1" />
+ </Object>
+ <Object type="FixedPoint" id="14" >
+ <Parent id="7" />
+ <Parent id="8" />
+ </Object>
+ <Object type="FixedPoint" id="15" >
+ <Parent id="10" />
+ <Parent id="4" />
+ </Object>
+ <Object type="LineAB" id="16" >
+ <Parent id="15" />
+ <Parent id="12" />
+ </Object>
+ <Object type="ConstrainedPoint" id="17" >
+ <Parent id="11" />
+ <Parent id="16" />
+ </Object>
+ <Object type="Locus" id="18" >
+ <Parent id="9" />
+ <Parent id="16" />
+ <Parent id="14" />
+ <Parent id="13" />
+ <Parent id="2" />
+ </Object>
+ <Object type="CircleBCP" id="19" >
+ <Parent id="14" />
+ <Parent id="17" />
+ </Object>
+ <Object type="RayAB" id="20" >
+ <Parent id="13" />
+ <Parent id="17" />
+ </Object>
+ <Object type="ConicLineIntersection" id="21" >
+ <Parent id="19" />
+ <Parent id="20" />
+ <Parent id="2" />
+ </Object>
+ </Hierarchy>
+ <View>
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="15" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="21" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="12" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="18" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="14" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="16" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="20" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="13" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="19" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="17" />
+ </View>
+</KigDocument>
diff --git a/kig/examples/ellipse.kig b/kig/examples/ellipse.kig
new file mode 100644
index 00000000..442ba664
--- /dev/null
+++ b/kig/examples/ellipse.kig
@@ -0,0 +1,29 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.4.0" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Objects>
+ <Data type="double" id="1" >-5.76253</Data>
+ <Data type="double" id="2" >0.831135</Data>
+ <Data type="double" id="3" >1.77309</Data>
+ <Data type="double" id="4" >1.20053</Data>
+ <Data type="double" id="5" >-2.29024</Data>
+ <Data type="double" id="6" >4.15567</Data>
+ <Object width="5" shown="true" type="FixedPoint" id="7" color="#0000ff" >
+ <Parent id="1" />
+ <Parent id="2" />
+ </Object>
+ <Object width="5" shown="true" type="FixedPoint" id="8" color="#0000ff" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object width="5" shown="true" type="FixedPoint" id="9" color="#0000ff" >
+ <Parent id="5" />
+ <Parent id="6" />
+ </Object>
+ <Object width="-1" shown="true" type="EllipseBFFP" id="10" color="#0000ff" >
+ <Parent id="7" />
+ <Parent id="8" />
+ <Parent id="9" />
+ </Object>
+ </Objects>
+</KigDocument>
diff --git a/kig/examples/figure_angle.fgeo b/kig/examples/figure_angle.fgeo
new file mode 100644
index 00000000..22db1113
--- /dev/null
+++ b/kig/examples/figure_angle.fgeo
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<drgenius>
+ <drgeo name="Figure 1" scale="30.000000" origin_x="0.000000" origin_y="0.000000" grid="False">
+ <point id="827A5C0" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-5.833333</x>
+ <y>2.950000</y>
+ </point>
+ <point id="8248660" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-4.666666</x>
+ <y>-0.783334</y>
+ </point>
+ <point id="822A6B0" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>2.333334</x>
+ <y>-0.216667</y>
+ </point>
+ <line id="822BC80" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="827A5C0"/>
+ <parent ref="8248660"/>
+ </line>
+ <line id="8249A48" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="822A6B0"/>
+ <parent ref="8248660"/>
+ </line>
+ <angle id="82B86D8" type="3pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="822A6B0"/>
+ <parent ref="8248660"/>
+ <parent ref="827A5C0"/>
+ </angle>
+ </drgeo>
+</drgenius>
diff --git a/kig/examples/figure_manyobjects.fgeo b/kig/examples/figure_manyobjects.fgeo
new file mode 100644
index 00000000..c03634e3
--- /dev/null
+++ b/kig/examples/figure_manyobjects.fgeo
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+<drgenius>
+ <drgeo name="Figure 1" scale="30.000000" origin_x="0.000000" origin_y="0.000000" grid="False">
+ <point id="82257B8" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-6.700000</x>
+ <y>2.250000</y>
+ </point>
+ <point id="8250458" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>0.266667</x>
+ <y>2.083333</y>
+ </point>
+ <point id="8250D30" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-0.800000</x>
+ <y>-2.516667</y>
+ </point>
+ <point id="8255158" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-2.766667</x>
+ <y>1.883333</y>
+ </point>
+ <point id="8226648" type="Middle_2pts" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <parent ref="82257B8"/>
+ <parent ref="8255158"/>
+ </point>
+ <halfLine id="8225B10" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="8250D30"/>
+ <parent ref="8250458"/>
+ </halfLine>
+ <point id="82043A0" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-2.833333</x>
+ <y>-0.983334</y>
+ </point>
+ <point id="8115668" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>1.500000</x>
+ <y>1.883333</y>
+ </point>
+ <point id="82AED28" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-0.566667</x>
+ <y>3.983333</y>
+ </point>
+ <segment id="82B0888" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="82257B8"/>
+ <parent ref="82AED28"/>
+ </segment>
+ <line id="82B1B80" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="82043A0"/>
+ <parent ref="8115668"/>
+ </line>
+ <point id="82B26F0" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-5.533333</x>
+ <y>-0.383333</y>
+ </point>
+ <vector id="82A3948" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <Ox>-2.800000</Ox>
+ <Oy>1.883333</Oy>
+ <parent ref="8255158"/>
+ <parent ref="82B26F0"/>
+ </vector>
+ <point id="82B4358" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>3.166667</x>
+ <y>-0.683333</y>
+ </point>
+ <circle id="82B5918" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="82B4358"/>
+ <parent ref="8115668"/>
+ </circle>
+ <arcCircle id="82B5D30" type="3pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="82257B8"/>
+ <parent ref="82B26F0"/>
+ <parent ref="8250D30"/>
+ </arcCircle>
+ </drgeo>
+</drgenius>
diff --git a/kig/examples/fregier.kigt b/kig/examples/fregier.kigt
new file mode 100644
index 00000000..7f986fec
--- /dev/null
+++ b/kig/examples/fregier.kigt
@@ -0,0 +1,61 @@
+<!DOCTYPE KigMacroFile>
+<KigMacroFile Number="1" Version="0.4.0" >
+ <Macro>
+ <Name>fregier</Name>
+ <Description></Description>
+ <Construction>
+ <input requirement="conic" id="1" />
+ <input requirement="point" id="2" />
+ <intermediate action="calc" type="ConicPolarLine" id="3" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <intermediate action="calc" type="LinePerpend" id="4" >
+ <arg>3</arg>
+ <arg>2</arg>
+ </intermediate>
+ <intermediate action="push" type="int" id="5" >1</intermediate>
+ <intermediate action="calc" type="ConicLineIntersection" id="6" >
+ <arg>1</arg>
+ <arg>4</arg>
+ <arg>5</arg>
+ </intermediate>
+ <intermediate action="calc" type="MidPoint" id="7" >
+ <arg>2</arg>
+ <arg>6</arg>
+ </intermediate>
+ <intermediate action="calc" type="LinePerpend" id="8" >
+ <arg>4</arg>
+ <arg>7</arg>
+ </intermediate>
+ <intermediate action="push" type="int" id="9" >-1</intermediate>
+ <intermediate action="calc" type="ConicLineIntersection" id="10" >
+ <arg>1</arg>
+ <arg>8</arg>
+ <arg>9</arg>
+ </intermediate>
+ <intermediate action="calc" type="RayAB" id="11" >
+ <arg>2</arg>
+ <arg>10</arg>
+ </intermediate>
+ <intermediate action="calc" type="LinePerpend" id="12" >
+ <arg>11</arg>
+ <arg>2</arg>
+ </intermediate>
+ <intermediate action="push" type="int" id="13" >1</intermediate>
+ <intermediate action="calc" type="ConicLineIntersection" id="14" >
+ <arg>1</arg>
+ <arg>12</arg>
+ <arg>13</arg>
+ </intermediate>
+ <intermediate action="calc" type="SegmentAB" id="15" >
+ <arg>10</arg>
+ <arg>14</arg>
+ </intermediate>
+ <result action="calc" type="LineLineIntersection" id="16" >
+ <arg>15</arg>
+ <arg>4</arg>
+ </result>
+ </Construction>
+ </Macro>
+</KigMacroFile>
diff --git a/kig/examples/locustest.kig b/kig/examples/locustest.kig
new file mode 100644
index 00000000..42f1ccc0
--- /dev/null
+++ b/kig/examples/locustest.kig
@@ -0,0 +1,116 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.4.0" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Objects>
+ <Data type="double" id="1" >9.99611</Data>
+ <Data type="double" id="2" >9.67971</Data>
+ <Data type="double" id="3" >9.18808</Data>
+ <Data type="double" id="4" >-2.03061</Data>
+ <Data type="double" id="5" >-1.55367</Data>
+ <Data type="double" id="6" >13.0171</Data>
+ <Data type="double" id="7" >-9.63092</Data>
+ <Data type="double" id="8" >9.86598</Data>
+ <Data type="double" id="9" >-10.4258</Data>
+ <Data type="double" id="10" >-10.3351</Data>
+ <Data type="double" id="11" >0.725237</Data>
+ <Data type="hierarchy" id="12" >
+ <input requirement="point" id="1" />
+ <input requirement="point" id="2" />
+ <input requirement="line" id="3" />
+ <input requirement="point" id="4" />
+ <input requirement="point" id="5" />
+ <intermediate action="calc" type="LineAB" id="6" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <intermediate action="calc" type="LineLineIntersection" id="7" >
+ <arg>6</arg>
+ <arg>3</arg>
+ </intermediate>
+ <intermediate action="calc" type="LineAB" id="8" >
+ <arg>7</arg>
+ <arg>4</arg>
+ </intermediate>
+ <intermediate action="calc" type="LineAB" id="9" >
+ <arg>1</arg>
+ <arg>5</arg>
+ </intermediate>
+ <result action="calc" type="LineLineIntersection" id="10" >
+ <arg>8</arg>
+ <arg>9</arg>
+ </result>
+ </Data>
+ <Object width="5" shown="true" type="FixedPoint" id="13" color="#0000ff" >
+ <Parent id="1" />
+ <Parent id="2" />
+ </Object>
+ <Object width="5" shown="true" type="FixedPoint" id="14" color="#0000ff" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object width="5" shown="true" type="FixedPoint" id="15" color="#0000ff" >
+ <Parent id="5" />
+ <Parent id="6" />
+ </Object>
+ <Object width="5" shown="true" type="FixedPoint" id="16" color="#0000ff" >
+ <Parent id="7" />
+ <Parent id="8" />
+ </Object>
+ <Object width="5" shown="true" type="FixedPoint" id="17" color="#0000ff" >
+ <Parent id="9" />
+ <Parent id="10" />
+ </Object>
+ <Object width="-1" shown="true" type="LineAB" id="18" color="#0000ff" >
+ <Parent id="15" />
+ <Parent id="14" />
+ </Object>
+ <Object width="-1" shown="true" type="LineAB" id="19" color="#0000ff" >
+ <Parent id="16" />
+ <Parent id="13" />
+ </Object>
+ <Object width="-1" shown="true" type="LineAB" id="20" color="#0000ff" >
+ <Parent id="16" />
+ <Parent id="17" />
+ </Object>
+ <Object width="-1" shown="true" type="LineAB" id="21" color="#0000ff" >
+ <Parent id="15" />
+ <Parent id="17" />
+ </Object>
+ <Object width="-1" shown="true" type="LineLineIntersection" id="22" color="#0000ff" >
+ <Parent id="19" />
+ <Parent id="18" />
+ </Object>
+ <Object width="5" shown="true" type="ConstrainedPoint" id="23" color="#0000ff" >
+ <Parent id="21" />
+ <Parent id="11" />
+ </Object>
+ <Object width="-1" shown="true" type="Locus" id="24" color="#0000ff" >
+ <Parent id="21" />
+ <Parent id="12" />
+ <Parent id="22" />
+ <Parent id="20" />
+ <Parent id="14" />
+ <Parent id="13" />
+ </Object>
+ <Object width="-1" shown="true" type="LineAB" id="25" color="#0000ff" >
+ <Parent id="23" />
+ <Parent id="13" />
+ </Object>
+ <Object width="-1" shown="true" type="LineAB" id="26" color="#0000ff" >
+ <Parent id="23" />
+ <Parent id="22" />
+ </Object>
+ <Object width="-1" shown="true" type="LineLineIntersection" id="27" color="#0000ff" >
+ <Parent id="26" />
+ <Parent id="20" />
+ </Object>
+ <Object width="-1" shown="true" type="LineAB" id="28" color="#0000ff" >
+ <Parent id="27" />
+ <Parent id="14" />
+ </Object>
+ <Object width="-1" shown="true" type="LineLineIntersection" id="29" color="#0000ff" >
+ <Parent id="28" />
+ <Parent id="25" />
+ </Object>
+ </Objects>
+</KigDocument>
diff --git a/kig/examples/parabolaBDF.kigt b/kig/examples/parabolaBDF.kigt
new file mode 100644
index 00000000..ea9253ab
--- /dev/null
+++ b/kig/examples/parabolaBDF.kigt
@@ -0,0 +1,28 @@
+<!DOCTYPE KigMacroFile>
+<KigMacroFile Number="1" Version="0.4.0" >
+ <Macro>
+ <Name>parabolaBDF</Name>
+ <Description></Description>
+ <Construction>
+ <input requirement="line" id="1" />
+ <input requirement="point" id="2" />
+ <intermediate action="calc" type="LinePerpend" id="3" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <intermediate action="calc" type="LineLineIntersection" id="4" >
+ <arg>3</arg>
+ <arg>1</arg>
+ </intermediate>
+ <intermediate action="calc" type="MidPoint" id="5" >
+ <arg>2</arg>
+ <arg>4</arg>
+ </intermediate>
+ <result action="calc" type="ConicBDFP" id="6" >
+ <arg>1</arg>
+ <arg>2</arg>
+ <arg>5</arg>
+ </result>
+ </Construction>
+ </Macro>
+</KigMacroFile>
diff --git a/kig/examples/session_alotofthings.fgeo b/kig/examples/session_alotofthings.fgeo
new file mode 100644
index 00000000..967dada9
--- /dev/null
+++ b/kig/examples/session_alotofthings.fgeo
@@ -0,0 +1,162 @@
+<?xml version="1.0"?>
+<drgenius>
+ <drgeo name="Figure 1" scale="30.000000" origin_x="0.000000" origin_y="0.000000" grid="False">
+ <point id="82076B0" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>0.766667</x>
+ <y>2.450000</y>
+ </point>
+ <point id="8281F08" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-3.300000</x>
+ <y>2.650000</y>
+ </point>
+ <point id="82535F0" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-7.900000</x>
+ <y>-2.583333</y>
+ </point>
+ <point id="822F448" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-7.800000</x>
+ <y>0.116667</y>
+ </point>
+ <point id="8208228" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-4.533333</x>
+ <y>1.216667</y>
+ </point>
+ <point id="822FB88" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-8.566667</x>
+ <y>3.116667</y>
+ </point>
+ <point id="82B08A0" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-7.066667</x>
+ <y>1.783334</y>
+ </point>
+ <line id="82C3C40" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="8281F08"/>
+ <parent ref="82076B0"/>
+ </line>
+ <arcCircle id="82C2F40" type="3pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="8208228"/>
+ <parent ref="822F448"/>
+ <parent ref="82535F0"/>
+ </arcCircle>
+ <halfLine id="82A86B8" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="822FB88"/>
+ <parent ref="82B08A0"/>
+ </halfLine>
+ <point id="82C8738" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-1.066667</x>
+ <y>-0.416667</y>
+ </point>
+ <point id="82C4DC8" type="Intersection" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="" extra="0">
+ <parent ref="82A86B8"/>
+ <parent ref="82C2F40"/>
+ </point>
+ <point id="82C5230" type="Intersection" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="" extra="1">
+ <parent ref="82A86B8"/>
+ <parent ref="82C2F40"/>
+ </point>
+ <line id="82BF640" type="perpendicular" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="82C8738"/>
+ <parent ref="82C3C40"/>
+ </line>
+ <point id="83030E0" type="Reflexion" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <parent ref="82C4DC8"/>
+ <parent ref="82BF640"/>
+ </point>
+ </drgeo>
+ <text name="Testo 1">Figure 1 contains:
+- some points;
+- an arc;
+- a line;
+- a perpendicular;
+- a ray;
+- an intersection point;
+- a reflection point;
+
+Figure 2 contains:
+- some points;
+- 2 lines;
+- a midpoint;
+- a parallel;
+- 2 intersection points;
+
+Figure 3 contains:
+- some points;
+- a circle;
+- a vector;
+- a moved circle;
+</text>
+ <drgeo name="Figure 2" scale="30.000000" origin_x="0.000000" origin_y="0.000000" grid="False">
+ <point id="831A340" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-5.200000</x>
+ <y>0.216667</y>
+ </point>
+ <point id="82D1958" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>1.200000</x>
+ <y>3.116667</y>
+ </point>
+ <point id="82EB588" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-7.666667</x>
+ <y>1.650000</y>
+ </point>
+ <line id="8337158" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="82EB588"/>
+ <parent ref="831A340"/>
+ </line>
+ <point id="8339778" type="Middle_2pts" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <parent ref="831A340"/>
+ <parent ref="82D1958"/>
+ </point>
+ <line id="8322C38" type="parallel" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="8339778"/>
+ <parent ref="8337158"/>
+ </line>
+ <point id="8322E28" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-6.200000</x>
+ <y>-1.483334</y>
+ </point>
+ <line id="831E530" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="8322E28"/>
+ <parent ref="82D1958"/>
+ </line>
+ <point id="8356028" type="Intersection" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="" extra="0">
+ <parent ref="831E530"/>
+ <parent ref="8337158"/>
+ </point>
+ <point id="8320CC8" type="Intersection" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="" extra="0">
+ <parent ref="8322C38"/>
+ <parent ref="831E530"/>
+ </point>
+ </drgeo>
+ <drgeo name="Figure 3" scale="30.000000" origin_x="0.000000" origin_y="0.000000" grid="False">
+ <point id="837C5E0" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-6.433334</x>
+ <y>2.050000</y>
+ </point>
+ <point id="83380E8" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-1.400000</x>
+ <y>2.583333</y>
+ </point>
+ <point id="83565C8" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-1.300000</x>
+ <y>-0.350000</y>
+ </point>
+ <point id="82FBCC8" type="Free" color="Red" thickness="Dashed" style="Round" filled="False" masked="False" name="">
+ <x>-3.433333</x>
+ <y>-0.883333</y>
+ </point>
+ <vector id="8108B10" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <Ox>-6.433334</Ox>
+ <Oy>2.050000</Oy>
+ <parent ref="837C5E0"/>
+ <parent ref="83380E8"/>
+ </vector>
+ <circle id="83A2B10" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="82FBCC8"/>
+ <parent ref="83565C8"/>
+ </circle>
+ <circle id="83D6820" type="Translation" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name="">
+ <parent ref="83A2B10"/>
+ <parent ref="8108B10"/>
+ </circle>
+ </drgeo>
+</drgenius>
diff --git a/kig/examples/sine-curve.kig b/kig/examples/sine-curve.kig
new file mode 100644
index 00000000..e20f24d4
--- /dev/null
+++ b/kig/examples/sine-curve.kig
@@ -0,0 +1,55 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.5.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Objects>
+ <Data internal="true" type="double" id="1" >-3.50779</Data>
+ <Data internal="true" type="double" id="2" >3.80326</Data>
+ <Data internal="true" type="double" id="3" >5.49045</Data>
+ <Data internal="true" type="double" id="4" >-0.492505</Data>
+ <Data internal="true" type="double" id="5" >0.65293</Data>
+ <Data internal="true" type="hierarchy" id="6" >
+ <input requirement="any" id="1" />
+ <input requirement="string" id="2" />
+ <intermediate action="calc" type="PythonCompileType" id="3" >
+ <arg>2</arg>
+ </intermediate>
+ <result action="calc" type="PythonExecuteType" id="4" >
+ <arg>3</arg>
+ <arg>1</arg>
+ </result>
+ </Data>
+ <Data internal="true" type="string" id="7" >def calc( arg1 ):
+ c = arg1.coordinate();
+ y = sin( c.x );
+ return Point( Coordinate( c.x, y ) )
+</Data>
+ <Object width="-1" internal="false" shown="true" type="FixedPoint" id="8" color="#0000ff" >
+ <Parent id="1" />
+ <Parent id="2" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="FixedPoint" id="9" color="#0000ff" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object width="-1" internal="true" shown="true" type="PythonCompileType" id="10" color="#0000ff" >
+ <Parent id="7" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="LineAB" id="11" color="#0000ff" >
+ <Parent id="8" />
+ <Parent id="9" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConstrainedPoint" id="12" color="#0000ff" >
+ <Parent id="11" />
+ <Parent id="5" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="Locus" id="13" color="#0000ff" >
+ <Parent id="11" />
+ <Parent id="6" />
+ <Parent id="7" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="PythonExecuteType" id="14" color="#0000ff" >
+ <Parent id="10" />
+ <Parent id="12" />
+ </Object>
+ </Objects>
+</KigDocument>
diff --git a/kig/examples/sine-curve.png b/kig/examples/sine-curve.png
new file mode 100644
index 00000000..dce01c74
--- /dev/null
+++ b/kig/examples/sine-curve.png
Binary files differ
diff --git a/kig/examples/trifolium-of-delongchamps.kig b/kig/examples/trifolium-of-delongchamps.kig
new file mode 100644
index 00000000..8b4f1fa3
--- /dev/null
+++ b/kig/examples/trifolium-of-delongchamps.kig
@@ -0,0 +1,163 @@
+<!DOCTYPE KigDocument>
+<KigDocument axes="1" grid="1" CompatibilityVersion="0.7.0" Version="0.9.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Hierarchy>
+ <Data type="double" id="1" >0</Data>
+ <Data type="int" id="2" >0</Data>
+ <Data type="double" id="3" >0</Data>
+ <Data type="double" id="4" >4</Data>
+ <Data type="double" id="5" >0</Data>
+ <Data type="double" id="6" >0</Data>
+ <Data type="string" id="7" >%1</Data>
+ <Data type="string" id="8" >O</Data>
+ <Data type="string" id="9" >%1</Data>
+ <Data type="double" id="10" >0</Data>
+ <Data type="int" id="11" >0</Data>
+ <Data type="double" id="12" >-0.740892</Data>
+ <Data type="hierarchy" id="13" >
+ <input requirement="point" id="1" />
+ <input requirement="point" id="2" />
+ <input requirement="any" id="3" />
+ <input requirement="any" id="4" />
+ <input requirement="point" id="5" />
+ <input requirement="line" id="6" />
+ <intermediate action="calc" type="LineAB" id="7" >
+ <arg>2</arg>
+ <arg>1</arg>
+ </intermediate>
+ <intermediate action="calc" type="LinePerpend" id="8" >
+ <arg>7</arg>
+ <arg>5</arg>
+ </intermediate>
+ <intermediate action="calc" type="LineLineIntersection" id="9" >
+ <arg>8</arg>
+ <arg>7</arg>
+ </intermediate>
+ <intermediate action="calc" type="LineReflection" id="10" >
+ <arg>9</arg>
+ <arg>6</arg>
+ </intermediate>
+ <intermediate action="calc" type="LinePerpend" id="11" >
+ <arg>7</arg>
+ <arg>10</arg>
+ </intermediate>
+ <result action="calc" type="LineLineIntersection" id="12" >
+ <arg>11</arg>
+ <arg>7</arg>
+ </result>
+ </Data>
+ <Data type="double" id="14" >1.53353</Data>
+ <Data type="double" id="15" >0.0197571</Data>
+ <Data type="string" id="16" >Trifolium of de Longchamps</Data>
+ <Data type="double" id="17" >0.427352</Data>
+ <Data type="int" id="18" >0</Data>
+ <Data type="double" id="19" >0</Data>
+ <Data type="string" id="20" >M</Data>
+ <Data type="point" id="21" >
+ <x>-2.36097</x>
+ <y>2.74624</y>
+ </Data>
+ <Object type="FixedPoint" id="22" >
+ <Parent id="4" />
+ <Parent id="1" />
+ </Object>
+ <Object type="FixedPoint" id="23" >
+ <Parent id="6" />
+ <Parent id="5" />
+ </Object>
+ <Object type="FixedPoint" id="24" >
+ <Parent id="12" />
+ <Parent id="14" />
+ </Object>
+ <Object type="Label" id="25" >
+ <Parent id="11" />
+ <Parent id="21" />
+ <Parent id="16" />
+ </Object>
+ <Object type="RelativePoint" id="26" >
+ <Parent id="15" />
+ <Parent id="3" />
+ <Parent id="22" />
+ </Object>
+ <Object type="LineAB" id="27" >
+ <Parent id="23" />
+ <Parent id="22" />
+ </Object>
+ <Object type="RelativePoint" id="28" >
+ <Parent id="10" />
+ <Parent id="19" />
+ <Parent id="23" />
+ </Object>
+ <Object type="CircleBCP" id="29" >
+ <Parent id="23" />
+ <Parent id="24" />
+ </Object>
+ <Object type="Label" id="30" >
+ <Parent id="18" />
+ <Parent id="26" />
+ <Parent id="7" />
+ <Parent id="20" />
+ </Object>
+ <Object type="Label" id="31" >
+ <Parent id="2" />
+ <Parent id="28" />
+ <Parent id="9" />
+ <Parent id="8" />
+ </Object>
+ <Object type="ConstrainedPoint" id="32" >
+ <Parent id="17" />
+ <Parent id="29" />
+ </Object>
+ <Object type="Locus" id="33" >
+ <Parent id="13" />
+ <Parent id="29" />
+ <Parent id="23" />
+ <Parent id="6" />
+ <Parent id="5" />
+ <Parent id="22" />
+ <Parent id="27" />
+ </Object>
+ <Object type="LineAB" id="34" >
+ <Parent id="23" />
+ <Parent id="32" />
+ </Object>
+ <Object type="LinePerpend" id="35" >
+ <Parent id="34" />
+ <Parent id="22" />
+ </Object>
+ <Object type="LineLineIntersection" id="36" >
+ <Parent id="35" />
+ <Parent id="34" />
+ </Object>
+ <Object type="LineReflection" id="37" >
+ <Parent id="36" />
+ <Parent id="27" />
+ </Object>
+ <Object type="LinePerpend" id="38" >
+ <Parent id="34" />
+ <Parent id="37" />
+ </Object>
+ <Object type="LineLineIntersection" id="39" >
+ <Parent id="38" />
+ <Parent id="34" />
+ </Object>
+ </Hierarchy>
+ <View>
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="30" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="33" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="31" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="false" color="#0000ff" object="29" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="false" color="#0000ff" object="24" />
+ <Draw width="-1" point-style="Round" namecalcer="8" style="SolidLine" shown="true" color="#0000ff" object="23" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="false" color="#0000ff" object="34" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="39" />
+ <Draw width="-1" point-style="Round" namecalcer="20" style="SolidLine" shown="true" color="#0000ff" object="22" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="27" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="false" color="#0000ff" object="38" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="false" color="#0000ff" object="35" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="false" color="#0000ff" object="37" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="32" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="false" color="#0000ff" object="36" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="25" />
+ </View>
+</KigDocument>
diff --git a/kig/filters/Makefile.am b/kig/filters/Makefile.am
new file mode 100644
index 00000000..bb827b5a
--- /dev/null
+++ b/kig/filters/Makefile.am
@@ -0,0 +1,38 @@
+INCLUDES=$(all_includes)
+
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES=libfilters.la
+noinst_HEADERS= \
+ cabri-filter.h \
+ exporter.h \
+ filter.h \
+ filters-common.h \
+ imageexporteroptions.h \
+ kgeo-filter.h \
+ kgeo-resource.h \
+ kseg-defs.h \
+ kseg-filter.h \
+ latexexporter.h \
+ native-filter.h \
+ svgexporter.h \
+ drgeo-filter.h \
+ drgeo-filter-chooser.h
+libfilters_la_SOURCES= \
+ cabri-filter.cc \
+ exporter.cc \
+ filter.cc \
+ filters-common.cc \
+ imageexporteroptions.cc \
+ imageexporteroptionsbase.ui \
+ kgeo-filter.cc \
+ kseg-filter.cc \
+ latexexporter.cc \
+ latexexporteroptions.ui \
+ native-filter.cc \
+ svgexporter.cc \
+ svgexporteroptions.ui \
+ drgeo-filter.cc \
+ drgeo-filter-chooser.cc \
+ drgeo-filter-chooserbase.ui
+
diff --git a/kig/filters/cabri-filter.cc b/kig/filters/cabri-filter.cc
new file mode 100644
index 00000000..6d19027b
--- /dev/null
+++ b/kig/filters/cabri-filter.cc
@@ -0,0 +1,577 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "cabri-filter.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../misc/coordinate.h"
+#include "../objects/arc_type.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/circle_type.h"
+#include "../objects/conic_types.h"
+#include "../objects/curve_imp.h"
+#include "../objects/line_imp.h"
+#include "../objects/line_type.h"
+#include "../objects/object_calcer.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_factory.h"
+#include "../objects/object_holder.h"
+#include "../objects/other_imp.h"
+#include "../objects/other_type.h"
+#include "../objects/point_type.h"
+#include "../objects/polygon_type.h"
+#include "../objects/transform_types.h"
+#include "../objects/vector_type.h"
+
+#include <qcolor.h>
+#include <qfile.h>
+#include <qregexp.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+/**
+ * a line:
+ * "Nr": Type, Unknown, "CN:"NumberOfParents, "VN:"Unknown
+ * Color, FillType, Thickness, "DS":Dots, "GT":SpecialAppearance, Visible, Fixed
+ * ["Const": Parents] ["Val": Constants]
+ *
+ * Nr: Simple sequential numbering of the objects in a file.
+ * Type: seen so far: Pt, Axes, Line, Cir
+ * NumberOfParents: The number of parents that will be specified in
+ * Parents
+ * Color:
+ * R -> red
+ * O -> purple
+ * Y -> yellow
+ * P -> dark purple
+ * V -> dark blue
+ * Bl -> blue
+ * lBl -> bright blue
+ * G -> bright green
+ * dG -> dark green
+ * Br -> brown
+ * dBr -> beige
+ * lGr -> light grey
+ * Gr -> grey
+ * dGr -> dark grey
+ * B -> black
+ * FillType:
+ * W -> not filled ( white ? )
+ * all values of the Color item are valid here too..
+ * Thickness:
+ * t -> thin
+ * tT -> medium
+ * T -> Thick
+ * Dots:
+ * a specification for how a line should be drawn ( with many
+ * dots, with short lines, it's a pretty generic format: the first
+ * number signifies the number of sequential dots to draw first, and
+ * the next is the sum of this first number with the number of
+ * spaces to leave before starting a new segment.
+ * SpecialAppearance:
+ * a number indicating some way of specially drawing an object. This
+ * can be modified using the "Modify Appearance" button in
+ * Cabri. For example, for a segment, the number indicates the
+ * amount of ticks to put on the segment, to indicate
+ * correspondances between segments..
+ * Visible:
+ * V means visible, I means invisible
+ * Fixed:
+ * St means fix this object ( if you move one of its parents, it
+ * won't move ), nSt ( the default ) means don't fix this object.
+ * Parents:
+ * The numbers of the objects this object depends on
+ * Constants:
+ * Constants whose meaning depends on the type of object. E.g. for
+ * a point, this means first x, then y component.
+ */
+
+struct CabriObject
+{
+ uint id;
+ QCString type;
+ uint numberOfParents;
+ QColor color;
+ QColor fillColor;
+ int thick;
+ int lineSegLength;
+ int lineSegSplit;
+ int specialAppearanceSwitch;
+ bool visible;
+ bool fixed;
+ std::vector<int> parents;
+ std::vector<double> data;
+};
+
+KigFilterCabri::KigFilterCabri()
+{
+}
+
+KigFilterCabri::~KigFilterCabri()
+{
+}
+
+bool KigFilterCabri::supportMime( const QString& mime )
+{
+ // ugly hack to avoid duplicate extension ( XFig and Cabri files
+ // have the same .fig extension ).
+ return ( mime == "image/x-xfig" ) ||
+ ( mime == "application/x-cabri" );
+}
+
+static QString readLine( QFile& file )
+{
+ QString ret;
+ file.readLine( ret, 10000L );
+ if ( ret[ret.length() - 1] == '\n' )
+ ret.truncate( ret.length() - 1 );
+ if ( ret[ret.length() - 1] == '\r' )
+ ret.truncate( ret.length() - 1 );
+ return ret;
+}
+
+static QColor translatecolor( const QString& s )
+{
+ if ( s == "R" ) return Qt::red;
+ if ( s == "O" ) return Qt::magenta;
+ if ( s == "Y" ) return Qt::yellow;
+ if ( s == "P" ) return Qt::darkMagenta;
+ if ( s == "V" ) return Qt::darkBlue;
+ if ( s == "Bl" ) return Qt::blue;
+ if ( s == "lBl" ) return Qt::cyan; // TODO: bright blue
+ if ( s == "G" ) return Qt::green;
+ if ( s == "dG" ) return Qt::darkGreen;
+ if ( s == "Br" ) return QColor( 165, 42, 42 );
+ if ( s == "dBr" ) return QColor( 128, 128, 0 );
+ if ( s == "lGr" ) return Qt::lightGray;
+ if ( s == "Gr" ) return Qt::gray;
+ if ( s == "dGr" ) return Qt::darkGray;
+ if ( s == "B" ) return Qt::black;
+ if ( s == "W" ) return Qt::white;
+
+ kdDebug() << k_funcinfo << "unknown color: " << s << endl;
+ return Qt::black;
+}
+
+bool KigFilterCabri::readObject( QFile& f, CabriObject& myobj )
+{
+ // there are 4 lines per object in the file, so we read them all
+ // four now.
+ QString line1, line2, line3, s;
+ QString file = f.name();
+ line1 = readLine( f );
+ line2 = readLine( f );
+ line3 = readLine( f );
+ // ignore line 4, it is empty..
+ s = readLine( f );
+
+ QRegExp firstlinere( "^([^:]+): ([^,]+), ([^,]+), CN:([^,]*), VN:(.*)$" );
+ if ( ! firstlinere.exactMatch( line1 ) )
+ KIG_FILTER_PARSE_ERROR;
+
+ bool ok;
+ QString tmp;
+
+ tmp = firstlinere.cap( 1 );
+ myobj.id = tmp.toInt( &ok );
+ if ( !ok ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = firstlinere.cap( 2 );
+ myobj.type = tmp.latin1();
+
+ tmp = firstlinere.cap( 3 );
+ // i have no idea what this number means..
+
+ tmp = firstlinere.cap( 4 );
+ myobj.numberOfParents = tmp.toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = firstlinere.cap( 5 );
+ // i have no idea what this number means..
+
+ QRegExp secondlinere( "^([^,]+), ([^,]+), ([^,]+), DS:([^ ]+) ([^,]+), GT:([^,]+), ([^,]+), (.*)$" );
+ if ( ! secondlinere.exactMatch( line2 ) )
+ KIG_FILTER_PARSE_ERROR;
+
+ tmp = secondlinere.cap( 1 );
+ myobj.color = translatecolor( tmp );
+// if ( ! color.isValid() ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = secondlinere.cap( 2 );
+ myobj.fillColor = translatecolor( tmp );
+// if ( ! fillcolor.isValid() ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = secondlinere.cap( 3 );
+ myobj.thick = tmp == "t" ? 1 : tmp == "tT" ? 2 : 3;
+
+ tmp = secondlinere.cap( 4 );
+ myobj.lineSegLength = tmp.toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = secondlinere.cap( 5 );
+ myobj.lineSegSplit = tmp.toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = secondlinere.cap( 6 );
+ myobj.specialAppearanceSwitch = tmp.toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+
+ tmp = secondlinere.cap( 7 );
+ myobj.visible = tmp == "V";
+
+ tmp = secondlinere.cap( 8 );
+ myobj.fixed = tmp == "St";
+
+ QRegExp thirdlinere( "^(Const: ([^,]*),? ?)?(Val: (.*))?$" );
+ if ( ! thirdlinere.exactMatch( line3 ) )
+ KIG_FILTER_PARSE_ERROR;
+
+ tmp = thirdlinere.cap( 2 );
+ QStringList parentsids = QStringList::split( ' ', tmp );
+ for ( QStringList::iterator i = parentsids.begin();
+ i != parentsids.end(); ++i )
+ {
+ myobj.parents.push_back( ( *i ).toInt( &ok ) );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+ }
+ if ( myobj.parents.size() != myobj.numberOfParents )
+ KIG_FILTER_PARSE_ERROR;
+
+ tmp = thirdlinere.cap( 4 );
+ QStringList valIds = QStringList::split( ' ', tmp );
+ for ( QStringList::iterator i = valIds.begin();
+ i != valIds.end(); ++i )
+ {
+ myobj.data.push_back( ( *i ).toDouble( &ok ) );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+ }
+// kdDebug()
+// << k_funcinfo << endl
+// << "id = " << myobj.id << endl
+// << "type = " << myobj.type << endl
+// << "numberOfParents = " << myobj.numberOfParents << endl
+// << "color = " << myobj.color.name() << endl
+// << "fillcolor = " << myobj.fillColor.name() << endl
+// << "thick = " << myobj.thick << endl
+// << "lineseglength = " << myobj.lineSegLength << endl
+// << "linesegsplit = " << myobj.lineSegSplit << endl
+// << "specialAppearanceSwitch = " << myobj.specialAppearanceSwitch << endl
+// << "visible = " << visible << endl
+// << "fixed = " << myobj.fixed << endl
+// << "parents =" << endl;
+// for ( std::vector<int>::iterator i = myobj.parents.begin(); i != myobj.parents.end(); ++i )
+// kdDebug() << " " << *i << endl;
+// kdDebug() << "vals = " << endl;
+// for ( std::vector<double>::iterator i = myobj.data.begin(); i != myobj.data.end(); ++i )
+// kdDebug() << " " << *i << endl;
+
+ return true;
+}
+
+KigDocument* KigFilterCabri::load( const QString& file )
+{
+ QFile f( file );
+ if ( ! f.open( IO_ReadOnly ) )
+ {
+ fileNotFound( file );
+ return 0;
+ }
+
+ KigDocument* ret = new KigDocument();
+
+ QString s = readLine( f );
+ QString a = s.left( 21 );
+ QString b = s.mid( 21 );
+ if( a != "FIGURE CabriII vers. " ||
+ ( b != "DOS 1.0" && b != "MS-Windows 1.0" ) )
+ {
+ if ( s.left( 5 ) == "#FIG " )
+ {
+ notSupported( file, i18n( "This is an XFig file, not a Cabri figure." ) );
+ return 0;
+ }
+ else
+ KIG_FILTER_PARSE_ERROR;
+ }
+
+ // next we have:
+ // line 2: empty line
+ // line 3: window dimensions -> we don't need/use that...
+ // line 4: empty line
+ // line 5 through 8: center point
+ // line 9 through 12: axes
+ // so we skip 11 lines...
+ for( int i = 0; i != 11; ++i)
+ s = readLine( f );
+
+ // all Cabri files seem to at least have these center and axes...
+ if ( f.atEnd() )
+ KIG_FILTER_PARSE_ERROR;
+
+ std::vector<ObjectHolder*> holders;
+ std::vector<ObjectCalcer*> calcers;
+
+ const ObjectFactory* fact = ObjectFactory::instance();
+
+ std::vector<ObjectCalcer*> args;
+ ObjectCalcer* oc = 0;
+
+ while ( ! f.atEnd() )
+ {
+ CabriObject obj;
+ // we do one object each iteration..
+ if ( !readObject( f, obj ) )
+ return 0;
+
+// reading linestyle
+ Qt::PenStyle ls = Qt::SolidLine;
+ if ( ( obj.lineSegLength > 1 ) && ( obj.lineSegLength < 6 ) &&
+ ( obj.lineSegSplit > 1 ) && ( obj.lineSegSplit <= 10 ) )
+ ls = Qt::DotLine;
+ else if ( ( obj.lineSegLength >= 6 ) && ( obj.lineSegSplit > 10 ) )
+ ls = Qt::DashLine;
+ int ps = 0;
+
+ args.clear();
+ for ( std::vector<int>::iterator i = obj.parents.begin();
+ i != obj.parents.end(); ++i )
+ args.push_back( calcers[*i-3] );
+
+ // two fake objects at the start ( origin and axes.. )
+ if ( obj.id != calcers.size() + 3 ) KIG_FILTER_PARSE_ERROR;
+ oc = 0;
+ if ( obj.type == "Pt" )
+ {
+ if ( ! args.empty() ) KIG_FILTER_PARSE_ERROR;
+ if ( obj.data.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+
+ switch ( obj.specialAppearanceSwitch )
+ {
+ case 0:
+ {
+ obj.thick -= 1;
+ break;
+ }
+ case 2:
+ {
+ obj.thick += 1;
+ break;
+ }
+ case 3:
+ {
+ obj.thick += 1;
+ ps = 1;
+ break;
+ }
+ case 4:
+ {
+ obj.thick += 2;
+ ps = 4;
+ break;
+ }
+ }
+ // different sizes for points..
+ obj.thick *= 2;
+
+ oc = fact->fixedPointCalcer( Coordinate( obj.data[0], obj.data[1] ) );
+ }
+ else if ( obj.type == "Cir" )
+ {
+ if ( args.size() == 1 )
+ {
+ if ( obj.data.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ ObjectConstCalcer* radc =
+ new ObjectConstCalcer( new DoubleImp( obj.data[0] ) );
+ args.push_back( radc );
+ oc = new ObjectTypeCalcer( CircleBPRType::instance(), args );
+ }
+ else if ( args.size() == 2 )
+ {
+ if ( ! obj.data.empty() ) KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( CircleBCPType::instance(), args );
+ }
+ else KIG_FILTER_PARSE_ERROR;
+ }
+ else if ( obj.type == "Line" || obj.type == "Ray" || obj.type == "Seg" ||
+ obj.type == "Vec" )
+ {
+ if ( args.size() == 1 )
+ {
+ if ( obj.data.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+ Coordinate vect( obj.data[0], obj.data[1] );
+ ObjectConstCalcer* vectorcalcer =
+ new ObjectConstCalcer( new VectorImp( Coordinate( 0, 0 ), vect ) );
+ args.push_back( vectorcalcer );
+ ObjectTypeCalcer* secondpoint =
+ new ObjectTypeCalcer( TranslatedType::instance(), args );
+ secondpoint->calc( *ret );
+ args[1] = secondpoint;
+ }
+ if ( args.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+ const ObjectType* t = 0;
+ if ( obj.type == "Line" ) t = LineABType::instance();
+ else if ( obj.type == "Ray" ) t = RayABType::instance();
+ else if ( obj.type == "Seg" ) t = SegmentABType::instance();
+ else if ( obj.type == "Vec" ) t = VectorType::instance();
+ else assert( t );
+ oc = new ObjectTypeCalcer( t, args );
+ }
+ else if ( obj.type == "Pt/" )
+ {
+ // different sizes for points..
+ obj.thick *= 2;
+ if ( args.size() != 1 || obj.data.size() != 2 )
+ KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* parent = args[0];
+ if ( !parent->imp()->inherits( CurveImp::stype() ) )
+ KIG_FILTER_PARSE_ERROR;
+ const CurveImp* curve = static_cast<const CurveImp*>( parent->imp() );
+ Coordinate pt = Coordinate( obj.data[0], obj.data[1] );
+ double param = curve->getParam( pt, *ret );
+ args.push_back( new ObjectConstCalcer( new DoubleImp( param ) ) );
+ oc = new ObjectTypeCalcer( ConstrainedPointType::instance(), args );
+ }
+ else if ( obj.type == "Perp" || obj.type == "Par" )
+ {
+ if ( args.size() != 2 || obj.data.size() != 0 )
+ KIG_FILTER_PARSE_ERROR;
+ const ObjectType* t = 0;
+ if ( obj.type == "Perp" ) t = LinePerpendLPType::instance();
+ else if ( obj.type == "Par" ) t = LineParallelLPType::instance();
+ else assert( false );
+ oc = new ObjectTypeCalcer( t, args );
+ }
+ else if ( obj.type == "Arc" )
+ {
+ if ( args.size() != 3 || ! obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( ArcBTPType::instance(), args );
+ }
+ else if ( obj.type == "Con" )
+ {
+ if ( args.size() != 5 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( ConicB5PType::instance(), args );
+ }
+ else if ( obj.type == "Mid" )
+ {
+ if ( args.size() == 2 )
+ {
+ ObjectCalcer* c =
+ new ObjectTypeCalcer( SegmentABType::instance(), args );
+ c->calc( *ret );
+ args.clear();
+ args.push_back( c );
+ }
+ // midpoint -> this can be the midpoint of a segment, two
+ // points, or a vector...
+ if ( args.size() != 1 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* parent = args[0];
+ if ( parent->imp()->inherits( SegmentImp::stype() ) )
+ oc = fact->propertyObjectCalcer( parent, "mid-point" ) ;
+ else if ( parent->imp()->inherits( VectorImp::stype() ) )
+ oc = fact->propertyObjectCalcer( parent, "vect-mid-point" );
+ else KIG_FILTER_PARSE_ERROR;
+ }
+ else if ( obj.type == "PBiss" )
+ {
+ if ( args.size() == 2 )
+ {
+ ObjectCalcer* c =
+ new ObjectTypeCalcer( SegmentABType::instance(), args );
+ c->calc( *ret );
+ args.clear();
+ args.push_back( c );
+ }
+ if ( args.size() != 1 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* parent = args[0];
+ ObjectCalcer* midpoint = 0;
+ if ( parent->imp()->inherits( SegmentImp::stype() ) )
+ midpoint = fact->propertyObjectCalcer( parent, "mid-point" ) ;
+// else if ( parent->imp()->inherits( VectorImp::stype() ) )
+// midpoint = fact->propertyObjectCalcer( parent, "vect-mid-point" );
+ else KIG_FILTER_PARSE_ERROR;
+ midpoint->calc( *ret );
+ args.push_back( midpoint );
+ oc = new ObjectTypeCalcer( LinePerpendLPType::instance(), args );
+ }
+ else if ( obj.type == "Pol" )
+ {
+ if ( args.size() < 3 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( PolygonBNPType::instance(), args );
+ }
+ else if ( obj.type == "Locus" )
+ {
+ if ( args.size() != 2 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = fact->locusCalcer( args[0], args[1] );
+ }
+ else if ( obj.type == "Refl" )
+ {
+ if ( args.size() != 2 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( LineReflectionType::instance(), args );
+ }
+ else if ( obj.type == "Sym" )
+ {
+ if ( args.size() != 2 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( PointReflectionType::instance(), args );
+ }
+ else if ( obj.type == "Tran" )
+ {
+ if ( args.size() != 2 || !obj.data.empty() )
+ KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( TranslatedType::instance(), args );
+ }
+ else
+ {
+ notSupported( file, i18n( "This Cabri file contains a \"%1\" object, "
+ "which Kig does not currently support." ).arg( obj.type ) );
+ return 0;
+ }
+
+ if ( oc == 0 ) KIG_FILTER_PARSE_ERROR;
+
+ oc->calc( *ret );
+ calcers.push_back( oc );
+ ObjectDrawer* d = new ObjectDrawer( obj.color, obj.thick, obj.visible, ls, ps );
+ ObjectHolder* oh = new ObjectHolder( oc, d );
+ holders.push_back( oh );
+
+ oc = 0;
+ }
+
+ ret->addObjects( holders );
+ ret->setGrid( false );
+ ret->setAxes( false );
+ return ret;
+}
+
+KigFilterCabri* KigFilterCabri::instance()
+{
+ static KigFilterCabri t;
+ return &t;
+}
diff --git a/kig/filters/cabri-filter.h b/kig/filters/cabri-filter.h
new file mode 100644
index 00000000..5760040f
--- /dev/null
+++ b/kig/filters/cabri-filter.h
@@ -0,0 +1,55 @@
+// This file is part of Kig, a KDE program for Interactive Geometry...
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_FILTERS_CABRI_FILTER_H
+#define KIG_FILTERS_CABRI_FILTER_H
+
+#include "filter.h"
+
+struct CabriObject;
+
+class QFile;
+
+/**
+ * This is an import filter for the output of the commercial program
+ * Cabri ("CAhier de BRouillon Interactif" or something like that),
+ * which is being pushed by Texas Instruments, but only exists for
+ * the Winblows(tm) platform and some TI scientific calculator...
+ *
+ * \note
+ * This is completely free code, i have not looked at any Cabri source
+ * code, and have implemented this implementation of the Cabri file
+ * format from zero, by just looking at the input and output from a
+ * (properly licensed) Cabri program...
+ */
+class KigFilterCabri
+ : public KigFilter
+{
+ KigFilterCabri();
+ ~KigFilterCabri();
+public:
+ static KigFilterCabri* instance();
+
+ bool supportMime ( const QString& mime );
+ KigDocument* load ( const QString& fromfile );
+private:
+ bool readObject( QFile& f, CabriObject& myobj );
+
+};
+
+#endif
diff --git a/kig/filters/drgeo-filter-chooser.cc b/kig/filters/drgeo-filter-chooser.cc
new file mode 100644
index 00000000..424a3462
--- /dev/null
+++ b/kig/filters/drgeo-filter-chooser.cc
@@ -0,0 +1,65 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "drgeo-filter-chooser.h"
+#include "drgeo-filter-chooser.moc"
+
+#include <klistbox.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+KigFilterDrgeoChooser::KigFilterDrgeoChooser( const QStringList& l )
+ : KigFilterDrgeoChooserBase( 0, "drgeo_filter", true )
+{
+ OKButton->setGuiItem( KStdGuiItem::ok() );
+ CancelButton->setGuiItem( KStdGuiItem::cancel() );
+
+ FigureListBox->insertStringList( l );
+
+ connect( OKButton, SIGNAL( clicked() ), SLOT( slotOKPressed() ) );
+ connect( CancelButton, SIGNAL( clicked() ), SLOT( slotCancelPressed() ) );
+ connect( FigureListBox, SIGNAL( executed( QListBoxItem* ) ), SLOT( slotExecuted( QListBoxItem* ) ) );
+}
+
+void KigFilterDrgeoChooser::slotOKPressed()
+{
+ const int r = FigureListBox->currentItem();
+ if ( r == -1 )
+ {
+ KMessageBox::sorry( 0, i18n( "Please select a figure." ) );
+ return;
+ }
+ done( r );
+}
+
+void KigFilterDrgeoChooser::slotCancelPressed()
+{
+ done( -1 );
+}
+
+KigFilterDrgeoChooser::~KigFilterDrgeoChooser()
+{
+
+}
+
+void KigFilterDrgeoChooser::slotExecuted( QListBoxItem* i )
+{
+ done( FigureListBox->index( i ) );
+}
diff --git a/kig/filters/drgeo-filter-chooser.h b/kig/filters/drgeo-filter-chooser.h
new file mode 100644
index 00000000..fd4ce606
--- /dev/null
+++ b/kig/filters/drgeo-filter-chooser.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef DRGEOFILTERCHOOSER_H
+#define DRGEOFILTERCHOOSER_H
+
+#include "drgeo-filter-chooserbase.h"
+
+class QListBoxItem;
+class QStringList;
+
+class KigFilterDrgeoChooser
+ : public KigFilterDrgeoChooserBase
+{
+ Q_OBJECT
+
+public:
+ KigFilterDrgeoChooser( const QStringList& l );
+ ~KigFilterDrgeoChooser();
+public slots:
+ void slotOKPressed();
+ void slotCancelPressed();
+ void slotExecuted( QListBoxItem* );
+};
+
+#endif
diff --git a/kig/filters/drgeo-filter-chooserbase.ui b/kig/filters/drgeo-filter-chooserbase.ui
new file mode 100644
index 00000000..829d84cc
--- /dev/null
+++ b/kig/filters/drgeo-filter-chooserbase.ui
@@ -0,0 +1,140 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>KigFilterDrgeoChooserBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KigFilterDrgeoChooserBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>300</width>
+ <height>202</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Dr. Geo Filter</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>ExplanationTextLabel</cstring>
+ </property>
+ <property name="text">
+ <string>The current Dr. Geo file contains more than one figure.
+Please select which to import:</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KListBox">
+ <property name="name">
+ <cstring>FigureListBox</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>OKButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>CancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klistbox.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kig/filters/drgeo-filter-status.txt b/kig/filters/drgeo-filter-status.txt
new file mode 100644
index 00000000..db399eae
--- /dev/null
+++ b/kig/filters/drgeo-filter-status.txt
@@ -0,0 +1,50 @@
+Dr. Geo filter status
+=====================
+
+Objects imported
+----------------
+
+Points most, On_curve (most)
+Rays ok
+Vectors ok
+Lines most
+Circles most
+Numberics most (as a label)
+Angles 3pts
+Arcs ok
+Locuses ok
+Transformations most
+Intersections most
+Scripts as a label
+Equations ok
+Polygons ok
+
+Colors ok
+Visibility ok
+Styles ok
+Grid ok
+
+Objects not imported
+--------------------
+
+Points Coordinate(*)
+Lines pt_slope(*)
+Circle radius(*)
+Numberics distance_pt_circle
+Angles vectors
+Transformations scaling(*)
+Intersections arc-circle(**), locus-other object(**)
+
+(*) objects which depend on numerics
+(**) objects which currently are not implemented in Kig
+
+Objects ignored
+---------------
+
+boundingBox
+customUI
+
+Known problems
+--------------
+
+* Point(On_curve): does not work with locuses
diff --git a/kig/filters/drgeo-filter.cc b/kig/filters/drgeo-filter.cc
new file mode 100644
index 00000000..8fa306cc
--- /dev/null
+++ b/kig/filters/drgeo-filter.cc
@@ -0,0 +1,809 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "drgeo-filter.h"
+
+#include "drgeo-filter-chooser.h"
+#include "filters-common.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../misc/common.h"
+#include "../misc/coordinate.h"
+#include "../objects/angle_type.h"
+#include "../objects/arc_type.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/circle_imp.h"
+#include "../objects/circle_type.h"
+#include "../objects/conic_imp.h"
+#include "../objects/conic_types.h"
+#include "../objects/curve_imp.h"
+#include "../objects/intersection_types.h"
+#include "../objects/line_imp.h"
+#include "../objects/line_type.h"
+#include "../objects/object_calcer.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_factory.h"
+#include "../objects/object_holder.h"
+#include "../objects/object_type.h"
+#include "../objects/other_imp.h"
+#include "../objects/other_type.h"
+#include "../objects/point_imp.h"
+#include "../objects/point_type.h"
+#include "../objects/polygon_type.h"
+#include "../objects/transform_types.h"
+#include "../objects/vector_type.h"
+
+#include <math.h>
+
+#include <qfile.h>
+#include <qnamespace.h>
+
+#include <klocale.h>
+
+#undef DRGEO_DEBUG
+//#define DRGEO_DEBUG
+
+struct DrGeoHierarchyElement
+{
+ QString id;
+ std::vector<QString> parents;
+};
+
+KigFilterDrgeo::KigFilterDrgeo()
+{
+}
+
+KigFilterDrgeo::~KigFilterDrgeo()
+{
+}
+
+bool KigFilterDrgeo::supportMime( const QString& mime )
+{
+ return mime == "application/x-drgeo";
+}
+
+KigDocument* KigFilterDrgeo::load( const QString& file )
+{
+ QFile f( file );
+ if ( ! f.open( IO_ReadOnly ) )
+ {
+ fileNotFound( file );
+ return 0;
+ }
+
+ QStringList figures;
+ QDomDocument doc( "drgenius" );
+ if ( !doc.setContent( &f ) )
+ KIG_FILTER_PARSE_ERROR;
+ QDomElement main = doc.documentElement();
+ int nmacros = 0;
+ // reading figures...
+ for ( QDomNode n = main.firstChild(); ! n.isNull(); n = n.nextSibling() )
+ {
+ QDomElement e = n.toElement();
+ if ( e.isNull() ) continue;
+ else if ( e.tagName() == "drgeo" )
+ figures.append( e.attribute( "name" ) );
+ else if ( e.tagName() == "macro" )
+ nmacros++;
+ }
+ if ( figures.isEmpty() ) {
+ if( nmacros > 0 )
+ warning( i18n( "The Dr. Geo file \"%1\" is a macro file so it contains no "
+ "figures." ).arg( file ) );
+ else
+ warning( i18n( "There are no figures in Dr. Geo file \"%1\"." ).arg( file ) );
+ return false;
+ }
+
+ int nfig = figures.count();
+ // no figures, no party...
+ if ( nfig == 0 )
+ return 0;
+
+ int myfig = 0;
+
+ if ( nfig > 1 )
+ {
+ // Dr. Geo file has more than 1 figure, let the user choose one...
+ KigFilterDrgeoChooser* c = new KigFilterDrgeoChooser( figures );
+ myfig = c->exec();
+ delete c;
+ }
+
+#ifdef DRGEO_DEBUG
+ kdDebug() << "drgeo file " << file << endl;
+#endif
+ int curfig = -1;
+
+ for ( QDomNode n = main.firstChild(); ! n.isNull(); n = n.nextSibling() )
+ {
+ QDomElement e = n.toElement();
+ if ( e.isNull() ) continue;
+ else if ( e.tagName() == "drgeo" )
+ {
+ curfig += 1;
+ if ( curfig == myfig )
+ {
+#ifdef DRGEO_DEBUG
+ kdDebug() << "- Figure: '" << e.attribute("name") << "'" << endl;
+#endif
+ bool grid = !e.attribute( "grid" ).isEmpty() &&
+ ( e.attribute( "grid" ) != "False" );
+ return importFigure( e.firstChild(), file, grid );
+ }
+ }
+ }
+
+ return 0;
+}
+
+int convertDrgeoIndex( const std::vector<DrGeoHierarchyElement> es, const QString myid )
+{
+ for ( uint i = 0; i < es.size(); ++i )
+ if ( es[i].id == myid )
+ return i;
+ return -1;
+}
+
+const Coordinate convertDrgeoLineParam( const double param, const LineData& line )
+{
+ const double n = ( param - 0.5 ) * M_PI;
+ const Coordinate c = line.dir() / line.dir().length();
+ const Coordinate p = line.a + tan( n ) * c;
+ return p;
+}
+
+const Coordinate convertDrgeoHalflineParam( const double param, const LineData& line )
+{
+ const double n = param * M_PI * 0.5;
+ const Coordinate c = line.dir() / line.dir().length();
+ const Coordinate p = line.a + tan( n ) * c;
+ return p;
+}
+
+KigDocument* KigFilterDrgeo::importFigure( QDomNode f, const QString& file, const bool grid )
+{
+ KigDocument* ret = new KigDocument();
+
+ using namespace std;
+ std::vector<DrGeoHierarchyElement> elems;
+ int withoutid = 0;
+
+ // 1st: fetch relationships and build an appropriate structure
+ for (QDomNode a = f; ! a.isNull(); a = a.nextSibling() )
+ {
+ QDomElement domelem = a.toElement();
+ if ( domelem.isNull() ) continue;
+ else
+ {
+ DrGeoHierarchyElement elem;
+#ifdef DRGEO_DEBUG
+ kdDebug() << " * " << domelem.tagName() << "(" << domelem.attribute("type") << ")" << endl;
+#endif
+ for ( QDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() )
+ {
+ QDomElement ce = c.toElement();
+ if ( ce.isNull() ) continue;
+ else if ( ce.tagName() == "parent" )
+ elem.parents.push_back( ce.attribute( "ref" ) );
+ }
+ QString curid = domelem.attribute( "id" );
+ elem.id = !curid.isNull() ? curid : QString::number( withoutid++ ) ;
+ elems.push_back( elem );
+ }
+ }
+
+#ifdef DRGEO_DEBUG
+ QString x;
+ kdDebug() << "+++ elems" << endl;
+ for ( uint i = 0; i < elems.size(); ++i )
+ {
+ x = "";
+ for ( uint j = 0; j < elems[i].parents.size(); ++j )
+ {
+ x += elems[i].parents[j] + "_";
+ }
+ kdDebug() << " --> " << i << " - " << elems[i].id << " - " << x << endl;
+ }
+#endif
+
+ // 2nd: let's draw!
+ int curid = 0;
+ const ObjectFactory* fact = ObjectFactory::instance();
+ std::vector<ObjectHolder*> holders;
+ std::vector<ObjectHolder*> holders2;
+ ObjectTypeCalcer* oc = 0;
+ ObjectCalcer* oc2 = 0;
+ int nignored = 0;
+
+ // there's no need to sort the objects because it seems that DrGeo objects
+ // appear in the right order... so let's go!
+ for (QDomNode a = f; ! a.isNull(); a = a.nextSibling() )
+ {
+#ifdef DRGEO_DEBUG
+ kdDebug() << "+++ id: " << curid << endl;
+#endif
+ const DrGeoHierarchyElement& el = elems[curid];
+ std::vector<ObjectCalcer*> parents;
+ for ( uint j = 0; j < el.parents.size(); ++j )
+ {
+ int parentid = convertDrgeoIndex( elems, el.parents[j] );
+ if ( parentid == -1 )
+ KIG_FILTER_PARSE_ERROR;
+ parents.push_back( holders[parentid-nignored]->calcer() );
+ };
+ QDomElement domelem = a.toElement();
+
+#ifdef DRGEO_DEBUG
+ if ( parents.size() > 0 )
+ for ( uint j = 0; j < parents.size(); ++j )
+ {
+ kdDebug() << "+++++++++ parent[" << j << "]: " << parents[j] << " - "
+ << parents[j]->imp()->type()->internalName() << endl;
+ }
+ else
+ kdDebug() << "+++++++++ parents: NO" << endl;
+ kdDebug() << "+++++++++ " << domelem.tagName() << " - " << domelem.attribute("type") << endl;
+#endif
+
+ if ( domelem.isNull() ) continue;
+ else if ( domelem.tagName() == "point" )
+ {
+ QString xs;
+ QString ys;
+ QString values;
+ for ( QDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() )
+ {
+ QDomElement ce = c.toElement();
+ if ( ce.isNull() ) continue;
+ else if ( ce.tagName() == "x" )
+ xs = ce.text();
+ else if ( ce.tagName() == "y" )
+ ys = ce.text();
+ else if ( ce.tagName() == "value" )
+ values = ce.text();
+ }
+ if ( domelem.attribute( "type" ) == "Free" )
+ {
+ bool ok;
+ bool ok2;
+ double x = xs.toDouble( &ok );
+ double y = ys.toDouble( &ok2 );
+ if ( ! ( ok && ok2 ) )
+ KIG_FILTER_PARSE_ERROR;
+ oc = fact->fixedPointCalcer( Coordinate( x, y ) );
+ }
+ else if ( domelem.attribute( "type" ) == "Middle_2pts" )
+ oc = new ObjectTypeCalcer( MidPointType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Middle_segment" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ if ( !parents[0]->imp()->inherits( SegmentImp::stype() ) )
+ KIG_FILTER_PARSE_ERROR;
+ ObjectPropertyCalcer* o1 = fact->propertyObjectCalcer( parents[0], "end-point-A" );
+ o1->calc( *ret );
+ ObjectPropertyCalcer* o2 = fact->propertyObjectCalcer( parents[0], "end-point-B" );
+ o2->calc( *ret );
+ std::vector<ObjectCalcer*> args;
+ args.push_back( o1 );
+ args.push_back( o2 );
+ oc = new ObjectTypeCalcer( MidPointType::instance(), args );
+ }
+ else if ( domelem.attribute( "type" ) == "On_curve" )
+ {
+ bool ok3;
+ double value = values.toDouble( &ok3 );
+ if ( ! ok3 )
+ KIG_FILTER_PARSE_ERROR;
+ if ( ( parents[0]->imp()->inherits( CircleImp::stype() ) ) ||
+ ( parents[0]->imp()->inherits( SegmentImp::stype() ) ) )
+ oc = fact->constrainedPointCalcer( parents[0], value );
+ else if ( parents[0]->imp()->inherits( LineImp::stype() ) )
+ {
+ const LineData l = static_cast<const LineImp*>( parents[0]->imp() )->data();
+ const Coordinate p = convertDrgeoLineParam( value, l );
+ oc = fact->constrainedPointCalcer( parents[0], p, *ret );
+ }
+ else if ( parents[0]->imp()->inherits( RayImp::stype() ) )
+ {
+ const LineData l = static_cast<const RayImp*>( parents[0]->imp() )->data();
+ const Coordinate p = convertDrgeoHalflineParam( value, l );
+ oc = fact->constrainedPointCalcer( parents[0], p, *ret );
+ }
+ else if ( parents[0]->imp()->inherits( ArcImp::stype() ) )
+ oc = fact->constrainedPointCalcer( parents[0], 1 - value );
+ else
+ {
+// oc = fact->constrainedPointCalcer( parents[0], value );
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ }
+ else if ( domelem.attribute( "type" ) == "Intersection" )
+ {
+ if ( ( parents[0]->imp()->inherits( AbstractLineImp::stype() ) ) &&
+ ( parents[1]->imp()->inherits( AbstractLineImp::stype() ) ) )
+ oc = new ObjectTypeCalcer( LineLineIntersectionType::instance(), parents );
+ else
+ {
+ bool ok;
+ int which = domelem.attribute( "extra" ).toInt( &ok );
+ if ( !ok ) KIG_FILTER_PARSE_ERROR;
+ if ( which == 1 ) which = -1;
+ else if ( which == 0 ) which = 1;
+ else KIG_FILTER_PARSE_ERROR;
+ std::vector<ObjectCalcer*> args = parents;
+ const ObjectType* type = 0;
+ args.push_back( new ObjectConstCalcer( new IntImp( which ) ) );
+ if ( ( parents[0]->imp()->inherits( CircleImp::stype() ) ) &&
+ ( parents[1]->imp()->inherits( CircleImp::stype() ) ) )
+ type = CircleCircleIntersectionType::instance();
+ else if ( ( parents[0]->imp()->inherits( CircleImp::stype() ) &&
+ parents[1]->imp()->inherits( AbstractLineImp::stype() ) ) ||
+ ( parents[1]->imp()->inherits( CircleImp::stype() ) &&
+ parents[0]->imp()->inherits( AbstractLineImp::stype() ) ) )
+ type = ConicLineIntersectionType::instance();
+ else if ( ( parents[0]->imp()->inherits( ArcImp::stype() ) &&
+ parents[1]->imp()->inherits( AbstractLineImp::stype() ) ) ||
+ ( parents[1]->imp()->inherits( ArcImp::stype() ) &&
+ parents[0]->imp()->inherits( AbstractLineImp::stype() ) ) )
+ type = ArcLineIntersectionType::instance();
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains an intersection type, "
+ "which Kig does not currently support." ) );
+ return false;
+ }
+ oc = new ObjectTypeCalcer( type, args );
+ }
+ }
+ else if ( domelem.attribute( "type" ) == "Reflexion" )
+ oc = new ObjectTypeCalcer( LineReflectionType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Symmetry" )
+ oc = new ObjectTypeCalcer( PointReflectionType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Translation" )
+ oc = new ObjectTypeCalcer( TranslatedType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Rotation" )
+ oc = new ObjectTypeCalcer( RotationType::instance(), parents );
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+#ifdef DRGEO_DEBUG
+ kdDebug() << "+++++++++ oc:" << oc << endl;
+#endif
+ }
+ else if( ( domelem.tagName() == "line" ) ||
+ ( domelem.tagName() == "halfLine" ) ||
+ ( domelem.tagName() == "segment" ) ||
+ ( domelem.tagName() == "vector" ) ||
+ ( domelem.tagName() == "circle" ) ||
+ ( domelem.tagName() == "arcCircle" ) ||
+ ( domelem.tagName() == "polygon" ) )
+ {
+ const ObjectType* type = 0;
+ if ( domelem.attribute( "type" ) == "2pts" )
+ {
+ if( domelem.tagName() == "line" )
+ type = LineABType::instance();
+ else if( domelem.tagName() == "halfLine" )
+ type = RayABType::instance();
+ else if( domelem.tagName() == "segment" )
+ type = SegmentABType::instance();
+ else if( domelem.tagName() == "vector" )
+ type = VectorType::instance();
+ else if( domelem.tagName() == "circle" )
+ type = CircleBCPType::instance();
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ oc = new ObjectTypeCalcer( type, parents );
+ }
+ else if( domelem.attribute( "type" ) == "3pts" )
+ {
+ if( domelem.tagName() == "arcCircle" )
+ type = ArcBTPType::instance();
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ oc = new ObjectTypeCalcer( type, parents );
+ }
+ else if( domelem.attribute( "type" ) == "segment" )
+ {
+ if( domelem.tagName() == "circle" )
+ {
+ type = CircleBPRType::instance();
+ ObjectPropertyCalcer* o = fact->propertyObjectCalcer( parents[1], "length" );
+ o->calc( *ret );
+ ObjectCalcer* a = parents[0];
+ parents.clear();
+ parents.push_back( a );
+ parents.push_back( o );
+ }
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ oc = new ObjectTypeCalcer( type, parents );
+ }
+ else if( domelem.attribute( "type" ) == "npts" )
+ {
+ if( domelem.tagName() == "polygon" )
+ {
+ if ( parents.size() < 3 ) KIG_FILTER_PARSE_ERROR;
+ type = PolygonBNPType::instance();
+ }
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ oc = new ObjectTypeCalcer( type, parents );
+ }
+ else if ( domelem.attribute( "type" ) == "perpendicular" )
+ oc = new ObjectTypeCalcer( LinePerpendLPType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "parallel" )
+ oc = new ObjectTypeCalcer( LineParallelLPType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Reflexion" )
+ oc = new ObjectTypeCalcer( LineReflectionType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Symmetry" )
+ oc = new ObjectTypeCalcer( PointReflectionType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Translation" )
+ oc = new ObjectTypeCalcer( TranslatedType::instance(), parents );
+ else if ( domelem.attribute( "type" ) == "Rotation" )
+ oc = new ObjectTypeCalcer( RotationType::instance(), parents );
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+#ifdef DRGEO_DEBUG
+ kdDebug() << "+++++++++ oc:" << oc << endl;
+#endif
+ }
+ else if( ( domelem.tagName() == "numeric" ) ||
+ ( domelem.tagName() == "equation" ) )
+ {
+ QString xs;
+ QString ys;
+ QString value;
+ for ( QDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() )
+ {
+ QDomElement ce = c.toElement();
+ if ( ce.isNull() ) continue;
+ else if ( ce.tagName() == "x" )
+ xs = ce.text();
+ else if ( ce.tagName() == "y" )
+ ys = ce.text();
+ else if ( ce.tagName() == "value" )
+ value = ce.text();
+ }
+ bool ok;
+ bool ok2;
+ double x = xs.toDouble( &ok );
+ double y = ys.toDouble( &ok2 );
+ if ( ! ( ok && ok2 ) )
+ KIG_FILTER_PARSE_ERROR;
+ Coordinate m( x, y );
+ // types of 'numeric'
+ // ugly hack to show value numerics...
+ if ( domelem.attribute( "type" ) == "value" )
+ {
+ bool ok3;
+ double dvalue = value.toDouble( &ok3 );
+ if ( ok3 )
+ value = QString( "%1" ).arg( dvalue, 0, 'g', 3 );
+ oc = fact->labelCalcer( value, m, false, std::vector<ObjectCalcer*>(), *ret );
+ }
+ else if ( domelem.attribute( "type" ) == "pt_abscissa" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "coordinate-x", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "pt_ordinate" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "coordinate-y", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "segment_length" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "length", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "circle_perimeter" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "circumference", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "arc_length" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "arc-length", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "distance_2pts" )
+ {
+ if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+ ObjectTypeCalcer* so = new ObjectTypeCalcer( SegmentABType::instance(), parents );
+ so->calc( *ret );
+ oc = filtersConstructTextObject( m, so, "length", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "vector_norm" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "length", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "vector_abscissa" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "length-x", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "vector_ordinate" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "length-y", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "slope" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "slope", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "distance_pt_line" )
+ {
+ if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+ std::vector<ObjectCalcer*> args;
+ args.push_back( parents[1] );
+ args.push_back( parents[0] );
+ ObjectTypeCalcer* po = new ObjectTypeCalcer( LinePerpendLPType::instance(), args );
+ po->calc( *ret );
+ args.clear();
+ args.push_back( parents[1] );
+ args.push_back( po );
+ ObjectTypeCalcer* io = new ObjectTypeCalcer( LineLineIntersectionType::instance(), args );
+ io->calc( *ret );
+ args.clear();
+ args.push_back( parents[0] );
+ args.push_back( io );
+ ObjectTypeCalcer* so = new ObjectTypeCalcer( SegmentABType::instance(), args );
+ so->calc( *ret );
+ oc = filtersConstructTextObject( m, so, "length", *ret, false );
+ }
+ // types of 'equation'
+ else if ( domelem.attribute( "type" ) == "line" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "equation", *ret, false );
+ }
+ else if ( domelem.attribute( "type" ) == "circle" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ oc = filtersConstructTextObject( m, parents[0], "simply-cartesian-equation", *ret, false );
+ }
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+#ifdef DRGEO_DEBUG
+ kdDebug() << "+++++++++ oc:" << oc << endl;
+#endif
+ }
+ else if ( domelem.tagName() == "angle" )
+ {
+ if ( domelem.attribute( "type" ) == "3pts" )
+ {
+ if ( parents.size() != 3 ) KIG_FILTER_PARSE_ERROR;
+ oc = new ObjectTypeCalcer( HalfAngleType::instance(), parents );
+ }
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+#ifdef DRGEO_DEBUG
+ kdDebug() << "+++++++++ oc:" << oc << endl;
+#endif
+ }
+ else if ( domelem.tagName() == "script" )
+ {
+ QString xs;
+ QString ys;
+ QString text;
+ for ( QDomNode c = domelem.firstChild(); ! c.isNull(); c = c.nextSibling() )
+ {
+ QDomElement ce = c.toElement();
+ if ( ce.isNull() ) continue;
+ else if ( ce.tagName() == "x" )
+ xs = ce.text();
+ else if ( ce.tagName() == "y" )
+ ys = ce.text();
+ else if ( ce.tagName() == "code" )
+ text = ce.text();
+ }
+ bool ok;
+ bool ok2;
+ double x = xs.toDouble( &ok );
+ double y = ys.toDouble( &ok2 );
+ if ( ! ( ok && ok2 ) )
+ KIG_FILTER_PARSE_ERROR;
+ // since Kig doesn't support Guile scripts, it will write script's text
+ // in a label, so the user can freely see the code and make whatever
+ // he/she wants
+ // possible idea: construct a new script object with the parents of Guile
+ // one and the Guile code inserted commented... depends on a better
+ // handling of arguments in scripts?
+ if ( domelem.attribute( "type" ) == "nitems" )
+ oc = fact->labelCalcer( text, Coordinate( x, y ), false, std::vector<ObjectCalcer*>(), *ret );
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ }
+ else if ( domelem.tagName() == "locus" )
+ {
+ if ( domelem.attribute( "type" ) == "None" )
+ oc = fact->locusCalcer( parents[0], parents[1] );
+ else
+ {
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+#ifdef DRGEO_DEBUG
+ kdDebug() << "+++++++++ oc:" << oc << endl;
+#endif
+ }
+ else if ( ( domelem.tagName() == "boundingBox" ) ||
+ ( domelem.tagName() == "customUI" ) )
+ {
+ // ignoring these elements, since they are not useful to us...
+ nignored++;
+ }
+ else
+ {
+#ifdef DRGEO_DEBUG
+ kdDebug() << ">>>>>>>>> UNKNOWN OBJECT" << endl;
+#endif
+ notSupported( file, i18n( "This Dr. Geo file contains a \"%1 %2\" object, "
+ "which Kig does not currently support." ).arg( domelem.tagName() ).arg(
+ domelem.attribute( "type" ) ) );
+ return false;
+ }
+ curid++;
+ if ( oc == 0 )
+ continue;
+
+// reading color
+ QColor co( domelem.attribute( "color" ) );
+ if ( ! co.isValid() )
+ if ( domelem.attribute( "color" ) == "Bordeaux" )
+ co.setRgb( 145, 0, 0 );
+ else
+ co = Qt::blue;
+// reading width and style
+// Dashed -> the little one
+// Normal -> the medium
+// Thick -> the biggest one
+ int w = -1;
+ Qt::PenStyle s = Qt::SolidLine;
+ if ( domelem.tagName() == "point" )
+ {
+ if ( domelem.attribute( "thickness" ) == "Normal" )
+ w = 7;
+ else if ( domelem.attribute( "thickness" ) == "Thick" )
+ w = 9;
+ }
+ else
+ {
+ if ( domelem.attribute( "thickness" ) == "Dashed" )
+ s = Qt::DotLine;
+ if ( domelem.attribute( "thickness" ) == "Thick" )
+ w = 2;
+ }
+ QString ps = domelem.attribute( "style" );
+ int pointstyle = ObjectDrawer::pointStyleFromString( ps );
+// show this object?
+ bool show = ( ( domelem.attribute( "masked" ) != "True" ) &&
+ ( domelem.attribute( "masked" ) != "Alway" ) );
+// costructing the ObjectDrawer*
+ ObjectDrawer* d = new ObjectDrawer( co, w, show, s, pointstyle );
+// reading object name
+ QString strname = domelem.attribute( "name" );
+ ObjectConstCalcer* name = new ObjectConstCalcer( new StringImp( strname ) );
+
+// creating the ObjectHolder*
+ ObjectHolder* o = new ObjectHolder( oc, d, name );
+ holders.push_back( o );
+// calc()
+#ifdef DRGEO_DEBUG
+ kdDebug() << ">>>>>>>>> calc" << endl;
+#endif
+ holders[curid-1-nignored]->calc( *ret );
+
+ if ( domelem.tagName() == "point" )
+ {
+ if ( !strname.isEmpty() )
+ {
+ std::vector<ObjectCalcer*> args2;
+ args2.push_back( o->nameCalcer() );
+ oc2 = fact->attachedLabelCalcer( QString::fromLatin1( "%1" ), oc,
+ static_cast<const PointImp*>( oc->imp() )->coordinate(),
+ false, args2, *ret );
+ co = Qt::black;
+ }
+ }
+ else if ( domelem.tagName() == "angle" )
+ {
+ oc2 = filtersConstructTextObject(
+ static_cast<const PointImp*>( holders[curid-1-nignored]->calcer()->parents()[1]->imp() )->coordinate(),
+ holders[curid-1-nignored]->calcer(), "angle-degrees", *ret, false );
+ }
+
+ oc = 0;
+
+ if ( oc2 != 0 )
+ {
+ oc2->calc( *ret );
+ ObjectDrawer* d2 = new ObjectDrawer( co );
+ ObjectHolder* o2 = new ObjectHolder( oc2, d2 );
+ holders2.push_back( o2 );
+ oc2 = 0;
+ }
+ }
+
+ ret->addObjects( holders );
+ ret->addObjects( holders2 );
+ ret->setGrid( grid );
+ ret->setAxes( grid );
+ return ret;
+}
+
+KigFilterDrgeo* KigFilterDrgeo::instance()
+{
+ static KigFilterDrgeo f;
+ return &f;
+}
diff --git a/kig/filters/drgeo-filter.h b/kig/filters/drgeo-filter.h
new file mode 100644
index 00000000..7485fd5b
--- /dev/null
+++ b/kig/filters/drgeo-filter.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_FILTERS_DRGEO_FILTER_H
+#define KIG_FILTERS_DRGEO_FILTER_H
+
+#include "filter.h"
+
+class QDomNode;
+class KigDocument;
+class QString;
+
+/**
+ * This is an import filter for the GNOME geometry program DrGeo.
+ */
+class KigFilterDrgeo
+ : public KigFilter
+{
+protected:
+ KigFilterDrgeo();
+ ~KigFilterDrgeo();
+public:
+ static KigFilterDrgeo* instance();
+
+ bool supportMime( const QString& mime );
+ KigDocument* load( const QString& file );
+private:
+ KigDocument* importFigure( QDomNode f, const QString& file, const bool grid );
+};
+
+#endif
diff --git a/kig/filters/exporter.cc b/kig/filters/exporter.cc
new file mode 100644
index 00000000..c2ece44e
--- /dev/null
+++ b/kig/filters/exporter.cc
@@ -0,0 +1,624 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "exporter.h"
+
+#include "imageexporteroptions.h"
+#include "latexexporter.h"
+#include "svgexporter.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../misc/common.h"
+#include "../misc/kigfiledialog.h"
+#include "../misc/kigpainter.h"
+#include "../objects/circle_imp.h"
+#include "../objects/line_imp.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_holder.h"
+#include "../objects/object_imp.h"
+#include "../objects/other_imp.h"
+#include "../objects/point_imp.h"
+#include "../objects/text_imp.h"
+
+#include <qcheckbox.h>
+#include <qcolor.h>
+#include <qfile.h>
+#include <qiconset.h>
+#include <qtextstream.h>
+
+#include <kaction.h>
+#include <kiconloader.h>
+#include <kimageio.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <knuminput.h>
+
+#include <map>
+
+// we need this for storing colors in a std::map..
+static bool operator<( const QColor& a, const QColor& b )
+{
+ return a.rgb() < b.rgb();
+}
+
+class ExporterAction
+ : public KAction
+{
+ KigExporter* mexp;
+ const KigPart* mdoc;
+ KigWidget* mw;
+public:
+ ExporterAction( const KigPart* doc, KigWidget* w,
+ KActionCollection* parent, KigExporter* exp );
+ void slotActivated();
+};
+
+ExporterAction::ExporterAction( const KigPart* doc, KigWidget* w,
+ KActionCollection* parent, KigExporter* exp )
+ : KAction( exp->menuEntryName(), KShortcut(), 0, 0, parent ),
+ mexp( exp ), mdoc( doc ), mw( w )
+{
+ QString iconstr = exp->menuIcon();
+ if ( iconstr.isEmpty() )
+ return;
+ KIconLoader* l = doc->instance()->iconLoader();
+ QPixmap icon = l->loadIcon( iconstr, KIcon::Small, 16, KIcon::DefaultState, 0L, true );
+ if ( !icon.isNull() )
+ setIconSet( QIconSet( icon ) );
+}
+
+void ExporterAction::slotActivated()
+{
+ mexp->run( *mdoc, *mw );
+}
+
+KigExporter::~KigExporter()
+{
+}
+
+ImageExporter::~ImageExporter()
+{
+}
+
+QString ImageExporter::exportToStatement() const
+{
+ return i18n( "&Export to image" );
+}
+
+QString ImageExporter::menuEntryName() const
+{
+ return i18n( "&Image..." );
+}
+
+QString ImageExporter::menuIcon() const
+{
+ return "image";
+}
+
+void ImageExporter::run( const KigPart& doc, KigWidget& w )
+{
+ static bool kimageioRegistered = false;
+ if ( ! kimageioRegistered )
+ {
+ KImageIO::registerFormats();
+ kimageioRegistered = true;
+ }
+
+ KigFileDialog* kfd = new KigFileDialog(
+ QString::null, KImageIO::pattern( KImageIO::Writing ),
+ i18n( "Export as Image" ), &w );
+ kfd->setOptionCaption( i18n( "Image Options" ) );
+ ImageExporterOptions* opts = new ImageExporterOptions( 0L, w.size() );
+ kfd->setOptionsWidget( opts );
+ opts->WidthInput->setValue( w.size().width() );
+ opts->HeightInput->setValue( w.size().height() );
+ opts->showGridCheckBox->setChecked( doc.document().grid() );
+ opts->showAxesCheckBox->setChecked( doc.document().axes() );
+ if ( !kfd->exec() )
+ return;
+
+ QString filename = kfd->selectedFile();
+ bool showgrid = opts->showGridCheckBox->isOn();
+ bool showaxes = opts->showAxesCheckBox->isOn();
+ int width = opts->WidthInput->value();
+ int height = opts->HeightInput->value();
+
+ delete opts;
+ delete kfd;
+
+ QString type = KImageIO::type( filename );
+ if ( type.isNull() )
+ {
+ KMessageBox::sorry( &w, i18n( "Sorry, this file format is not supported." ) );
+ return;
+ };
+
+ kdDebug() << k_funcinfo << type << endl;
+
+ QFile file( filename );
+ if ( ! file.open( IO_WriteOnly ) )
+ {
+ KMessageBox::sorry( &w,
+ i18n( "The file \"%1\" could not be opened. Please check if the file permissions are set correctly." )
+ .arg( filename ) );
+ return;
+ };
+
+ QPixmap img( QSize( width, height ) );
+ img.fill( Qt::white );
+ KigPainter p( ScreenInfo( w.screenInfo().shownRect(), img.rect() ), &img, doc.document() );
+ p.setWholeWinOverlay();
+ p.drawGrid( doc.document().coordinateSystem(), showgrid, showaxes );
+ // FIXME: show the selections ?
+ p.drawObjects( doc.document().objects(), false );
+ if ( ! img.save( filename, type.latin1() ) )
+ {
+ KMessageBox::error( &w, i18n( "Sorry, something went wrong while saving to image \"%1\"" ).arg( filename ) );
+ }
+
+}
+
+KigExportManager::KigExportManager()
+{
+ mexporters.push_back( new ImageExporter );
+ // working on this one ;)
+ mexporters.push_back( new XFigExporter );
+ mexporters.push_back( new LatexExporter );
+ mexporters.push_back( new SVGExporter );
+}
+
+KigExportManager::~KigExportManager()
+{
+ for ( uint i = 0; i < mexporters.size(); ++i )
+ delete mexporters[i];
+}
+
+void KigExportManager::addMenuAction( const KigPart* doc, KigWidget* w,
+ KActionCollection* coll )
+{
+ KActionMenu* m =
+ new KActionMenu( i18n( "&Export To" ), coll, "file_export" );
+ for ( uint i = 0; i < mexporters.size(); ++i )
+ m->insert( new ExporterAction( doc, w, coll, mexporters[i] ) );
+}
+
+KigExportManager* KigExportManager::instance()
+{
+ static KigExportManager m;
+ return &m;
+}
+
+XFigExporter::~XFigExporter()
+{
+}
+
+QString XFigExporter::exportToStatement() const
+{
+ return i18n( "Export to &XFig file" );
+}
+
+
+QString XFigExporter::menuEntryName() const
+{
+ return i18n( "&XFig File..." );
+}
+
+QString XFigExporter::menuIcon() const
+{
+ return "kig_xfig";
+}
+
+class XFigExportImpVisitor
+ : public ObjectImpVisitor
+{
+ QTextStream& mstream;
+ ObjectHolder* mcurobj;
+ const KigWidget& mw;
+ Rect msr;
+ std::map<QColor, int> mcolormap;
+ int mnextcolorid;
+ int mcurcolorid;
+
+ QPoint convertCoord( const Coordinate& c )
+ {
+ Coordinate ret = ( c - msr.bottomLeft() );
+ ret.y = msr.height() - ret.y;
+// kdDebug() << "msr: " << msr << endl
+// << "ret: " << ret << endl
+// << "c: " << c << endl;
+ ret *= 9450;
+ ret /= msr.width();
+ return ret.toQPoint();
+ }
+
+ void emitLine( const Coordinate& a, const Coordinate& b, int width, bool vector = false );
+public:
+ void visit( ObjectHolder* obj );
+ void mapColor( const ObjectDrawer* obj );
+
+ XFigExportImpVisitor( QTextStream& s, const KigWidget& w )
+ : mstream( s ), mw( w ), msr( mw.showingRect() ),
+ mnextcolorid( 32 )
+ {
+ // predefined colors in XFig..
+ mcolormap[Qt::black] = 0;
+ mcolormap[Qt::blue] = 1;
+ mcolormap[Qt::green] = 2;
+ mcolormap[Qt::cyan] = 3;
+ mcolormap[Qt::red] = 4;
+ mcolormap[Qt::magenta] = 5;
+ mcolormap[Qt::yellow] = 6;
+ mcolormap[Qt::white] = 7;
+ }
+ void visit( const LineImp* imp );
+ void visit( const PointImp* imp );
+ void visit( const TextImp* imp );
+ void visit( const AngleImp* imp );
+ void visit( const VectorImp* imp );
+ void visit( const LocusImp* imp );
+ void visit( const CircleImp* imp );
+ void visit( const ConicImp* imp );
+ void visit( const CubicImp* imp );
+ void visit( const SegmentImp* imp );
+ void visit( const RayImp* imp );
+ void visit( const ArcImp* imp );
+};
+
+void XFigExportImpVisitor::mapColor( const ObjectDrawer* obj )
+{
+ if ( ! obj->shown() ) return;
+ QColor color = obj->color();
+ if ( mcolormap.find( color ) == mcolormap.end() )
+ {
+ int newcolorid = mnextcolorid++;
+ mstream << "0 "
+ << newcolorid << " "
+ << color.name() << "\n";
+ mcolormap[color] = newcolorid;
+ }
+}
+
+void XFigExportImpVisitor::visit( ObjectHolder* obj )
+{
+ if ( ! obj->drawer()->shown() ) return;
+ assert( mcolormap.find( obj->drawer()->color() ) != mcolormap.end() );
+ mcurcolorid = mcolormap[ obj->drawer()->color() ];
+ mcurobj = obj;
+ obj->imp()->visit( this );
+}
+
+void XFigExportImpVisitor::visit( const LineImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+ calcBorderPoints( a, b, msr );
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ if ( a != b )
+ emitLine( a, b, width );
+}
+
+void XFigExportImpVisitor::emitLine( const Coordinate& a, const Coordinate& b, int width, bool vector )
+{
+ mstream << "2 "; // polyline type;
+ mstream << "1 "; // polyline subtype;
+ mstream << "0 "; // line_style: Solid
+ mstream << width << " "; // thickness: *1/80 inch
+ mstream << mcurcolorid << " "; // pen_color: default
+ mstream << "7 "; // fill_color: white
+ mstream << "50 "; // depth: 50
+ mstream << "-1 "; // pen_style: unused by XFig
+ mstream << "-1 "; // area_fill: no fill
+ mstream << "0.000 "; // style_val: the distance between dots and
+ // dashes in case of dotted or dashed lines..
+ mstream << "0 "; // join_style: Miter
+ mstream << "0 "; // cap_style: Butt
+ mstream << "-1 "; // radius in case of an arc-box, but we're a
+ // polyline, so nothing here..
+ if ( ! vector )
+ mstream << "0 "; // forward arrow: no
+ else
+ mstream << "1 "; // forward arrow: yes
+ mstream << "0 "; // backward arrow: no
+ mstream << "2"; // a two points polyline..
+
+ mstream << "\n\t ";
+
+ if ( vector )
+ {
+ // first the arrow line in case of a vector..
+ mstream << "1 " // arrow_type: closed triangle
+ << "1 " // arrow_style: filled with pen color..
+ << "1.00 " // arrow_thickness: 1
+ << "195.00 " // arrow_width
+ << "165.00 " // arrow_height
+ << "\n\t";
+ }
+ QPoint ca = convertCoord( a );
+ QPoint cb = convertCoord( b );
+
+ mstream << ca.x() << " " << ca.y() << " " << cb.x() << " " << cb.y() << "\n";
+}
+
+void XFigExportImpVisitor::visit( const PointImp* imp )
+{
+ const QPoint center = convertCoord( imp->coordinate() );
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 5;
+ width *= 10;
+
+ mstream << "1 " // Ellipse type
+ << "3 " // circle defined by radius subtype
+ << "0 "; // line_style: Solid
+ mstream << "1 " << " " // thickness: *1/80 inch
+ << mcurcolorid << " " // pen_color: default
+ << mcurcolorid << " " // fill_color: black
+ << "50 " // depth: 50
+ << "-1 " // pen_style: unused by XFig
+ << "20 " // area_fill: full saturation of the fill color
+ << "0.000 " // style_val: the distance between dots and
+ // dashes in case of dotted or dashed lines..
+ << "1 " // direction: always 1
+ << "0.0000 " // angle: the radius of the x-axis: 0
+ << center.x() << " " << center.y() << " " // the center..
+ << width << " " << width << " " // radius_x and radius_y
+ << center.x() << " " // start_x and start_y, appear
+ << center.y() << " " // unused..
+ << center.x() + width << " " // end_x and end_y,
+ << center.y() << "\n"; // appear unused too...
+}
+
+void XFigExportImpVisitor::visit( const TextImp* imp )
+{
+ QString text = imp->text();
+ QPoint coord = convertCoord( imp->surroundingRect().bottomLeft() );
+
+ mstream << "4 " // text type
+ << "0 " // subtype: left justfied
+ << mcurcolorid << " " // color: black
+ << "50 " // depth: 50
+ << "-1 " // pen style: unused
+ << "0 " // font: default
+ << "11 " // font-size: 11
+ << "0 " // angle
+ << "0 " // font-flags: all the defaults..
+ << "500 500 " // height, width: large enough..
+ << coord.x() << " " // x, y
+ << coord.y() << " "
+ << text.ascii() << "\\001" // text, terminated by \001
+ << "\n";
+}
+
+void XFigExportImpVisitor::visit( const AngleImp* )
+{
+}
+
+void XFigExportImpVisitor::visit( const VectorImp* imp )
+{
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+ emitLine( imp->a(), imp->b(), width, true );
+}
+
+void XFigExportImpVisitor::visit( const LocusImp* )
+{
+
+}
+
+void XFigExportImpVisitor::visit( const CircleImp* imp )
+{
+ const QPoint center = convertCoord( imp->center() );
+ const int radius =
+ ( convertCoord( imp->center() + Coordinate( imp->radius(), 0 ) ) - center ).x();
+
+ mstream << "1 " // Ellipse type
+ << "3 " // circle defined by radius subtype
+ << "0 "; // line_style: Solid
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+ mstream << width << " " // thickness: *1/80 inch
+ << mcurcolorid << " " // pen_color: default
+ << "7 " // fill_color: white
+ << "50 " // depth: 50
+ << "-1 " // pen_style: unused by XFig
+ << "-1 " // area_fill: no fill
+ << "0.000 " // style_val: the distance between dots and
+ // dashes in case of dotted or dashed lines..
+ << "1 " // direction: always 1
+ << "0.0000 " // angle: the radius of the x-axis: 0
+ << center.x() << " " << center.y() << " " // the center..
+ << radius << " " << radius << " " // radius_x and radius_y
+ << center.x() << " " // start_x and start_y, appear
+ << center.y() << " " // unused..
+ << center.x() + radius << " " // end_x and end_y,
+ << center.y() << "\n"; // appear unused too...
+}
+
+void XFigExportImpVisitor::visit( const ConicImp* imp )
+{
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+ if ( imp->conicType() == 1 )
+ {
+ // an ellipse, this is good, cause this allows us to export to a
+ // real ellipse type..
+ const ConicPolarData data = imp->polarData();
+
+ // gather some necessary data..
+ // the angle of the x axis..
+ double anglex = atan2( data.esintheta0, data.ecostheta0 );
+ // the exentricity
+ double e = hypot( data.esintheta0, data.ecostheta0 );
+ // the x radius is easy to find..
+ double radiusx = data.pdimen / ( 1 - e * e );
+ // the y radius is a bit harder: we first find the distance from
+ // the focus point to the mid point of the two focuses, this is:
+ double d = -e * data.pdimen / ( 1 - e * e );
+ // the distance from the first focus to the intersection of the
+ // second axis with the conic equals radiusx:
+ double r = radiusx;
+ double radiusy = sqrt( r*r - d*d );
+
+ Coordinate center = data.focus1 - Coordinate( cos( anglex ), sin( anglex ) ).normalize( d );
+ const QPoint qcenter = convertCoord( center );
+ const int radius_x = ( convertCoord( center + Coordinate( radiusx, 0 ) ) -
+ convertCoord( center ) ).x();
+ const int radius_y = ( convertCoord( center + Coordinate( radiusy, 0 ) ) -
+ convertCoord( center ) ).x();
+ const QPoint qpoint2 = convertCoord( center + Coordinate( -sin( anglex ), cos( anglex ) ) * radiusy );
+
+ mstream << "1 " // ellipse type
+ << "1 " // subtype: ellipse defined by readii
+ << "0 " // line_style: Solid
+ << width << " " // thickness
+ << mcurcolorid << " " // pen_color: black
+ << "7 " // fill_color: white
+ << "50 " // depth: 50
+ << "-1 " // pan_style: not used
+ << "-1 " // area_fill: no fill
+ << "0.000 " // style_val: not used
+ << "1 " // direction: always 1
+ << anglex << " " // angle of the main axis
+ << qcenter.x() << " " // center
+ << qcenter.y() << " "
+ << radius_x << " " // radiuses
+ << radius_y << " "
+ << qcenter.x() << " " // start point
+ << qcenter.y() << " "
+ << qpoint2.x() << " " // end point
+ << qpoint2.y() << " ";
+ }
+ else return;
+}
+
+void XFigExportImpVisitor::visit( const CubicImp* )
+{
+}
+
+void XFigExportImpVisitor::visit( const SegmentImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ emitLine( a, b, width );
+}
+
+void XFigExportImpVisitor::visit( const RayImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+ calcRayBorderPoints( a, b, msr );
+
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ emitLine( a, b, width );
+}
+
+void XFigExportImpVisitor::visit( const ArcImp* imp )
+{
+ const Coordinate center = imp->center();
+ const double radius = imp->radius();
+ const double startangle = imp->startAngle();
+ const double endangle = startangle + imp->angle();
+ const double middleangle = ( startangle + endangle ) / 2;
+ const Coordinate ad = Coordinate( cos( startangle ), sin( startangle ) ).normalize( radius );
+ const Coordinate bd = Coordinate( cos( middleangle ), sin( middleangle ) ).normalize( radius );
+ const Coordinate cd = Coordinate( cos( endangle ), sin( endangle ) ).normalize( radius );
+ const QPoint a = convertCoord( center + ad );
+ const QPoint b = convertCoord( center + bd );
+ const QPoint c = convertCoord( center + cd );
+ const QPoint cent = convertCoord( center );
+
+ mstream << "5 " // Ellipse type
+ << "1 " // subtype: open ended arc
+ << "0 "; // line_style: Solid
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+ mstream << width << " " // thickness: *1/80 inch
+ << mcurcolorid << " " // pen_color: default
+ << "7 " // fill_color: white
+ << "50 " // depth: 50
+ << "-1 " // pen_style: unused by XFig
+ << "-1 " // area_fill: no fill
+ << "0.000 " // style_val: the distance between dots and
+ // dashes in case of dotted or dashed lines..
+ << "0 "; // cap_style: Butt..
+ // 0 is clockwise, 1 is counterclockwise .
+ int direction = imp->angle() > 0 ? 1 : 0;
+ // direction next
+ mstream << direction << " " // direction..
+ << "0 " // forward_arrow: no
+ << "0 " // backward_arrow: no
+ << cent.x() << " " << cent.y() << " " // the center..
+ << a.x() << " " << a.y() << " " // x1, y1
+ << b.x() << " " << b.y() << " " // x2, y2
+ << c.x() << " " << c.y() << " " // x3, y3
+ << "\n";
+}
+
+void XFigExporter::run( const KigPart& doc, KigWidget& w )
+{
+ KigFileDialog* kfd = new KigFileDialog(
+ ":document", i18n( "*.fig|XFig Documents (*.fig)" ),
+ i18n( "Export as XFig File" ), &w );
+ if ( !kfd->exec() )
+ return;
+
+ QString file_name = kfd->selectedFile();
+
+ delete kfd;
+
+ QFile file( file_name );
+ if ( ! file.open( IO_WriteOnly ) )
+ {
+ KMessageBox::sorry( &w, i18n( "The file \"%1\" could not be opened. Please "
+ "check if the file permissions are set correctly." )
+ .arg( file_name ) );
+ return;
+ };
+ QTextStream stream( &file );
+ stream << "#FIG 3.2\n";
+ stream << "Landscape\n";
+ stream << "Center\n";
+ stream << "Metric\n";
+ stream << "A4\n";
+ stream << "100.00\n";
+ stream << "Single\n";
+ stream << "-2\n";
+ stream << "1200 2\n";
+
+ std::vector<ObjectHolder*> os = doc.document().objects();
+ XFigExportImpVisitor visitor( stream, w );
+
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ {
+ visitor.mapColor( ( *i )->drawer() );
+ };
+
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ {
+ visitor.visit( *i );
+ };
+}
diff --git a/kig/filters/exporter.h b/kig/filters/exporter.h
new file mode 100644
index 00000000..4fc74453
--- /dev/null
+++ b/kig/filters/exporter.h
@@ -0,0 +1,102 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_FILTERS_EXPORTER_H
+#define KIG_FILTERS_EXPORTER_H
+
+#include <vector>
+
+class QString;
+class KigDocument;
+class KigPart;
+class KigWidget;
+class KActionCollection;
+
+class KigExporter;
+
+class KigExportManager
+{
+ std::vector<KigExporter*> mexporters;
+ KigExportManager();
+ ~KigExportManager();
+public:
+ static KigExportManager* instance();
+ void addMenuAction( const KigPart* doc, KigWidget* w,
+ KActionCollection* coll );
+};
+
+/**
+ * Base class for a Kig exporter.
+ *
+ * Subclass it and implement its methods to have it working.
+ */
+class KigExporter
+{
+public:
+ virtual ~KigExporter();
+
+ /**
+ * Returns a statement like i18n( "Export to image" )
+ */
+ virtual QString exportToStatement() const = 0;
+ /**
+ * Returns a string like i18n( "Image..." )
+ */
+ virtual QString menuEntryName() const = 0;
+ /**
+ * Returns a string with the name of the icon
+ */
+ virtual QString menuIcon() const = 0;
+
+ /**
+ * Do what you need to do. It's up to the individual exporters to
+ * ask the user for which file to export to etc., because they can
+ * do a much better job at that..
+ */
+ virtual void run( const KigPart& doc, KigWidget& w ) = 0;
+};
+
+/**
+ * This exporter takes care of the "Export to Image" stuff..
+ */
+class ImageExporter
+ : public KigExporter
+{
+public:
+ ~ImageExporter();
+ QString exportToStatement() const;
+ QString menuEntryName() const;
+ QString menuIcon() const;
+ void run( const KigPart& doc, KigWidget& w );
+};
+
+/**
+ * Guess what this one does ;)
+ * It exports to the XFig file format, as documented in the file
+ * FORMAT3.2 in the XFig source distribution.
+ */
+class XFigExporter
+ : public KigExporter
+{
+public:
+ ~XFigExporter();
+ QString exportToStatement() const;
+ QString menuEntryName() const;
+ QString menuIcon() const;
+ void run( const KigPart& doc, KigWidget& w );
+};
+#endif
diff --git a/kig/filters/filter.cc b/kig/filters/filter.cc
new file mode 100644
index 00000000..70290e8a
--- /dev/null
+++ b/kig/filters/filter.cc
@@ -0,0 +1,114 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "filter.h"
+
+#include "kgeo-filter.h"
+#include "cabri-filter.h"
+#include "native-filter.h"
+#include "kseg-filter.h"
+#include "drgeo-filter.h"
+
+#include <kmessagebox.h>
+#include <klocale.h>
+
+KigFilters* KigFilters::sThis;
+
+KigFilter* KigFilters::find(const QString& mime)
+{
+ for (vect::iterator i = mFilters.begin(); i != mFilters.end(); ++i)
+ {
+ if ((*i)->supportMime(mime)) return *i;
+ };
+ return 0;
+}
+
+KigFilters::KigFilters()
+{
+ mFilters.push_back( KigFilterKGeo::instance() );
+ mFilters.push_back( KigFilterKSeg::instance() );
+ mFilters.push_back( KigFilterCabri::instance() );
+ mFilters.push_back( KigFilterNative::instance() );
+ mFilters.push_back( KigFilterDrgeo::instance() );
+}
+
+KigFilters* KigFilters::instance()
+{
+ return sThis ? sThis : ( sThis = new KigFilters() );
+}
+
+KigFilter::KigFilter()
+{
+}
+
+KigFilter::~KigFilter()
+{
+}
+
+bool KigFilter::supportMime( const QString& )
+{
+ return false;
+}
+
+void KigFilter::fileNotFound( const QString& file ) const
+{
+ KMessageBox::sorry( 0,
+ i18n( "The file \"%1\" could not be opened. "
+ "This probably means that it does not "
+ "exist, or that it cannot be opened due to "
+ "its permissions" ).arg( file ) );
+}
+
+void KigFilter::parseError( const QString& file, const QString& explanation ) const
+{
+ const QString text =
+ i18n( "An error was encountered while parsing the file \"%1\". It "
+ "cannot be opened." ).arg( file );
+ const QString title = i18n( "Parse Error" );
+
+ if ( explanation.isNull() )
+ KMessageBox::sorry( 0, text, title );
+ else
+ KMessageBox::detailedSorry( 0, text, explanation, title );
+}
+
+void KigFilter::notSupported( const QString& file, const QString& explanation ) const
+{
+ KMessageBox::detailedSorry( 0,
+ i18n( "Kig cannot open the file \"%1\"." ).arg( file ),
+ explanation, i18n( "Not Supported" ) );
+}
+
+void KigFilter::warning( const QString& explanation ) const
+{
+ KMessageBox::information( 0, explanation );
+}
+
+bool KigFilters::save( const KigDocument& data, const QString& tofile )
+{
+ return KigFilterNative::instance()->save( data, tofile );
+}
+
+/*
+bool KigFilters::save( const KigDocument& data, QTextStream& stream )
+{
+ return KigFilterNative::instance()->save( data, stream );
+}
+*/
diff --git a/kig/filters/filter.h b/kig/filters/filter.h
new file mode 100644
index 00000000..f5d8b0f9
--- /dev/null
+++ b/kig/filters/filter.h
@@ -0,0 +1,96 @@
+// This file is part of Kig, a KDE program for Interactive Geometry...
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef FILTER_H
+#define FILTER_H
+
+#include <qstring.h>
+
+#include <vector>
+
+class KigFilter;
+class ScreenInfo;
+class KigDocument;
+
+/**
+ * This singleton class handles all the input filters.
+ */
+class KigFilters
+{
+public:
+ static KigFilters* instance();
+ KigFilter* find (const QString& mime);
+
+// bool save ( const KigDocument& data, QTextStream& stream );
+ /**
+ * saving is always done with the native filter. We don't support
+ * output filters..
+ */
+ bool save ( const KigDocument& data, const QString& outfile );
+protected:
+ KigFilters();
+ static KigFilters* sThis;
+ typedef std::vector<KigFilter*> vect;
+ vect mFilters;
+};
+
+// KigFilter::load functions should use this macro to conveniently
+// return a very useful parse error in a filter's load function..
+#define KIG_FILTER_PARSE_ERROR \
+ { \
+ QString locs = i18n( "An error was encountered at " \
+ "line %1 in file %2." ) \
+ .arg( __LINE__ ).arg( __FILE__ ); \
+ parseError( file, locs ); \
+ return 0; \
+ }
+
+/**
+ * This is the base class for an input filter.
+ *
+ * All the needed work to add a new input filter to Kig is
+ * subclassing this class and implement supportMime() and load().
+ */
+class KigFilter
+{
+protected:
+ // shows errors to the user..
+ void fileNotFound( const QString& file ) const;
+ void parseError( const QString& file, const QString& explanation = QString::null ) const;
+ void notSupported( const QString& file, const QString& explanation ) const;
+ void warning( const QString& explanation ) const;
+public:
+ KigFilter();
+ virtual ~KigFilter();
+
+ /**
+ * can the filter handle the mimetype \p mime ?
+ */
+ virtual bool supportMime ( const QString& mime );
+
+ /**
+ * load file \p fromfile and build a KigDocument from it.. If this
+ * function returns 0, that means that an error occurred while
+ * loading ( implementations of this function are responsible for
+ * showing an error message themselves, using the above error
+ * functions ). If this functions returns non-0, the caller owns
+ * the returned KigDocument ( that was allocated with "new" ).
+ */
+ virtual KigDocument* load ( const QString& fromfile ) = 0;
+};
+#endif
diff --git a/kig/filters/filters-common.cc b/kig/filters/filters-common.cc
new file mode 100644
index 00000000..d25c2e14
--- /dev/null
+++ b/kig/filters/filters-common.cc
@@ -0,0 +1,39 @@
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "filters-common.h"
+
+#include <vector>
+
+#include <qcstring.h>
+#include <qstring.h>
+
+#include "../objects/object_calcer.h"
+#include "../objects/object_factory.h"
+
+ObjectTypeCalcer* filtersConstructTextObject(
+ const Coordinate& c, ObjectCalcer* o,
+ const QCString& arg, const KigDocument& doc, bool needframe )
+{
+ const ObjectFactory* fact = ObjectFactory::instance();
+ ObjectCalcer* propo = fact->propertyObjectCalcer( o, arg );
+ propo->calc( doc );
+ std::vector<ObjectCalcer*> args;
+ args.push_back( propo );
+ return fact->labelCalcer( QString::fromLatin1( "%1" ), c, needframe,
+ args, doc );
+}
diff --git a/kig/filters/filters-common.h b/kig/filters/filters-common.h
new file mode 100644
index 00000000..c46facc4
--- /dev/null
+++ b/kig/filters/filters-common.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+class ObjectTypeCalcer;
+class Coordinate;
+class ObjectCalcer;
+class QCString;
+class KigDocument;
+
+/**
+ * constructs a text object with text "%1", location \p c, and variable
+ * parts given by the argument \p arg of obj \p o.
+ */
+ObjectTypeCalcer* filtersConstructTextObject(
+ const Coordinate& c, ObjectCalcer* o,
+ const QCString& arg, const KigDocument& doc, bool needframe );
diff --git a/kig/filters/imageexporteroptions.cc b/kig/filters/imageexporteroptions.cc
new file mode 100644
index 00000000..cb996926
--- /dev/null
+++ b/kig/filters/imageexporteroptions.cc
@@ -0,0 +1,57 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "imageexporteroptions.h"
+#include "imageexporteroptions.moc"
+
+#include <qcheckbox.h>
+#include <qsize.h>
+
+#include <knuminput.h>
+
+ImageExporterOptions::ImageExporterOptions( QWidget* parent, const QSize& s )
+ : ImageExporterOptionsBase( parent, "imageexporteroptions" ), msize( s ),
+ minternallysettingstuff( false )
+{
+ keepAspectRatio->setChecked( true );
+ connect( WidthInput, SIGNAL( valueChanged( int ) ), this, SLOT( slotWidthChanged( int ) ) );
+ connect( HeightInput, SIGNAL( valueChanged( int ) ), this, SLOT( slotHeightChanged( int ) ) );
+}
+
+ImageExporterOptions::~ImageExporterOptions()
+{
+}
+
+void ImageExporterOptions::slotWidthChanged( int w )
+{
+ if ( ! minternallysettingstuff && keepAspectRatio->isOn() )
+ {
+ minternallysettingstuff = true;
+ HeightInput->setValue( w * msize.height() / msize.width() );
+ minternallysettingstuff = false;
+ };
+}
+
+void ImageExporterOptions::slotHeightChanged( int h )
+{
+ if ( ! minternallysettingstuff && keepAspectRatio->isOn() )
+ {
+ minternallysettingstuff = true;
+ WidthInput->setValue( h * msize.width() / msize.height() );
+ minternallysettingstuff = false;
+ };
+}
diff --git a/kig/filters/imageexporteroptions.h b/kig/filters/imageexporteroptions.h
new file mode 100644
index 00000000..1ef6a855
--- /dev/null
+++ b/kig/filters/imageexporteroptions.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_FILTERS_IMAGEEXPORTEROPTIONS_H
+#define KIG_FILTERS_IMAGEEXPORTEROPTIONS_H
+
+#include "imageexporteroptionsbase.h"
+
+class QSize;
+
+class ImageExporterOptions
+ : public ImageExporterOptionsBase
+{
+ Q_OBJECT
+
+ QSize msize;
+
+ // this is set by slotWidthChanged() when they set the other input
+ // widget's value, to avoid reacting to internal changes to the
+ // value like to user changes...
+ bool minternallysettingstuff;
+public:
+ ImageExporterOptions( QWidget* parent, const QSize& s );
+ ~ImageExporterOptions();
+
+protected slots:
+ void slotWidthChanged( int );
+ void slotHeightChanged( int );
+};
+
+#endif
diff --git a/kig/filters/imageexporteroptionsbase.ui b/kig/filters/imageexporteroptionsbase.ui
new file mode 100644
index 00000000..03145dec
--- /dev/null
+++ b/kig/filters/imageexporteroptionsbase.ui
@@ -0,0 +1,152 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>ImageExporterOptionsBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ImageExporterOptionsBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>250</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Resolution</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout2_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>WidthLabel_2</cstring>
+ </property>
+ <property name="text">
+ <string>Width:</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>WidthInput</cstring>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="suffix">
+ <string> pixels</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout3_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>HeightLabel_2</cstring>
+ </property>
+ <property name="text">
+ <string>Height:</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>HeightInput</cstring>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="suffix">
+ <string> pixels</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>keepAspectRatio</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Keep aspect ratio</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>showGridCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show grid</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>showAxesCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show axes</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/kig/filters/kgeo-filter.cc b/kig/filters/kgeo-filter.cc
new file mode 100644
index 00000000..da26457d
--- /dev/null
+++ b/kig/filters/kgeo-filter.cc
@@ -0,0 +1,374 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "kgeo-filter.h"
+
+#include "kgeo-resource.h"
+#include "filters-common.h"
+
+#include "../kig/kig_part.h"
+#include "../kig/kig_document.h"
+#include "../objects/angle_type.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/circle_imp.h"
+#include "../objects/circle_type.h"
+#include "../objects/intersection_types.h"
+#include "../objects/line_type.h"
+#include "../objects/object_calcer.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_factory.h"
+#include "../objects/object_holder.h"
+#include "../objects/other_type.h"
+#include "../objects/point_imp.h"
+#include "../objects/point_type.h"
+#include "../objects/text_type.h"
+#include "../objects/transform_types.h"
+#include "../objects/vector_type.h"
+
+#include <ksimpleconfig.h>
+
+#include <algorithm>
+#include <functional>
+
+bool KigFilterKGeo::supportMime( const QString& mime )
+{
+ return mime == "application/x-kgeo";
+}
+
+KigDocument* KigFilterKGeo::load( const QString& sFrom )
+{
+ // kgeo uses a KSimpleConfig to save its contents...
+ KSimpleConfig config ( sFrom );
+
+ loadMetrics ( &config );
+ return loadObjects ( sFrom, &config );
+}
+
+void KigFilterKGeo::loadMetrics(KSimpleConfig* c )
+{
+ c->setGroup("Main");
+ xMax = c->readNumEntry("XMax", 16);
+ yMax = c->readNumEntry("YMax", 11);
+ grid = c->readBoolEntry( "Grid", true );
+ axes = c->readBoolEntry( "Axes", true );
+ // the rest is not relevant to us (yet ?)...
+}
+
+struct KGeoHierarchyElement
+{
+ int id;
+ std::vector<int> parents;
+};
+
+static void visitElem( std::vector<KGeoHierarchyElement>& ret,
+ const std::vector<KGeoHierarchyElement>& elems,
+ std::vector<bool>& seen,
+ int i )
+{
+ if ( !seen[i] )
+ {
+ for ( uint j = 0; j < elems[i].parents.size(); ++j )
+ visitElem( ret, elems, seen, elems[i].parents[j] );
+ ret.push_back( elems[i] );
+ seen[i] = true;
+ };
+}
+
+static std::vector<KGeoHierarchyElement> sortElems( const std::vector<KGeoHierarchyElement> elems )
+{
+ std::vector<KGeoHierarchyElement> ret;
+ std::vector<bool> seenElems( elems.size(), false );
+ for ( uint i = 0; i < elems.size(); ++i )
+ visitElem( ret, elems, seenElems, i );
+ return ret;
+}
+
+KigDocument* KigFilterKGeo::loadObjects( const QString& file, KSimpleConfig* c )
+{
+ KigDocument* ret = new KigDocument();
+
+ using namespace std;
+
+ QString group;
+ bool ok = true;
+ c->setGroup("Main");
+ int number = c->readNumEntry ("Number");
+
+ // first we determine the parent relationships, and sort the
+ // elements in an order that we can be sure all of an object's
+ // parents will have been handled before it is handled itself..
+ // ( aka topological sort of the parent relations graph..
+ std::vector<KGeoHierarchyElement> elems;
+ elems.reserve( number );
+
+ for ( int i = 0; i < number; ++i )
+ {
+ KGeoHierarchyElement elem;
+ elem.id = i;
+ group.setNum( i + 1 );
+ group.prepend( "Object " );
+ c->setGroup( group );
+ QStrList parents;
+ c->readListEntry( "Parents", parents );
+ elems.push_back( elem );
+ for ( const char* parent = parents.first(); parent; parent = parents.next() )
+ {
+ int parentIndex = QString::fromLatin1( parent ).toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+ if ( parentIndex != 0 )
+ elems[i].parents.push_back( parentIndex - 1 );
+ };
+ };
+
+ std::vector<KGeoHierarchyElement> sortedElems = sortElems( elems );
+ std::vector<ObjectHolder*> os;
+ os.resize( number, 0 );
+ const ObjectFactory* factory = ObjectFactory::instance();
+
+ // now we iterate over the elems again in the newly determined
+ // order..
+ for ( uint i = 0; i < sortedElems.size(); ++i )
+ {
+ const KGeoHierarchyElement& e = sortedElems[i];
+ int id = e.id;
+ group.setNum( id + 1 );
+ group.prepend( "Object " );
+ c->setGroup( group );
+ int objID = c->readNumEntry( "Geo" );
+
+ std::vector<ObjectCalcer*> parents;
+ for ( uint j = 0; j < e.parents.size(); ++j )
+ {
+ int parentid = e.parents[j];
+ parents.push_back( os[parentid]->calcer() );
+ };
+
+ ObjectCalcer* o = 0;
+ switch (objID)
+ {
+ case ID_point:
+ {
+ // fetch the coordinates...
+ QString strX = c->readEntry("QPointX");
+ QString strY = c->readEntry("QPointY");
+ double x = strX.toDouble(&ok);
+ if (!ok) KIG_FILTER_PARSE_ERROR;
+ double y = strY.toDouble(&ok);
+ if (!ok) KIG_FILTER_PARSE_ERROR;
+ Coordinate m( x, y );
+ uint nparents = parents.size();
+ if ( nparents == 0 )
+ o = factory->fixedPointCalcer( m );
+ else if ( nparents == 1 )
+ o = factory->constrainedPointCalcer( parents[0], m, *ret );
+ else
+ KIG_FILTER_PARSE_ERROR;
+ break;
+ }
+ case ID_segment:
+ {
+ o = new ObjectTypeCalcer( SegmentABType::instance(), parents );
+ break;
+ }
+ case ID_circle:
+ {
+ o = new ObjectTypeCalcer( CircleBCPType::instance(), parents );
+ break;
+ }
+ case ID_line:
+ {
+ o = new ObjectTypeCalcer( LineABType::instance(), parents );
+ break;
+ }
+ case ID_bisection:
+ {
+ // if this is the bisection of two points, first build a segment
+ // between them..
+ if ( parents.size() == 2 )
+ {
+ ObjectTypeCalcer* seg = new ObjectTypeCalcer( SegmentABType::instance(), parents );
+ parents.clear();
+ parents.push_back( seg );
+ }
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ o = factory->propertyObjectCalcer( parents[0], "mid-point" );
+ break;
+ };
+ case ID_perpendicular:
+ {
+ o = new ObjectTypeCalcer( LinePerpendLPType::instance(), parents );
+ break;
+ }
+ case ID_parallel:
+ {
+ o = new ObjectTypeCalcer( LineParallelLPType::instance(), parents );
+ break;
+ }
+ case ID_vector:
+ {
+ o = new ObjectTypeCalcer( VectorType::instance(), parents );
+ break;
+ }
+ case ID_ray:
+ {
+ o = new ObjectTypeCalcer( RayABType::instance(), parents );
+ break;
+ }
+ case ID_move:
+ {
+ o = new ObjectTypeCalcer( TranslatedType::instance(), parents );
+ break;
+ }
+ case ID_mirrorPoint:
+ {
+ o = new ObjectTypeCalcer( PointReflectionType::instance(), parents );
+ break;
+ }
+ case ID_pointOfConc:
+ {
+ o = new ObjectTypeCalcer( LineLineIntersectionType::instance(), parents );
+ break;
+ }
+ case ID_text:
+ {
+ bool frame = c->readBoolEntry( "Frame" );
+ double x = c->readDoubleNumEntry( "TextRectCenterX" );
+ double y = c->readDoubleNumEntry( "TextRectCenterY" );
+ QString text = c->readEntry( "TextRectEntry" );
+ double height = c->readNumEntry( "TextRectHeight" );
+ double width = c->readNumEntry( "TextRectWidth" );
+ // we don't want the center, but the top left..
+ x -= width / 80;
+ y -= height / 80;
+ o = factory->labelCalcer(
+ text, Coordinate( x, y ), frame, std::vector<ObjectCalcer*>(), *ret );
+ break;
+ }
+ case ID_fixedCircle:
+ {
+ double r = c->readDoubleNumEntry( "Radius" );
+ parents.push_back( new ObjectConstCalcer( new DoubleImp( r ) ) );
+ o = new ObjectTypeCalcer( CircleBPRType::instance(), parents );
+ break;
+ }
+ case ID_angle:
+ {
+ if ( parents.size() == 3 )
+ {
+ ObjectTypeCalcer* ao = new ObjectTypeCalcer( AngleType::instance(), parents );
+ ao->calc( *ret );
+ parents.clear();
+ parents.push_back( ao );
+ };
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* angle = parents[0];
+ parents.clear();
+ const Coordinate c =
+ static_cast<const PointImp*>( angle->parents()[1]->imp() )->coordinate();
+ o = filtersConstructTextObject( c, angle, "angle-degrees", *ret, true );
+ break;
+ }
+ case ID_distance:
+ {
+ if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+ ObjectTypeCalcer* segment = new ObjectTypeCalcer( SegmentABType::instance(), parents );
+ segment->calc( *ret );
+ Coordinate m = ( static_cast<const PointImp*>( parents[0]->imp() )->coordinate() +
+ static_cast<const PointImp*>( parents[1]->imp() )->coordinate() ) / 2;
+ o = filtersConstructTextObject( m, segment, "length", *ret, true );
+ break;
+ }
+ case ID_arc:
+ {
+ o = new ObjectTypeCalcer( AngleType::instance(), parents );
+ break;
+ }
+ case ID_area:
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ const CircleImp* circle = static_cast<const CircleImp*>( parents[0]->imp() );
+ const Coordinate c = circle->center() + Coordinate( circle->radius(), 0 );
+ o = filtersConstructTextObject( c, parents[0], "surface", *ret, true );
+ break;
+ }
+ case ID_slope:
+ {
+ // if parents contains a segment, line, vector or whatever, we
+ // take its parents cause we want points..
+ if ( parents.size() == 1 ) parents = parents[0]->parents();
+ if ( parents.size() != 2 ) KIG_FILTER_PARSE_ERROR;
+ const Coordinate c = (
+ static_cast<const PointImp*>( parents[0]->imp() )->coordinate() +
+ static_cast<const PointImp*>( parents[1]->imp() )->coordinate() ) / 2;
+ ObjectTypeCalcer* line = new ObjectTypeCalcer( LineABType::instance(), parents );
+ line->calc( *ret );
+ o = filtersConstructTextObject( c, line, "slope", *ret, true );
+ break;
+ }
+ case ID_circumference:
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ const CircleImp* c = static_cast<const CircleImp*>( parents[0]->imp() );
+ const Coordinate m = c->center() + Coordinate( c->radius(), 0 );
+ o = filtersConstructTextObject( m, parents[0], "circumference", *ret, true );
+ break;
+ }
+ case ID_rotation:
+ {
+ // in kig, the rotated object should be last..
+ ObjectCalcer* t = parents[2];
+ parents[2] = parents[0];
+ parents[0] = t;
+ o = new ObjectTypeCalcer( RotationType::instance(), parents );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ };
+
+ // set the color...
+ QColor co = c->readColorEntry( "Color" );
+ if( !co.isValid() )
+ co = Qt::blue;
+ ObjectDrawer* d = new ObjectDrawer( co );
+
+ os[i] = new ObjectHolder( o, d );
+ os[i]->calc( *ret );
+ }; // for loop (creating KGeoHierarchyElements..
+
+ ret->addObjects( os );
+ ret->setGrid( grid );
+ ret->setAxes( axes );
+ return ret;
+}
+
+KigFilterKGeo::KigFilterKGeo()
+{
+}
+
+KigFilterKGeo::~KigFilterKGeo()
+{
+}
+
+KigFilterKGeo* KigFilterKGeo::instance()
+{
+ static KigFilterKGeo f;
+ return &f;
+}
diff --git a/kig/filters/kgeo-filter.h b/kig/filters/kgeo-filter.h
new file mode 100644
index 00000000..1a2ff83d
--- /dev/null
+++ b/kig/filters/kgeo-filter.h
@@ -0,0 +1,55 @@
+// This file is part of Kig, a KDE program for Interactive Geometry...
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_FILTERS_KGEO_FILTER_H
+#define KIG_FILTERS_KGEO_FILTER_H
+
+#include "filter.h"
+
+class KSimpleConfig;
+
+/**
+ * This is an import filter for files generated by the program KGeo,
+ * which was an interactive geometry program in kdeedu. Kig is
+ * supposed to be its successor, and this import filter is part of my
+ * attempt to achieve that :)
+ *
+ * Status: a significant part of KGeo's format is supported, not all
+ * yet, though..
+ */
+class KigFilterKGeo
+ : public KigFilter
+{
+public:
+ static KigFilterKGeo* instance();
+ bool supportMime ( const QString& mime );
+ KigDocument* load ( const QString& from );
+protected:
+ KigFilterKGeo();
+ ~KigFilterKGeo();
+
+ void loadMetrics ( KSimpleConfig* );
+ KigDocument* loadObjects ( const QString& file, KSimpleConfig* );
+
+ int xMax;
+ int yMax;
+ bool grid;
+ bool axes;
+};
+
+#endif
diff --git a/kig/filters/kgeo-resource.h b/kig/filters/kgeo-resource.h
new file mode 100644
index 00000000..2a272ed0
--- /dev/null
+++ b/kig/filters/kgeo-resource.h
@@ -0,0 +1,204 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+
+/// note: this code comes from KGeo by Marc Bartsch..
+
+
+/***************************************************************************
+ resource.h - description
+ -------------------
+ begin : Die Okt 3 09:00:59 CEST 2000
+ copyright : (C) 2000 by Marc Bartsch
+ email : marc.bartsch@topmail.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef RESOURCE_H
+#define RESOURCE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <iostream>
+#include <qstring.h>
+#include <klocale.h>
+
+///////////////////////////////////////////////////////////////////
+// resource.h -- contains macros used for commands
+
+
+///////////////////////////////////////////////////////////////////
+// COMMAND VALUES FOR MENUBAR AND TOOLBAR ENTRIES
+
+
+///////////////////////////////////////////////////////////////////
+// File-menu entries
+#define ID_FILE_NEW_WINDOW 10010
+#define ID_FILE_NEW 10020
+#define ID_FILE_OPEN 10030
+#define ID_FILE_OPEN_RECENT 10040
+#define ID_FILE_CLOSE 10050
+
+#define ID_FILE_SAVE 10060
+#define ID_FILE_SAVE_AS 10070
+
+#define ID_FILE_PRINT 10080
+
+#define ID_FILE_QUIT 10090
+
+///////////////////////////////////////////////////////////////////
+// Edit-menu entries
+#define ID_EDIT_COPY 11010
+#define ID_EDIT_CUT 11020
+#define ID_EDIT_PASTE 11030
+// domi: disabled, breaks --enable-final, and is not used anyway.
+//#define ID_EDIT_PREFERENCES 11040
+#define ID_EDIT_FULLSCREEN 11050
+
+///////////////////////////////////////////////////////////////////
+// View-menu entries
+#define ID_VIEW_TOOLBAR 12010
+#define ID_VIEW_STATUSBAR 12020
+#define ID_VIEW_FULLSCREEN 12030
+
+///////////////////////////////////////////////////////////////////
+// Help-menu entries
+#define ID_HELP_CONTENTS 1002
+
+///////////////////////////////////////////////////////////////////
+// General application values
+#define ID_STATUS_MSG 1001
+
+#define IDS_STATUS_DEFAULT "Ready."
+
+#define ID_infinite -1
+
+#define ID_point 1
+#define ID_pointxy 14
+#define ID_pointOnLine 15
+#define ID_pointOfConc 7
+#define ID_bisection 5
+#define ID_mirrorPoint 9
+
+#define ID_segment 2
+#define ID_circle 3
+#define ID_line 4
+#define ID_fixedCircle 6
+#define ID_arc 8
+#define ID_eraser 10
+#define ID_attacher 11
+#define ID_tracer 12
+#define ID_triangle 13
+#define ID_colorizer 16
+#define ID_thicker 17
+#define ID_geoPoint 18
+#define ID_geoTool 19
+#define ID_geoObject 20
+#define ID_geoMeasure 21
+#define ID_distance 22
+#define ID_angle 23
+#define ID_area 24
+#define ID_slope 25
+#define ID_circumference 26
+#define ID_vector 27
+#define ID_geoLine 28
+#define ID_ray 29
+#define ID_parallel 30
+#define ID_perpendicular 31
+#define ID_move 32
+#define ID_rotation 33
+#define ID_text 34
+
+#define ID_buttonFileNew 100
+#define ID_buttonKiosk 101
+
+#define ID_buttonPoint 110
+#define ID_buttonPointxy 111
+#define ID_buttonPointOnLine 112
+#define ID_buttonPointOfConc 113
+#define ID_buttonBisection 114
+#define ID_buttonMirrorPoint 115
+#define ID_buttonMove 116
+#define ID_buttonRotation 117
+
+#define ID_buttonSegment 120
+#define ID_buttonLine 121
+#define ID_buttonVector 122
+#define ID_buttonRay 123
+#define ID_buttonParallel 124
+#define ID_buttonPerpendicular 125
+#define ID_buttonTriangle 126
+
+#define ID_buttonBaseCircle 130
+#define ID_buttonCircle 131
+#define ID_buttonArc 132
+
+#define ID_buttonDistance 140
+#define ID_buttonAngle 141
+#define ID_buttonArea 142
+#define ID_buttonSlope 143
+#define ID_buttonCircumference 144
+
+#define ID_buttonBlack 150
+#define ID_buttonDarkGray 151
+#define ID_buttonLightGray 152
+#define ID_buttonWhite 153
+#define ID_buttonBlue 154
+#define ID_buttonRed 155
+#define ID_buttonGreen 156
+
+#define ID_buttonThinLine 160
+#define ID_buttonMiddleLine 161
+#define ID_buttonThickLine 162
+
+#define ID_buttonEraser 170
+#define ID_buttonAttacher 171
+#define ID_buttonTracer 172
+#define ID_buttonText 173
+#define ID_buttonMoveGrid 174
+#define ID_buttonPointer 175
+#define ID_buttonDrawColor 176
+#define ID_buttonSizer 177
+
+#define ID_drawingModeNoMode 0
+#define ID_drawingModeMovingGrid 1
+#define ID_drawingModeMovingObjects 2
+#define ID_drawingModeConstructing 3
+
+#define MinimumPointSize 3
+
+#define Str_AppName "KGeo"
+
+
+#define ID_overlayRectSize 24
+
+#define PI 3.1415926535
+
+#endif // RESOURCE_H
diff --git a/kig/filters/kseg-defs.h b/kig/filters/kseg-defs.h
new file mode 100644
index 00000000..ad90fa1a
--- /dev/null
+++ b/kig/filters/kseg-defs.h
@@ -0,0 +1,301 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// this is a collection of definitions we need from KSeg. It includes
+// code from defs.H and G_drawstyle.H. Thanks to Ilya Baran for
+// making KSeg GPL, so there are no license probs or whatever..
+
+/*
+ * KSeg
+ * Copyright (C) 1999-2003 Ilya Baran
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA.
+ *
+ * Send comments and/or bug reports to:
+ * ibaran@mit.edu
+ */
+
+
+#ifndef DEFS_H
+#define DEFS_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <qglobal.h>
+
+using namespace std;
+
+#define DRAW_MAX 5000 // maximum coordinate. assumes you have a screen resolution less than this.
+
+#define BIG (1e+37)
+#define SMALL (1e-10)
+
+inline int ROUND(double x) { return ((int)(x + 0.5)); }
+inline int SIGN(double x) { return (x < 0) ? -1 : 1; }
+inline int INTRAND(int a, int b) { return QMIN(a, b) + rand() % abs(a - b); }
+#define SQR(x) ((x) * (x))
+#define CUBE(x) ((x) * (x) * (x))
+#define QUAD(x) (((x) * (x)) * ((x) * (x)))
+
+enum G_Type
+{
+ G_POINT = 1,
+ G_SEGMENT = 2,
+ G_RAY = 4,
+ G_LINE = 8,
+ G_CIRCLE = 16,
+ G_ARC = 32,
+ G_POLYGON = 64,
+ G_CIRCLEINTERIOR = 128,
+ G_ARCSECTOR = 256,
+ G_ARCSEGMENT = 512,
+ //non-primitive geometric types now:
+ G_LOCUS = 1024,
+ G_MEASURE = 2048,
+ G_CALCULATE = 4096,
+ G_ANNOTATION = 8192,
+ //fake type for scripting:
+ G_LOOP = 16384,
+ //compound types now:
+ G_STRAIGHT = G_SEGMENT | G_LINE | G_RAY,
+ G_CURVE = G_STRAIGHT | G_ARC | G_CIRCLE,
+ G_FILLED = G_POLYGON | G_CIRCLEINTERIOR | G_ARCSECTOR | G_ARCSEGMENT,
+ G_GEOMETRIC = G_POINT | G_CURVE | G_FILLED | G_LOCUS,
+ G_VALUE = G_MEASURE | G_CALCULATE,
+ G_TEXT = G_VALUE | G_ANNOTATION,
+ G_ANY = G_GEOMETRIC | G_TEXT | G_LOOP
+};
+
+enum G_AnyType
+{
+ G_TRANSLATED,
+ G_ROTATED,
+ G_SCALED,
+ G_REFLECTED
+};
+
+#define IS_TRANSFORM(x) ((x) == G_TRANSLATED || (x) == G_ROTATED || (x) == G_SCALED || (x) == G_REFLECTED)
+
+enum G_PointType
+{
+ G_FREE_POINT = G_REFLECTED + 1,
+ G_CONSTRAINED_POINT,
+ G_INTERSECTION_POINT,
+ G_INTERSECTION2_POINT,
+ G_MID_POINT
+};
+
+enum G_SegmentType
+{
+ G_ENDPOINTS_SEGMENT = G_REFLECTED + 1
+};
+
+enum G_RayType
+{
+ G_TWOPOINTS_RAY = G_REFLECTED + 1,
+ G_BISECTOR_RAY
+};
+
+enum G_LineType
+{
+ G_TWOPOINTS_LINE = G_REFLECTED + 1,
+ G_PARALLEL_LINE,
+ G_PERPENDICULAR_LINE
+};
+
+enum G_CircleType
+{
+ G_CENTERPOINT_CIRCLE = G_REFLECTED + 1,
+ G_CENTERRADIUS_CIRCLE
+};
+
+enum G_ArcType
+{
+ G_THREEPOINTS_ARC = G_REFLECTED + 1
+};
+
+enum G_FilledType
+{
+ G_DEFAULT_FILLED = G_REFLECTED + 1
+};
+
+enum G_LocusType
+{
+ G_OBJECT_LOCUS = G_REFLECTED + 1
+};
+
+enum G_MeasureType
+{
+ G_DISTANCE_MEASURE,
+ G_LENGTH_MEASURE,
+ G_RADIUS_MEASURE,
+ G_ANGLE_MEASURE,
+ G_RATIO_MEASURE,
+ G_SLOPE_MEASURE,
+ G_AREA_MEASURE
+};
+
+enum G_CalculateType
+{
+ G_REGULAR_CALCULATE
+};
+
+
+enum MenuIDs
+{
+ ID_NEW_SEGMENT = 1,
+ ID_NEW_MIDPOINT,
+ ID_NEW_LINE,
+ ID_NEW_PERPENDICULAR,
+ ID_NEW_RAY,
+ ID_NEW_BISECTOR,
+ ID_NEW_CIRCLE,
+ ID_NEW_INTERSECTION,
+ ID_NEW_ARC,
+ ID_NEW_LOCUS,
+ ID_NEW_ARCSECTOR,
+ ID_NEW_ARCSEGMENT,
+ ID_NEW_CIRCLEINTERIOR,
+ ID_NEW_POLYGON,
+
+ ID_EDIT_UNDO,
+ ID_EDIT_REDO,
+ ID_EDIT_DELETE,
+ ID_EDIT_TOGGLELABELS,
+ ID_EDIT_SHOWLABELS,
+ ID_EDIT_HIDELABELS,
+ ID_EDIT_CHANGELABEL,
+ ID_EDIT_HIDE,
+ ID_EDIT_SHOWHIDDEN,
+ ID_EDIT_COLOR,
+ ID_EDIT_POINTSTYLE,
+ ID_EDIT_LINESTYLE,
+ ID_EDIT_FONT,
+ ID_EDIT_CHANGE_NUMBER_OF_SAMPLES,
+ ID_EDIT_PREFERENCES,
+
+ ID_EDIT_COLOR_BLACK,
+ ID_EDIT_COLOR_GRAY,
+ ID_EDIT_COLOR_RED,
+ ID_EDIT_COLOR_GREEN,
+ ID_EDIT_COLOR_BLUE,
+ ID_EDIT_COLOR_YELLOW,
+ ID_EDIT_COLOR_PURPLE,
+ ID_EDIT_COLOR_CYAN,
+ ID_EDIT_COLOR_OTHER,
+
+ ID_EDIT_POINTSTYLE_LARGECIRCLE,
+ ID_EDIT_POINTSTYLE_MEDIUMCIRCLE,
+ ID_EDIT_POINTSTYLE_SMALLCIRCLE,
+
+ ID_EDIT_LINESTYLE_SOLID,
+ ID_EDIT_LINESTYLE_DASHED,
+ ID_EDIT_LINESTYLE_DOTTED,
+ ID_EDIT_LINESTYLE_THIN,
+ ID_EDIT_LINESTYLE_NORMAL,
+ ID_EDIT_LINESTYLE_THICK,
+
+ ID_EDIT_FONT_10,
+ ID_EDIT_FONT_12,
+ ID_EDIT_FONT_14,
+ ID_EDIT_FONT_20,
+ ID_EDIT_FONT_30,
+ ID_EDIT_FONT_FONT,
+
+ ID_MEASURE_DISTANCE,
+ ID_MEASURE_LENGTH,
+ ID_MEASURE_RADIUS,
+ ID_MEASURE_ANGLE,
+ ID_MEASURE_RATIO,
+ ID_MEASURE_SLOPE,
+ ID_MEASURE_AREA,
+ ID_MEASURE_CALCULATE,
+
+ ID_TRANSFORM_CHOOSE_VECTOR,
+ ID_TRANSFORM_CHOOSE_MIRROR,
+ ID_TRANSFORM_CHOOSE_CENTER,
+ ID_TRANSFORM_CHOOSE_RATIO,
+ ID_TRANSFORM_CHOOSE_ANGLE,
+ ID_TRANSFORM_CLEAR_CHOSEN,
+ ID_TRANSFORM_TRANSLATE,
+ ID_TRANSFORM_ROTATE,
+ ID_TRANSFORM_REFLECT,
+ ID_TRANSFORM_SCALE,
+
+ ID_CONSTRUCTION_MAKE_NORMAL,
+ ID_CONSTRUCTION_MAKE_GIVEN,
+ ID_CONSTRUCTION_MAKE_FINAL,
+ ID_CONSTRUCTION_MAKE_INITIAL,
+ ID_CONSTRUCTION_RECURSE,
+
+ ID_PLAY_QUICKPLAY,
+
+ ID_QUICKPLAY_SET_DIRECTORY,
+
+ ID_FILE_RECENTLIST_START //should be the last entry
+};
+
+#endif //DEFS_H
+
+
+/*
+ * KSeg
+ * Copyright (C) 1999-2003 Ilya Baran
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA.
+ *
+ * Send comments and/or bug reports to:
+ * ibaran@mit.edu
+ */
+
+
+#ifndef G_DRAWSTYLE_H
+#define G_DRAWSTYLE_H
+
+enum PointStyle
+{
+ ANY = 0,
+ SMALL_CIRCLE,
+ MEDIUM_CIRCLE,
+ LARGE_CIRCLE
+};
+
+#endif //G_DRAWSTYLE_H
diff --git a/kig/filters/kseg-filter-status.txt b/kig/filters/kseg-filter-status.txt
new file mode 100644
index 00000000..eb896726
--- /dev/null
+++ b/kig/filters/kseg-filter-status.txt
@@ -0,0 +1,41 @@
+KSeg filter status
+==================
+
+Objects imported
+----------------
+
+Points ok
+Rays ok
+Vectors ok
+Lines ok
+Circles ok
+Angles ok
+Arcs ok
+Locuses some
+Transformations most
+Intersections most
+Polygons ok
+Labels ok
+
+Colors ok
+Visibility ok
+Styles ok
+Grid ok
+
+Objects not imported
+--------------------
+
+Transformations scaling (with ratio as formula) (*)
+Intersections arc-circle(*)
+Filled circles (*)
+Arc sectors (*)
+Arc segments (*)
+Formulas (*)
+
+(*) objects which currently are not implemented in Kig
+
+Known problems
+--------------
+
+* Some locuses may crash the filter.
+* Label text should be correctly encoded.
diff --git a/kig/filters/kseg-filter.cc b/kig/filters/kseg-filter.cc
new file mode 100644
index 00000000..f2ba901b
--- /dev/null
+++ b/kig/filters/kseg-filter.cc
@@ -0,0 +1,679 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "kseg-filter.h"
+
+#include "kseg-defs.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../misc/coordinate.h"
+#include "../objects/angle_type.h"
+#include "../objects/arc_type.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/circle_type.h"
+#include "../objects/conic_imp.h"
+#include "../objects/conic_types.h"
+#include "../objects/intersection_types.h"
+#include "../objects/line_imp.h"
+#include "../objects/line_type.h"
+#include "../objects/object_calcer.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_factory.h"
+#include "../objects/object_holder.h"
+#include "../objects/other_imp.h"
+#include "../objects/other_type.h"
+#include "../objects/point_imp.h"
+#include "../objects/point_type.h"
+#include "../objects/polygon_type.h"
+#include "../objects/transform_types.h"
+#include "../objects/vector_type.h"
+
+#include <qfont.h>
+#include <qpen.h>
+#include <qbrush.h>
+#include <qfile.h>
+#include <qdatastream.h>
+#include <qbuffer.h>
+
+#include <klocale.h>
+
+KigFilterKSeg::KigFilterKSeg()
+{
+}
+
+KigFilterKSeg::~KigFilterKSeg()
+{
+}
+
+bool KigFilterKSeg::supportMime( const QString& mime )
+{
+ return mime == "application/x-kseg";
+}
+
+struct drawstyle
+{
+ Q_INT8 pointstyle;
+ QFont font;
+ QPen pen;
+ QBrush brush;
+};
+
+static Coordinate readKSegCoordinate( QDataStream& stream )
+{
+ // read the coord..
+ float inx, iny;
+ stream >> inx >> iny;
+ // KSeg uses a coordinate system, where the topleft is (0,0), and
+ // the bottom right is the widget coordinate in the window: if the
+ // KSeg window had a width of 600 pixels and a height of 600, then
+ // the bottom right will be at (600,600). We assume a window of
+ // such a height here, and transform it into Kig Coordinates. This
+ // function is quite similar to ScreenInfo::fromScreen, and it's
+ // basically a simple modification of that code to floats..
+
+ // invert the y-axis: 0 is at the bottom !
+ Coordinate t( inx, 600 - iny );
+ t *= 14;
+ t /= 600;
+ return t + Coordinate( -7, -7 );
+}
+
+static ObjectTypeCalcer* intersectionPoint( const std::vector<ObjectCalcer*>& parents, int which )
+{
+ if ( parents.size() != 2 ) return 0;
+ int nlines = 0;
+ int nconics = 0;
+ int narcs = 0;
+ for ( int i = 0; i < 2; ++i )
+ {
+ if ( parents[i]->imp()->inherits( AbstractLineImp::stype() ) ) ++nlines;
+ else if ( parents[i]->imp()->inherits( ConicImp::stype() ) ) ++nconics;
+ else if ( parents[i]->imp()->inherits( ArcImp::stype() ) ) ++narcs;
+ else return 0;
+ };
+ if ( nlines == 2 )
+ return which == -1 ? new ObjectTypeCalcer( LineLineIntersectionType::instance(), parents ) : 0;
+ else if ( nlines == 1 && nconics == 1 )
+ {
+ std::vector<ObjectCalcer*> intparents( parents );
+ intparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) );
+ return new ObjectTypeCalcer( ConicLineIntersectionType::instance(), intparents );
+ }
+ else if ( nlines == 0 && nconics == 2 )
+ {
+ std::vector<ObjectCalcer*> rparents( parents );
+ rparents.push_back( new ObjectConstCalcer( new IntImp( 1 ) ) );
+ rparents.push_back( new ObjectConstCalcer( new IntImp( 1 ) ) );
+ rparents.push_back( new ObjectTypeCalcer( ConicRadicalType::instance(), rparents ) );
+ std::vector<ObjectCalcer*> iparents;
+ iparents.push_back( parents[0] );
+ iparents.push_back( rparents.back() );
+ iparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) );
+ return new ObjectTypeCalcer( ConicLineIntersectionType::instance(), iparents );
+ }
+ else if ( nlines == 1 && narcs == 1 )
+ {
+ std::vector<ObjectCalcer*> intparents( parents );
+ intparents.push_back( new ObjectConstCalcer( new IntImp( which ) ) );
+ return new ObjectTypeCalcer( ArcLineIntersectionType::instance(), intparents );
+ }
+ else return 0;
+}
+
+ObjectCalcer* KigFilterKSeg::transformObject( const QString& file, KigDocument& kigdoc,
+ std::vector<ObjectCalcer*>& parents,
+ int subtype, bool& ok )
+{
+ ok = true;
+ ObjectCalcer* retobj = 0;
+ switch( subtype )
+ {
+ case G_TRANSLATED:
+ {
+ std::vector<ObjectCalcer*> vectorparents( parents.begin() + 1, parents.end() );
+ ObjectTypeCalcer* vector = new ObjectTypeCalcer( VectorType::instance(), vectorparents );
+ vector->calc( kigdoc );
+
+ std::vector<ObjectCalcer*> transparents;
+ transparents.push_back( parents[0] );
+ transparents.push_back( vector );
+ retobj = new ObjectTypeCalcer( TranslatedType::instance(), transparents );
+ break;
+ }
+ case G_ROTATED:
+ {
+ std::vector<ObjectCalcer*> angleparents( parents.begin() + 2, parents.end() );
+ ObjectTypeCalcer* angle = new ObjectTypeCalcer( AngleType::instance(), angleparents );
+ angle->calc( kigdoc );
+
+ std::vector<ObjectCalcer*> rotparents;
+ rotparents.push_back( parents[0] );
+ rotparents.push_back( parents[1] );
+ rotparents.push_back( angle );
+ retobj = new ObjectTypeCalcer( RotationType::instance(), rotparents );
+ break;
+ }
+ case G_SCALED:
+ {
+ if ( parents.size() == 4 )
+ {
+ retobj = new ObjectTypeCalcer( ScalingOverCenter2Type::instance(), parents );
+ }
+ else
+ {
+ // TODO
+ notSupported( file, i18n( "This KSeg document uses a scaling "
+ "transformation, which Kig currently "
+ "cannot import." ) );
+ ok = false;
+ return 0;
+ }
+ break;
+ }
+ case G_REFLECTED:
+ {
+ std::vector<ObjectCalcer*> mirparents( parents.begin(), parents.end() );
+ retobj = new ObjectTypeCalcer( LineReflectionType::instance(), mirparents );
+ break;
+ }
+ }
+
+ return retobj;
+}
+
+KigDocument* KigFilterKSeg::load( const QString& file )
+{
+ QFile ffile( file );
+ if ( ! ffile.open( IO_ReadOnly ) )
+ {
+ fileNotFound( file );
+ return false;
+ };
+
+ KigDocument* retdoc = new KigDocument();
+
+ QDataStream fstream( &ffile );
+
+ QString versionstring;
+ fstream >> versionstring;
+ if ( !versionstring.startsWith( "KSeg Document Version " ) )
+ KIG_FILTER_PARSE_ERROR;
+
+ QByteArray array;
+ fstream >> array;
+ QBuffer buf( array );
+ buf.open( IO_ReadOnly );
+ QDataStream stream( &buf );
+
+ stream.setVersion( 3 );
+
+ // G_drawstyles:
+ short numstyles;
+ stream >> numstyles;
+ std::vector<drawstyle> drawstyles( numstyles );
+ for ( short i = 0; i < numstyles; ++i )
+ {
+ stream >> drawstyles[i].pointstyle;
+ stream >> drawstyles[i].font;
+ stream >> drawstyles[i].pen;
+ stream >> drawstyles[i].brush;
+ };
+
+ std::vector<ObjectHolder*> ret;
+ std::vector<ObjectHolder*> ret2;
+
+ // G_refs
+ unsigned int count;
+ stream >> count;
+
+ ret.resize( count, 0 );
+ const ObjectFactory* fact = ObjectFactory::instance();
+
+ // KSeg topologically sorts the objects before saving, that means we
+ // can read the entire file in one iteration..
+ for ( uint i = 0; i < count; ++i )
+ {
+ short styleid;
+ stream >> styleid;
+ short nparents;
+ stream >> nparents;
+ std::vector<ObjectCalcer*> parents( nparents, 0 );
+ for ( short j = 0; j < nparents; ++j )
+ {
+ int parent;
+ stream >> parent;
+ parents[j] = ret[parent]->calcer();
+ };
+
+ // read the object..
+ short info;
+ stream >> info;
+ int type = 1 << (info & 31);
+ info >>= 5;
+ int descendtype = (info & 15);
+ info >>= 4;
+ bool visible = info & 1;
+ bool labelVisible = info & 2;
+ bool given = info & 4;
+ bool final = info & 8;
+
+ // avoid g++ warnings about unused vars..
+ // this doesn't really do anything..
+ (void) given;
+ (void) final;
+
+ drawstyle style = drawstyles[styleid];
+
+ if ( type == G_LOOP ) continue;
+ // read the label..
+ QString labeltext;
+ stream >> labeltext;
+ Coordinate relcoord = readKSegCoordinate( stream );
+ // shut up gcc
+ (void) relcoord;
+ if ( type & G_CURVE )
+ {
+ Coordinate relcurvecoord = readKSegCoordinate( stream );
+ // shut up gcc
+ (void) relcurvecoord;
+ };
+
+ // now load the object data..
+ ObjectHolder* object = 0;
+ ObjectCalcer* o = 0;
+ bool ok = true;
+
+ QColor color = style.pen.color();
+ int width = style.pen.width();
+
+/*
+ kdDebug() << "type: " << type << endl
+ << "descendtype: " << descendtype << endl
+ << "label: " << labeltext << endl;
+//*/
+
+ switch ( type )
+ {
+ case G_POINT:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_FREE_POINT:
+ {
+ // fixed point
+ if ( nparents != 0 ) KIG_FILTER_PARSE_ERROR;
+ Coordinate c = readKSegCoordinate( stream );
+ o = fact->fixedPointCalcer( c );
+ break;
+ }
+ case G_CONSTRAINED_POINT:
+ {
+ // constrained point
+ double p;
+ stream >> p;
+ if ( nparents != 1 ) KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* parent = parents[0];
+ assert( parent );
+ o = fact->constrainedPointCalcer( parent, p );
+ break;
+ }
+ case G_INTERSECTION_POINT:
+ {
+ // KSeg has somewhat weird intersection objects..
+ // for all objects G_INTERSECTION_POINT gets the
+ // first intersection of its parents, G_INTERSECTION2_POINT
+ // represents the second, if present.
+ o = intersectionPoint( parents, -1 );
+ if ( ! o ) KIG_FILTER_PARSE_ERROR;
+ break;
+ }
+ case G_INTERSECTION2_POINT:
+ {
+ o = intersectionPoint( parents, 1 );
+ if ( ! o ) KIG_FILTER_PARSE_ERROR;
+ break;
+ }
+ case G_MID_POINT:
+ {
+ // midpoint of a segment..
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ if ( !parents[0]->imp()->inherits( SegmentImp::stype() ) )
+ KIG_FILTER_PARSE_ERROR;
+ int index = parents[0]->imp()->propertiesInternalNames().findIndex( "mid-point" );
+ assert( index != -1 );
+ o = new ObjectPropertyCalcer( parents[0], index );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ };
+ width = style.pointstyle == SMALL_CIRCLE ? 2 : style.pointstyle == MEDIUM_CIRCLE ? 3 : 5;
+ color = style.brush.color();
+ break;
+ };
+ case G_SEGMENT:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_ENDPOINTS_SEGMENT:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( SegmentABType::instance(), parents );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ }
+ break;
+ };
+ case G_RAY:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_TWOPOINTS_RAY:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( RayABType::instance(), parents );
+ break;
+ }
+ case G_BISECTOR_RAY:
+ {
+ ObjectTypeCalcer* angle = new ObjectTypeCalcer( HalfAngleType::instance(), parents );
+ angle->calc( *retdoc );
+ o = fact->propertyObjectCalcer( angle, "angle-bisector" );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ };
+ break;
+ };
+ case G_LINE:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_TWOPOINTS_LINE:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( LineABType::instance(), parents );
+ break;
+ }
+ case G_PARALLEL_LINE:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( LineParallelLPType::instance(), parents );
+ break;
+ }
+ case G_PERPENDICULAR_LINE:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( LinePerpendLPType::instance(), parents );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ };
+ break;
+ };
+ case G_CIRCLE:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_CENTERPOINT_CIRCLE:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( CircleBCPType::instance(), parents );
+ break;
+ }
+ case G_CENTERRADIUS_CIRCLE:
+ {
+ ObjectCalcer* point;
+ ObjectCalcer* segment;
+ if ( parents[0]->imp()->inherits( PointImp::stype() ) )
+ {
+ point = parents[0];
+ segment = parents[1];
+ }
+ else
+ {
+ point = parents[1];
+ segment = parents[0];
+ };
+ int index = segment->imp()->propertiesInternalNames().findIndex( "length" );
+ if ( index == -1 ) KIG_FILTER_PARSE_ERROR;
+ ObjectPropertyCalcer* length = new ObjectPropertyCalcer( segment, index );
+ length->calc( *retdoc );
+ std::vector<ObjectCalcer*> cparents;
+ cparents.push_back( point );
+ cparents.push_back( length );
+ o = new ObjectTypeCalcer( CircleBPRType::instance(), cparents );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ };
+ break;
+ };
+ case G_ARC:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_THREEPOINTS_ARC:
+ {
+ if ( nparents != 3 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( ArcBTPType::instance(), parents );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ }
+ break;
+ };
+ case G_POLYGON:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ default:
+ {
+ if ( nparents < 3 ) KIG_FILTER_PARSE_ERROR;
+ o = new ObjectTypeCalcer( PolygonBNPType::instance(), parents );
+ }
+ }
+// default:
+// KIG_FILTER_PARSE_ERROR;
+ break;
+ };
+ case G_CIRCLEINTERIOR:
+ {
+ notSupported( file, i18n( "This KSeg file contains a filled circle, "
+ "which Kig does not currently support." ) );
+ return false;
+ };
+ case G_ARCSECTOR:
+ {
+ notSupported( file, i18n( "This KSeg file contains an arc sector, "
+ "which Kig does not currently support." ) );
+ return false;
+ };
+ case G_ARCSEGMENT:
+ {
+ notSupported( file, i18n( "This KSeg file contains an arc segment, "
+ "which Kig does not currently support." ) );
+ return false;
+ };
+ case G_LOCUS:
+ {
+ switch( descendtype )
+ {
+ case G_TRANSLATED:
+ case G_ROTATED:
+ case G_SCALED:
+ case G_REFLECTED:
+ {
+ o = transformObject( file, *retdoc, parents, descendtype, ok );
+ break;
+ }
+ case G_OBJECT_LOCUS:
+ {
+ if ( nparents != 2 ) KIG_FILTER_PARSE_ERROR;
+ o = fact->locusCalcer( parents[0], parents[1] );
+ break;
+ }
+ default:
+ KIG_FILTER_PARSE_ERROR;
+ }
+ break;
+ };
+ case G_MEASURE:
+ KIG_FILTER_PARSE_ERROR;
+ case G_CALCULATE:
+ KIG_FILTER_PARSE_ERROR;
+ case G_ANNOTATION:
+ KIG_FILTER_PARSE_ERROR;
+ case G_LOOP:
+ KIG_FILTER_PARSE_ERROR;
+ default:
+ KIG_FILTER_PARSE_ERROR;
+
+ }
+
+ // checking if the object was correctly created
+ if ( ! o )
+ {
+ if ( ok )
+ KIG_FILTER_PARSE_ERROR
+ else
+ return 0;
+ }
+
+ ObjectDrawer* d = new ObjectDrawer( color, width, visible, style.pen.style() );
+ if ( !labeltext.isEmpty() )
+ {
+ ObjectConstCalcer* name = new ObjectConstCalcer( new StringImp( labeltext ) );
+ object = new ObjectHolder( o, d, name );
+ }
+ else
+ {
+ object = new ObjectHolder( o, d );
+ }
+
+ assert( object );
+ ret[i] = object;
+ object->calc( *retdoc );
+ if ( !labeltext.isEmpty() && labelVisible )
+ {
+ std::vector<ObjectCalcer*> args2;
+ args2.push_back( object->nameCalcer() );
+ ObjectCalcer* oc2 = fact->attachedLabelCalcer(
+ QString::fromLatin1( "%1" ), object->calcer(),
+ static_cast<const PointImp*>( object->imp() )->coordinate(),
+ false, args2, *retdoc );
+ oc2->calc( *retdoc );
+ ObjectDrawer* d2 = new ObjectDrawer( style.pen.color() );
+ ObjectHolder* o2 = new ObjectHolder( oc2, d2 );
+ ret2.push_back( o2 );
+ }
+ };
+
+ // selection groups ( we ignore them, but we pretend to read them
+ // out anyway, so we can find what comes after them.. )
+ int selgroupcount;
+ stream >> selgroupcount;
+ for ( int i = 0; i < selgroupcount; ++i )
+ {
+ QString name;
+ stream >> name;
+ int size;
+ stream >> size;
+ for ( int i = 0; i < size; ++i )
+ {
+ short object;
+ stream >> object;
+ (void) object;
+ };
+ };
+
+ // no more data in the file..
+ retdoc->addObjects( ret );
+ retdoc->addObjects( ret2 );
+ retdoc->setAxes( false );
+ retdoc->setGrid( false );
+ return retdoc;
+}
+
+KigFilterKSeg* KigFilterKSeg::instance()
+{
+ static KigFilterKSeg f;
+ return &f;
+}
diff --git a/kig/filters/kseg-filter.h b/kig/filters/kseg-filter.h
new file mode 100644
index 00000000..af475a7a
--- /dev/null
+++ b/kig/filters/kseg-filter.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_FILTERS_KSEG_FILTER_H
+#define KIG_FILTERS_KSEG_FILTER_H
+
+#include "filter.h"
+
+class ObjectCalcer;
+
+class KigFilterKSeg
+ : public KigFilter
+{
+ KigFilterKSeg();
+ ~KigFilterKSeg();
+
+ ObjectCalcer* transformObject( const QString& file, KigDocument& kigdoc,
+ std::vector<ObjectCalcer*>& parents,
+ int subtype, bool& ok );
+
+public:
+ static KigFilterKSeg* instance();
+
+ bool supportMime ( const QString& mime );
+ KigDocument* load ( const QString& fromfile );
+};
+
+#endif
diff --git a/kig/filters/latexexporter.cc b/kig/filters/latexexporter.cc
new file mode 100644
index 00000000..955ac148
--- /dev/null
+++ b/kig/filters/latexexporter.cc
@@ -0,0 +1,608 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include <config.h>
+
+#include "latexexporter.h"
+
+#include "latexexporteroptions.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../misc/common.h"
+#include "../misc/goniometry.h"
+#include "../misc/kigfiledialog.h"
+#include "../misc/rect.h"
+#include "../objects/circle_imp.h"
+#include "../objects/cubic_imp.h"
+#include "../objects/curve_imp.h"
+#include "../objects/line_imp.h"
+#include "../objects/locus_imp.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_holder.h"
+#include "../objects/object_imp.h"
+#include "../objects/other_imp.h"
+#include "../objects/point_imp.h"
+#include "../objects/polygon_imp.h"
+#include "../objects/text_imp.h"
+
+#include <math.h>
+#include <algorithm>
+
+#include <qcheckbox.h>
+#include <qcolor.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#ifdef HAVE_TRUNC
+#define KDE_TRUNC(a) trunc(a)
+#else
+#define KDE_TRUNC(a) rint(a)
+#endif
+
+struct ColorMap {
+ QColor color;
+ QString name;
+};
+
+LatexExporter::~LatexExporter()
+{
+}
+
+QString LatexExporter::exportToStatement() const
+{
+ return i18n( "Export to &Latex..." );
+}
+
+QString LatexExporter::menuEntryName() const
+{
+ return i18n( "&Latex..." );
+}
+
+QString LatexExporter::menuIcon() const
+{
+ // TODO
+ return "tex";
+}
+
+class LatexExportImpVisitor
+ : public ObjectImpVisitor
+{
+ QTextStream& mstream;
+ ObjectHolder* mcurobj;
+ const KigWidget& mw;
+ Rect msr;
+ std::vector<ColorMap> mcolors;
+ QString mcurcolorid;
+public:
+ void visit( ObjectHolder* obj );
+ void mapColor( QColor color );
+
+ LatexExportImpVisitor( QTextStream& s, const KigWidget& w )
+ : mstream( s ), mw( w ), msr( mw.showingRect() )
+ {
+ }
+ void visit( const LineImp* imp );
+ void visit( const PointImp* imp );
+ void visit( const TextImp* imp );
+ void visit( const AngleImp* imp );
+ void visit( const VectorImp* imp );
+ void visit( const LocusImp* imp );
+ void visit( const CircleImp* imp );
+ void visit( const ConicImp* imp );
+ void visit( const CubicImp* imp );
+ void visit( const SegmentImp* imp );
+ void visit( const RayImp* imp );
+ void visit( const ArcImp* imp );
+ void visit( const PolygonImp* imp );
+
+ double unit;
+
+private:
+ /**
+ * Converts Kig coords to pstrick coord system and sends them to stream
+ * using the format: (xcoord,ycoord)
+ */
+ void emitCoord( const Coordinate& c );
+ /**
+ * Draws a line (segment) or a vector if vector is true.
+ */
+ void emitLine( const Coordinate& a, const Coordinate& b, const int width,
+ const Qt::PenStyle s, bool vector = false );
+ /**
+ * Sends a new line character ( \n ) to stream.
+ */
+ void newLine();
+ /**
+ * Searches if a color is already mapped into mcolors, and returns its
+ * index or -1 if not found.
+ */
+ int findColor( QColor c );
+ /**
+ * Use to convert a dimension "on the screen" to a dimension wrt.
+ * Kig coordinate system.
+ */
+ double dimRealToCoord( int dim );
+ /**
+ * Converts a pen style into latex style string.
+ */
+ QString writeStyle( Qt::PenStyle style );
+ /**
+ * Plots a generic curve though its points calc'ed with getPoint.
+ */
+ void plotGenericCurve( const CurveImp* imp );
+};
+
+void LatexExportImpVisitor::emitCoord( const Coordinate& c )
+{
+ mstream << "(" << c.x - msr.left() << "," << c.y - msr.bottom() << ")";
+}
+
+void LatexExportImpVisitor::emitLine( const Coordinate& a, const Coordinate& b,
+ const int width, const Qt::PenStyle s,
+ bool vector )
+{
+ mstream << "\\psline[linecolor=" << mcurcolorid << ",linewidth=" << width / 100.0
+ << "," << writeStyle( s );
+ if ( vector )
+ mstream << ",arrowscale=3,arrowinset=1.3";
+ mstream << "]";
+ if ( vector )
+ mstream << "{->}";
+ emitCoord( a );
+ emitCoord( b );
+ newLine();
+}
+
+void LatexExportImpVisitor::newLine()
+{
+ mstream << "\n";
+}
+
+int LatexExportImpVisitor::findColor( QColor c )
+{
+ for ( uint i = 0; i < mcolors.size(); ++i )
+ {
+ if ( c == mcolors[i].color )
+ return i;
+ }
+ return -1;
+}
+
+void LatexExportImpVisitor::mapColor( QColor color )
+{
+ if ( findColor( color ) == -1 )
+ {
+ ColorMap newcolor;
+ newcolor.color = color;
+ QString tmpname = color.name();
+ tmpname.replace( "#", "" );
+ newcolor.name = tmpname;
+ mcolors.push_back( newcolor );
+ mstream << "\\newrgbcolor{" << tmpname << "}{"
+ << color.red() / 255.0 << " " << color.green() / 255.0 << " "
+ << color.blue() / 255.0 << "}\n";
+ }
+}
+
+double LatexExportImpVisitor::dimRealToCoord( int dim )
+{
+ QRect qr( 0, 0, dim, dim );
+ Rect r = mw.screenInfo().fromScreen( qr );
+ return fabs( r.width() );
+}
+
+QString LatexExportImpVisitor::writeStyle( Qt::PenStyle style )
+{
+ QString ret( "linestyle=" );
+ if ( style == Qt::DashLine )
+ ret += "dashed";
+ else if ( style == Qt::DotLine )
+ ret += "dotted,dotsep=2pt";
+ else
+ ret += "solid";
+ return ret;
+}
+
+void LatexExportImpVisitor::plotGenericCurve( const CurveImp* imp )
+{
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ QString prefix = QString( "\\pscurve[linecolor=%1,linewidth=%2,%3]" )
+ .arg( mcurcolorid )
+ .arg( width / 100.0 )
+ .arg( writeStyle( mcurobj->drawer()->style() ) );
+
+ std::vector< std::vector< Coordinate > > coordlist;
+ coordlist.push_back( std::vector< Coordinate >() );
+ uint curid = 0;
+
+ Coordinate c;
+ Coordinate prev = Coordinate::invalidCoord();
+ for ( double i = 0.0; i <= 1.0; i += 0.005 )
+ {
+ c = imp->getPoint( i, mw.document() );
+ if ( !c.valid() )
+ {
+ if ( coordlist[curid].size() > 0 )
+ {
+ coordlist.push_back( std::vector< Coordinate >() );
+ ++curid;
+ prev = Coordinate::invalidCoord();
+ }
+ continue;
+ }
+ if ( ! ( ( fabs( c.x ) <= 1000 ) && ( fabs( c.y ) <= 1000 ) ) )
+ continue;
+ // if there's too much distance between this coordinate and the previous
+ // one, then it's another piece of curve not joined with the rest
+ if ( prev.valid() && ( c.distance( prev ) > 4.0 ) )
+ {
+ coordlist.push_back( std::vector< Coordinate >() );
+ ++curid;
+ }
+ coordlist[curid].push_back( c );
+ prev = c;
+ }
+ // special case for ellipse
+ if ( const ConicImp* conic = dynamic_cast< const ConicImp* >( imp ) )
+ {
+ // if ellipse, close its path
+ if ( conic->conicType() == 1 && coordlist.size() == 1 && coordlist[0].size() > 1 )
+ {
+ coordlist[0].push_back( coordlist[0][0] );
+ }
+ }
+ for ( uint i = 0; i < coordlist.size(); ++i )
+ {
+ uint s = coordlist[i].size();
+ // there's no point in draw curves empty or with only one point
+ if ( s <= 1 )
+ continue;
+
+ mstream << prefix;
+ for ( uint j = 0; j < s; ++j )
+ emitCoord( coordlist[i][j] );
+ newLine();
+ }
+}
+
+void LatexExportImpVisitor::visit( ObjectHolder* obj )
+{
+ if ( ! obj->drawer()->shown() )
+ return;
+ const int id = findColor( obj->drawer()->color() );
+ if ( id == -1 )
+ return;
+ mcurcolorid = mcolors[id].name;
+ mcurobj = obj;
+ obj->imp()->visit( this );
+}
+
+void LatexExportImpVisitor::visit( const LineImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+ calcBorderPoints( a, b, msr );
+
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ emitLine( a, b, width, mcurobj->drawer()->style() );
+}
+
+void LatexExportImpVisitor::visit( const PointImp* imp )
+{
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 5;
+ width /= 5;
+
+ mstream << "\\psdots[linecolor=" << mcurcolorid
+ << ",dotscale=" << width << ",dotstyle=";
+ const int ps = mcurobj->drawer()->pointStyle();
+ QString pss( "*,fillstyle=solid,fillcolor=" + mcurcolorid );
+ if ( ps == 1 )
+ pss = "o,fillstyle=none";
+ else if ( ps == 2 )
+ pss = "square*,fillstyle=solid,fillcolor=" + mcurcolorid;
+ else if ( ps == 3 )
+ pss = "square,fillstyle=none";
+ else if ( ps == 4 )
+ pss = "+,dotangle=45";
+ mstream << pss << "]";
+ emitCoord( imp->coordinate() );
+ newLine();
+}
+
+void LatexExportImpVisitor::visit( const TextImp* imp )
+{
+ // FIXME: support multiline texts...
+ mstream << "\\rput[tl]";
+ emitCoord( imp->coordinate() );
+ newLine();
+ mstream << "{";
+ newLine();
+ if ( imp->hasFrame() )
+ {
+ mstream << " \\psframebox[linecolor=c5c2c5,linewidth=0.01"
+ << ",fillstyle=solid,fillcolor=ffffde]"
+ << "{" << imp->text() << "}";
+ }
+ else
+ {
+ mstream << imp->text();
+ }
+ newLine();
+ mstream << "}";
+ newLine();
+}
+
+void LatexExportImpVisitor::visit( const AngleImp* imp )
+{
+ const Coordinate center = imp->point();
+ const double radius = dimRealToCoord( 50 ) * unit;
+ double startangle = imp->startAngle();
+ double endangle = startangle + imp->angle();
+// if ( startangle > M_PI )
+// startangle -= 2 * M_PI;
+ startangle = Goniometry::convert( startangle, Goniometry::Rad, Goniometry::Deg );
+// if ( endangle > 2 * M_PI )
+// endangle -= 2 * M_PI;
+ endangle = Goniometry::convert( endangle, Goniometry::Rad, Goniometry::Deg );
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ mstream << "\\psarc[linecolor=" << mcurcolorid << ",linewidth=" << width / 100.0
+ << "," << writeStyle( mcurobj->drawer()->style() ) << ",arrowscale=3,arrowinset=0]{->}";
+ emitCoord( center );
+ mstream << "{" << radius << "}{" << startangle << "}{" << endangle << "}";
+ newLine();
+}
+
+void LatexExportImpVisitor::visit( const VectorImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ emitLine( a, b, width, mcurobj->drawer()->style(), true );
+}
+
+void LatexExportImpVisitor::visit( const LocusImp* imp )
+{
+ plotGenericCurve( imp );
+}
+
+void LatexExportImpVisitor::visit( const CircleImp* imp )
+{
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ mstream << "\\pscircle[linecolor=" << mcurcolorid << ",linewidth=" << width / 100.0
+ << "," << writeStyle( mcurobj->drawer()->style() ) << "]";
+ emitCoord( imp->center() );
+ mstream << "{" << imp->radius() * unit << "}";
+ newLine();
+}
+
+void LatexExportImpVisitor::visit( const ConicImp* imp )
+{
+ plotGenericCurve( imp );
+}
+
+void LatexExportImpVisitor::visit( const CubicImp* )
+{
+ // FIXME: cubic are not drawn correctly with plotGenericCurve
+// plotGenericCurve( imp );
+}
+
+void LatexExportImpVisitor::visit( const SegmentImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ emitLine( a, b, width, mcurobj->drawer()->style() );
+}
+
+void LatexExportImpVisitor::visit( const RayImp* imp )
+{
+ Coordinate a = imp->data().a;
+ Coordinate b = imp->data().b;
+ calcRayBorderPoints( a, b, msr );
+
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ emitLine( a, b, width, mcurobj->drawer()->style() );
+}
+
+void LatexExportImpVisitor::visit( const ArcImp* imp )
+{
+ const Coordinate center = imp->center();
+ const double radius = imp->radius() * unit;
+ double startangle = imp->startAngle();
+ double endangle = startangle + imp->angle();
+// if ( startangle > M_PI )
+// startangle -= 2 * M_PI;
+ startangle = Goniometry::convert( startangle, Goniometry::Rad, Goniometry::Deg );
+// if ( endangle > M_PI )
+// endangle -= 2 * M_PI;
+ endangle = Goniometry::convert( endangle, Goniometry::Rad, Goniometry::Deg );
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ mstream << "\\psarc[linecolor=" << mcurcolorid << ",linewidth=" << width / 100.0
+ << "," << writeStyle( mcurobj->drawer()->style() ) << "]";
+ emitCoord( center );
+ mstream << "{" << radius << "}{" << startangle << "}{" << endangle << "}";
+ newLine();
+}
+
+void LatexExportImpVisitor::visit( const PolygonImp* imp )
+{
+ int width = mcurobj->drawer()->width();
+ if ( width == -1 ) width = 1;
+
+ mstream << "\\pspolygon[linecolor=" << mcurcolorid << ",linewidth=0"
+ << "," << writeStyle( mcurobj->drawer()->style() )
+ << ",hatchcolor=" << mcurcolorid << ",hatchwidth=0.5pt,hatchsep=0.5pt"
+ << ",fillcolor=" << mcurcolorid << ",fillstyle=crosshatch]";
+
+ std::vector<Coordinate> pts = imp->points();
+ for ( uint i = 0; i < pts.size(); i++ )
+ {
+ emitCoord( pts[i] );
+ }
+ newLine();
+}
+
+void LatexExporter::run( const KigPart& doc, KigWidget& w )
+{
+ KigFileDialog* kfd = new KigFileDialog(
+ QString::null, i18n( "*.tex|Latex Documents (*.tex)" ),
+ i18n( "Export as Latex" ), &w );
+ kfd->setOptionCaption( i18n( "Latex Options" ) );
+ LatexExporterOptions* opts = new LatexExporterOptions( 0L );
+ kfd->setOptionsWidget( opts );
+ opts->showGridCheckBox->setChecked( doc.document().grid() );
+ opts->showAxesCheckBox->setChecked( doc.document().axes() );
+ opts->showExtraFrameCheckBox->setChecked( false );
+ if ( !kfd->exec() )
+ return;
+
+ QString file_name = kfd->selectedFile();
+ bool showgrid = opts->showGridCheckBox->isOn();
+ bool showaxes = opts->showAxesCheckBox->isOn();
+ bool showframe = opts->showExtraFrameCheckBox->isOn();
+
+ delete opts;
+ delete kfd;
+
+ QFile file( file_name );
+ if ( ! file.open( IO_WriteOnly ) )
+ {
+ KMessageBox::sorry( &w, i18n( "The file \"%1\" could not be opened. Please "
+ "check if the file permissions are set correctly." )
+ .arg( file_name ) );
+ return;
+ };
+
+ QTextStream stream( &file );
+ stream << "\\documentclass[a4paper]{minimal}\n";
+// stream << "\\usepackage[latin1]{inputenc}\n";
+ stream << "\\usepackage{pstricks}\n";
+ stream << "\\usepackage{pst-plot}\n";
+ stream << "\\author{Kig " << KIGVERSION << "}\n";
+ stream << "\\begin{document}\n";
+
+ const double bottom = w.showingRect().bottom();
+ const double left = w.showingRect().left();
+ const double height = w.showingRect().height();
+ const double width = w.showingRect().width();
+
+/*
+ // TODO: calculating aspect ratio...
+ if ( 297 / 210 >= height / width )
+ {
+
+ }
+*/
+ const double tmpwidth = 15.0;
+ const double xunit = tmpwidth / width;
+ const double yunit = xunit;
+
+ stream << "\\begin{pspicture*}(0,0)(" << tmpwidth << "," << yunit * height << ")\n";
+ stream << "\\psset{xunit=" << xunit << "}\n";
+ stream << "\\psset{yunit=" << yunit << "}\n";
+
+ std::vector<ObjectHolder*> os = doc.document().objects();
+ LatexExportImpVisitor visitor( stream, w );
+ visitor.unit = xunit;
+
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ {
+ if ( ! ( *i )->shown() ) continue;
+ visitor.mapColor( ( *i )->drawer()->color() );
+ };
+ visitor.mapColor( QColor( 255, 255, 222 ) ); // ffffde - text label background
+ visitor.mapColor( QColor( 197, 194, 197 ) ); // c5c2c5 - text label border line
+ visitor.mapColor( QColor( 160, 160, 164 ) ); // a0a0a4 - axes color
+ visitor.mapColor( QColor( 192, 192, 192 ) ); // c0c0c0 - grid color
+
+ // extra frame
+ if ( showframe )
+ {
+ stream << "\\psframe[linecolor=black,linewidth=0.02]"
+ << "(0,0)"
+ << "(" << width << "," << height << ")"
+ << "\n";
+ }
+
+ // grid
+ if ( showgrid )
+ {
+ // vertical lines...
+ double startingpoint = - left - 1 + static_cast<int>( KDE_TRUNC( left ) );
+ for ( double i = startingpoint; i < width; ++i )
+ {
+ stream << "\\psline[linecolor=c0c0c0,linewidth=0.01,linestyle=dashed]"
+ << "(" << i << ",0)"
+ << "(" << i << "," << height << ")"
+ << "\n";
+ }
+
+ // horizontal lines...
+ startingpoint = - bottom - 1 + static_cast<int>( KDE_TRUNC( bottom ) );
+ for ( double i = startingpoint; i < height; ++i )
+ {
+ stream << "\\psline[linecolor=c0c0c0,linewidth=0.01,linestyle=dashed]"
+ << "(0," << i << ")"
+ << "(" << width << "," << i << ")"
+ << "\n";
+ }
+ }
+
+ // axes
+ if ( showaxes )
+ {
+ stream << "\\psaxes[linecolor=a0a0a4,linewidth=0.03,ticks=none,arrowinset=0]{->}"
+ << "(" << -left << "," << -bottom << ")"
+ << "(0,0)"
+ << "(" << width << "," << height << ")"
+ << "\n";
+ }
+
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ {
+ visitor.visit( *i );
+ };
+
+ stream << "\\end{pspicture*}\n";
+ stream << "\\end{document}\n";
+}
diff --git a/kig/filters/latexexporter.h b/kig/filters/latexexporter.h
new file mode 100644
index 00000000..32638de1
--- /dev/null
+++ b/kig/filters/latexexporter.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_FILTERS_LATEXEXPORTER_H
+#define KIG_FILTERS_LATEXEXPORTER_H
+
+#include "exporter.h"
+
+class QString;
+class KigPart;
+class KigWidget;
+
+/**
+ * Export to LaTex.
+ */
+class LatexExporter
+ : public KigExporter
+{
+public:
+ ~LatexExporter();
+ QString exportToStatement() const;
+ QString menuEntryName() const;
+ QString menuIcon() const;
+ void run( const KigPart& doc, KigWidget& w );
+};
+
+#endif
diff --git a/kig/filters/latexexporteroptions.ui b/kig/filters/latexexporteroptions.ui
new file mode 100644
index 00000000..d2e60c5b
--- /dev/null
+++ b/kig/filters/latexexporteroptions.ui
@@ -0,0 +1,69 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>LatexExporterOptions</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>LatexExporterOptions</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>450</width>
+ <height>150</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>showGridCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show grid</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>showAxesCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show axes</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>showExtraFrameCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show extra frame</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+</includehints>
+</UI>
diff --git a/kig/filters/native-filter.cc b/kig/filters/native-filter.cc
new file mode 100644
index 00000000..6cecf09b
--- /dev/null
+++ b/kig/filters/native-filter.cc
@@ -0,0 +1,747 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "native-filter.h"
+
+#include "../kig/kig_part.h"
+#include "../kig/kig_document.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/object_type.h"
+#include "../objects/object_imp.h"
+#include "../objects/object_calcer.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_holder.h"
+#include "../objects/object_type_factory.h"
+#include "../objects/object_imp_factory.h"
+#include "../misc/calcpaths.h"
+#include "../misc/coordinate_system.h"
+
+#include "config.h"
+
+#include <qdom.h>
+#include <qfile.h>
+#include <qregexp.h>
+
+#include <karchive.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <ktar.h>
+
+#include <stdio.h>
+
+#include <vector>
+#include <algorithm>
+#include <map>
+
+struct HierElem
+{
+ int id;
+ std::vector<int> parents;
+ QDomElement el;
+};
+
+static void extendVect( std::vector<HierElem>& vect, uint size )
+{
+ if ( size > vect.size() )
+ {
+ int osize = vect.size();
+ vect.resize( size );
+ for ( uint i = osize; i < size; ++i )
+ vect[i].id = i+1;
+ };
+}
+
+static void visitElem( std::vector<HierElem>& ret,
+ const std::vector<HierElem>& elems,
+ std::vector<bool>& seen,
+ int i )
+{
+ if ( !seen[i] )
+ {
+ for ( uint j = 0; j < elems[i].parents.size(); ++j )
+ visitElem( ret, elems, seen, elems[i].parents[j] - 1);
+ ret.push_back( elems[i] );
+ seen[i] = true;
+ };
+}
+
+static std::vector<HierElem> sortElems( const std::vector<HierElem> elems )
+{
+ std::vector<HierElem> ret;
+ std::vector<bool> seenElems( elems.size(), false );
+ for ( uint i = 0; i < elems.size(); ++i )
+ visitElem( ret, elems, seenElems, i );
+ return ret;
+}
+
+KigFilterNative::KigFilterNative()
+{
+}
+
+KigFilterNative::~KigFilterNative()
+{
+}
+
+bool KigFilterNative::supportMime( const QString& mime )
+{
+ return mime == "application/x-kig";
+}
+
+KigDocument* KigFilterNative::load( const QString& file )
+{
+ QFile ffile( file );
+ if ( ! ffile.open( IO_ReadOnly ) )
+ {
+ fileNotFound( file );
+ return 0;
+ };
+
+ QFile kigdoc( file );
+#ifndef KIG_NO_COMPRESSED_FILES
+ bool iscompressed = false;
+ if ( !file.endsWith( ".kig", false ) )
+ {
+ // the file is compressed, so we have to decompress it and fetch the
+ // kig file inside it...
+ iscompressed = true;
+
+ QString tempdir = KGlobal::dirs()->saveLocation( "tmp" );
+ if ( tempdir.isEmpty() )
+ KIG_FILTER_PARSE_ERROR;
+
+ QString tempname = file.section( '/', -1 );
+ if ( file.endsWith( ".kigz", false ) )
+ {
+ tempname.remove( QRegExp( "\\.[Kk][Ii][Gg][Zz]$" ) );
+ }
+ else
+ KIG_FILTER_PARSE_ERROR;
+ // reading compressed file
+ KTar* ark = new KTar( file, "application/x-gzip" );
+ ark->open( IO_ReadOnly );
+ const KArchiveDirectory* dir = ark->directory();
+// assert( dir );
+ QStringList entries = dir->entries();
+ QStringList kigfiles = entries.grep( QRegExp( "\\.kig$" ) );
+ if ( kigfiles.count() != 1 )
+ // I throw a generic parse error here, but I should warn the user that
+ // this kig archive file doesn't contain one kig file (it contains no
+ // kig files or more than one).
+ KIG_FILTER_PARSE_ERROR;
+ const KArchiveEntry* kigz = dir->entry( kigfiles[0] );
+ if ( !kigz->isFile() )
+ KIG_FILTER_PARSE_ERROR;
+ dynamic_cast<const KArchiveFile*>( kigz )->copyTo( tempdir );
+ kdDebug() << "extracted file: " << tempdir + kigz->name() << endl
+ << "exists: " << QFile::exists( tempdir + kigz->name() ) << endl;
+
+ kigdoc.setName( tempdir + kigz->name() );
+ }
+#endif
+
+ if ( !kigdoc.open( IO_ReadOnly ) )
+ KIG_FILTER_PARSE_ERROR;
+
+ QDomDocument doc( "KigDocument" );
+ if ( !doc.setContent( &kigdoc ) )
+ KIG_FILTER_PARSE_ERROR;
+ kigdoc.close();
+
+#ifndef KIG_NO_COMPRESSED_FILES
+ // removing temp file
+ if ( iscompressed )
+ kigdoc.remove();
+#endif
+
+ QDomElement main = doc.documentElement();
+
+ QString version = main.attribute( "CompatibilityVersion" );
+ if ( version.isEmpty() ) version = main.attribute( "Version" );
+ if ( version.isEmpty() ) version = main.attribute( "version" );
+ if ( version.isEmpty() )
+ KIG_FILTER_PARSE_ERROR;
+
+ // matches 0.1, 0.2.0, 153.128.99 etc.
+ QRegExp versionre( "(\\d+)\\.(\\d+)(\\.(\\d+))?" );
+ if ( ! versionre.exactMatch( version ) )
+ KIG_FILTER_PARSE_ERROR;
+ bool ok = true;
+ int major = versionre.cap( 1 ).toInt( &ok );
+ bool ok2 = true;
+ int minor = versionre.cap( 2 ).toInt( &ok2 );
+ if ( ! ok || ! ok2 )
+ KIG_FILTER_PARSE_ERROR;
+
+ // int minorminor = versionre.cap( 4 ).toInt( &ok );
+
+ // we only support 0.[0-7] and 1.0.*
+ if ( major > 0 || minor > 9 )
+ {
+ notSupported( file, i18n( "This file was created by Kig version \"%1\", "
+ "which this version cannot open." ).arg( version ) );
+ return false;
+ }
+ else if ( major == 0 && minor <= 3 )
+ {
+ notSupported( file, i18n( "This file was created by Kig version \"%1\".\n"
+ "Support for older Kig formats (pre-0.4) has been "
+ "removed from Kig.\n"
+ "You can try to open this file with an older Kig "
+ "version (0.4 to 0.6),\n"
+ "and then save it again, which will save it in the "
+ "new format." ).arg( version ) );
+ return false;
+ }
+ else if ( major == 0 && minor <= 6 )
+ return load04( file, main );
+ else
+ return load07( file, main );
+}
+
+KigDocument* KigFilterNative::load04( const QString& file, const QDomElement& docelem )
+{
+ bool ok = true;
+
+ KigDocument* ret = new KigDocument();
+
+ for ( QDomNode n = docelem.firstChild(); ! n.isNull(); n = n.nextSibling() )
+ {
+ QDomElement e = n.toElement();
+ if ( e.isNull() ) continue;
+ if ( e.tagName() == "CoordinateSystem" )
+ {
+ const QCString type = e.text().latin1();
+ CoordinateSystem* s = CoordinateSystemFactory::build( type );
+ if ( ! s )
+ {
+ warning( i18n( "This Kig file has a coordinate system "
+ "that this Kig version does not support.\n"
+ "A standard coordinate system will be used "
+ "instead." ) );
+ }
+ else ret->setCoordinateSystem( s );
+ }
+ else if ( e.tagName() == "Objects" )
+ {
+ std::vector<ObjectCalcer*> retcalcers;
+ std::vector<ObjectHolder*> retholders;
+
+ // first pass: do a topological sort of the objects, to support
+ // randomly ordered files...
+ std::vector<HierElem> elems;
+ QDomElement objectselem = e;
+ for ( QDomNode o = objectselem.firstChild(); ! o.isNull(); o = o.nextSibling() )
+ {
+ e = o.toElement();
+ if ( e.isNull() ) continue;
+ uint id;
+ if ( e.tagName() == "Data" || e.tagName() == "Property" || e.tagName() == "Object" )
+ {
+ // fetch the id
+ QString tmp = e.attribute("id");
+ id = tmp.toInt(&ok);
+ if ( !ok ) KIG_FILTER_PARSE_ERROR;
+
+ extendVect( elems, id );
+ elems[id-1].el = e;
+ }
+ else continue;
+
+ for ( QDomNode p = e.firstChild(); !p.isNull(); p = p.nextSibling() )
+ {
+ QDomElement f = p.toElement();
+ if ( f.isNull() ) continue;
+ if ( f.tagName() == "Parent" )
+ {
+ QString tmp = f.attribute( "id" );
+ uint pid = tmp.toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+
+ extendVect( elems, id );
+ elems[id-1].parents.push_back( pid );
+ }
+ }
+ };
+
+ for ( uint i = 0; i < elems.size(); ++i )
+ if ( elems[i].el.isNull() )
+ KIG_FILTER_PARSE_ERROR;
+ elems = sortElems( elems );
+
+ retcalcers.resize( elems.size(), 0 );
+
+ for ( std::vector<HierElem>::iterator i = elems.begin();
+ i != elems.end(); ++i )
+ {
+ QDomElement e = i->el;
+ bool internal = e.attribute( "internal" ) == "true" ? true : false;
+ ObjectCalcer* o = 0;
+ if ( e.tagName() == "Data" )
+ {
+ QString tmp = e.attribute( "type" );
+ if ( tmp.isNull() )
+ KIG_FILTER_PARSE_ERROR;
+ QString error;
+ ObjectImp* imp = ObjectImpFactory::instance()->deserialize( tmp, e, error );
+ if ( ( !imp ) && !error.isEmpty() )
+ {
+ parseError( file, error );
+ return false;
+ }
+ o = new ObjectConstCalcer( imp );
+ }
+ else if ( e.tagName() == "Property" )
+ {
+ QCString propname;
+ for ( QDomElement ec = e.firstChild().toElement(); !ec.isNull();
+ ec = ec.nextSibling().toElement() )
+ {
+ if ( ec.tagName() == "Property" )
+ propname = ec.text().latin1();
+ };
+
+ if ( i->parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* parent = retcalcers[i->parents[0] -1];
+ QCStringList propnames = parent->imp()->propertiesInternalNames();
+ int propid = propnames.findIndex( propname );
+ if ( propid == -1 )
+ KIG_FILTER_PARSE_ERROR;
+
+ o = new ObjectPropertyCalcer( parent, propid );
+ }
+ else if ( e.tagName() == "Object" )
+ {
+ QString tmp = e.attribute( "type" );
+ if ( tmp.isNull() )
+ KIG_FILTER_PARSE_ERROR;
+
+ const ObjectType* type =
+ ObjectTypeFactory::instance()->find( tmp.latin1() );
+ if ( !type )
+ {
+ notSupported( file, i18n( "This Kig file uses an object of type \"%1\", "
+ "which this Kig version does not support."
+ "Perhaps you have compiled Kig without support "
+ "for this object type,"
+ "or perhaps you are using an older Kig version." ).arg( tmp ) );
+ return false;
+ };
+
+ std::vector<ObjectCalcer*> parents;
+ for ( std::vector<int>::iterator j = i->parents.begin();
+ j != i->parents.end(); ++j )
+ parents.push_back( retcalcers[*j - 1] );
+
+ o = new ObjectTypeCalcer( type, parents );
+ }
+ else continue;
+
+ o->calc( *ret );
+ retcalcers[i->id - 1] = o;
+
+ if ( ! internal )
+ {
+ QString tmp = e.attribute( "color" );
+ QColor color( tmp );
+ if ( !color.isValid() )
+ KIG_FILTER_PARSE_ERROR;
+
+ tmp = e.attribute( "shown" );
+ bool shown = !( tmp == "false" || tmp == "no" );
+
+ tmp = e.attribute( "width" );
+ int width = tmp.toInt( &ok );
+ if ( ! ok ) width = -1;
+
+ ObjectDrawer* d = new ObjectDrawer( color, width, shown );
+ retholders.push_back( new ObjectHolder( o, d ) );
+ }
+ }
+ ret->addObjects( retholders );
+ }
+ else continue; // be forward-compatible..
+ };
+
+ return ret;
+}
+
+KigFilterNative* KigFilterNative::instance()
+{
+ static KigFilterNative f;
+ return &f;
+}
+
+KigDocument* KigFilterNative::load07( const QString& file, const QDomElement& docelem )
+{
+ KigDocument* ret = new KigDocument();
+
+ bool ok = true;
+ std::vector<ObjectCalcer::shared_ptr> calcers;
+ std::vector<ObjectHolder*> holders;
+
+ QString t = docelem.attribute( "grid" );
+ bool tmphide = ( t == "false" ) || ( t == "no" ) || ( t == "0" );
+ ret->setGrid( !tmphide );
+ t = docelem.attribute( "axes" );
+ tmphide = ( t == "false" ) || ( t == "no" ) || ( t == "0" );
+ ret->setAxes( !tmphide );
+
+ for ( QDomElement subsectionelement = docelem.firstChild().toElement(); ! subsectionelement.isNull();
+ subsectionelement = subsectionelement.nextSibling().toElement() )
+ {
+ if ( subsectionelement.tagName() == "CoordinateSystem" )
+ {
+ QString tmptype = subsectionelement.text();
+ // compatibility code - to support Invisible coord system...
+ if ( tmptype == "Invisible" )
+ {
+ tmptype = "Euclidean";
+ ret->setGrid( false );
+ ret->setAxes( false );
+ }
+ const QCString type = tmptype.latin1();
+ CoordinateSystem* s = CoordinateSystemFactory::build( type );
+ if ( ! s )
+ {
+ warning( i18n( "This Kig file has a coordinate system "
+ "that this Kig version does not support.\n"
+ "A standard coordinate system will be used "
+ "instead." ) );
+ }
+ else ret->setCoordinateSystem( s );
+ }
+ else if ( subsectionelement.tagName() == "Hierarchy" )
+ {
+ for ( QDomElement e = subsectionelement.firstChild().toElement(); ! e.isNull();
+ e = e.nextSibling().toElement() )
+ {
+ QString tmp = e.attribute( "id" );
+ uint id = tmp.toInt( &ok );
+ if ( id <= 0 ) KIG_FILTER_PARSE_ERROR;
+
+ std::vector<ObjectCalcer*> parents;
+ for ( QDomElement parentel = e.firstChild().toElement(); ! parentel.isNull();
+ parentel = parentel.nextSibling().toElement() )
+ {
+ if ( parentel.tagName() != "Parent" ) continue;
+ QString tmp = parentel.attribute( "id" );
+ uint parentid = tmp.toInt( &ok );
+ if ( ! ok ) KIG_FILTER_PARSE_ERROR;
+ if ( parentid == 0 || parentid > calcers.size() ) KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* parent = calcers[parentid - 1].get();
+ if ( ! parent ) KIG_FILTER_PARSE_ERROR;
+ parents.push_back( parent );
+ }
+
+ ObjectCalcer* o = 0;
+
+ if ( e.tagName() == "Data" )
+ {
+ if ( !parents.empty() ) KIG_FILTER_PARSE_ERROR;
+ QString tmp = e.attribute( "type" );
+ QString error;
+ ObjectImp* imp = ObjectImpFactory::instance()->deserialize( tmp, e, error );
+ if ( ( !imp ) && !error.isEmpty() )
+ {
+ parseError( file, error );
+ return false;
+ }
+ o = new ObjectConstCalcer( imp );
+ }
+ else if ( e.tagName() == "Property" )
+ {
+ if ( parents.size() != 1 ) KIG_FILTER_PARSE_ERROR;
+ QCString propname = e.attribute( "which" ).latin1();
+
+ ObjectCalcer* parent = parents[0];
+ int propid = parent->imp()->propertiesInternalNames().findIndex( propname );
+ if ( propid == -1 ) KIG_FILTER_PARSE_ERROR;
+
+ o = new ObjectPropertyCalcer( parent, propid );
+ }
+ else if ( e.tagName() == "Object" )
+ {
+ QString tmp = e.attribute( "type" );
+ const ObjectType* type =
+ ObjectTypeFactory::instance()->find( tmp.latin1() );
+ if ( ! type )
+ {
+ notSupported( file, i18n( "This Kig file uses an object of type \"%1\", "
+ "which this Kig version does not support."
+ "Perhaps you have compiled Kig without support "
+ "for this object type,"
+ "or perhaps you are using an older Kig version." ).arg( tmp ) );
+ return false;
+ }
+
+ // mp: (I take the responsibility for this!) explanation: the usual ObjectTypeCalcer
+ // constructor also "sortArgs" the parents. I believe that this *must not* be done
+ // when loading from a saved kig file for the following reasons:
+ // 1. the arguments should already be in their intended order, since the file was
+ // saved from a working hierarchy; furthermore we actually want to restore the original
+ // hierarchy, not really to also fix possible problems with the original hierarchy;
+ // 2. calling sortArgs could have undesirable side effects in particular situations,
+ // since kig actually allow an ObjectType to produce different type of ObjectImp's
+ // it may happen that the parents of an object do not satisfy the requirements
+ // enforced by sortArgs (while moving around the free objects) but still be
+ // perfectly valid
+ o = new ObjectTypeCalcer( type, parents, false );
+ }
+ else KIG_FILTER_PARSE_ERROR;
+
+ o->calc( *ret );
+ calcers.resize( id, 0 );
+ calcers[id-1] = o;
+ }
+ }
+ else if ( subsectionelement.tagName() == "View" )
+ {
+ for ( QDomElement e = subsectionelement.firstChild().toElement(); ! e.isNull();
+ e = e.nextSibling().toElement() )
+ {
+ if ( e.tagName() != "Draw" ) KIG_FILTER_PARSE_ERROR;
+
+ QString tmp = e.attribute( "object" );
+ uint id = tmp.toInt( &ok );
+ if ( !ok ) KIG_FILTER_PARSE_ERROR;
+ if ( id <= 0 || id > calcers.size() )
+ KIG_FILTER_PARSE_ERROR;
+ ObjectCalcer* calcer = calcers[id-1].get();
+
+ tmp = e.attribute( "color" );
+ QColor color( tmp );
+ if ( !color.isValid() )
+ KIG_FILTER_PARSE_ERROR;
+
+ tmp = e.attribute( "shown" );
+ bool shown = !( tmp == "false" || tmp == "no" );
+
+ tmp = e.attribute( "width" );
+ int width = tmp.toInt( &ok );
+ if ( ! ok ) width = -1;
+
+ tmp = e.attribute( "style" );
+ Qt::PenStyle style = ObjectDrawer::styleFromString( tmp );
+
+ tmp = e.attribute( "point-style" );
+ int pointstyle = ObjectDrawer::pointStyleFromString( tmp );
+
+ ObjectConstCalcer* namecalcer = 0;
+ tmp = e.attribute( "namecalcer" );
+ if ( tmp != "none" && !tmp.isEmpty() )
+ {
+ int ncid = tmp.toInt( &ok );
+ if ( !ok ) KIG_FILTER_PARSE_ERROR;
+ if ( ncid <= 0 || ncid > calcers.size() )
+ KIG_FILTER_PARSE_ERROR;
+ if ( ! dynamic_cast<ObjectConstCalcer*>( calcers[ncid-1].get() ) )
+ KIG_FILTER_PARSE_ERROR;
+ namecalcer = static_cast<ObjectConstCalcer*>( calcers[ncid-1].get() );
+ }
+
+ ObjectDrawer* drawer = new ObjectDrawer( color, width, shown, style, pointstyle );
+ holders.push_back( new ObjectHolder( calcer, drawer, namecalcer ) );
+ }
+ }
+ }
+
+ ret->addObjects( holders );
+ return ret;
+}
+
+bool KigFilterNative::save07( const KigDocument& kdoc, QTextStream& stream )
+{
+ QDomDocument doc( "KigDocument" );
+
+ QDomElement docelem = doc.createElement( "KigDocument" );
+ docelem.setAttribute( "Version", KIGVERSION );
+ docelem.setAttribute( "CompatibilityVersion", "0.7.0" );
+ docelem.setAttribute( "grid", kdoc.grid() );
+ docelem.setAttribute( "axes", kdoc.axes() );
+
+ QDomElement cselem = doc.createElement( "CoordinateSystem" );
+ cselem.appendChild( doc.createTextNode( kdoc.coordinateSystem().type() ) );
+ docelem.appendChild( cselem );
+
+ std::vector<ObjectHolder*> holders = kdoc.objects();
+ std::vector<ObjectCalcer*> calcers = getAllParents( getAllCalcers( holders ) );
+ calcers = calcPath( calcers );
+
+ QDomElement hierelem = doc.createElement( "Hierarchy" );
+ std::map<const ObjectCalcer*, int> idmap;
+ for ( std::vector<ObjectCalcer*>::const_iterator i = calcers.begin();
+ i != calcers.end(); ++i )
+ idmap[*i] = ( i - calcers.begin() ) + 1;
+ int id = 1;
+
+ for ( std::vector<ObjectCalcer*>::const_iterator i = calcers.begin(); i != calcers.end(); ++i )
+ {
+ QDomElement objectelem;
+ if ( dynamic_cast<ObjectConstCalcer*>( *i ) )
+ {
+ objectelem = doc.createElement( "Data" );
+ QString ser =
+ ObjectImpFactory::instance()->serialize( *(*i)->imp(), objectelem, doc );
+ objectelem.setAttribute( "type", ser );
+ }
+ else if ( dynamic_cast<const ObjectPropertyCalcer*>( *i ) )
+ {
+ const ObjectPropertyCalcer* o = static_cast<const ObjectPropertyCalcer*>( *i );
+ objectelem = doc.createElement( "Property" );
+
+ QCString propname = o->parent()->imp()->propertiesInternalNames()[o->propId()];
+ objectelem.setAttribute( "which", propname );
+ }
+ else if ( dynamic_cast<const ObjectTypeCalcer*>( *i ) )
+ {
+ const ObjectTypeCalcer* o = static_cast<const ObjectTypeCalcer*>( *i );
+ objectelem = doc.createElement( "Object" );
+ objectelem.setAttribute( "type", o->type()->fullName() );
+ }
+ else assert( false );
+
+ const std::vector<ObjectCalcer*> parents = ( *i )->parents();
+ for ( std::vector<ObjectCalcer*>::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ {
+ std::map<const ObjectCalcer*,int>::const_iterator idp = idmap.find( *i );
+ assert( idp != idmap.end() );
+ int pid = idp->second;
+ QDomElement pel = doc.createElement( "Parent" );
+ pel.setAttribute( "id", pid );
+ objectelem.appendChild( pel );
+ }
+
+ objectelem.setAttribute( "id", id++ );
+ hierelem.appendChild( objectelem );
+ }
+ docelem.appendChild( hierelem );
+
+ QDomElement windowelem = doc.createElement( "View" );
+ for ( std::vector<ObjectHolder*>::iterator i = holders.begin(); i != holders.end(); ++i )
+ {
+ std::map<const ObjectCalcer*,int>::const_iterator idp = idmap.find( ( *i )->calcer() );
+ assert( idp != idmap.end() );
+ int id = idp->second;
+
+ const ObjectDrawer* d = ( *i )->drawer();
+ QDomElement drawelem = doc.createElement( "Draw" );
+ drawelem.setAttribute( "object", id );
+ drawelem.setAttribute( "color", d->color().name() );
+ drawelem.setAttribute( "shown", QString::fromLatin1( d->shown() ? "true" : "false" ) );
+ drawelem.setAttribute( "width", QString::number( d->width() ) );
+ drawelem.setAttribute( "style", d->styleToString() );
+ drawelem.setAttribute( "point-style", d->pointStyleToString() );
+
+ ObjectCalcer* namecalcer = ( *i )->nameCalcer();
+ if ( namecalcer )
+ {
+ std::map<const ObjectCalcer*,int>::const_iterator ncp = idmap.find( namecalcer );
+ assert( ncp != idmap.end() );
+ int ncid = ncp->second;
+ drawelem.setAttribute( "namecalcer", ncid );
+ }
+ else
+ {
+ drawelem.setAttribute( "namecalcer", "none" );
+ }
+
+ windowelem.appendChild( drawelem );
+ };
+ docelem.appendChild( windowelem );
+
+ doc.appendChild( docelem );
+ stream << doc.toString();
+ return true;
+}
+
+bool KigFilterNative::save( const KigDocument& data, const QString& file )
+{
+ return save07( data, file );
+}
+
+bool KigFilterNative::save07( const KigDocument& data, const QString& outfile )
+{
+ // we have an empty outfile, so we have to print all to stdout
+ if ( outfile.isEmpty() )
+ {
+ QTextStream stdoutstream( stdout, IO_WriteOnly );
+ return save07( data, stdoutstream );
+ }
+#ifndef KIG_NO_COMPRESSED_FILES
+ if ( !outfile.endsWith( ".kig", false ) )
+ {
+ // the user wants to save a compressed file, so we have to save our kig
+ // file to a temp file and then compress it...
+
+ QString tempdir = KGlobal::dirs()->saveLocation( "tmp" );
+ if ( tempdir.isEmpty() )
+ return false;
+
+ QString tempname = outfile.section( '/', -1 );
+ if ( outfile.endsWith( ".kigz", false ) )
+ tempname.remove( QRegExp( "\\.[Kk][Ii][Gg][Zz]$" ) );
+ else
+ return false;
+
+ QString tmpfile = tempdir + tempname + ".kig";
+ QFile ftmpfile( tmpfile );
+ if ( !ftmpfile.open( IO_WriteOnly ) )
+ return false;
+ QTextStream stream( &ftmpfile );
+ if ( !save07( data, stream ) )
+ return false;
+ ftmpfile.close();
+
+ kdDebug() << "tmp saved file: " << tmpfile << endl;
+
+ // creating the archive and adding our file
+ KTar* ark = new KTar( outfile, "application/x-gzip" );
+ ark->open( IO_WriteOnly );
+ ark->addLocalFile( tmpfile, tempname + ".kig" );
+ ark->close();
+
+ // finally, removing temp file
+ QFile::remove( tmpfile );
+
+ return true;
+ }
+ else
+ {
+#endif
+ QFile file( outfile );
+ if ( ! file.open( IO_WriteOnly ) )
+ {
+ fileNotFound( outfile );
+ return false;
+ }
+ QTextStream stream( &file );
+ return save07( data, stream );
+#ifndef KIG_NO_COMPRESSED_FILES
+ }
+
+ // we should never reach this point...
+ return false;
+#endif
+}
+
+/*
+bool KigFilterNative::save( const KigDocument& data, QTextStream& stream )
+{
+ return save07( data, stream );
+}
+*/
diff --git a/kig/filters/native-filter.h b/kig/filters/native-filter.h
new file mode 100644
index 00000000..12778f35
--- /dev/null
+++ b/kig/filters/native-filter.h
@@ -0,0 +1,66 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_FILTERS_NATIVE_FILTER_H
+#define KIG_FILTERS_NATIVE_FILTER_H
+
+#include "filter.h"
+
+class QDomElement;
+class KigDocument;
+class QTextStream;
+class QString;
+
+/**
+ * Kig's native format. Between versions 0.3.1 and 0.4, there was a
+ * change in the file format. This filter no longer supports pre-0.4
+ * formats, it did up until Kig 0.6.
+ */
+class KigFilterNative
+ : public KigFilter
+{
+private:
+ /**
+ * this is the load function for the Kig format that is used,
+ * starting at Kig 0.4
+ */
+ KigDocument* load04( const QString& file, const QDomElement& doc );
+ /**
+ * this is the load function for the Kig format that is used
+ * starting at Kig 0.7
+ */
+ KigDocument* load07( const QString& file, const QDomElement& doc );
+
+ /**
+ * save in the Kig format that is used starting at Kig 0.7
+ */
+ bool save07( const KigDocument& data, const QString& outfile );
+ bool save07( const KigDocument& data, QTextStream& file );
+
+ KigFilterNative();
+ ~KigFilterNative();
+public:
+ static KigFilterNative* instance();
+
+ bool supportMime( const QString& mime );
+ KigDocument* load( const QString& file );
+
+ bool save( const KigDocument& data, const QString& file );
+// bool save( const KigDocument& data, QTextStream& stream );
+};
+
+#endif
diff --git a/kig/filters/svgexporter.cc b/kig/filters/svgexporter.cc
new file mode 100644
index 00000000..6e945de2
--- /dev/null
+++ b/kig/filters/svgexporter.cc
@@ -0,0 +1,111 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "svgexporter.h"
+
+#include "svgexporteroptions.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../misc/common.h"
+#include "../misc/kigfiledialog.h"
+#include "../misc/kigpainter.h"
+
+#include <qcheckbox.h>
+#include <qfile.h>
+#include <qpicture.h>
+#include <qrect.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include <map>
+
+SVGExporter::~SVGExporter()
+{
+}
+
+QString SVGExporter::exportToStatement() const
+{
+ return i18n( "&Export to SVG..." );
+}
+
+QString SVGExporter::menuEntryName() const
+{
+ return i18n( "&SVG..." );
+}
+
+QString SVGExporter::menuIcon() const
+{
+ // TODO
+ return "vectorgfx";
+}
+
+void SVGExporter::run( const KigPart& part, KigWidget& w )
+{
+ KigFileDialog* kfd = new KigFileDialog(
+ QString::null, i18n( "*.svg|Scalable Vector Graphics (*.svg)" ),
+ i18n( "Export as SVG" ), &w );
+ kfd->setOptionCaption( i18n( "SVG Options" ) );
+ SVGExporterOptions* opts = new SVGExporterOptions( 0L );
+ kfd->setOptionsWidget( opts );
+ opts->showGridCheckBox->setChecked( part.document().grid() );
+ opts->showAxesCheckBox->setChecked( part.document().axes() );
+ if ( !kfd->exec() )
+ return;
+
+ QString file_name = kfd->selectedFile();
+ bool showgrid = opts->showGridCheckBox->isOn();
+ bool showaxes = opts->showAxesCheckBox->isOn();
+
+ delete opts;
+ delete kfd;
+
+ QFile file( file_name );
+ if ( ! file.open( IO_WriteOnly ) )
+ {
+ KMessageBox::sorry( &w, i18n( "The file \"%1\" could not be opened. Please "
+ "check if the file permissions are set correctly." )
+ .arg( file_name ) );
+ return;
+ };
+
+ QRect viewrect( w.screenInfo().viewRect() );
+ QRect r( 0, 0, viewrect.width(), viewrect.height() );
+
+ QPicture pic;
+ pic.setBoundingRect( r );
+ KigPainter* p = new KigPainter( ScreenInfo( w.screenInfo().shownRect(), viewrect ),
+ &pic, part.document() );
+// p->setWholeWinOverlay();
+// p->setBrushColor( Qt::white );
+// p->setBrushStyle( Qt::SolidPattern );
+// p->drawRect( r );
+// p->setBrushStyle( Qt::NoBrush );
+// p->setWholeWinOverlay();
+ p->drawGrid( part.document().coordinateSystem(), showgrid, showaxes );
+ p->drawObjects( part.document().objects(), false );
+
+ delete p;
+
+ if ( !pic.save( file_name, "SVG" ) )
+ {
+ KMessageBox::error( &w, i18n( "Sorry, something went wrong while saving to SVG file \"%1\"" ).arg( file_name ) );
+ }
+
+}
diff --git a/kig/filters/svgexporter.h b/kig/filters/svgexporter.h
new file mode 100644
index 00000000..17193673
--- /dev/null
+++ b/kig/filters/svgexporter.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_FILTERS_SVGEXPORTER_H
+#define KIG_FILTERS_SVGEXPORTER_H
+
+#include "exporter.h"
+
+class QString;
+class KigPart;
+class KigWidget;
+
+/**
+ * Export to Scalable Vector Graphics (SVG)
+ */
+class SVGExporter
+ : public KigExporter
+{
+public:
+ ~SVGExporter();
+ QString exportToStatement() const;
+ QString menuEntryName() const;
+ QString menuIcon() const;
+ void run( const KigPart& part, KigWidget& w );
+};
+
+#endif
diff --git a/kig/filters/svgexporteroptions.ui b/kig/filters/svgexporteroptions.ui
new file mode 100644
index 00000000..2de679cb
--- /dev/null
+++ b/kig/filters/svgexporteroptions.ui
@@ -0,0 +1,61 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>SVGExporterOptions</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>SVGExporterOptions</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>440</width>
+ <height>200</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>showGridCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show grid</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="1">
+ <property name="name">
+ <cstring>showAxesCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show axes</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+</includehints>
+</UI>
diff --git a/kig/filters/tests/circleBCP.FIG b/kig/filters/tests/circleBCP.FIG
new file mode 100644
index 00000000..aeaa9689
--- /dev/null
+++ b/kig/filters/tests/circleBCP.FIG
@@ -0,0 +1,24 @@
+FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.89479166666667 0.291041666666667
+
+4: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -1.61395833333333 2.43416666666667
+
+5: Cir, 0, CN:2, VN:2
+Bl, W, t, DS:1 1, GT:0, V, nSt
+Const: 3 4
+
diff --git a/kig/filters/tests/constrainedPoint.FIG b/kig/filters/tests/constrainedPoint.FIG
new file mode 100644
index 00000000..ac086421
--- /dev/null
+++ b/kig/filters/tests/constrainedPoint.FIG
@@ -0,0 +1,24 @@
+FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.18583333333333 1.11125
+
+4: Line, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 3, Val: 0.958665525176453 0.284535429846892
+
+5: Pt/, 0, CN:1, VN:3
+R, W, t, DS:1 1, GT:1, V, nSt
+Const: 4, Val: -2.80458333333333 1.81801369863014
+
diff --git a/kig/filters/tests/cubiclineintersect.kig b/kig/filters/tests/cubiclineintersect.kig
new file mode 100644
index 00000000..a157f611
--- /dev/null
+++ b/kig/filters/tests/cubiclineintersect.kig
@@ -0,0 +1,105 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.6.0" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Objects>
+ <Data internal="true" type="double" id="1" >-5.63522</Data>
+ <Data internal="true" type="double" id="2" >1.0566</Data>
+ <Data internal="true" type="double" id="3" >-1.49686</Data>
+ <Data internal="true" type="double" id="4" >2.33333</Data>
+ <Data internal="true" type="double" id="5" >-1.14465</Data>
+ <Data internal="true" type="double" id="6" >-0.220126</Data>
+ <Data internal="true" type="double" id="7" >-4.66667</Data>
+ <Data internal="true" type="double" id="8" >-1.14465</Data>
+ <Data internal="true" type="double" id="9" >-8.1927</Data>
+ <Data internal="true" type="double" id="10" >-2.01515</Data>
+ <Data internal="true" type="double" id="11" >-8.36478</Data>
+ <Data internal="true" type="double" id="12" >1.36478</Data>
+ <Data internal="true" type="double" id="13" >-7.48428</Data>
+ <Data internal="true" type="double" id="14" >2.64151</Data>
+ <Data internal="true" type="double" id="15" >-4.88679</Data>
+ <Data internal="true" type="double" id="16" >3.12579</Data>
+ <Data internal="true" type="double" id="17" >-3.03774</Data>
+ <Data internal="true" type="double" id="18" >1.49686</Data>
+ <Data internal="true" type="double" id="19" >-6.25157</Data>
+ <Data internal="true" type="double" id="20" >3.91824</Data>
+ <Data internal="true" type="double" id="21" >-2.06918</Data>
+ <Data internal="true" type="double" id="22" >-3.47799</Data>
+ <Data internal="true" type="int" id="23" >1</Data>
+ <Data internal="true" type="int" id="24" >2</Data>
+ <Data internal="true" type="int" id="25" >3</Data>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="26" color="#0000ff" >
+ <Parent id="1" />
+ <Parent id="2" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="27" color="#0000ff" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="28" color="#0000ff" >
+ <Parent id="5" />
+ <Parent id="6" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="29" color="#0000ff" >
+ <Parent id="7" />
+ <Parent id="8" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="30" color="#0000ff" >
+ <Parent id="9" />
+ <Parent id="10" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="31" color="#0000ff" >
+ <Parent id="11" />
+ <Parent id="12" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="32" color="#0000ff" >
+ <Parent id="13" />
+ <Parent id="14" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="33" color="#0000ff" >
+ <Parent id="15" />
+ <Parent id="16" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="34" color="#0000ff" >
+ <Parent id="17" />
+ <Parent id="18" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="35" color="#0000ff" >
+ <Parent id="19" />
+ <Parent id="20" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="36" color="#0000ff" >
+ <Parent id="21" />
+ <Parent id="22" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="CubicB9P" id="37" color="#0000ff" >
+ <Parent id="26" />
+ <Parent id="27" />
+ <Parent id="28" />
+ <Parent id="29" />
+ <Parent id="30" />
+ <Parent id="31" />
+ <Parent id="32" />
+ <Parent id="33" />
+ <Parent id="34" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="LineAB" id="38" color="#0000ff" >
+ <Parent id="35" />
+ <Parent id="36" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="LineCubicIntersection" id="39" color="#0000ff" >
+ <Parent id="37" />
+ <Parent id="38" />
+ <Parent id="23" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="LineCubicIntersection" id="40" color="#0000ff" >
+ <Parent id="37" />
+ <Parent id="38" />
+ <Parent id="24" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="LineCubicIntersection" id="41" color="#0000ff" >
+ <Parent id="37" />
+ <Parent id="38" />
+ <Parent id="25" />
+ </Object>
+ </Objects>
+</KigDocument>
diff --git a/kig/filters/tests/intersectandasymptotestest.kig b/kig/filters/tests/intersectandasymptotestest.kig
new file mode 100644
index 00000000..d521e241
--- /dev/null
+++ b/kig/filters/tests/intersectandasymptotestest.kig
@@ -0,0 +1,111 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.6.0" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Objects>
+ <Data internal="true" type="double" id="1" >-6.73585</Data>
+ <Data internal="true" type="double" id="2" >-1.0566</Data>
+ <Data internal="true" type="double" id="3" >-2.92721</Data>
+ <Data internal="true" type="double" id="4" >2.22373</Data>
+ <Data internal="true" type="double" id="5" >-5.45912</Data>
+ <Data internal="true" type="double" id="6" >4.40252</Data>
+ <Data internal="true" type="double" id="7" >-6.16352</Data>
+ <Data internal="true" type="double" id="8" >2.11321</Data>
+ <Data internal="true" type="int" id="9" >-1</Data>
+ <Data internal="true" type="int" id="10" >1</Data>
+ <Data internal="true" type="double" id="11" >-12.1069</Data>
+ <Data internal="true" type="double" id="12" >1.0566</Data>
+ <Data internal="true" type="double" id="13" >2.50943</Data>
+ <Data internal="true" type="double" id="14" >-1.10063</Data>
+ <Data internal="true" type="int" id="15" >1</Data>
+ <Data internal="true" type="int" id="16" >-1</Data>
+ <Data internal="true" type="double" id="17" >1.84906</Data>
+ <Data internal="true" type="double" id="18" >1.45283</Data>
+ <Data internal="true" type="double" id="19" >7.04403</Data>
+ <Data internal="true" type="double" id="20" >1.49686</Data>
+ <Data internal="true" type="double" id="21" >6.42767</Data>
+ <Data internal="true" type="double" id="22" >-0.440252</Data>
+ <Data internal="true" type="int" id="23" >1</Data>
+ <Data internal="true" type="int" id="24" >-1</Data>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="25" color="#0000ff" >
+ <Parent id="1" />
+ <Parent id="2" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="26" color="#0000ff" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="27" color="#0000ff" >
+ <Parent id="5" />
+ <Parent id="6" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="28" color="#0000ff" >
+ <Parent id="7" />
+ <Parent id="8" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="29" color="#0000ff" >
+ <Parent id="11" />
+ <Parent id="12" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="30" color="#0000ff" >
+ <Parent id="13" />
+ <Parent id="14" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="31" color="#0000ff" >
+ <Parent id="17" />
+ <Parent id="18" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="32" color="#0000ff" >
+ <Parent id="19" />
+ <Parent id="20" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="33" color="#0000ff" >
+ <Parent id="21" />
+ <Parent id="22" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="CircleBCP" id="34" color="#0000ff" >
+ <Parent id="25" />
+ <Parent id="26" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="SegmentAB" id="35" color="#0000ff" >
+ <Parent id="27" />
+ <Parent id="28" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="LineAB" id="36" color="#0000ff" >
+ <Parent id="29" />
+ <Parent id="30" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="HyperbolaBFFP" id="37" color="#0000ff" >
+ <Parent id="31" />
+ <Parent id="32" />
+ <Parent id="33" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicLineIntersection" id="38" color="#0000ff" >
+ <Parent id="34" />
+ <Parent id="35" />
+ <Parent id="9" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicLineIntersection" id="39" color="#0000ff" >
+ <Parent id="34" />
+ <Parent id="35" />
+ <Parent id="10" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicLineIntersection" id="40" color="#0000ff" >
+ <Parent id="34" />
+ <Parent id="36" />
+ <Parent id="15" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicLineIntersection" id="41" color="#0000ff" >
+ <Parent id="34" />
+ <Parent id="36" />
+ <Parent id="16" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicAsymptote" id="42" color="#0000ff" >
+ <Parent id="37" />
+ <Parent id="23" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicAsymptote" id="43" color="#0000ff" >
+ <Parent id="37" />
+ <Parent id="24" />
+ </Object>
+ </Objects>
+</KigDocument>
diff --git a/kig/filters/tests/intersection-test.seg b/kig/filters/tests/intersection-test.seg
new file mode 100644
index 00000000..44d69b70
--- /dev/null
+++ b/kig/filters/tests/intersection-test.seg
Binary files differ
diff --git a/kig/filters/tests/invisibleLine.FIG b/kig/filters/tests/invisibleLine.FIG
new file mode 100644
index 00000000..5eeb6ae3
--- /dev/null
+++ b/kig/filters/tests/invisibleLine.FIG
@@ -0,0 +1,32 @@
+FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.159375 -0.608541666666667
+
+4: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -2.91041666666667 3.54541666666667
+
+5: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 2.19604166666667 0.79375
+
+6: Line, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, I, nSt
+Const: 5 3
+
+7: Perp, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 4 6
+
diff --git a/kig/filters/tests/lineBTP.FIG b/kig/filters/tests/lineBTP.FIG
new file mode 100644
index 00000000..7926b787
--- /dev/null
+++ b/kig/filters/tests/lineBTP.FIG
@@ -0,0 +1,24 @@
+FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.318125 2.16958333333333
+
+4: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -1.29645833333333 3.01625
+
+5: Line, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 3 4
+
diff --git a/kig/filters/tests/linebyonepoint.FIG b/kig/filters/tests/linebyonepoint.FIG
new file mode 100644
index 00000000..4cdac84e
--- /dev/null
+++ b/kig/filters/tests/linebyonepoint.FIG
@@ -0,0 +1,20 @@
+FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.683125 1.93145833333333
+
+4: Line, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 3, Val: 0.972745500001038 0.231875380814201
+
diff --git a/kig/filters/tests/locus.fgeo b/kig/filters/tests/locus.fgeo
new file mode 100644
index 00000000..a914068c
--- /dev/null
+++ b/kig/filters/tests/locus.fgeo
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<drgenius><drgeo name="Figuur 1" scale="30.000000" origin_x="0.000000" origin_y="0.000000" grid="False"><point id="8293DE0" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>-1.666666</x><y>3.216667</y></point><point id="8306C70" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>-2.766667</x><y>0.550000</y></point><circle id="8307268" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name=""><parent ref="8293DE0"/><parent ref="8306C70"/></circle><point id="8309098" type="On_curve" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><value>0.080691</value><parent ref="8307268"/></point><point id="830A920" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>3.000000</x><y>3.016667</y></point><line id="8172970" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name=""><parent ref="8309098"/><parent ref="830A920"/></line><point id="8339730" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>2.866667</x><y>-0.750000</y></point><line id="833AD18" type="2pts" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name=""><parent ref="8309098"/><parent ref="8339730"/></line><point id="8338A50" type="Free" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><x>2.600000</x><y>3.816667</y></point><line id="833BBB8" type="perpendicular" color="Black" thickness="Normal" style="Cross" filled="False" masked="False" name=""><parent ref="8338A50"/><parent ref="833AD18"/></line><point id="8342478" type="Intersection" color="Red" thickness="Dashed" style="Cross" filled="False" masked="False" name="" extra="0"><parent ref="8172970"/><parent ref="833BBB8"/></point><locus id="8345D60" type="None" color="Black" thickness="Dashed" style="Cross" filled="False" masked="False" name=""><parent ref="8309098"/><parent ref="8342478"/></locus></drgeo></drgenius>
diff --git a/kig/filters/tests/lotsOfObjects.FIG b/kig/filters/tests/lotsOfObjects.FIG
new file mode 100644
index 00000000..67b24164
--- /dev/null
+++ b/kig/filters/tests/lotsOfObjects.FIG
@@ -0,0 +1,148 @@
+FIGURE CabriII vers. MS-Windows 1.0
+
+Window center x: 0 y: 0 Window size x: 16.2983333333333 y: 9.68375
+
+1: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, I, nSt
+Val: 0 0
+
+2: Axes, 1, CN:1, VN:3
+Gr, W, t, DS:1 1, GT:0, I, nSt
+Const: 1, Val: 1 0, 0 1
+
+3: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -6.72041666666667 3.94229166666667
+
+4: Line, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 3, Val: -0.0202661071897195 -0.999794621359494
+
+5: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 0.582083333333333 2.35479166666667
+
+6: Line, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 5 3
+
+7: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.78895833333333 -0.661458333333333
+
+8: Seg, 0, CN:2, VN:0
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 5 7
+
+9: Ray, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 7, Val: 0.965226371919943 -0.261415475728318
+
+10: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -2.19604166666667 -2.56645833333333
+
+11: Ray, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 7 10
+
+12: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:0, V, nSt
+Val: -0.687916666666667 -0.820208333333333
+
+13: Vec, 0, CN:2, VN:0
+P, W, t, DS:1 1, GT:0, V, nSt
+Const: 10 12
+
+14: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 3.75708333333333 -0.661458333333333
+
+15: Cir, 0, CN:1, VN:2
+Bl, W, t, DS:1 1, GT:0, V, nSt
+Const: 14, Val: 2.32351774734393
+
+16: Cir, 0, CN:2, VN:2
+Bl, W, t, DS:1 1, GT:0, V, nSt
+Const: 14 5
+
+17: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.70958333333333 2.19604166666667
+
+18: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -6.19125 1.00541666666667
+
+19: Arc, 0, CN:3, VN:4
+R, W, t, DS:1 1, GT:0, V, nSt
+Const: 7 17 18
+
+20: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -2.96333333333333 3.78354166666667
+
+21: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -0.0264583333333333 4.1275
+
+22: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 1.95791666666667 2.69875
+
+23: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: 0.0264583333333333 0.582083333333333
+
+24: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.25979166666667 1.08479166666667
+
+25: Con, 1, CN:5, VN:6
+Bl, W, t, DS:1 1, GT:0, V, nSt
+Const: 20 21 22 23 24
+
+26: Perp, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 14 11
+
+27: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.37104166666667 -2.56645833333333
+
+28: Par, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 27 11
+
+29: Mid, 0, CN:1, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Const: 13
+
+30: Mid, 0, CN:1, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Const: 8
+
+31: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -5.97958333333333 3.254375
+
+32: Mid, 0, CN:2, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Const: 31 18
+
+33: PBiss, 0, CN:1, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 8
+
+34: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -4.55083333333333 -2.460625
+
+35: Pt, 0, CN:0, VN:1
+R, W, t, DS:1 1, GT:1, V, nSt
+Val: -3.889375 -1.71979166666667
+
+36: PBiss, 0, CN:2, VN:2
+V, W, t, DS:1 1, GT:0, V, nSt
+Const: 34 35
+
diff --git a/kig/filters/tests/python-script.kig b/kig/filters/tests/python-script.kig
new file mode 100644
index 00000000..edac8b48
--- /dev/null
+++ b/kig/filters/tests/python-script.kig
@@ -0,0 +1,29 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.5.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Objects>
+ <Data internal="true" type="double" id="1" >-3.93514</Data>
+ <Data internal="true" type="double" id="2" >2.97568</Data>
+ <Data internal="true" type="double" id="3" >-2.03636</Data>
+ <Data internal="true" type="double" id="4" >1.57224</Data>
+ <Data internal="true" type="string" id="5" >def calc( arg1, arg2 ):
+ return Point( ( arg1.coordinate() + arg2.coordinate() ) / 2 )
+</Data>
+ <Object width="-1" internal="false" shown="true" type="FixedPoint" id="6" color="#0000ff" >
+ <Parent id="1" />
+ <Parent id="2" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="FixedPoint" id="7" color="#0000ff" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object width="-1" internal="true" shown="true" type="PythonCompileType" id="8" color="#0000ff" >
+ <Parent id="5" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="PythonExecuteType" id="9" color="#0000ff" >
+ <Parent id="8" />
+ <Parent id="6" />
+ <Parent id="7" />
+ </Object>
+ </Objects>
+</KigDocument>
diff --git a/kig/filters/tests/radicallinestest.kig b/kig/filters/tests/radicallinestest.kig
new file mode 100644
index 00000000..82b1e564
--- /dev/null
+++ b/kig/filters/tests/radicallinestest.kig
@@ -0,0 +1,85 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.6.0" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Objects>
+ <Data internal="true" type="double" id="1" >-3.43396</Data>
+ <Data internal="true" type="double" id="2" >1.54088</Data>
+ <Data internal="true" type="double" id="3" >-1.10063</Data>
+ <Data internal="true" type="double" id="4" >2.01216</Data>
+ <Data internal="true" type="double" id="5" >-0.0880503</Data>
+ <Data internal="true" type="double" id="6" >-0.748428</Data>
+ <Data internal="true" type="double" id="7" >-2.28931</Data>
+ <Data internal="true" type="double" id="8" >0.968553</Data>
+ <Data internal="true" type="double" id="9" >-0.836478</Data>
+ <Data internal="true" type="double" id="10" >4.35849</Data>
+ <Data internal="true" type="int" id="11" >1</Data>
+ <Data internal="true" type="int" id="12" >1</Data>
+ <Data internal="true" type="int" id="13" >-1</Data>
+ <Data internal="true" type="int" id="14" >1</Data>
+ <Data internal="true" type="double" id="15" >5.50314</Data>
+ <Data internal="true" type="double" id="16" >-0.0440252</Data>
+ <Data internal="true" type="double" id="17" >1.01258</Data>
+ <Data internal="true" type="double" id="18" >1.80503</Data>
+ <Data internal="true" type="int" id="19" >1</Data>
+ <Data internal="true" type="int" id="20" >1</Data>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="21" color="#0000ff" >
+ <Parent id="1" />
+ <Parent id="2" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="22" color="#0000ff" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="23" color="#0000ff" >
+ <Parent id="5" />
+ <Parent id="6" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="24" color="#0000ff" >
+ <Parent id="7" />
+ <Parent id="8" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="25" color="#0000ff" >
+ <Parent id="9" />
+ <Parent id="10" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="26" color="#0000ff" >
+ <Parent id="15" />
+ <Parent id="16" />
+ </Object>
+ <Object width="5" internal="false" shown="true" type="FixedPoint" id="27" color="#0000ff" >
+ <Parent id="17" />
+ <Parent id="18" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="CircleBCP" id="28" color="#0000ff" >
+ <Parent id="21" />
+ <Parent id="22" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="CircleBTP" id="29" color="#0000ff" >
+ <Parent id="23" />
+ <Parent id="24" />
+ <Parent id="25" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="CircleBCP" id="30" color="#0000ff" >
+ <Parent id="26" />
+ <Parent id="27" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicRadical" id="31" color="#0000ff" >
+ <Parent id="28" />
+ <Parent id="29" />
+ <Parent id="11" />
+ <Parent id="12" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicRadical" id="32" color="#0000ff" >
+ <Parent id="28" />
+ <Parent id="29" />
+ <Parent id="13" />
+ <Parent id="14" />
+ </Object>
+ <Object width="-1" internal="false" shown="true" type="ConicRadical" id="33" color="#0000ff" >
+ <Parent id="29" />
+ <Parent id="30" />
+ <Parent id="19" />
+ <Parent id="20" />
+ </Object>
+ </Objects>
+</KigDocument>
diff --git a/kig/filters/tests/stylestest.kig b/kig/filters/tests/stylestest.kig
new file mode 100644
index 00000000..f9a91951
--- /dev/null
+++ b/kig/filters/tests/stylestest.kig
@@ -0,0 +1,27 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.7.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Hierarchy>
+ <Data type="double" id="1" >-3.41511</Data>
+ <Data type="double" id="2" >-0.798177</Data>
+ <Data type="double" id="3" >2.53813</Data>
+ <Data type="double" id="4" >3.67781</Data>
+ <Object type="FixedPoint" id="5" >
+ <Parent id="1" />
+ <Parent id="3" />
+ </Object>
+ <Object type="FixedPoint" id="6" >
+ <Parent id="4" />
+ <Parent id="2" />
+ </Object>
+ <Object type="LineAB" id="7" >
+ <Parent id="5" />
+ <Parent id="6" />
+ </Object>
+ </Hierarchy>
+ <View>
+ <Draw width="-1" point-style="Round" style="DashLine" shown="true" color="#0000ff" object="7" />
+ <Draw width="-1" point-style="Cross" style="SolidLine" shown="true" color="#0000ff" object="5" />
+ <Draw width="-1" point-style="RectangularEmpty" style="SolidLine" shown="true" color="#0000ff" object="6" />
+ </View>
+</KigDocument>
diff --git a/kig/filters/tests/test.kgeo b/kig/filters/tests/test.kgeo
new file mode 100644
index 00000000..e0edaa9d
--- /dev/null
+++ b/kig/filters/tests/test.kgeo
@@ -0,0 +1,145 @@
+[Colors]
+Background=255,255,255
+Draw=0,0,0
+
+[Main]
+Axes=true
+Grid=true
+Number=17
+Numbers=true
+Scaling=false
+Version=KGeo 1.0.2
+XMax=11
+YMax=7
+
+[Object 1]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=-3.4
+QPointY=1.3
+Size=3
+
+[Object 10]
+Color=0,0,0
+Geo=31
+Parents=8,9
+Size=1
+
+[Object 11]
+Color=0,0,0
+Geo=27
+Parents=5,7
+Size=1
+
+[Object 12]
+Color=0,0,0
+Geo=29
+Parents=9,5
+Size=1
+
+[Object 13]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=3.8
+QPointY=-1.7
+Size=3
+
+[Object 14]
+Color=0,0,0
+Geo=32
+Parents=13,11
+Position=1
+QPointX=-0.2
+QPointY=-0.3
+Size=3
+
+[Object 15]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=-7.4
+QPointY=7.8
+Size=3
+
+[Object 16]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=-7.4
+QPointY=6.4
+Size=3
+
+[Object 17]
+Color=0,0,0
+Geo=9
+Parents=15,16
+Position=1
+QPointX=-7.4
+QPointY=5
+Size=3
+
+[Object 2]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=-3.4
+QPointY=2.4
+Size=3
+
+[Object 3]
+Color=0,0,0
+Geo=3
+Parents=1,2
+Size=1
+
+[Object 4]
+Color=0,0,0
+Geo=4
+Parents=1,2
+Size=1
+
+[Object 5]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=1.5
+QPointY=3.6
+Size=3
+
+[Object 6]
+Color=0,0,0
+Geo=2
+Parents=1,5
+Size=1
+
+[Object 7]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=-2.5
+QPointY=5
+Size=3
+
+[Object 8]
+Color=0,0,0
+Geo=30
+Parents=6,7
+Size=1
+
+[Object 9]
+Color=0,0,0
+Geo=1
+Parents=
+Position=1
+QPointX=-5.1
+QPointY=-4.1
+Size=3
diff --git a/kig/filters/tests/test.seg b/kig/filters/tests/test.seg
new file mode 100644
index 00000000..d51c281d
--- /dev/null
+++ b/kig/filters/tests/test.seg
Binary files differ
diff --git a/kig/filters/tests/testalotofeverything.kig b/kig/filters/tests/testalotofeverything.kig
new file mode 100644
index 00000000..1e7a5fcb
--- /dev/null
+++ b/kig/filters/tests/testalotofeverything.kig
@@ -0,0 +1,174 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.7.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Hierarchy>
+ <Data type="double" id="1" >4.20683</Data>
+ <Data type="double" id="2" >-1.93144</Data>
+ <Data type="double" id="3" >0.661451</Data>
+ <Data type="double" id="4" >-2.91039</Data>
+ <Data type="double" id="5" >0.694042</Data>
+ <Data type="double" id="6" >-2.38123</Data>
+ <Data type="double" id="7" >-2.27539</Data>
+ <Data type="double" id="8" >3.2808</Data>
+ <Data type="double" id="9" >-0.8202</Data>
+ <Data type="double" id="10" >0.24161</Data>
+ <Data type="double" id="11" >2.0671</Data>
+ <Data type="double" id="12" >5.39744</Data>
+ <Data type="double" id="13" >2.17293</Data>
+ <Data type="double" id="14" >5.39744</Data>
+ <Data type="double" id="15" >-1.66686</Data>
+ <Data type="double" id="16" >-0.0760034</Data>
+ <Data type="double" id="17" >3.09559</Data>
+ <Data type="double" id="18" >0.434012</Data>
+ <Data type="int" id="19" >1</Data>
+ <Data type="double" id="20" >-3.91579</Data>
+ <Data type="double" id="21" >6.42931</Data>
+ <Data type="double" id="22" >4.73936</Data>
+ <Data type="string" id="23" >%1</Data>
+ <Data type="double" id="24" >-1.34936</Data>
+ <Data type="point" id="25" >
+ <x>4.55079</x>
+ <y>3.67767</y>
+ </Data>
+ <Data type="double" id="26" >-1.76794</Data>
+ <Data type="hierarchy" id="27" >
+ <input requirement="point" id="1" />
+ <input requirement="point" id="2" />
+ <input requirement="double" id="3" />
+ <intermediate action="calc" type="LineAB" id="4" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <result action="calc" type="ConstrainedPoint" id="5" >
+ <arg>3</arg>
+ <arg>4</arg>
+ </result>
+ </Data>
+ <Data type="double" id="28" >1.93481</Data>
+ <Data type="string" id="29" >def calc( arg1 ):
+ return Point( arg1.coordinate() + Coordinate( 1,.8))</Data>
+ <Object type="FixedPoint" id="30" >
+ <Parent id="3" />
+ <Parent id="2" />
+ </Object>
+ <Object type="FixedPoint" id="31" >
+ <Parent id="7" />
+ <Parent id="9" />
+ </Object>
+ <Object type="FixedPoint" id="32" >
+ <Parent id="15" />
+ <Parent id="6" />
+ </Object>
+ <Object type="FixedPoint" id="33" >
+ <Parent id="12" />
+ <Parent id="16" />
+ </Object>
+ <Object type="FixedPoint" id="34" >
+ <Parent id="17" />
+ <Parent id="8" />
+ </Object>
+ <Object type="FixedPoint" id="35" >
+ <Parent id="20" />
+ <Parent id="11" />
+ </Object>
+ <Object type="FixedPoint" id="36" >
+ <Parent id="1" />
+ <Parent id="21" />
+ </Object>
+ <Object type="FixedPoint" id="37" >
+ <Parent id="4" />
+ <Parent id="22" />
+ </Object>
+ <Object type="FixedPoint" id="38" >
+ <Parent id="24" />
+ <Parent id="13" />
+ </Object>
+ <Object type="FixedPoint" id="39" >
+ <Parent id="26" />
+ <Parent id="18" />
+ </Object>
+ <Object type="FixedPoint" id="40" >
+ <Parent id="14" />
+ <Parent id="28" />
+ </Object>
+ <Object type="PythonCompileType" id="41" >
+ <Parent id="29" />
+ </Object>
+ <Object type="Vector" id="42" >
+ <Parent id="36" />
+ <Parent id="34" />
+ </Object>
+ <Object type="Vector" id="43" >
+ <Parent id="35" />
+ <Parent id="38" />
+ </Object>
+ <Object type="CircleBCP" id="44" >
+ <Parent id="33" />
+ <Parent id="40" />
+ </Object>
+ <Object type="PythonExecuteType" id="45" >
+ <Parent id="41" />
+ <Parent id="37" />
+ </Object>
+ <Object type="LineByVector" id="46" >
+ <Parent id="43" />
+ <Parent id="37" />
+ </Object>
+ <Object type="VectorEquality" id="47" >
+ <Parent id="43" />
+ <Parent id="42" />
+ </Object>
+ <Object type="ConstrainedPoint" id="48" >
+ <Parent id="10" />
+ <Parent id="44" />
+ </Object>
+ <Object type="Locus" id="49" >
+ <Parent id="27" />
+ <Parent id="44" />
+ <Parent id="39" />
+ <Parent id="5" />
+ </Object>
+ <Property which="test-result" id="50" >
+ <Parent id="47" />
+ </Property>
+ <Object type="LineAB" id="51" >
+ <Parent id="48" />
+ <Parent id="39" />
+ </Object>
+ <Object type="Similitude" id="52" >
+ <Parent id="49" />
+ <Parent id="31" />
+ <Parent id="32" />
+ <Parent id="30" />
+ </Object>
+ <Object type="Label" id="53" >
+ <Parent id="19" />
+ <Parent id="25" />
+ <Parent id="23" />
+ <Parent id="50" />
+ </Object>
+ </Hierarchy>
+ <View>
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="35" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="39" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="48" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="51" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="53" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="30" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="43" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="31" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="38" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="40" />
+ <Draw width="5" point-style="Round" style="SolidLine" shown="true" color="#ffff00" object="52" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="42" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="34" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="32" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="33" />
+ <Draw width="7" point-style="Round" style="DotLine" shown="true" color="#a0a0a4" object="49" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="36" />
+ <Draw width="7" point-style="Round" style="DashDotDotLine" shown="true" color="#00ff00" object="46" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="44" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="37" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="45" />
+ </View>
+</KigDocument>
diff --git a/kig/filters/tests/testlocuswithinvalidpoints.kig b/kig/filters/tests/testlocuswithinvalidpoints.kig
new file mode 100644
index 00000000..6bb3f57d
--- /dev/null
+++ b/kig/filters/tests/testlocuswithinvalidpoints.kig
@@ -0,0 +1,177 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.7.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Hierarchy>
+ <Data type="int" id="1" >0</Data>
+ <Data type="hierarchy" id="2" >
+ <input requirement="point" id="1" />
+ <input requirement="double" id="2" />
+ <input requirement="circle" id="3" />
+ <input requirement="int" id="4" />
+ <intermediate action="calc" type="CircleBPR" id="5" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <intermediate action="calc" type="CircleCircleIntersection" id="6" >
+ <arg>3</arg>
+ <arg>5</arg>
+ <arg>4</arg>
+ </intermediate>
+ <intermediate action="calc" type="SegmentAB" id="7" >
+ <arg>6</arg>
+ <arg>1</arg>
+ </intermediate>
+ <result action="fetch-property" property="mid-point" id="8" >
+ <arg>7</arg>
+ </result>
+ </Data>
+ <Data type="double" id="3" >-1.40273</Data>
+ <Data type="double" id="4" >-0.608162</Data>
+ <Data type="int" id="5" >1</Data>
+ <Data type="int" id="6" >0</Data>
+ <Data type="double" id="7" >1.74813</Data>
+ <Data type="double" id="8" >-8.26962</Data>
+ <Data type="double" id="9" >-2.18736</Data>
+ <Data type="double" id="10" >-9.17811</Data>
+ <Data type="double" id="11" >-8.44019</Data>
+ <Data type="double" id="12" >-9.66304</Data>
+ <Data type="string" id="13" >Q</Data>
+ <Data type="double" id="14" >3.24779</Data>
+ <Data type="double" id="15" >-0.401053</Data>
+ <Data type="double" id="16" >3.41264</Data>
+ <Data type="double" id="17" >-0.327406</Data>
+ <Data type="double" id="18" >2.46458</Data>
+ <Data type="double" id="19" >-9.94648</Data>
+ <Data type="string" id="20" >P</Data>
+ <Data type="double" id="21" >-0.816147</Data>
+ <Data type="int" id="22" >-1</Data>
+ <Data type="double" id="23" >-5.54805</Data>
+ <Data type="double" id="24" >0.177996</Data>
+ <Object type="FixedPoint" id="25" >
+ <Parent id="8" />
+ <Parent id="7" />
+ </Object>
+ <Object type="FixedPoint" id="26" >
+ <Parent id="12" />
+ <Parent id="14" />
+ </Object>
+ <Object type="FixedPoint" id="27" >
+ <Parent id="10" />
+ <Parent id="15" />
+ </Object>
+ <Object type="FixedPoint" id="28" >
+ <Parent id="11" />
+ <Parent id="16" />
+ </Object>
+ <Object type="FixedPoint" id="29" >
+ <Parent id="4" />
+ <Parent id="18" />
+ </Object>
+ <Object type="FixedPoint" id="30" >
+ <Parent id="19" />
+ <Parent id="9" />
+ </Object>
+ <Object type="FixedPoint" id="31" >
+ <Parent id="17" />
+ <Parent id="21" />
+ </Object>
+ <Object type="FixedPoint" id="32" >
+ <Parent id="23" />
+ <Parent id="3" />
+ </Object>
+ <Object type="SegmentAB" id="33" >
+ <Parent id="27" />
+ <Parent id="25" />
+ </Object>
+ <Object type="SegmentAB" id="34" >
+ <Parent id="26" />
+ <Parent id="28" />
+ </Object>
+ <Object type="SegmentAB" id="35" >
+ <Parent id="30" />
+ <Parent id="32" />
+ </Object>
+ <Property which="length" id="36" >
+ <Parent id="33" />
+ </Property>
+ <Property which="length" id="37" >
+ <Parent id="34" />
+ </Property>
+ <Property which="length" id="38" >
+ <Parent id="35" />
+ </Property>
+ <Object type="CircleBPR" id="39" >
+ <Parent id="29" />
+ <Parent id="36" />
+ </Object>
+ <Object type="CircleBPR" id="40" >
+ <Parent id="31" />
+ <Parent id="37" />
+ </Object>
+ <Object type="ConstrainedPoint" id="41" >
+ <Parent id="24" />
+ <Parent id="40" />
+ </Object>
+ <Object type="Locus" id="42" >
+ <Parent id="2" />
+ <Parent id="40" />
+ <Parent id="38" />
+ <Parent id="39" />
+ <Parent id="5" />
+ </Object>
+ <Object type="CircleBPR" id="43" >
+ <Parent id="41" />
+ <Parent id="38" />
+ </Object>
+ <Object type="Label" id="44" >
+ <Parent id="1" />
+ <Parent id="41" />
+ <Parent id="20" />
+ </Object>
+ <Object type="CircleCircleIntersection" id="45" >
+ <Parent id="39" />
+ <Parent id="43" />
+ <Parent id="22" />
+ </Object>
+ <Object type="CircleCircleIntersection" id="46" >
+ <Parent id="39" />
+ <Parent id="43" />
+ <Parent id="5" />
+ </Object>
+ <Object type="SegmentAB" id="47" >
+ <Parent id="46" />
+ <Parent id="41" />
+ </Object>
+ <Property which="mid-point" id="48" >
+ <Parent id="47" />
+ </Property>
+ <Object type="Label" id="49" >
+ <Parent id="6" />
+ <Parent id="48" />
+ <Parent id="13" />
+ </Object>
+ </Hierarchy>
+ <View>
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="44" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="26" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="42" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="43" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="33" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="30" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="46" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="49" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="41" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="31" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="27" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="35" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="28" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="40" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="32" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="39" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="45" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="25" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="29" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="48" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="34" />
+ </View>
+</KigDocument>
diff --git a/kig/filters/tests/testnames.kig b/kig/filters/tests/testnames.kig
new file mode 100644
index 00000000..3fd10730
--- /dev/null
+++ b/kig/filters/tests/testnames.kig
@@ -0,0 +1,62 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.7.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Hierarchy>
+ <Data type="int" id="1" >0</Data>
+ <Data type="double" id="2" >1.3131</Data>
+ <Data type="string" id="3" >%1</Data>
+ <Data type="double" id="4" >-4.04756</Data>
+ <Data type="double" id="5" >4.22311</Data>
+ <Data type="double" id="6" >0.661366</Data>
+ <Data type="int" id="7" >0</Data>
+ <Data type="double" id="8" >0.55381</Data>
+ <Data type="string" id="9" >%1</Data>
+ <Data type="string" id="10" >ab</Data>
+ <Data type="int" id="11" >0</Data>
+ <Data type="string" id="12" >%1</Data>
+ <Data type="string" id="13" >a</Data>
+ <Data type="string" id="14" >b</Data>
+ <Object type="FixedPoint" id="15" >
+ <Parent id="4" />
+ <Parent id="2" />
+ </Object>
+ <Object type="FixedPoint" id="16" >
+ <Parent id="6" />
+ <Parent id="5" />
+ </Object>
+ <Object type="Label" id="17" >
+ <Parent id="11" />
+ <Parent id="15" />
+ <Parent id="12" />
+ <Parent id="14" />
+ </Object>
+ <Object type="SegmentAB" id="18" >
+ <Parent id="15" />
+ <Parent id="16" />
+ </Object>
+ <Object type="Label" id="19" >
+ <Parent id="1" />
+ <Parent id="16" />
+ <Parent id="3" />
+ <Parent id="13" />
+ </Object>
+ <Object type="ConstrainedPoint" id="20" >
+ <Parent id="8" />
+ <Parent id="18" />
+ </Object>
+ <Object type="Label" id="21" >
+ <Parent id="7" />
+ <Parent id="20" />
+ <Parent id="9" />
+ <Parent id="10" />
+ </Object>
+ </Hierarchy>
+ <View>
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="19" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="21" />
+ <Draw width="-1" point-style="Round" namecalcer="10" style="SolidLine" shown="true" color="#0000ff" object="18" />
+ <Draw width="-1" point-style="Round" namecalcer="13" style="SolidLine" shown="true" color="#0000ff" object="16" />
+ <Draw width="-1" point-style="Round" namecalcer="14" style="SolidLine" shown="true" color="#0000ff" object="15" />
+ <Draw width="-1" point-style="Round" namecalcer="none" style="SolidLine" shown="true" color="#0000ff" object="17" />
+ </View>
+</KigDocument>
diff --git a/kig/filters/tests/testtest.kig b/kig/filters/tests/testtest.kig
new file mode 100644
index 00000000..b232d227
--- /dev/null
+++ b/kig/filters/tests/testtest.kig
@@ -0,0 +1,66 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.7.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Hierarchy>
+ <Data type="point" id="1" >
+ <x>0.446592</x>
+ <y>0.0161959</y>
+ </Data>
+ <Data type="double" id="2" >0.278897</Data>
+ <Data type="double" id="3" >-0.288971</Data>
+ <Data type="double" id="4" >0.278897</Data>
+ <Data type="double" id="5" >-2.2855</Data>
+ <Data type="double" id="6" >-2.92606</Data>
+ <Data type="double" id="7" >-3.91425</Data>
+ <Data type="double" id="8" >2.27542</Data>
+ <Data type="int" id="9" >1</Data>
+ <Data type="double" id="10" >0.157621</Data>
+ <Data type="string" id="11" >%1</Data>
+ <Object type="FixedPoint" id="12" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object type="FixedPoint" id="13" >
+ <Parent id="5" />
+ <Parent id="6" />
+ </Object>
+ <Object type="FixedPoint" id="14" >
+ <Parent id="7" />
+ <Parent id="2" />
+ </Object>
+ <Object type="FixedPoint" id="15" >
+ <Parent id="10" />
+ <Parent id="8" />
+ </Object>
+ <Object type="LineAB" id="16" >
+ <Parent id="12" />
+ <Parent id="13" />
+ </Object>
+ <Object type="SegmentAB" id="17" >
+ <Parent id="15" />
+ <Parent id="14" />
+ </Object>
+ <Object type="AreOrthogonal" id="18" >
+ <Parent id="16" />
+ <Parent id="17" />
+ </Object>
+ <Property which="test-result" id="19" >
+ <Parent id="18" />
+ </Property>
+ <Object type="Label" id="20" >
+ <Parent id="9" />
+ <Parent id="1" />
+ <Parent id="11" />
+ <Parent id="19" />
+ </Object>
+ </Hierarchy>
+ <View>
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="14" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="12" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="16" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="13" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="20" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="15" />
+ <Draw width="-1" point-style="Round" style="SolidLine" shown="true" color="#0000ff" object="17" />
+ </View>
+</KigDocument>
diff --git a/kig/filters/tests/transform-test.seg b/kig/filters/tests/transform-test.seg
new file mode 100644
index 00000000..e2dc7219
--- /dev/null
+++ b/kig/filters/tests/transform-test.seg
Binary files differ
diff --git a/kig/filters/tests/transformlocustest.kig b/kig/filters/tests/transformlocustest.kig
new file mode 100644
index 00000000..f9c8500c
--- /dev/null
+++ b/kig/filters/tests/transformlocustest.kig
@@ -0,0 +1,82 @@
+<!DOCTYPE KigDocument>
+<KigDocument Version="0.4.0" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Objects>
+ <Data type="double" id="1" >-4.86</Data>
+ <Data type="double" id="2" >0</Data>
+ <Data type="double" id="3" >-6.93</Data>
+ <Data type="double" id="4" >0.42</Data>
+ <Data type="double" id="5" >0.346818</Data>
+ <Data type="double" id="6" >0.12</Data>
+ <Data type="double" id="7" >4.14</Data>
+ <Data type="double" id="8" >0.698969</Data>
+ <Data type="hierarchy" id="9" >
+ <input requirement="point" id="1" />
+ <input requirement="point" id="2" />
+ <input requirement="double" id="3" />
+ <intermediate action="calc" type="LineAB" id="4" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <result action="calc" type="ConstrainedPoint" id="5" >
+ <arg>3</arg>
+ <arg>4</arg>
+ </result>
+ </Data>
+ <Data type="double" id="10" >0.15</Data>
+ <Data type="double" id="11" >0</Data>
+ <Data type="double" id="12" >3.63</Data>
+ <Data type="double" id="13" >-0.12</Data>
+ <Object width="-1" shown="true" type="FixedPoint" id="14" color="#0000ff" >
+ <Parent id="1" />
+ <Parent id="2" />
+ </Object>
+ <Object width="-1" shown="true" type="FixedPoint" id="15" color="#0000ff" >
+ <Parent id="3" />
+ <Parent id="4" />
+ </Object>
+ <Object width="-1" shown="true" type="FixedPoint" id="16" color="#0000ff" >
+ <Parent id="6" />
+ <Parent id="7" />
+ </Object>
+ <Object width="-1" shown="true" type="FixedPoint" id="17" color="#0000ff" >
+ <Parent id="10" />
+ <Parent id="11" />
+ </Object>
+ <Object width="-1" shown="true" type="FixedPoint" id="18" color="#0000ff" >
+ <Parent id="12" />
+ <Parent id="13" />
+ </Object>
+ <Object width="-1" shown="true" type="CircleBCP" id="19" color="#0000ff" >
+ <Parent id="14" />
+ <Parent id="15" />
+ </Object>
+ <Object width="-1" shown="true" type="SegmentAB" id="20" color="#0000ff" >
+ <Parent id="17" />
+ <Parent id="18" />
+ </Object>
+ <Object width="-1" shown="true" type="ConstrainedPoint" id="21" color="#0000ff" >
+ <Parent id="5" />
+ <Parent id="19" />
+ </Object>
+ <Object width="-1" shown="true" type="Locus" id="22" color="#0000ff" >
+ <Parent id="19" />
+ <Parent id="9" />
+ <Parent id="16" />
+ <Parent id="8" />
+ </Object>
+ <Object width="-1" shown="true" type="LineAB" id="23" color="#0000ff" >
+ <Parent id="21" />
+ <Parent id="16" />
+ </Object>
+ <Object width="-1" shown="true" type="ConstrainedPoint" id="24" color="#0000ff" >
+ <Parent id="8" />
+ <Parent id="23" />
+ </Object>
+ <Object width="-1" shown="true" type="ScalingOverLine" id="25" color="#0000ff" >
+ <Parent id="22" />
+ <Parent id="23" />
+ <Parent id="20" />
+ </Object>
+ </Objects>
+</KigDocument>
diff --git a/kig/gencontributors.sh b/kig/gencontributors.sh
new file mode 100644
index 00000000..f73ba22c
--- /dev/null
+++ b/kig/gencontributors.sh
@@ -0,0 +1,9 @@
+tempfile=`tempfile`
+cat kig/aboutdata.h | sed -ne '/tmp->addAuthor/,/setTranslator/p' | sed -e '$d' > $tempfile
+tempfile2=`tempfile`
+cat $tempfile | tr $'\n' " " | sed -e 's/"[[:blank:]]*"//g' | sed -e 's/I18N_NOOP([[:blank:]]*\("[^"]*"\)[[:blank:]]*)/\1/g' | sed -e 's/,[[:blank:]]*"/, "/g' | sed -e 's/^[[:blank:]]*//g' | sed -e 's/;[[:blank:]]*/\n/g' > $tempfile2
+cat $tempfile2 | grep addAuthor | sed -e 's/tmp->addAuthor(\([^,]*\), "[^"]*",\([^)]*\))/ $appinfo->addAuthor(\1,\2);/g' | sed -e 's/@/ AT /g' | sed -e 's/\./ DOT /g'
+cat $tempfile2 | sed -e 's/[^(]*(\([^,]*\), \("[^"]*"\), \([^)]*\))/ $appinfo->addContributor( \1, \3, \2 );/g'
+
+rm $tempfile
+rm $tempfile2
diff --git a/kig/generate_todo_inc.pl b/kig/generate_todo_inc.pl
new file mode 100644
index 00000000..6999f217
--- /dev/null
+++ b/kig/generate_todo_inc.pl
@@ -0,0 +1,26 @@
+#! /usr/bin/env perl
+
+use warnings;
+
+print "<ul>\n";
+open( TODO, "<TODO" );
+while( <TODO> )
+ {
+ if( /^\* (.*)$/ )
+ {
+ print "</li></ul></li>\n\n" if( $inlist );
+ print "<li><span style=\"font-weight:bold\">$1</span><br/>\n";
+ $inlist = 0;
+ $initem = 0;
+ }
+ elsif( /^- (.*)$/ )
+ {
+ if( $initem ) { print "</li>"; };
+ print "<ul>\n" if( ! $inlist );
+ $inlist = 1;
+ print "<li>$1\n";
+ $initem = 1;
+ }
+ else { print unless /^$/; }
+ };
+print "</li></ul></li></ul>\n";
diff --git a/kig/icons/Makefile.am b/kig/icons/Makefile.am
new file mode 100644
index 00000000..c98325ed
--- /dev/null
+++ b/kig/icons/Makefile.am
@@ -0,0 +1,2 @@
+appicondir = $(kde_datadir)/kig/icons
+appicon_ICON = AUTO
diff --git a/kig/icons/hi16-action-kig_xfig.png b/kig/icons/hi16-action-kig_xfig.png
new file mode 100644
index 00000000..48f00f63
--- /dev/null
+++ b/kig/icons/hi16-action-kig_xfig.png
Binary files differ
diff --git a/kig/icons/hi22-action-angle.png b/kig/icons/hi22-action-angle.png
new file mode 100644
index 00000000..ec31b4fb
--- /dev/null
+++ b/kig/icons/hi22-action-angle.png
Binary files differ
diff --git a/kig/icons/hi22-action-angle_bisector.png b/kig/icons/hi22-action-angle_bisector.png
new file mode 100644
index 00000000..790d2985
--- /dev/null
+++ b/kig/icons/hi22-action-angle_bisector.png
Binary files differ
diff --git a/kig/icons/hi22-action-angle_size.png b/kig/icons/hi22-action-angle_size.png
new file mode 100644
index 00000000..4ee03ab5
--- /dev/null
+++ b/kig/icons/hi22-action-angle_size.png
Binary files differ
diff --git a/kig/icons/hi22-action-arc.png b/kig/icons/hi22-action-arc.png
new file mode 100644
index 00000000..61c161e9
--- /dev/null
+++ b/kig/icons/hi22-action-arc.png
Binary files differ
diff --git a/kig/icons/hi22-action-arc_center.png b/kig/icons/hi22-action-arc_center.png
new file mode 100644
index 00000000..f16a4b18
--- /dev/null
+++ b/kig/icons/hi22-action-arc_center.png
Binary files differ
diff --git a/kig/icons/hi22-action-areaCircle.png b/kig/icons/hi22-action-areaCircle.png
new file mode 100644
index 00000000..07a54ed2
--- /dev/null
+++ b/kig/icons/hi22-action-areaCircle.png
Binary files differ
diff --git a/kig/icons/hi22-action-attacher.png b/kig/icons/hi22-action-attacher.png
new file mode 100644
index 00000000..ef9b1814
--- /dev/null
+++ b/kig/icons/hi22-action-attacher.png
Binary files differ
diff --git a/kig/icons/hi22-action-baseCircle.png b/kig/icons/hi22-action-baseCircle.png
new file mode 100644
index 00000000..20692aae
--- /dev/null
+++ b/kig/icons/hi22-action-baseCircle.png
Binary files differ
diff --git a/kig/icons/hi22-action-bisection.png b/kig/icons/hi22-action-bisection.png
new file mode 100644
index 00000000..406dc2d8
--- /dev/null
+++ b/kig/icons/hi22-action-bisection.png
Binary files differ
diff --git a/kig/icons/hi22-action-centerofcurvature.png b/kig/icons/hi22-action-centerofcurvature.png
new file mode 100644
index 00000000..1cf73f96
--- /dev/null
+++ b/kig/icons/hi22-action-centerofcurvature.png
Binary files differ
diff --git a/kig/icons/hi22-action-centralsymmetry.png b/kig/icons/hi22-action-centralsymmetry.png
new file mode 100644
index 00000000..e2d4f635
--- /dev/null
+++ b/kig/icons/hi22-action-centralsymmetry.png
Binary files differ
diff --git a/kig/icons/hi22-action-circlebcl.png b/kig/icons/hi22-action-circlebcl.png
new file mode 100644
index 00000000..71b2e663
--- /dev/null
+++ b/kig/icons/hi22-action-circlebcl.png
Binary files differ
diff --git a/kig/icons/hi22-action-circlebcp.png b/kig/icons/hi22-action-circlebcp.png
new file mode 100644
index 00000000..7697c2bc
--- /dev/null
+++ b/kig/icons/hi22-action-circlebcp.png
Binary files differ
diff --git a/kig/icons/hi22-action-circlebpd.png b/kig/icons/hi22-action-circlebpd.png
new file mode 100644
index 00000000..d36fadb6
--- /dev/null
+++ b/kig/icons/hi22-action-circlebpd.png
Binary files differ
diff --git a/kig/icons/hi22-action-circlebps.png b/kig/icons/hi22-action-circlebps.png
new file mode 100644
index 00000000..0b05d686
--- /dev/null
+++ b/kig/icons/hi22-action-circlebps.png
Binary files differ
diff --git a/kig/icons/hi22-action-circlebtp.png b/kig/icons/hi22-action-circlebtp.png
new file mode 100644
index 00000000..a0f124f0
--- /dev/null
+++ b/kig/icons/hi22-action-circlebtp.png
Binary files differ
diff --git a/kig/icons/hi22-action-circlelineintersection.png b/kig/icons/hi22-action-circlelineintersection.png
new file mode 100644
index 00000000..158d1115
--- /dev/null
+++ b/kig/icons/hi22-action-circlelineintersection.png
Binary files differ
diff --git a/kig/icons/hi22-action-circumference.png b/kig/icons/hi22-action-circumference.png
new file mode 100644
index 00000000..6b043838
--- /dev/null
+++ b/kig/icons/hi22-action-circumference.png
Binary files differ
diff --git a/kig/icons/hi22-action-conicasymptotes.png b/kig/icons/hi22-action-conicasymptotes.png
new file mode 100644
index 00000000..c86d3590
--- /dev/null
+++ b/kig/icons/hi22-action-conicasymptotes.png
Binary files differ
diff --git a/kig/icons/hi22-action-conicb5p.png b/kig/icons/hi22-action-conicb5p.png
new file mode 100644
index 00000000..90c9dd2f
--- /dev/null
+++ b/kig/icons/hi22-action-conicb5p.png
Binary files differ
diff --git a/kig/icons/hi22-action-coniclineintersection.png b/kig/icons/hi22-action-coniclineintersection.png
new file mode 100644
index 00000000..94f9b5fd
--- /dev/null
+++ b/kig/icons/hi22-action-coniclineintersection.png
Binary files differ
diff --git a/kig/icons/hi22-action-conicsradicalline.png b/kig/icons/hi22-action-conicsradicalline.png
new file mode 100644
index 00000000..7b145143
--- /dev/null
+++ b/kig/icons/hi22-action-conicsradicalline.png
Binary files differ
diff --git a/kig/icons/hi22-action-convexhull.png b/kig/icons/hi22-action-convexhull.png
new file mode 100644
index 00000000..f75978f7
--- /dev/null
+++ b/kig/icons/hi22-action-convexhull.png
Binary files differ
diff --git a/kig/icons/hi22-action-curvelineintersection.png b/kig/icons/hi22-action-curvelineintersection.png
new file mode 100644
index 00000000..259f8c0c
--- /dev/null
+++ b/kig/icons/hi22-action-curvelineintersection.png
Binary files differ
diff --git a/kig/icons/hi22-action-directrix.png b/kig/icons/hi22-action-directrix.png
new file mode 100644
index 00000000..f944ba62
--- /dev/null
+++ b/kig/icons/hi22-action-directrix.png
Binary files differ
diff --git a/kig/icons/hi22-action-distance.png b/kig/icons/hi22-action-distance.png
new file mode 100644
index 00000000..f6b7cd6e
--- /dev/null
+++ b/kig/icons/hi22-action-distance.png
Binary files differ
diff --git a/kig/icons/hi22-action-ellipsebffp.png b/kig/icons/hi22-action-ellipsebffp.png
new file mode 100644
index 00000000..93d38018
--- /dev/null
+++ b/kig/icons/hi22-action-ellipsebffp.png
Binary files differ
diff --git a/kig/icons/hi22-action-en.png b/kig/icons/hi22-action-en.png
new file mode 100644
index 00000000..435e3386
--- /dev/null
+++ b/kig/icons/hi22-action-en.png
Binary files differ
diff --git a/kig/icons/hi22-action-equilateralhyperbolab4p.png b/kig/icons/hi22-action-equilateralhyperbolab4p.png
new file mode 100644
index 00000000..1a30b464
--- /dev/null
+++ b/kig/icons/hi22-action-equilateralhyperbolab4p.png
Binary files differ
diff --git a/kig/icons/hi22-action-equitriangle.png b/kig/icons/hi22-action-equitriangle.png
new file mode 100644
index 00000000..76bd910a
--- /dev/null
+++ b/kig/icons/hi22-action-equitriangle.png
Binary files differ
diff --git a/kig/icons/hi22-action-genericaffinity.png b/kig/icons/hi22-action-genericaffinity.png
new file mode 100644
index 00000000..41fb2ae2
--- /dev/null
+++ b/kig/icons/hi22-action-genericaffinity.png
Binary files differ
diff --git a/kig/icons/hi22-action-genericprojectivity.png b/kig/icons/hi22-action-genericprojectivity.png
new file mode 100644
index 00000000..f43a1815
--- /dev/null
+++ b/kig/icons/hi22-action-genericprojectivity.png
Binary files differ
diff --git a/kig/icons/hi22-action-halflinebyvector.png b/kig/icons/hi22-action-halflinebyvector.png
new file mode 100644
index 00000000..a1046e48
--- /dev/null
+++ b/kig/icons/hi22-action-halflinebyvector.png
Binary files differ
diff --git a/kig/icons/hi22-action-harmonichomology.png b/kig/icons/hi22-action-harmonichomology.png
new file mode 100644
index 00000000..25b15086
--- /dev/null
+++ b/kig/icons/hi22-action-harmonichomology.png
Binary files differ
diff --git a/kig/icons/hi22-action-hexagonbcv.png b/kig/icons/hi22-action-hexagonbcv.png
new file mode 100644
index 00000000..3f87bfa9
--- /dev/null
+++ b/kig/icons/hi22-action-hexagonbcv.png
Binary files differ
diff --git a/kig/icons/hi22-action-hyperbolabffp.png b/kig/icons/hi22-action-hyperbolabffp.png
new file mode 100644
index 00000000..5dfcb7e3
--- /dev/null
+++ b/kig/icons/hi22-action-hyperbolabffp.png
Binary files differ
diff --git a/kig/icons/hi22-action-intersection.png b/kig/icons/hi22-action-intersection.png
new file mode 100644
index 00000000..1e460abc
--- /dev/null
+++ b/kig/icons/hi22-action-intersection.png
Binary files differ
diff --git a/kig/icons/hi22-action-inversion.png b/kig/icons/hi22-action-inversion.png
new file mode 100644
index 00000000..ab8e61d7
--- /dev/null
+++ b/kig/icons/hi22-action-inversion.png
Binary files differ
diff --git a/kig/icons/hi22-action-kig_polygon.png b/kig/icons/hi22-action-kig_polygon.png
new file mode 100644
index 00000000..67c9f102
--- /dev/null
+++ b/kig/icons/hi22-action-kig_polygon.png
Binary files differ
diff --git a/kig/icons/hi22-action-kig_text.png b/kig/icons/hi22-action-kig_text.png
new file mode 100644
index 00000000..ff32a431
--- /dev/null
+++ b/kig/icons/hi22-action-kig_text.png
Binary files differ
diff --git a/kig/icons/hi22-action-line.png b/kig/icons/hi22-action-line.png
new file mode 100644
index 00000000..867cba2f
--- /dev/null
+++ b/kig/icons/hi22-action-line.png
Binary files differ
diff --git a/kig/icons/hi22-action-linebyvector.png b/kig/icons/hi22-action-linebyvector.png
new file mode 100644
index 00000000..34671d5f
--- /dev/null
+++ b/kig/icons/hi22-action-linebyvector.png
Binary files differ
diff --git a/kig/icons/hi22-action-locus.png b/kig/icons/hi22-action-locus.png
new file mode 100644
index 00000000..f5759d4a
--- /dev/null
+++ b/kig/icons/hi22-action-locus.png
Binary files differ
diff --git a/kig/icons/hi22-action-mirrorpoint.png b/kig/icons/hi22-action-mirrorpoint.png
new file mode 100644
index 00000000..80572a73
--- /dev/null
+++ b/kig/icons/hi22-action-mirrorpoint.png
Binary files differ
diff --git a/kig/icons/hi22-action-move.png b/kig/icons/hi22-action-move.png
new file mode 100644
index 00000000..24820ff8
--- /dev/null
+++ b/kig/icons/hi22-action-move.png
Binary files differ
diff --git a/kig/icons/hi22-action-paint.png b/kig/icons/hi22-action-paint.png
new file mode 100644
index 00000000..3114b729
--- /dev/null
+++ b/kig/icons/hi22-action-paint.png
Binary files differ
diff --git a/kig/icons/hi22-action-parabolabtp.png b/kig/icons/hi22-action-parabolabtp.png
new file mode 100644
index 00000000..502ef8fa
--- /dev/null
+++ b/kig/icons/hi22-action-parabolabtp.png
Binary files differ
diff --git a/kig/icons/hi22-action-parallel.png b/kig/icons/hi22-action-parallel.png
new file mode 100644
index 00000000..81ee7bf9
--- /dev/null
+++ b/kig/icons/hi22-action-parallel.png
Binary files differ
diff --git a/kig/icons/hi22-action-perpendicular.png b/kig/icons/hi22-action-perpendicular.png
new file mode 100644
index 00000000..ad8643dd
--- /dev/null
+++ b/kig/icons/hi22-action-perpendicular.png
Binary files differ
diff --git a/kig/icons/hi22-action-point.png b/kig/icons/hi22-action-point.png
new file mode 100644
index 00000000..20429af9
--- /dev/null
+++ b/kig/icons/hi22-action-point.png
Binary files differ
diff --git a/kig/icons/hi22-action-pointOnLine.png b/kig/icons/hi22-action-pointOnLine.png
new file mode 100644
index 00000000..c7928747
--- /dev/null
+++ b/kig/icons/hi22-action-pointOnLine.png
Binary files differ
diff --git a/kig/icons/hi22-action-pointxy.png b/kig/icons/hi22-action-pointxy.png
new file mode 100644
index 00000000..779e00f1
--- /dev/null
+++ b/kig/icons/hi22-action-pointxy.png
Binary files differ
diff --git a/kig/icons/hi22-action-polygonsides.png b/kig/icons/hi22-action-polygonsides.png
new file mode 100644
index 00000000..279ba34a
--- /dev/null
+++ b/kig/icons/hi22-action-polygonsides.png
Binary files differ
diff --git a/kig/icons/hi22-action-polygonvertices.png b/kig/icons/hi22-action-polygonvertices.png
new file mode 100644
index 00000000..f13d1b52
--- /dev/null
+++ b/kig/icons/hi22-action-polygonvertices.png
Binary files differ
diff --git a/kig/icons/hi22-action-python.png b/kig/icons/hi22-action-python.png
new file mode 100644
index 00000000..32c621e9
--- /dev/null
+++ b/kig/icons/hi22-action-python.png
Binary files differ
diff --git a/kig/icons/hi22-action-radicalline.png b/kig/icons/hi22-action-radicalline.png
new file mode 100644
index 00000000..8ba5cfdb
--- /dev/null
+++ b/kig/icons/hi22-action-radicalline.png
Binary files differ
diff --git a/kig/icons/hi22-action-ray.png b/kig/icons/hi22-action-ray.png
new file mode 100644
index 00000000..7efa138d
--- /dev/null
+++ b/kig/icons/hi22-action-ray.png
Binary files differ
diff --git a/kig/icons/hi22-action-rotation.png b/kig/icons/hi22-action-rotation.png
new file mode 100644
index 00000000..8eb81599
--- /dev/null
+++ b/kig/icons/hi22-action-rotation.png
Binary files differ
diff --git a/kig/icons/hi22-action-scale.png b/kig/icons/hi22-action-scale.png
new file mode 100644
index 00000000..7196ed73
--- /dev/null
+++ b/kig/icons/hi22-action-scale.png
Binary files differ
diff --git a/kig/icons/hi22-action-segment.png b/kig/icons/hi22-action-segment.png
new file mode 100644
index 00000000..e0510b1a
--- /dev/null
+++ b/kig/icons/hi22-action-segment.png
Binary files differ
diff --git a/kig/icons/hi22-action-segment_midpoint.png b/kig/icons/hi22-action-segment_midpoint.png
new file mode 100644
index 00000000..475ca7ae
--- /dev/null
+++ b/kig/icons/hi22-action-segment_midpoint.png
Binary files differ
diff --git a/kig/icons/hi22-action-segmentaxis.png b/kig/icons/hi22-action-segmentaxis.png
new file mode 100644
index 00000000..15b4d6fc
--- /dev/null
+++ b/kig/icons/hi22-action-segmentaxis.png
Binary files differ
diff --git a/kig/icons/hi22-action-similitude.png b/kig/icons/hi22-action-similitude.png
new file mode 100644
index 00000000..79c4116f
--- /dev/null
+++ b/kig/icons/hi22-action-similitude.png
Binary files differ
diff --git a/kig/icons/hi22-action-sizer.png b/kig/icons/hi22-action-sizer.png
new file mode 100644
index 00000000..92b1b029
--- /dev/null
+++ b/kig/icons/hi22-action-sizer.png
Binary files differ
diff --git a/kig/icons/hi22-action-slope.png b/kig/icons/hi22-action-slope.png
new file mode 100644
index 00000000..66ffe77c
--- /dev/null
+++ b/kig/icons/hi22-action-slope.png
Binary files differ
diff --git a/kig/icons/hi22-action-square.png b/kig/icons/hi22-action-square.png
new file mode 100644
index 00000000..251d5542
--- /dev/null
+++ b/kig/icons/hi22-action-square.png
Binary files differ
diff --git a/kig/icons/hi22-action-stretch.png b/kig/icons/hi22-action-stretch.png
new file mode 100644
index 00000000..250ecaae
--- /dev/null
+++ b/kig/icons/hi22-action-stretch.png
Binary files differ
diff --git a/kig/icons/hi22-action-tangent.png b/kig/icons/hi22-action-tangent.png
new file mode 100644
index 00000000..dce7d6ea
--- /dev/null
+++ b/kig/icons/hi22-action-tangent.png
Binary files differ
diff --git a/kig/icons/hi22-action-test.png b/kig/icons/hi22-action-test.png
new file mode 100644
index 00000000..252e4e68
--- /dev/null
+++ b/kig/icons/hi22-action-test.png
Binary files differ
diff --git a/kig/icons/hi22-action-testcollinear.png b/kig/icons/hi22-action-testcollinear.png
new file mode 100644
index 00000000..02b03978
--- /dev/null
+++ b/kig/icons/hi22-action-testcollinear.png
Binary files differ
diff --git a/kig/icons/hi22-action-testcontains.png b/kig/icons/hi22-action-testcontains.png
new file mode 100644
index 00000000..4abac538
--- /dev/null
+++ b/kig/icons/hi22-action-testcontains.png
Binary files differ
diff --git a/kig/icons/hi22-action-testdistance.png b/kig/icons/hi22-action-testdistance.png
new file mode 100644
index 00000000..e32c4353
--- /dev/null
+++ b/kig/icons/hi22-action-testdistance.png
Binary files differ
diff --git a/kig/icons/hi22-action-testorthogonal.png b/kig/icons/hi22-action-testorthogonal.png
new file mode 100644
index 00000000..9d768baa
--- /dev/null
+++ b/kig/icons/hi22-action-testorthogonal.png
Binary files differ
diff --git a/kig/icons/hi22-action-testparallel.png b/kig/icons/hi22-action-testparallel.png
new file mode 100644
index 00000000..73fe257f
--- /dev/null
+++ b/kig/icons/hi22-action-testparallel.png
Binary files differ
diff --git a/kig/icons/hi22-action-translation.png b/kig/icons/hi22-action-translation.png
new file mode 100644
index 00000000..d5f670ab
--- /dev/null
+++ b/kig/icons/hi22-action-translation.png
Binary files differ
diff --git a/kig/icons/hi22-action-triangle.png b/kig/icons/hi22-action-triangle.png
new file mode 100644
index 00000000..688a00ed
--- /dev/null
+++ b/kig/icons/hi22-action-triangle.png
Binary files differ
diff --git a/kig/icons/hi22-action-vector.png b/kig/icons/hi22-action-vector.png
new file mode 100644
index 00000000..49ef6ac9
--- /dev/null
+++ b/kig/icons/hi22-action-vector.png
Binary files differ
diff --git a/kig/icons/hi22-action-vectordifference.png b/kig/icons/hi22-action-vectordifference.png
new file mode 100644
index 00000000..38cb1dd6
--- /dev/null
+++ b/kig/icons/hi22-action-vectordifference.png
Binary files differ
diff --git a/kig/icons/hi22-action-vectorsum.png b/kig/icons/hi22-action-vectorsum.png
new file mode 100644
index 00000000..95d38c98
--- /dev/null
+++ b/kig/icons/hi22-action-vectorsum.png
Binary files differ
diff --git a/kig/icons/hi22-action-view_fit_to_page.png b/kig/icons/hi22-action-view_fit_to_page.png
new file mode 100644
index 00000000..2e850c91
--- /dev/null
+++ b/kig/icons/hi22-action-view_fit_to_page.png
Binary files differ
diff --git a/kig/icons/hi22-action-w.png b/kig/icons/hi22-action-w.png
new file mode 100644
index 00000000..1c781187
--- /dev/null
+++ b/kig/icons/hi22-action-w.png
Binary files differ
diff --git a/kig/icons/hi32-action-angle.png b/kig/icons/hi32-action-angle.png
new file mode 100644
index 00000000..95eceec3
--- /dev/null
+++ b/kig/icons/hi32-action-angle.png
Binary files differ
diff --git a/kig/icons/hi32-action-angle_bisector.png b/kig/icons/hi32-action-angle_bisector.png
new file mode 100644
index 00000000..24461aab
--- /dev/null
+++ b/kig/icons/hi32-action-angle_bisector.png
Binary files differ
diff --git a/kig/icons/hi32-action-angle_size.png b/kig/icons/hi32-action-angle_size.png
new file mode 100644
index 00000000..a76c84e2
--- /dev/null
+++ b/kig/icons/hi32-action-angle_size.png
Binary files differ
diff --git a/kig/icons/hi32-action-arc.png b/kig/icons/hi32-action-arc.png
new file mode 100644
index 00000000..0f7effd0
--- /dev/null
+++ b/kig/icons/hi32-action-arc.png
Binary files differ
diff --git a/kig/icons/hi32-action-arc_center.png b/kig/icons/hi32-action-arc_center.png
new file mode 100644
index 00000000..4a64172b
--- /dev/null
+++ b/kig/icons/hi32-action-arc_center.png
Binary files differ
diff --git a/kig/icons/hi32-action-areaCircle.png b/kig/icons/hi32-action-areaCircle.png
new file mode 100644
index 00000000..4908ca91
--- /dev/null
+++ b/kig/icons/hi32-action-areaCircle.png
Binary files differ
diff --git a/kig/icons/hi32-action-attacher.png b/kig/icons/hi32-action-attacher.png
new file mode 100644
index 00000000..bc66fd40
--- /dev/null
+++ b/kig/icons/hi32-action-attacher.png
Binary files differ
diff --git a/kig/icons/hi32-action-baseCircle.png b/kig/icons/hi32-action-baseCircle.png
new file mode 100644
index 00000000..03c22c3b
--- /dev/null
+++ b/kig/icons/hi32-action-baseCircle.png
Binary files differ
diff --git a/kig/icons/hi32-action-bisection.png b/kig/icons/hi32-action-bisection.png
new file mode 100644
index 00000000..fe24f5e2
--- /dev/null
+++ b/kig/icons/hi32-action-bisection.png
Binary files differ
diff --git a/kig/icons/hi32-action-centerofcurvature.png b/kig/icons/hi32-action-centerofcurvature.png
new file mode 100644
index 00000000..a5e089af
--- /dev/null
+++ b/kig/icons/hi32-action-centerofcurvature.png
Binary files differ
diff --git a/kig/icons/hi32-action-centralsymmetry.png b/kig/icons/hi32-action-centralsymmetry.png
new file mode 100644
index 00000000..222c06ca
--- /dev/null
+++ b/kig/icons/hi32-action-centralsymmetry.png
Binary files differ
diff --git a/kig/icons/hi32-action-circlebcl.png b/kig/icons/hi32-action-circlebcl.png
new file mode 100644
index 00000000..73ee7909
--- /dev/null
+++ b/kig/icons/hi32-action-circlebcl.png
Binary files differ
diff --git a/kig/icons/hi32-action-circlebcp.png b/kig/icons/hi32-action-circlebcp.png
new file mode 100644
index 00000000..91f0e6ec
--- /dev/null
+++ b/kig/icons/hi32-action-circlebcp.png
Binary files differ
diff --git a/kig/icons/hi32-action-circlebpd.png b/kig/icons/hi32-action-circlebpd.png
new file mode 100644
index 00000000..e51dda03
--- /dev/null
+++ b/kig/icons/hi32-action-circlebpd.png
Binary files differ
diff --git a/kig/icons/hi32-action-circlebps.png b/kig/icons/hi32-action-circlebps.png
new file mode 100644
index 00000000..c1c054ac
--- /dev/null
+++ b/kig/icons/hi32-action-circlebps.png
Binary files differ
diff --git a/kig/icons/hi32-action-circlebtp.png b/kig/icons/hi32-action-circlebtp.png
new file mode 100644
index 00000000..a0e438e4
--- /dev/null
+++ b/kig/icons/hi32-action-circlebtp.png
Binary files differ
diff --git a/kig/icons/hi32-action-circlelineintersection.png b/kig/icons/hi32-action-circlelineintersection.png
new file mode 100644
index 00000000..fbd65d4e
--- /dev/null
+++ b/kig/icons/hi32-action-circlelineintersection.png
Binary files differ
diff --git a/kig/icons/hi32-action-circumference.png b/kig/icons/hi32-action-circumference.png
new file mode 100644
index 00000000..7af7f209
--- /dev/null
+++ b/kig/icons/hi32-action-circumference.png
Binary files differ
diff --git a/kig/icons/hi32-action-conicasymptotes.png b/kig/icons/hi32-action-conicasymptotes.png
new file mode 100644
index 00000000..bd9feaeb
--- /dev/null
+++ b/kig/icons/hi32-action-conicasymptotes.png
Binary files differ
diff --git a/kig/icons/hi32-action-conicb5p.png b/kig/icons/hi32-action-conicb5p.png
new file mode 100644
index 00000000..3062bacc
--- /dev/null
+++ b/kig/icons/hi32-action-conicb5p.png
Binary files differ
diff --git a/kig/icons/hi32-action-coniclineintersection.png b/kig/icons/hi32-action-coniclineintersection.png
new file mode 100644
index 00000000..7dbeb738
--- /dev/null
+++ b/kig/icons/hi32-action-coniclineintersection.png
Binary files differ
diff --git a/kig/icons/hi32-action-conicsradicalline.png b/kig/icons/hi32-action-conicsradicalline.png
new file mode 100644
index 00000000..455735b9
--- /dev/null
+++ b/kig/icons/hi32-action-conicsradicalline.png
Binary files differ
diff --git a/kig/icons/hi32-action-convexhull.png b/kig/icons/hi32-action-convexhull.png
new file mode 100644
index 00000000..c5777e2c
--- /dev/null
+++ b/kig/icons/hi32-action-convexhull.png
Binary files differ
diff --git a/kig/icons/hi32-action-curvelineintersection.png b/kig/icons/hi32-action-curvelineintersection.png
new file mode 100644
index 00000000..8cf6b2c5
--- /dev/null
+++ b/kig/icons/hi32-action-curvelineintersection.png
Binary files differ
diff --git a/kig/icons/hi32-action-directrix.png b/kig/icons/hi32-action-directrix.png
new file mode 100644
index 00000000..694cbd83
--- /dev/null
+++ b/kig/icons/hi32-action-directrix.png
Binary files differ
diff --git a/kig/icons/hi32-action-distance.png b/kig/icons/hi32-action-distance.png
new file mode 100644
index 00000000..9e85728c
--- /dev/null
+++ b/kig/icons/hi32-action-distance.png
Binary files differ
diff --git a/kig/icons/hi32-action-ellipsebffp.png b/kig/icons/hi32-action-ellipsebffp.png
new file mode 100644
index 00000000..e324bfe4
--- /dev/null
+++ b/kig/icons/hi32-action-ellipsebffp.png
Binary files differ
diff --git a/kig/icons/hi32-action-en.png b/kig/icons/hi32-action-en.png
new file mode 100644
index 00000000..0f689847
--- /dev/null
+++ b/kig/icons/hi32-action-en.png
Binary files differ
diff --git a/kig/icons/hi32-action-equilateralhyperbolab4p.png b/kig/icons/hi32-action-equilateralhyperbolab4p.png
new file mode 100644
index 00000000..d32fec90
--- /dev/null
+++ b/kig/icons/hi32-action-equilateralhyperbolab4p.png
Binary files differ
diff --git a/kig/icons/hi32-action-equitriangle.png b/kig/icons/hi32-action-equitriangle.png
new file mode 100644
index 00000000..198788c3
--- /dev/null
+++ b/kig/icons/hi32-action-equitriangle.png
Binary files differ
diff --git a/kig/icons/hi32-action-genericaffinity.png b/kig/icons/hi32-action-genericaffinity.png
new file mode 100644
index 00000000..4450bbf1
--- /dev/null
+++ b/kig/icons/hi32-action-genericaffinity.png
Binary files differ
diff --git a/kig/icons/hi32-action-genericprojectivity.png b/kig/icons/hi32-action-genericprojectivity.png
new file mode 100644
index 00000000..55908522
--- /dev/null
+++ b/kig/icons/hi32-action-genericprojectivity.png
Binary files differ
diff --git a/kig/icons/hi32-action-halflinebyvector.png b/kig/icons/hi32-action-halflinebyvector.png
new file mode 100644
index 00000000..3e8e92a8
--- /dev/null
+++ b/kig/icons/hi32-action-halflinebyvector.png
Binary files differ
diff --git a/kig/icons/hi32-action-harmonichomology.png b/kig/icons/hi32-action-harmonichomology.png
new file mode 100644
index 00000000..1d6e42b4
--- /dev/null
+++ b/kig/icons/hi32-action-harmonichomology.png
Binary files differ
diff --git a/kig/icons/hi32-action-hexagonbcv.png b/kig/icons/hi32-action-hexagonbcv.png
new file mode 100644
index 00000000..97309f49
--- /dev/null
+++ b/kig/icons/hi32-action-hexagonbcv.png
Binary files differ
diff --git a/kig/icons/hi32-action-hyperbolabffp.png b/kig/icons/hi32-action-hyperbolabffp.png
new file mode 100644
index 00000000..4dc82334
--- /dev/null
+++ b/kig/icons/hi32-action-hyperbolabffp.png
Binary files differ
diff --git a/kig/icons/hi32-action-intersection.png b/kig/icons/hi32-action-intersection.png
new file mode 100644
index 00000000..be2fb008
--- /dev/null
+++ b/kig/icons/hi32-action-intersection.png
Binary files differ
diff --git a/kig/icons/hi32-action-inversion.png b/kig/icons/hi32-action-inversion.png
new file mode 100644
index 00000000..7d8223d1
--- /dev/null
+++ b/kig/icons/hi32-action-inversion.png
Binary files differ
diff --git a/kig/icons/hi32-action-kig_polygon.png b/kig/icons/hi32-action-kig_polygon.png
new file mode 100644
index 00000000..67d9982c
--- /dev/null
+++ b/kig/icons/hi32-action-kig_polygon.png
Binary files differ
diff --git a/kig/icons/hi32-action-kig_text.png b/kig/icons/hi32-action-kig_text.png
new file mode 100644
index 00000000..22136c5b
--- /dev/null
+++ b/kig/icons/hi32-action-kig_text.png
Binary files differ
diff --git a/kig/icons/hi32-action-line.png b/kig/icons/hi32-action-line.png
new file mode 100644
index 00000000..a0e4c656
--- /dev/null
+++ b/kig/icons/hi32-action-line.png
Binary files differ
diff --git a/kig/icons/hi32-action-linebyvector.png b/kig/icons/hi32-action-linebyvector.png
new file mode 100644
index 00000000..c64205fe
--- /dev/null
+++ b/kig/icons/hi32-action-linebyvector.png
Binary files differ
diff --git a/kig/icons/hi32-action-locus.png b/kig/icons/hi32-action-locus.png
new file mode 100644
index 00000000..90bb23a7
--- /dev/null
+++ b/kig/icons/hi32-action-locus.png
Binary files differ
diff --git a/kig/icons/hi32-action-mirrorpoint.png b/kig/icons/hi32-action-mirrorpoint.png
new file mode 100644
index 00000000..840f5e9e
--- /dev/null
+++ b/kig/icons/hi32-action-mirrorpoint.png
Binary files differ
diff --git a/kig/icons/hi32-action-move.png b/kig/icons/hi32-action-move.png
new file mode 100644
index 00000000..88ab3cef
--- /dev/null
+++ b/kig/icons/hi32-action-move.png
Binary files differ
diff --git a/kig/icons/hi32-action-paint.png b/kig/icons/hi32-action-paint.png
new file mode 100644
index 00000000..feb1f2ab
--- /dev/null
+++ b/kig/icons/hi32-action-paint.png
Binary files differ
diff --git a/kig/icons/hi32-action-parabolabtp.png b/kig/icons/hi32-action-parabolabtp.png
new file mode 100644
index 00000000..4edea289
--- /dev/null
+++ b/kig/icons/hi32-action-parabolabtp.png
Binary files differ
diff --git a/kig/icons/hi32-action-parallel.png b/kig/icons/hi32-action-parallel.png
new file mode 100644
index 00000000..64e4b09d
--- /dev/null
+++ b/kig/icons/hi32-action-parallel.png
Binary files differ
diff --git a/kig/icons/hi32-action-perpendicular.png b/kig/icons/hi32-action-perpendicular.png
new file mode 100644
index 00000000..d9c82f5a
--- /dev/null
+++ b/kig/icons/hi32-action-perpendicular.png
Binary files differ
diff --git a/kig/icons/hi32-action-point.png b/kig/icons/hi32-action-point.png
new file mode 100644
index 00000000..a541f857
--- /dev/null
+++ b/kig/icons/hi32-action-point.png
Binary files differ
diff --git a/kig/icons/hi32-action-pointOnLine.png b/kig/icons/hi32-action-pointOnLine.png
new file mode 100644
index 00000000..f9cb6168
--- /dev/null
+++ b/kig/icons/hi32-action-pointOnLine.png
Binary files differ
diff --git a/kig/icons/hi32-action-pointxy.png b/kig/icons/hi32-action-pointxy.png
new file mode 100644
index 00000000..d3ede624
--- /dev/null
+++ b/kig/icons/hi32-action-pointxy.png
Binary files differ
diff --git a/kig/icons/hi32-action-polygonsides.png b/kig/icons/hi32-action-polygonsides.png
new file mode 100644
index 00000000..fe57f99a
--- /dev/null
+++ b/kig/icons/hi32-action-polygonsides.png
Binary files differ
diff --git a/kig/icons/hi32-action-polygonvertices.png b/kig/icons/hi32-action-polygonvertices.png
new file mode 100644
index 00000000..84c22f1c
--- /dev/null
+++ b/kig/icons/hi32-action-polygonvertices.png
Binary files differ
diff --git a/kig/icons/hi32-action-python.png b/kig/icons/hi32-action-python.png
new file mode 100644
index 00000000..ee93b7d5
--- /dev/null
+++ b/kig/icons/hi32-action-python.png
Binary files differ
diff --git a/kig/icons/hi32-action-radicalline.png b/kig/icons/hi32-action-radicalline.png
new file mode 100644
index 00000000..47786034
--- /dev/null
+++ b/kig/icons/hi32-action-radicalline.png
Binary files differ
diff --git a/kig/icons/hi32-action-ray.png b/kig/icons/hi32-action-ray.png
new file mode 100644
index 00000000..68545397
--- /dev/null
+++ b/kig/icons/hi32-action-ray.png
Binary files differ
diff --git a/kig/icons/hi32-action-rotation.png b/kig/icons/hi32-action-rotation.png
new file mode 100644
index 00000000..a2e1f3df
--- /dev/null
+++ b/kig/icons/hi32-action-rotation.png
Binary files differ
diff --git a/kig/icons/hi32-action-scale.png b/kig/icons/hi32-action-scale.png
new file mode 100644
index 00000000..f0d70870
--- /dev/null
+++ b/kig/icons/hi32-action-scale.png
Binary files differ
diff --git a/kig/icons/hi32-action-segment.png b/kig/icons/hi32-action-segment.png
new file mode 100644
index 00000000..fc5a0c4d
--- /dev/null
+++ b/kig/icons/hi32-action-segment.png
Binary files differ
diff --git a/kig/icons/hi32-action-segment_midpoint.png b/kig/icons/hi32-action-segment_midpoint.png
new file mode 100644
index 00000000..6fa5bf1d
--- /dev/null
+++ b/kig/icons/hi32-action-segment_midpoint.png
Binary files differ
diff --git a/kig/icons/hi32-action-segmentaxis.png b/kig/icons/hi32-action-segmentaxis.png
new file mode 100644
index 00000000..885cb9e7
--- /dev/null
+++ b/kig/icons/hi32-action-segmentaxis.png
Binary files differ
diff --git a/kig/icons/hi32-action-similitude.png b/kig/icons/hi32-action-similitude.png
new file mode 100644
index 00000000..87f6e486
--- /dev/null
+++ b/kig/icons/hi32-action-similitude.png
Binary files differ
diff --git a/kig/icons/hi32-action-sizer.png b/kig/icons/hi32-action-sizer.png
new file mode 100644
index 00000000..82ff17ab
--- /dev/null
+++ b/kig/icons/hi32-action-sizer.png
Binary files differ
diff --git a/kig/icons/hi32-action-slope.png b/kig/icons/hi32-action-slope.png
new file mode 100644
index 00000000..6bfdb0e3
--- /dev/null
+++ b/kig/icons/hi32-action-slope.png
Binary files differ
diff --git a/kig/icons/hi32-action-square.png b/kig/icons/hi32-action-square.png
new file mode 100644
index 00000000..a9f1b401
--- /dev/null
+++ b/kig/icons/hi32-action-square.png
Binary files differ
diff --git a/kig/icons/hi32-action-stretch.png b/kig/icons/hi32-action-stretch.png
new file mode 100644
index 00000000..43b4e899
--- /dev/null
+++ b/kig/icons/hi32-action-stretch.png
Binary files differ
diff --git a/kig/icons/hi32-action-tangent.png b/kig/icons/hi32-action-tangent.png
new file mode 100644
index 00000000..92922634
--- /dev/null
+++ b/kig/icons/hi32-action-tangent.png
Binary files differ
diff --git a/kig/icons/hi32-action-test.png b/kig/icons/hi32-action-test.png
new file mode 100644
index 00000000..4a240dfe
--- /dev/null
+++ b/kig/icons/hi32-action-test.png
Binary files differ
diff --git a/kig/icons/hi32-action-testcollinear.png b/kig/icons/hi32-action-testcollinear.png
new file mode 100644
index 00000000..c999715e
--- /dev/null
+++ b/kig/icons/hi32-action-testcollinear.png
Binary files differ
diff --git a/kig/icons/hi32-action-testcontains.png b/kig/icons/hi32-action-testcontains.png
new file mode 100644
index 00000000..0694e261
--- /dev/null
+++ b/kig/icons/hi32-action-testcontains.png
Binary files differ
diff --git a/kig/icons/hi32-action-testdistance.png b/kig/icons/hi32-action-testdistance.png
new file mode 100644
index 00000000..518a4d51
--- /dev/null
+++ b/kig/icons/hi32-action-testdistance.png
Binary files differ
diff --git a/kig/icons/hi32-action-testorthogonal.png b/kig/icons/hi32-action-testorthogonal.png
new file mode 100644
index 00000000..4ce981c0
--- /dev/null
+++ b/kig/icons/hi32-action-testorthogonal.png
Binary files differ
diff --git a/kig/icons/hi32-action-testparallel.png b/kig/icons/hi32-action-testparallel.png
new file mode 100644
index 00000000..c2fa12af
--- /dev/null
+++ b/kig/icons/hi32-action-testparallel.png
Binary files differ
diff --git a/kig/icons/hi32-action-translation.png b/kig/icons/hi32-action-translation.png
new file mode 100644
index 00000000..e31ff95e
--- /dev/null
+++ b/kig/icons/hi32-action-translation.png
Binary files differ
diff --git a/kig/icons/hi32-action-triangle.png b/kig/icons/hi32-action-triangle.png
new file mode 100644
index 00000000..85c69a1b
--- /dev/null
+++ b/kig/icons/hi32-action-triangle.png
Binary files differ
diff --git a/kig/icons/hi32-action-vector.png b/kig/icons/hi32-action-vector.png
new file mode 100644
index 00000000..1de28bba
--- /dev/null
+++ b/kig/icons/hi32-action-vector.png
Binary files differ
diff --git a/kig/icons/hi32-action-vectordifference.png b/kig/icons/hi32-action-vectordifference.png
new file mode 100644
index 00000000..ef60e0bf
--- /dev/null
+++ b/kig/icons/hi32-action-vectordifference.png
Binary files differ
diff --git a/kig/icons/hi32-action-vectorsum.png b/kig/icons/hi32-action-vectorsum.png
new file mode 100644
index 00000000..07771710
--- /dev/null
+++ b/kig/icons/hi32-action-vectorsum.png
Binary files differ
diff --git a/kig/icons/hi32-action-w.png b/kig/icons/hi32-action-w.png
new file mode 100644
index 00000000..156707c2
--- /dev/null
+++ b/kig/icons/hi32-action-w.png
Binary files differ
diff --git a/kig/icons/hisc-action-angle.svgz b/kig/icons/hisc-action-angle.svgz
new file mode 100644
index 00000000..b08e88a8
--- /dev/null
+++ b/kig/icons/hisc-action-angle.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-angle_bisector.svgz b/kig/icons/hisc-action-angle_bisector.svgz
new file mode 100644
index 00000000..c2ce2411
--- /dev/null
+++ b/kig/icons/hisc-action-angle_bisector.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-angle_size.svgz b/kig/icons/hisc-action-angle_size.svgz
new file mode 100644
index 00000000..aced5dfd
--- /dev/null
+++ b/kig/icons/hisc-action-angle_size.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-arc.svgz b/kig/icons/hisc-action-arc.svgz
new file mode 100644
index 00000000..af79d93d
--- /dev/null
+++ b/kig/icons/hisc-action-arc.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-arc_center.svgz b/kig/icons/hisc-action-arc_center.svgz
new file mode 100644
index 00000000..65d4da89
--- /dev/null
+++ b/kig/icons/hisc-action-arc_center.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-areaCircle.svgz b/kig/icons/hisc-action-areaCircle.svgz
new file mode 100644
index 00000000..36223591
--- /dev/null
+++ b/kig/icons/hisc-action-areaCircle.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-attacher.svgz b/kig/icons/hisc-action-attacher.svgz
new file mode 100644
index 00000000..6f5f7743
--- /dev/null
+++ b/kig/icons/hisc-action-attacher.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-baseCircle.svgz b/kig/icons/hisc-action-baseCircle.svgz
new file mode 100644
index 00000000..3a431868
--- /dev/null
+++ b/kig/icons/hisc-action-baseCircle.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-bisection.svgz b/kig/icons/hisc-action-bisection.svgz
new file mode 100644
index 00000000..7b1bfc01
--- /dev/null
+++ b/kig/icons/hisc-action-bisection.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-centerofcurvature.svgz b/kig/icons/hisc-action-centerofcurvature.svgz
new file mode 100644
index 00000000..a66db2bd
--- /dev/null
+++ b/kig/icons/hisc-action-centerofcurvature.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-centralsymmetry.svgz b/kig/icons/hisc-action-centralsymmetry.svgz
new file mode 100644
index 00000000..b065a6d3
--- /dev/null
+++ b/kig/icons/hisc-action-centralsymmetry.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-circlebcl.svgz b/kig/icons/hisc-action-circlebcl.svgz
new file mode 100644
index 00000000..1e9162d5
--- /dev/null
+++ b/kig/icons/hisc-action-circlebcl.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-circlebcp.svgz b/kig/icons/hisc-action-circlebcp.svgz
new file mode 100644
index 00000000..f05a2f2c
--- /dev/null
+++ b/kig/icons/hisc-action-circlebcp.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-circlebpd.svgz b/kig/icons/hisc-action-circlebpd.svgz
new file mode 100644
index 00000000..c636bfd8
--- /dev/null
+++ b/kig/icons/hisc-action-circlebpd.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-circlebps.svgz b/kig/icons/hisc-action-circlebps.svgz
new file mode 100644
index 00000000..27463564
--- /dev/null
+++ b/kig/icons/hisc-action-circlebps.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-circlebtp.svgz b/kig/icons/hisc-action-circlebtp.svgz
new file mode 100644
index 00000000..cd1df6e9
--- /dev/null
+++ b/kig/icons/hisc-action-circlebtp.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-circlelineintersection.svgz b/kig/icons/hisc-action-circlelineintersection.svgz
new file mode 100644
index 00000000..031ee82b
--- /dev/null
+++ b/kig/icons/hisc-action-circlelineintersection.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-circumference.svgz b/kig/icons/hisc-action-circumference.svgz
new file mode 100644
index 00000000..b695ef3c
--- /dev/null
+++ b/kig/icons/hisc-action-circumference.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-conicasymptotes.svgz b/kig/icons/hisc-action-conicasymptotes.svgz
new file mode 100644
index 00000000..9d63239c
--- /dev/null
+++ b/kig/icons/hisc-action-conicasymptotes.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-conicb5p.svgz b/kig/icons/hisc-action-conicb5p.svgz
new file mode 100644
index 00000000..80d15b8e
--- /dev/null
+++ b/kig/icons/hisc-action-conicb5p.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-coniclineintersection.svgz b/kig/icons/hisc-action-coniclineintersection.svgz
new file mode 100644
index 00000000..853cca71
--- /dev/null
+++ b/kig/icons/hisc-action-coniclineintersection.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-conicsradicalline.svgz b/kig/icons/hisc-action-conicsradicalline.svgz
new file mode 100644
index 00000000..6991b9b7
--- /dev/null
+++ b/kig/icons/hisc-action-conicsradicalline.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-convexhull.svgz b/kig/icons/hisc-action-convexhull.svgz
new file mode 100644
index 00000000..1d1121df
--- /dev/null
+++ b/kig/icons/hisc-action-convexhull.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-curvelineintersection.svgz b/kig/icons/hisc-action-curvelineintersection.svgz
new file mode 100644
index 00000000..948b027b
--- /dev/null
+++ b/kig/icons/hisc-action-curvelineintersection.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-directrix.svgz b/kig/icons/hisc-action-directrix.svgz
new file mode 100644
index 00000000..f1e36ab5
--- /dev/null
+++ b/kig/icons/hisc-action-directrix.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-distance.svgz b/kig/icons/hisc-action-distance.svgz
new file mode 100644
index 00000000..aa982a87
--- /dev/null
+++ b/kig/icons/hisc-action-distance.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-ellipsebffp.svgz b/kig/icons/hisc-action-ellipsebffp.svgz
new file mode 100644
index 00000000..b927f644
--- /dev/null
+++ b/kig/icons/hisc-action-ellipsebffp.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-en.svgz b/kig/icons/hisc-action-en.svgz
new file mode 100644
index 00000000..2f461a23
--- /dev/null
+++ b/kig/icons/hisc-action-en.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-equilateralhyperbolab4p.svgz b/kig/icons/hisc-action-equilateralhyperbolab4p.svgz
new file mode 100644
index 00000000..3e029768
--- /dev/null
+++ b/kig/icons/hisc-action-equilateralhyperbolab4p.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-equitriangle.svgz b/kig/icons/hisc-action-equitriangle.svgz
new file mode 100644
index 00000000..46dd9b2d
--- /dev/null
+++ b/kig/icons/hisc-action-equitriangle.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-genericaffinity.svgz b/kig/icons/hisc-action-genericaffinity.svgz
new file mode 100644
index 00000000..3b1c7d46
--- /dev/null
+++ b/kig/icons/hisc-action-genericaffinity.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-genericprojectivity.svgz b/kig/icons/hisc-action-genericprojectivity.svgz
new file mode 100644
index 00000000..bc74c671
--- /dev/null
+++ b/kig/icons/hisc-action-genericprojectivity.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-halflinebyvector.svgz b/kig/icons/hisc-action-halflinebyvector.svgz
new file mode 100644
index 00000000..92be9ece
--- /dev/null
+++ b/kig/icons/hisc-action-halflinebyvector.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-harmonichomology.svgz b/kig/icons/hisc-action-harmonichomology.svgz
new file mode 100644
index 00000000..30ba3d89
--- /dev/null
+++ b/kig/icons/hisc-action-harmonichomology.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-hexagonbcv.svgz b/kig/icons/hisc-action-hexagonbcv.svgz
new file mode 100644
index 00000000..82cd94e2
--- /dev/null
+++ b/kig/icons/hisc-action-hexagonbcv.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-hyperbolabffp.svgz b/kig/icons/hisc-action-hyperbolabffp.svgz
new file mode 100644
index 00000000..4c0fb479
--- /dev/null
+++ b/kig/icons/hisc-action-hyperbolabffp.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-intersection.svgz b/kig/icons/hisc-action-intersection.svgz
new file mode 100644
index 00000000..05171c8c
--- /dev/null
+++ b/kig/icons/hisc-action-intersection.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-inversion.svgz b/kig/icons/hisc-action-inversion.svgz
new file mode 100644
index 00000000..4508bc49
--- /dev/null
+++ b/kig/icons/hisc-action-inversion.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-kig_polygon.svgz b/kig/icons/hisc-action-kig_polygon.svgz
new file mode 100644
index 00000000..cf74ff91
--- /dev/null
+++ b/kig/icons/hisc-action-kig_polygon.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-kig_text.svgz b/kig/icons/hisc-action-kig_text.svgz
new file mode 100644
index 00000000..7934c739
--- /dev/null
+++ b/kig/icons/hisc-action-kig_text.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-line.svgz b/kig/icons/hisc-action-line.svgz
new file mode 100644
index 00000000..10f4e4f1
--- /dev/null
+++ b/kig/icons/hisc-action-line.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-linebyvector.svgz b/kig/icons/hisc-action-linebyvector.svgz
new file mode 100644
index 00000000..c5e5e6ea
--- /dev/null
+++ b/kig/icons/hisc-action-linebyvector.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-locus.svgz b/kig/icons/hisc-action-locus.svgz
new file mode 100644
index 00000000..1eda537a
--- /dev/null
+++ b/kig/icons/hisc-action-locus.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-mirrorpoint.svgz b/kig/icons/hisc-action-mirrorpoint.svgz
new file mode 100644
index 00000000..072016c3
--- /dev/null
+++ b/kig/icons/hisc-action-mirrorpoint.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-move.svgz b/kig/icons/hisc-action-move.svgz
new file mode 100644
index 00000000..b26cdb23
--- /dev/null
+++ b/kig/icons/hisc-action-move.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-paint.svgz b/kig/icons/hisc-action-paint.svgz
new file mode 100644
index 00000000..7739240d
--- /dev/null
+++ b/kig/icons/hisc-action-paint.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-parabolabtp.svgz b/kig/icons/hisc-action-parabolabtp.svgz
new file mode 100644
index 00000000..91c7d6cf
--- /dev/null
+++ b/kig/icons/hisc-action-parabolabtp.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-parallel.svgz b/kig/icons/hisc-action-parallel.svgz
new file mode 100644
index 00000000..d6992058
--- /dev/null
+++ b/kig/icons/hisc-action-parallel.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-perpendicular.svgz b/kig/icons/hisc-action-perpendicular.svgz
new file mode 100644
index 00000000..b0713e36
--- /dev/null
+++ b/kig/icons/hisc-action-perpendicular.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-point.svgz b/kig/icons/hisc-action-point.svgz
new file mode 100644
index 00000000..df7b856a
--- /dev/null
+++ b/kig/icons/hisc-action-point.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-pointOnLine.svgz b/kig/icons/hisc-action-pointOnLine.svgz
new file mode 100644
index 00000000..53ac009e
--- /dev/null
+++ b/kig/icons/hisc-action-pointOnLine.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-pointxy.svgz b/kig/icons/hisc-action-pointxy.svgz
new file mode 100644
index 00000000..4fab2148
--- /dev/null
+++ b/kig/icons/hisc-action-pointxy.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-polygonsides.svgz b/kig/icons/hisc-action-polygonsides.svgz
new file mode 100644
index 00000000..6348509c
--- /dev/null
+++ b/kig/icons/hisc-action-polygonsides.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-polygonvertices.svgz b/kig/icons/hisc-action-polygonvertices.svgz
new file mode 100644
index 00000000..27a2876b
--- /dev/null
+++ b/kig/icons/hisc-action-polygonvertices.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-python.svgz b/kig/icons/hisc-action-python.svgz
new file mode 100644
index 00000000..47415a43
--- /dev/null
+++ b/kig/icons/hisc-action-python.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-radicalline.svgz b/kig/icons/hisc-action-radicalline.svgz
new file mode 100644
index 00000000..87416911
--- /dev/null
+++ b/kig/icons/hisc-action-radicalline.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-ray.svgz b/kig/icons/hisc-action-ray.svgz
new file mode 100644
index 00000000..aff05709
--- /dev/null
+++ b/kig/icons/hisc-action-ray.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-rotation.svgz b/kig/icons/hisc-action-rotation.svgz
new file mode 100644
index 00000000..9ab8dc14
--- /dev/null
+++ b/kig/icons/hisc-action-rotation.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-scale.svgz b/kig/icons/hisc-action-scale.svgz
new file mode 100644
index 00000000..43ad5f72
--- /dev/null
+++ b/kig/icons/hisc-action-scale.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-segment.svgz b/kig/icons/hisc-action-segment.svgz
new file mode 100644
index 00000000..baeeaef3
--- /dev/null
+++ b/kig/icons/hisc-action-segment.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-segment_midpoint.svgz b/kig/icons/hisc-action-segment_midpoint.svgz
new file mode 100644
index 00000000..57cb6d66
--- /dev/null
+++ b/kig/icons/hisc-action-segment_midpoint.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-segmentaxis.svgz b/kig/icons/hisc-action-segmentaxis.svgz
new file mode 100644
index 00000000..40f82b6c
--- /dev/null
+++ b/kig/icons/hisc-action-segmentaxis.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-similitude.svgz b/kig/icons/hisc-action-similitude.svgz
new file mode 100644
index 00000000..823a384d
--- /dev/null
+++ b/kig/icons/hisc-action-similitude.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-sizer.svgz b/kig/icons/hisc-action-sizer.svgz
new file mode 100644
index 00000000..d49c69bc
--- /dev/null
+++ b/kig/icons/hisc-action-sizer.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-slope.svgz b/kig/icons/hisc-action-slope.svgz
new file mode 100644
index 00000000..c4e993dc
--- /dev/null
+++ b/kig/icons/hisc-action-slope.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-square.svgz b/kig/icons/hisc-action-square.svgz
new file mode 100644
index 00000000..4e5b6527
--- /dev/null
+++ b/kig/icons/hisc-action-square.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-stretch.svgz b/kig/icons/hisc-action-stretch.svgz
new file mode 100644
index 00000000..54db9e2c
--- /dev/null
+++ b/kig/icons/hisc-action-stretch.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-tangent.svgz b/kig/icons/hisc-action-tangent.svgz
new file mode 100644
index 00000000..74cda333
--- /dev/null
+++ b/kig/icons/hisc-action-tangent.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-test.svgz b/kig/icons/hisc-action-test.svgz
new file mode 100644
index 00000000..77f16d69
--- /dev/null
+++ b/kig/icons/hisc-action-test.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-testcollinear.svgz b/kig/icons/hisc-action-testcollinear.svgz
new file mode 100644
index 00000000..ee3de1ae
--- /dev/null
+++ b/kig/icons/hisc-action-testcollinear.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-testcontains.svgz b/kig/icons/hisc-action-testcontains.svgz
new file mode 100644
index 00000000..af07e486
--- /dev/null
+++ b/kig/icons/hisc-action-testcontains.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-testdistance.svgz b/kig/icons/hisc-action-testdistance.svgz
new file mode 100644
index 00000000..4f62efd4
--- /dev/null
+++ b/kig/icons/hisc-action-testdistance.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-testorthogonal.svgz b/kig/icons/hisc-action-testorthogonal.svgz
new file mode 100644
index 00000000..c5fa277b
--- /dev/null
+++ b/kig/icons/hisc-action-testorthogonal.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-testparallel.svgz b/kig/icons/hisc-action-testparallel.svgz
new file mode 100644
index 00000000..b4b52d58
--- /dev/null
+++ b/kig/icons/hisc-action-testparallel.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-translation.svgz b/kig/icons/hisc-action-translation.svgz
new file mode 100644
index 00000000..6a0bc10a
--- /dev/null
+++ b/kig/icons/hisc-action-translation.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-triangle.svgz b/kig/icons/hisc-action-triangle.svgz
new file mode 100644
index 00000000..c2ea4424
--- /dev/null
+++ b/kig/icons/hisc-action-triangle.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-vector.svgz b/kig/icons/hisc-action-vector.svgz
new file mode 100644
index 00000000..8e18082f
--- /dev/null
+++ b/kig/icons/hisc-action-vector.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-vectordifference.svgz b/kig/icons/hisc-action-vectordifference.svgz
new file mode 100644
index 00000000..dfa6c75e
--- /dev/null
+++ b/kig/icons/hisc-action-vectordifference.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-vectorsum.svgz b/kig/icons/hisc-action-vectorsum.svgz
new file mode 100644
index 00000000..7bd5543f
--- /dev/null
+++ b/kig/icons/hisc-action-vectorsum.svgz
Binary files differ
diff --git a/kig/icons/hisc-action-w.svgz b/kig/icons/hisc-action-w.svgz
new file mode 100644
index 00000000..d6d56abc
--- /dev/null
+++ b/kig/icons/hisc-action-w.svgz
Binary files differ
diff --git a/kig/kfile/Makefile.am b/kig/kfile/Makefile.am
new file mode 100644
index 00000000..b8de2d3d
--- /dev/null
+++ b/kig/kfile/Makefile.am
@@ -0,0 +1,24 @@
+INCLUDES = $(all_includes)
+
+noinst_HEADERS = \
+ kfile_drgeo.h \
+ kfile_kig.h
+
+kde_module_LTLIBRARIES = \
+ kfile_drgeo.la \
+ kfile_kig.la
+
+kfile_drgeo_la_SOURCES = kfile_drgeo.cpp
+kfile_drgeo_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_drgeo_la_LIBADD = $(LIB_KIO)
+
+kfile_kig_la_SOURCES = kfile_kig.cpp
+kfile_kig_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_kig_la_LIBADD = $(LIB_KIO)
+
+METASOURCES = AUTO
+
+services_DATA = \
+ kfile_drgeo.desktop \
+ kfile_kig.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kig/kfile/kfile_drgeo.cpp b/kig/kfile/kfile_drgeo.cpp
new file mode 100644
index 00000000..26ed7923
--- /dev/null
+++ b/kig/kfile/kfile_drgeo.cpp
@@ -0,0 +1,99 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Pino Toscano *
+ * toscano.pino@tiscali.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "kfile_drgeo.h"
+
+#include <qdom.h>
+#include <qfile.h>
+
+#include <kgenericfactory.h>
+
+typedef KGenericFactory<DrgeoPlugin> drgeoFactory;
+
+K_EXPORT_COMPONENT_FACTORY( kfile_drgeo, drgeoFactory( "kfile_drgeo" ) )
+
+DrgeoPlugin::DrgeoPlugin( QObject *parent, const char *name, const QStringList &args )
+ : KFilePlugin( parent, name, args )
+{
+ info = addMimeTypeInfo( "application/x-drgeo" );
+
+ KFileMimeTypeInfo::GroupInfo* group = addGroupInfo( info, "DrgeoInfo", i18n( "Summary" ) );
+ KFileMimeTypeInfo::ItemInfo* item;
+ item = addItemInfo( group, "NumOfFigures", i18n( "Figures" ), QVariant::Int );
+ item = addItemInfo( group, "NumOfTexts", i18n( "Texts" ), QVariant::Int );
+ item = addItemInfo( group, "NumOfMacros", i18n( "Macros" ), QVariant::Int );
+
+ group_contents = addGroupInfo( info, "DrgeoContents", i18n( "Translators: what this drgeo "
+ "file contains", "Contents" ) );
+}
+
+bool DrgeoPlugin::readInfo( KFileMetaInfo& metainfo, uint /*what*/ )
+{
+ KFileMetaInfoGroup metagroup = appendGroup( metainfo, "DrgeoContents");
+
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ QFile f( metainfo.path() );
+ QDomDocument doc( "drgenius" );
+ if ( !doc.setContent( &f ) )
+ return false;
+ QDomElement main = doc.documentElement();
+ int numfig = 0;
+ int numtext = 0;
+ int nummacro = 0;
+ QString sectname;
+ // reading figures...
+ for ( QDomNode n = main.firstChild(); ! n.isNull(); n = n.nextSibling() )
+ {
+ QDomElement e = n.toElement();
+ if ( e.isNull() ) continue;
+ else if ( e.tagName() == "drgeo" )
+ {
+ numfig++;
+ sectname = QString( "Figure" ) + QString::number( numfig );
+ item = addItemInfo( group_contents, sectname, i18n( "Figure" ), QVariant::String );
+ appendItem( metagroup, sectname, e.attribute( "name" ) );
+ }
+ else if ( e.tagName() == "text" )
+ {
+ numtext++;
+ sectname = QString( "Text" ) + QString::number( numtext );
+ item = addItemInfo( group_contents, sectname, i18n( "Text" ), QVariant::String );
+ appendItem( metagroup, sectname, e.attribute( "name" ) );
+ }
+ else if ( e.tagName() == "macro" )
+ {
+ nummacro++;
+ sectname = QString( "Macro" ) + QString::number( nummacro );
+ item = addItemInfo( group_contents, sectname, i18n( "Macro" ), QVariant::String );
+ appendItem( metagroup, sectname, e.attribute( "name" ) );
+ }
+ }
+
+ metagroup = appendGroup( metainfo, "DrgeoInfo");
+ appendItem( metagroup, "NumOfFigures", numfig );
+ appendItem( metagroup, "NumOfTexts", numtext );
+ appendItem( metagroup, "NumOfMacros", nummacro );
+
+ return true;
+}
+
+#include "kfile_drgeo.moc"
+
diff --git a/kig/kfile/kfile_drgeo.desktop b/kig/kfile/kfile_drgeo.desktop
new file mode 100644
index 00000000..1b9ea997
--- /dev/null
+++ b/kig/kfile/kfile_drgeo.desktop
@@ -0,0 +1,55 @@
+[Desktop Entry]
+Type=Service
+Name=Dr. Geo Info
+Name[af]=Dr. Geo inligting
+Name[be]=ЗвеÑткі Dr. Geo
+Name[bn]=ড. জিও সংকà§à¦°à¦¾à¦¨à§à¦¤ তথà§à¦¯
+Name[br]=Titouroù diwar-benn Dr. Geo
+Name[ca]=Informació Dr. Geo
+Name[cs]=Dr. Geo info
+Name[csb]=Wëdowiédzô Dr Geo
+Name[cy]=Gwybodaeth Dr. Geo
+Name[da]=Dr. Geo info
+Name[el]=ΠληÏοφοÏίες για το Dr. Geo
+Name[eo]=Dr. Geo info
+Name[es]=Información de Dr. Geo
+Name[et]=Dr. Geo info
+Name[eu]=Dr. Geo informazioa
+Name[fa]=اطلاعات دکتر جیو
+Name[fi]=Dr. Geo
+Name[fr]=Informations de Dr. Geo
+Name[ga]=Eolas faoi Dr. Geo
+Name[gl]=Información de Dr. Geo
+Name[he]=מידע על Dr. Geo
+Name[hi]=डॉ. जिओ जानकारी
+Name[hu]=Dr. Geo-jellemzők
+Name[is]=Dr. Geo upplýsingar
+Name[it]=Informazioni Dr. Geo
+Name[ja]=Dr. Geo 情報
+Name[ka]=Dr. Geo - მáƒáƒœáƒáƒªáƒ”მები
+Name[km]=áž–áŸážáŸŒáž˜áž¶áž“ Dr. Geo
+Name[mk]=Dr. Geo инфо
+Name[nb]=Dr. Geo-info
+Name[ne]=डा. जिव जानकारी
+Name[nn]=Dr. Geo-info
+Name[pa]=Dr. Geo ਜਾਣਕਾਰੀ
+Name[pl]=Informacja Dr. Geo
+Name[pt]=Informação do Dr. Geo
+Name[pt_BR]=Informações do Dr. Geo
+Name[ru]=Файл Dr. Geo
+Name[sl]=Podatki Dr. Geo
+Name[sr]=Dr. Geo информације
+Name[sr@Latn]=Dr. Geo informacije
+Name[sv]=Dr. Geo-information
+Name[ta]=டா. ஜியோ தகவலà¯
+Name[tg]=Ðхборот дар бораи ГеометриÑ
+Name[tr]=Dr. Geo Bilgisi
+Name[uk]=Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð´Ð»Ñ Dr. Geo
+Name[vi]=Tiến sÄ© Thông tin Hình há»c
+Name[zh_CN]=Dr. Geo ä¿¡æ¯
+Name[zh_TW]=Dr. Geo 資訊
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_drgeo
+MimeType=application/x-drgeo
+PreferredGroups=DrgeoInfo
+PreferredItems=NumOfFigures;NumOfTexts;NumOfMacros
diff --git a/kig/kfile/kfile_drgeo.h b/kig/kfile/kfile_drgeo.h
new file mode 100644
index 00000000..b6e388da
--- /dev/null
+++ b/kig/kfile/kfile_drgeo.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Pino Toscano *
+ * toscano.pino@tiscali.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef KIG_KFILE_KFILE_DRGEO_H
+#define KIG_KFILE_KFILE_DRGEO_H
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class DrgeoPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ DrgeoPlugin( QObject *parent, const char *name, const QStringList& args );
+
+ virtual bool readInfo( KFileMetaInfo& metainfo, uint what);
+protected:
+ KFileMimeTypeInfo* info;
+ KFileMimeTypeInfo::GroupInfo* group_contents;
+};
+
+#endif
diff --git a/kig/kfile/kfile_kig.cpp b/kig/kfile/kfile_kig.cpp
new file mode 100644
index 00000000..eca2f79d
--- /dev/null
+++ b/kig/kfile/kfile_kig.cpp
@@ -0,0 +1,153 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Pino Toscano *
+ * toscano.pino@tiscali.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "kfile_kig.h"
+
+#include <qdom.h>
+#include <qfile.h>
+#include <qregexp.h>
+
+#include <karchive.h>
+#include <kgenericfactory.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <ktar.h>
+
+typedef KGenericFactory<KigPlugin> kigFactory;
+
+K_EXPORT_COMPONENT_FACTORY( kfile_kig, kigFactory( "kfile_kig" ) )
+
+KigPlugin::KigPlugin( QObject *parent, const char *name, const QStringList &args )
+ : KFilePlugin( parent, name, args )
+{
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ info = addMimeTypeInfo( "application/x-kig" );
+
+ group = addGroupInfo( info, "KigInfo", i18n( "Summary" ) );
+ item = addItemInfo( group, "Version", i18n( "Version" ), QVariant::String );
+ item = addItemInfo( group, "CompatVersion", i18n( "Compatibility Version" ), QVariant::String );
+ item = addItemInfo( group, "CoordSystem", i18n( "Coordinate System" ), QVariant::String );
+ item = addItemInfo( group, "Grid", i18n( "Grid" ), QVariant::String );
+ item = addItemInfo( group, "Axes", i18n( "Axes" ), QVariant::String );
+ item = addItemInfo( group, "Compressed", i18n( "Compressed" ), QVariant::String );
+}
+
+bool KigPlugin::readInfo( KFileMetaInfo& metainfo, uint /*what*/ )
+{
+ KFileMetaInfoGroup metagroup = appendGroup( metainfo, "KigInfo");
+
+ QString sfile = metainfo.path();
+ bool iscompressed = false;
+ QFile f( sfile );
+ if ( !sfile.endsWith( ".kig", false ) )
+ {
+ iscompressed = true;
+
+ QString tempdir = KGlobal::dirs()->saveLocation( "tmp" );
+ if ( tempdir.isEmpty() )
+ return false;
+
+ QString tempname = sfile.section( '/', -1 );
+ if ( sfile.endsWith( ".kigz", false ) )
+ {
+ tempname.remove( QRegExp( "\\.[Kk][Ii][Gg][Zz]$" ) );
+ }
+ else
+ return false;
+ // reading compressed file
+ KTar* ark = new KTar( sfile, "application/x-gzip" );
+ ark->open( IO_ReadOnly );
+ const KArchiveDirectory* dir = ark->directory();
+ QStringList entries = dir->entries();
+ QStringList kigfiles = entries.grep( QRegExp( "\\.kig$" ) );
+ if ( kigfiles.count() != 1 )
+ return false;
+ const KArchiveEntry* kigz = dir->entry( kigfiles[0] );
+ if ( !kigz->isFile() )
+ return false;
+ dynamic_cast<const KArchiveFile*>( kigz )->copyTo( tempdir );
+
+ f.setName( tempdir + kigz->name() );
+ }
+
+ if ( !f.open( IO_ReadOnly ) )
+ return false;
+
+ QDomDocument doc( "KigDocument" );
+ if ( !doc.setContent( &f ) )
+ return false;
+
+ f.close();
+
+ // removing temp file
+ if ( iscompressed )
+ f.remove();
+
+ QDomElement main = doc.documentElement();
+
+ // reading the version...
+ QString version = main.attribute( "Version" );
+ if ( version.isEmpty() ) version = main.attribute( "version" );
+ if ( version.isEmpty() ) version = i18n( "Translators: Not Available", "n/a" );
+ appendItem( metagroup, "Version", version );
+
+ // reading the compatibility version...
+ QString compatversion = main.attribute( "CompatibilityVersion" );
+ if ( compatversion.isEmpty() )
+ compatversion = i18n( "%1 represents Kig version",
+ "%1 (as the version)" ).arg( version );
+ appendItem( metagroup, "CompatVersion", compatversion );
+
+ // reading the Coordinate System...
+ QCString coordsystem;
+ for ( QDomNode n = main.firstChild(); ! n.isNull(); n = n.nextSibling() )
+ {
+ QDomElement e = n.toElement();
+ if ( e.isNull() ) continue;
+ if ( e.tagName() == "CoordinateSystem" )
+ coordsystem = e.text().latin1();
+ }
+ appendItem( metagroup, "CoordSystem", coordsystem );
+
+ // has Kig document the grid?
+ bool btmp = true;
+ QString stmp = main.attribute( "grid" );
+ if ( !( stmp.isEmpty() || ( stmp != "0" ) ) )
+ btmp = ( stmp != "0" );
+ QString stmp2 = btmp ? i18n( "Yes" ) : i18n( "No" );
+ appendItem( metagroup, "Grid", stmp2 );
+
+ // has Kig document the axes?
+ btmp = true;
+ stmp = main.attribute( "axes" );
+ if ( !( stmp.isEmpty() || ( stmp != "0" ) ) )
+ btmp = ( stmp != "0" );
+ stmp2 = btmp ? i18n( "Yes" ) : i18n( "No" );
+ appendItem( metagroup, "Axes", stmp2 );
+
+ stmp2 = iscompressed ? i18n( "Yes" ) : i18n( "No" );
+ appendItem( metagroup, "Compressed", stmp2 );
+
+ return true;
+}
+
+#include "kfile_kig.moc"
diff --git a/kig/kfile/kfile_kig.desktop b/kig/kfile/kfile_kig.desktop
new file mode 100644
index 00000000..03ee474b
--- /dev/null
+++ b/kig/kfile/kfile_kig.desktop
@@ -0,0 +1,54 @@
+[Desktop Entry]
+Type=Service
+Name=Kig Info
+Name[af]=Kig inligting
+Name[be]=ЗвеÑткі Kig
+Name[bn]=কিগ সংকà§à¦°à¦¾à¦¨à§à¦¤ তথà§à¦¯
+Name[br]=Titouroù diwar-benn Kig
+Name[ca]=Informació Kig
+Name[cs]=Kig info
+Name[csb]=Wëdowiédzô Kig
+Name[cy]=Gwybodaeth Kig
+Name[da]=Kig info
+Name[el]=ΠληÏοφοÏίες για το Kig
+Name[eo]=Kig info
+Name[es]=Información de Kig
+Name[et]=Kigi info
+Name[eu]=Kig informazioa
+Name[fa]=اطلاعات Kig
+Name[fr]=Informations de Kig
+Name[ga]=Eolas faoi Kig
+Name[gl]=Información de Kig
+Name[he]=Kig מידע
+Name[hi]=केआईजी जानकारी
+Name[hu]=Kig-jellemzők
+Name[is]=Kig upplýsingar
+Name[it]=Informazioni Kig
+Name[ja]=Kig 情報
+Name[ka]=Kig - მáƒáƒœáƒáƒªáƒ”მები
+Name[km]=áž–áŸážáŸŒáž˜áž¶áž“ Kig
+Name[mk]=Kig инфо
+Name[nb]=Kig-info
+Name[ne]=किग जानकारी
+Name[nn]=Kig-info
+Name[pa]=ਕਿਗ ਜਾਣਕਾਰੀ
+Name[pl]=Informacja Kig
+Name[pt]=Informação do Kig
+Name[pt_BR]=Informações do Kig
+Name[ru]=Файл Kig
+Name[sl]=Podatki Kig
+Name[sr]=Kig информације
+Name[sr@Latn]=Kig informacije
+Name[sv]=Kig-information
+Name[ta]=கிக௠தகவலà¯
+Name[tg]=Ðхборот дар бораи Kig
+Name[tr]=Kig Bilgisi
+Name[uk]=Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð´Ð»Ñ Kig
+Name[vi]=Thông tin Kig
+Name[zh_CN]=Kig ä¿¡æ¯
+Name[zh_TW]=Kig 資訊
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_kig
+MimeType=application/x-kig
+PreferredGroups=KigInfo
+PreferredItems=Version;CoordSytem
diff --git a/kig/kfile/kfile_kig.h b/kig/kfile/kfile_kig.h
new file mode 100644
index 00000000..8580ec48
--- /dev/null
+++ b/kig/kfile/kfile_kig.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Pino Toscano *
+ * toscano.pino@tiscali.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef KIG_KFILE_KFILE_KIG_H
+#define KIG_KFILE_KFILE_KIG_H
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class KigPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KigPlugin( QObject *parent, const char *name, const QStringList& args );
+
+ virtual bool readInfo( KFileMetaInfo& metainfo, uint what);
+protected:
+ KFileMimeTypeInfo* info;
+ KFileMimeTypeInfo::GroupInfo* group;
+};
+
+#endif
diff --git a/kig/kig.lsm.in b/kig/kig.lsm.in
new file mode 100644
index 00000000..8b1d504d
--- /dev/null
+++ b/kig/kig.lsm.in
@@ -0,0 +1,18 @@
+Begin3
+Title: Kig
+Version: @KIGVERSION@
+Entered-date: 8 Dec 02
+Description: Kig is an application meant to allow high school
+ students to interactively explore mathematical
+ concepts, much like Dr.Geo, KGeo, KSeg and Cabri.
+Keywords: KDE Interactive Geometry KGeo KDE-Edu KSeg Cabri
+ math GPL
+Author: Kig developers <kde-edu-devel@kde.org>
+Maintained-by: Kig developers <kde-edu-devel@kde.org>
+Home-page: http://edu.kde.org/kig
+Primary-site: ftp://ftp.kde.org/pub/kde/stable/apps/KDE3.x/math/
+ xxxxxx kig-@KIGVERSION@.tar.bz2
+ xxx kig-@KIGVERSION@.lsm
+Platform: Unix
+Copying-policy: GPL
+End
diff --git a/kig/kig/Makefile.am b/kig/kig/Makefile.am
new file mode 100644
index 00000000..719886cc
--- /dev/null
+++ b/kig/kig/Makefile.am
@@ -0,0 +1,53 @@
+# this has all of the subdirectories that make will recurse into. if
+# there are none, comment this out
+#SUBDIRS = pics icons
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kig.h kig_document.h kig_part.h kig_view.h kig_commands.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+KDE_ICON = AUTO
+
+# this Makefile creates both a KPart application and a KPart
+#########################################################################
+# APPLICATION SECTION
+#########################################################################
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+bin_PROGRAMS = kig
+
+# the application source, library search path, and link libraries
+kig_SOURCES = main.cpp kig.cpp
+kig_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+kig_LDADD = $(LIB_KPARTS)
+
+# this is where the desktop file will go
+xdg_apps_DATA = kig.desktop
+
+# this is where the shell's XML-GUI resource file goes
+rcdir = $(kde_datadir)/kig
+rc_DATA = kigui.rc kigpartui.rc
+
+#########################################################################
+# KPART SECTION
+#########################################################################
+noinst_LTLIBRARIES = libkigparttemp.la
+
+# the Part's source, library search path, and link libraries
+libkigparttemp_la_SOURCES = \
+ kig_document.cc \
+ kig_part.cpp \
+ kig_view.cpp \
+ kig_commands.cpp
+
+libkigparttemp_la_LDFLAGS = $(all_libraries)
+libkigparttemp_la_LIBADD = $(LIB_KDEPRINT) $(LIB_KIO)
+
+# this is where the desktop file will go
+partdesktopdir = $(kde_servicesdir)
+partdesktop_DATA = kig_part.desktop
diff --git a/kig/kig/aboutdata.h b/kig/kig/aboutdata.h
new file mode 100644
index 00000000..db4f3689
--- /dev/null
+++ b/kig/kig/aboutdata.h
@@ -0,0 +1,89 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include <kaboutdata.h>
+#include <klocale.h>
+
+#include "config.h"
+
+inline KAboutData* kigAboutData( const char* name, const char* iname )
+{
+ const char* version = "v" KIGVERSION;
+ const char* description = I18N_NOOP( "KDE Interactive Geometry" );
+
+ KAboutData* tmp = new KAboutData( name, iname, version,
+ description, KAboutData::License_GPL,
+ I18N_NOOP( "(C) 2002-2005, The Kig developers" ),
+ 0, "http://edu.kde.org/kig" );
+ tmp->addAuthor("Dominique Devriese",
+ I18N_NOOP("Original author, long time maintainer, design and lots of code."),
+ "devriese@kde.org" );
+
+ tmp->addAuthor("Maurizio Paolini",
+ I18N_NOOP( "Did a lot of important work all around Kig, "
+ "including, but not limited to conics, cubics, "
+ "transformations and property tests support." ),
+ "paolini@dmf.unicatt.it");
+
+ tmp->addAuthor( "Pino Toscano",
+ I18N_NOOP( "Actual maintainer, Dr. Geo import filter, point and "
+ "line styles, Italian translation, "
+ "miscellaneous stuff here and there." ),
+ "toscano.pino@tiscali.it" );
+
+ tmp->addAuthor( "Franco Pasquarelli",
+ I18N_NOOP( "Helped a lot with the implementation of the Locus object, "
+ "there's quite some math involved in doing it right, and "
+ "Franco wrote the most difficult parts." ),
+ "pasqui@dmf.unicatt.it" );
+
+ tmp->addCredit( "Eric Depagne",
+ I18N_NOOP( "The French translator, who also sent me some useful "
+ "feedback, like feature requests and bug reports." ),
+ "edepagne@eso.org" );
+
+ tmp->addCredit("Marc Bartsch",
+ I18N_NOOP("Author of KGeo, where I got inspiration, "
+ "some source, and most of the artwork from." ),
+ "marc.bartsch@web.de");
+
+ tmp->addCredit("Christophe Devriese",
+ I18N_NOOP( "Domi's brother, who he got to write the algorithm for "
+ "calculating the center of the circle with three "
+ "points given." ),
+ "oelewapperke@ulyssis.org" );
+
+ tmp->addCredit("Christophe Prud'homme",
+ I18N_NOOP( "Sent me a patch for some bugs." ),
+ "prudhomm@mit.edu" );
+
+ tmp->addCredit("Robert Gogolok",
+ I18N_NOOP("Gave me some good feedback on Kig, some feature "
+ "requests, cleanups and style fixes, and someone "
+ "to chat with on irc :)" ),
+ "robertgogolok@gmx.de");
+
+ tmp->addCredit("David Vignoni",
+ I18N_NOOP("Responsible for the nice application SVG Icon." ),
+ "david80v@tin.it");
+
+ tmp->addCredit( "Danny Allen",
+ I18N_NOOP( "Responsible for the new object action icons." ),
+ "danny@dannyallen.co.uk" );
+
+ return tmp;
+}
diff --git a/kig/kig/hi128-app-kig.png b/kig/kig/hi128-app-kig.png
new file mode 100644
index 00000000..48eac877
--- /dev/null
+++ b/kig/kig/hi128-app-kig.png
Binary files differ
diff --git a/kig/kig/hi16-app-kig.png b/kig/kig/hi16-app-kig.png
new file mode 100644
index 00000000..67e1d839
--- /dev/null
+++ b/kig/kig/hi16-app-kig.png
Binary files differ
diff --git a/kig/kig/hi22-app-kig.png b/kig/kig/hi22-app-kig.png
new file mode 100644
index 00000000..bb3f7359
--- /dev/null
+++ b/kig/kig/hi22-app-kig.png
Binary files differ
diff --git a/kig/kig/hi32-app-kig.png b/kig/kig/hi32-app-kig.png
new file mode 100644
index 00000000..f7d51c72
--- /dev/null
+++ b/kig/kig/hi32-app-kig.png
Binary files differ
diff --git a/kig/kig/hi48-app-kig.png b/kig/kig/hi48-app-kig.png
new file mode 100644
index 00000000..b28d3b96
--- /dev/null
+++ b/kig/kig/hi48-app-kig.png
Binary files differ
diff --git a/kig/kig/hi64-app-kig.png b/kig/kig/hi64-app-kig.png
new file mode 100644
index 00000000..e9586819
--- /dev/null
+++ b/kig/kig/hi64-app-kig.png
Binary files differ
diff --git a/kig/kig/hisc-app-kig.svgz b/kig/kig/hisc-app-kig.svgz
new file mode 100644
index 00000000..baf0f149
--- /dev/null
+++ b/kig/kig/hisc-app-kig.svgz
Binary files differ
diff --git a/kig/kig/kig.cpp b/kig/kig/kig.cpp
new file mode 100644
index 00000000..2429c843
--- /dev/null
+++ b/kig/kig/kig.cpp
@@ -0,0 +1,308 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "kig.h"
+#include "kig.moc"
+
+#include <qevent.h>
+#include <qtimer.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kedittoolbar.h>
+#include <kfiledialog.h>
+#include <kkeydialog.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstatusbar.h>
+#include <kstdaction.h>
+#include <ktip.h>
+#include <kurl.h>
+#include <kurldrag.h>
+
+#include <assert.h>
+
+Kig::Kig()
+ : KParts::MainWindow( 0L, "Kig" ), m_part( 0 )
+{
+ // setting the configation file
+ config = new KConfig( "kigrc" );
+ // set the shell's ui resource file
+ setXMLFile("kigui.rc");
+ // then, setup our actions
+ setupActions();
+
+ // this routine will find and load our Part. it finds the Part by
+ // name which is a bad idea usually.. but it's alright in this
+ // case since our Part is made for this Shell
+
+ // we use globalLibrary() because if we use python scripting, then
+ // we need the python symbols to be exported, in order for python to
+ // be able to load its dll modules.. Another part of the problem is
+ // that boost.python fails to link against python ( on Debian at
+ // least ).
+ KLibrary* library = KLibLoader::self()->globalLibrary("libkigpart");
+ KLibFactory* factory = 0;
+ if ( library ) factory = library->factory();
+ if (factory)
+ {
+ // now that the Part is loaded, we cast it to a Part to get
+ // our hands on it
+ m_part = static_cast<KParts::ReadWritePart*>
+ (factory->create(this, "kig_part", "KParts::ReadWritePart" ));
+ if (m_part)
+ {
+ // tell the KParts::MainWindow that this is indeed the main widget
+ setCentralWidget(m_part->widget());
+
+ // and integrate the part's GUI with the shell's
+ createGUI(m_part);
+ // finally show tip-of-day ( if the user wants it :) )
+ QTimer::singleShot( 0, this, SLOT( startupTipOfDay() ) );
+ }
+ }
+ else
+ {
+ // if we couldn't find our Part, we exit since the Shell by
+ // itself can't do anything useful
+ KMessageBox::error(this, i18n( "Could not find the necessary Kig library, check your installation." ) );
+ KApplication::exit();
+ return;
+ }
+
+ // we have drag'n'drop
+ setAcceptDrops(true);
+
+ // save the window settings on exit.
+ setAutoSaveSettings();
+}
+
+Kig::~Kig()
+{
+ m_recentFilesAction->saveEntries(config);
+ delete config;
+}
+
+void Kig::setupActions()
+{
+ KStdAction::openNew(this, SLOT(fileNew()), actionCollection());
+ KStdAction::open(this, SLOT(fileOpen()), actionCollection());
+ KStdAction::quit(this, SLOT(close()), actionCollection());
+
+#ifdef KIG_DONT_USE_NEW_KMAINWINDOW_FEATURES
+ m_toolbarAction = KStdAction::showToolbar(this, SLOT(optionsShowToolbar()), actionCollection());
+ m_statusbarAction = KStdAction::showStatusbar(this, SLOT(optionsShowStatusbar()), actionCollection());
+#else
+ createStandardStatusBarAction();
+ setStandardToolBarMenuEnabled(true);
+#endif
+
+ // FIXME: this (recent files) should be app-wide, not specific to each window...
+ m_recentFilesAction = KStdAction::openRecent(this, SLOT(openURL(const KURL&)), actionCollection());
+ m_recentFilesAction->loadEntries(config);
+
+#if KDE_IS_VERSION( 3, 2, 90 )
+ KStdAction::keyBindings( guiFactory(), SLOT( configureShortcuts() ), actionCollection() );
+#else
+ KStdAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection());
+#endif
+ KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection());
+
+ KStdAction::tipOfDay( this, SLOT( tipOfDay() ), actionCollection(), "help_tipofday" );
+}
+
+void Kig::saveProperties(KConfig* config)
+{
+ // the 'config' object points to the session managed
+ // config file. anything you write here will be available
+ // later when this app is restored
+ config->writePathEntry("fileName", m_part->url().path());
+}
+
+void Kig::readProperties(KConfig* config)
+{
+ // the 'config' object points to the session managed
+ // config file. this function is automatically called whenever
+ // the app is being restored. read in here whatever you wrote
+ // in 'saveProperties'
+ load ( KURL(config->readPathEntry("fileName")));
+}
+
+void Kig::load(const KURL& url)
+{
+ // we check for m_part not being 0, because in the case of us not
+ // finding our library, we would otherwise get a crash...
+ if ( m_part && m_part->openURL( url ) ) m_recentFilesAction->addURL( url );
+}
+
+void Kig::fileNew()
+{
+ // this slot is called whenever the File->New menu is selected,
+ // the New shortcut is pressed (usually CTRL+N) or the New toolbar
+ // button is clicked
+
+ // create a new window if we aren't in the "initial state" ( see
+ // the KDE style guide on the file menu stuff...)
+ if ( ! m_part->url().isEmpty() || m_part->isModified() )
+ (new Kig)->show();
+}
+
+void Kig::openURL(const KURL& url)
+{
+ // Called for opening a file by either the KRecentFilesAction or our
+ // own fileOpen() method.
+ // if we are in the "initial state", we open the url in this window:
+ if ( m_part->url().isEmpty() && ! m_part->isModified() )
+ {
+ load( url );
+ }
+ else
+ {
+ // otherwise we open it in a new window...
+ Kig* widget = new Kig;
+ widget->load(url);
+ widget->show();
+ };
+}
+
+void Kig::optionsConfigureKeys()
+{
+#if KDE_IS_VERSION( 3, 2, 90 )
+ assert( false );
+#else
+ KKeyDialog dlg( true, this );
+ dlg.insert( actionCollection() );
+ dlg.insert( m_part->actionCollection() );
+ (void) dlg.configure( true );
+#endif
+}
+
+void Kig::optionsConfigureToolbars()
+{
+ saveMainWindowSettings(KGlobal::config(), "MainWindow");
+
+ // use the standard toolbar editor
+ KEditToolbar dlg(factory());
+ connect(&dlg, SIGNAL(newToolbarConfig()),
+ this, SLOT(applyNewToolbarConfig()));
+ dlg.exec();
+}
+
+void Kig::applyNewToolbarConfig()
+{
+ applyMainWindowSettings(KGlobal::config(), "MainWindow");
+}
+
+bool Kig::queryClose()
+{
+ if (!m_part->isReadWrite() || !m_part->isModified()) return true;
+ switch( KMessageBox::warningYesNoCancel
+ (
+ widget(),
+ i18n("Save changes to document %1?").arg(m_part->url().path()),
+ i18n("Save Changes?"),KStdGuiItem::save(),KStdGuiItem::discard()
+ ))
+ {
+ case KMessageBox::Yes:
+ if (m_part->save()) return true;
+ else return false;
+ break;
+ case KMessageBox::No:
+ return true;
+ break;
+ default: // cancel
+ return false;
+ break;
+ };
+}
+
+void Kig::dragEnterEvent(QDragEnterEvent* e)
+{
+ e->accept(KURLDrag::canDecode(e));
+}
+
+void Kig::dropEvent(QDropEvent* e)
+{
+ KURL::List urls;
+ if ( KURLDrag::decode (e, urls) )
+ {
+ for (KURL::List::iterator u = urls.begin(); u != urls.end(); ++u)
+ {
+ Kig* k = new Kig;
+ k->show();
+ k->load(*u);
+ };
+ };
+}
+
+void Kig::fileOpen()
+{
+ QString formats =
+ i18n( "*.kig *.kigz *.kgeo *.seg|All Supported Files (*.kig *.kigz *.kgeo *.seg)\n"
+ "*.kig|Kig Documents (*.kig)\n"
+ "*.kigz|Compressed Kig Documents (*.kigz)\n"
+ "*.kgeo|KGeo Documents (*.kgeo)\n"
+ "*.seg|KSeg Documents (*.seg)\n"
+ "*.fgeo|Dr. Geo Documents (*.fgeo)\n"
+ "*.fig *.FIG|Cabri Documents (*.fig *.FIG)" );
+
+ // this slot is connected to the KStdAction::open action...
+ QString file_name = KFileDialog::getOpenFileName(":document", formats );
+
+ if (!file_name.isEmpty()) openURL(file_name);
+}
+
+// ifdef's disabled, cause Qt moc doesn't handle ifdef's..
+// #ifdef KIG_DONT_USE_NEW_KMAINWINDOW_FEATURES
+void Kig::optionsShowToolbar()
+{
+#ifdef KIG_DONT_USE_NEW_KMAINWINDOW_FEATURES
+ if (m_toolbarAction->isChecked())
+ toolBar()->show();
+ else
+ toolBar()->hide();
+#else
+ assert( false );
+#endif
+}
+
+void Kig::optionsShowStatusbar()
+{
+#ifdef KIG_DONT_USE_NEW_KMAINWINDOW_FEATURES
+ if (m_statusbarAction->isChecked())
+ statusBar()->show();
+ else
+ statusBar()->hide();
+#else
+ assert( false );
+#endif
+}
+// #endif
+
+void Kig::tipOfDay() {
+ KTipDialog::showTip( "kig/tips", true );
+}
+
+void Kig::startupTipOfDay() {
+ KTipDialog::showTip( "kig/tips" );
+}
diff --git a/kig/kig/kig.desktop b/kig/kig/kig.desktop
new file mode 100644
index 00000000..b2e11e40
--- /dev/null
+++ b/kig/kig/kig.desktop
@@ -0,0 +1,121 @@
+[Desktop Entry]
+Name=Kig
+Name[bn]=কিগ
+Name[hi]=केआईजी
+Name[ne]=किग
+Name[pa]=ਕਿਗ
+Name[ta]=கிகà¯
+GenericName=Interactive Geometry
+GenericName[af]=Interaktiewe Meetkunde
+GenericName[be]=ІнтÑÑ€Ð°ÐºÑ‚Ñ‹ÑžÐ½Ð°Ñ Ð³ÐµÐ°Ð¼ÐµÑ‚Ñ€Ñ‹Ñ
+GenericName[bg]=Интерактивна геометриÑ
+GenericName[bn]=ইনà§à¦Ÿà¦¾à¦°à¦…à§à¦¯à¦¾à¦•à¦Ÿà¦¿à¦­ জà§à¦¯à¦¾à¦®à¦¿à¦¤à¦¿
+GenericName[bs]=Interaktivna geometrija
+GenericName[ca]=Geometria interactiva
+GenericName[cs]=Interaktivní geometrie
+GenericName[csb]=Interaktiwnô geòmetrëjô
+GenericName[cy]=Geometreg Rhyngweithiol
+GenericName[da]=Interaktiv geometri
+GenericName[de]=Interaktive Geometrie
+GenericName[el]=AλληλεπιδÏαστική γεωμετÏία
+GenericName[eo]=Interaga geometrios
+GenericName[es]=Geometría interactiva
+GenericName[et]=Interaktiivne geomeetria
+GenericName[eu]=Geometria interaktiboa
+GenericName[fa]=هندسۀ تعاملی
+GenericName[fi]=Interaktiivinen Geometria
+GenericName[fr]=Géométrie interactive
+GenericName[ga]=Céimseata Idirghníomhach
+GenericName[gl]=Xeometría Interactiva
+GenericName[he]=×’×ומטריה ×ינטר×קטיבית
+GenericName[hi]=इंटरà¤à¤•à¥à¤Ÿà¤¿à¤µ जà¥à¤¯à¥‰à¤®à¤¿à¤¤à¥€
+GenericName[hr]=Interaktivna geometrija
+GenericName[hu]=Interaktív geometria
+GenericName[is]=Gagnvirk rúmfræði
+GenericName[it]=Geometria interattiva
+GenericName[ja]=幾何学ã¨ã®å¯¾è©±
+GenericName[ka]=ინტერáƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒ˜ გეáƒáƒ›áƒ”ტრიáƒ
+GenericName[km]=ធរណីមាážáŸ’រ​អន្ážážšáž€áž˜áŸ’ម
+GenericName[lt]=Interaktyvi geometrija
+GenericName[ms]=Geometri Interaktif
+GenericName[nb]=Interaktiv geometri
+GenericName[nds]=Wesselwarken Geometrie
+GenericName[ne]=अनà¥à¤¤à¤°à¥à¤•à¥à¤°à¤¿à¤¯à¤¾à¤¤à¥à¤®à¤• भूगोल
+GenericName[nl]=Interactieve geometry
+GenericName[nn]=Interaktiv geometri
+GenericName[pa]=ਦਿਲ-ਖਿਚਵੀਂ ਜà©à¨®à©ˆà¨Ÿà¨°à©€
+GenericName[pl]=Interaktywna geometria
+GenericName[pt]=Geometria Interactiva
+GenericName[pt_BR]=Geometria interativa
+GenericName[ru]=Ð˜Ð½Ñ‚ÐµÑ€Ð°ÐºÑ‚Ð¸Ð²Ð½Ð°Ñ Ð³ÐµÐ¾Ð¼ÐµÑ‚Ñ€Ð¸Ñ
+GenericName[sk]=Interaktívna geometria
+GenericName[sl]=Interaktivna geometrija
+GenericName[sr]=Интерактивна геометрија
+GenericName[sr@Latn]=Interaktivna geometrija
+GenericName[sv]=Interaktiv geometri
+GenericName[ta]= ஊடாடà¯à®®à¯ வடிவியலà¯
+GenericName[tg]=ГеометриÑи интерактивӣ
+GenericName[tr]=EtkileÅŸimli Geometri
+GenericName[uk]=Інтерактивна геометріÑ
+GenericName[ven]=Geometry yau shumea nayo
+GenericName[vi]=Hình há»c TÆ°Æ¡ng tác
+GenericName[xh]=Umyili Wesiboniso Esingaphakathi
+GenericName[zh_CN]=交互几何
+GenericName[zh_TW]=交互å¼å¹¾ä½•ä½œåœ–
+GenericName[zu]=Ukubekeka Kwebalazwe Kokukhulumisanayo
+Comment=Explore Geometric Constructions
+Comment[be]=ВывучÑнне геаметрычных фігур
+Comment[bg]=Геометрични конÑтрукции
+Comment[bn]=জà§à¦¯à¦¾à¦®à¦¿à¦¤à¦¿ ছবি আà¦à¦•à¦¾ চরà§à¦šà¦¾ করà§à¦¨
+Comment[bs]=Istražite geometrijske konstrukcije
+Comment[ca]=Explora construccions geomètriques
+Comment[cs]=Objevujte geometrické konstrukce
+Comment[csb]=Exploatëjë geòmetriczne kònstrukcëjë
+Comment[da]=Udforsk geometriske konstruktioner
+Comment[de]=Geometrische Konstruktionen untersuchen
+Comment[el]=ΕξεÏεÏνηση γεωμετÏικών κατασκευών
+Comment[eo]=Explorado de geometriaj konstruaĵoj
+Comment[es]=Exploración de construcciones geométricas
+Comment[et]=Geomeetriliste kujundite tundmaõppimine
+Comment[eu]=Arakatu geometria egiturak
+Comment[fa]=کاوش ساختارهای هندسی
+Comment[fi]=Tutki geometrisia rakenteita
+Comment[fr]=Explorer les constructions géométriques
+Comment[ga]=Taiscéal Tógálacha Céimseatúla
+Comment[gl]=Explore as Figuras Xeométricas
+Comment[he]=חקור ×ž×‘× ×™× ×’×ומטריי×
+Comment[hr]=Upoznajte geometrijske konstrukcije
+Comment[hu]=Geometriai oktatóprogram
+Comment[is]=Kanna rúmfræðilega byggingu forma
+Comment[it]=Esplora le costruzioni geometriche
+Comment[ja]=幾何学ã¨ã®å¯¾è©±
+Comment[ka]=გეáƒáƒ›áƒ”ტრიულ ფიგურáƒáƒ—რშესწáƒáƒ•áƒšáƒ
+Comment[km]=រុករក​សំណង់​ធរណីមាážáŸ’ážš
+Comment[lt]=Geometrinių konstrukcijų tyrinėjimas
+Comment[ms]=Jelahan Pembinaan Geometrik
+Comment[nb]=Utforsk geometriske konstruksjoner
+Comment[nds]=Geometersch Konstrukschonen bekieken
+Comment[ne]=भूगोल बनावट अनà¥à¤µà¥‡à¤·à¤£ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Ruimtelijke constructies verkennen
+Comment[nn]=Utforsk geometriske konstruksjonar
+Comment[pl]=Zabawa konstrukcjami geometrycznymi
+Comment[pt]=Explorar Construções Geométricas
+Comment[pt_BR]=Explore construções geométricas
+Comment[ru]=Работа Ñ Ð³ÐµÐ¾Ð¼ÐµÑ‚Ñ€Ð¸Ñ‡ÐµÑкими поÑтроениÑми
+Comment[sk]=Prieskum geometrických konštrukcií
+Comment[sl]=Raziskovanje geometrijskih konstrukcij
+Comment[sr]=ИÑтражујте геометријÑке конÑтрукције
+Comment[sr@Latn]=Istražujte geometrijske konstrukcije
+Comment[sv]=Utforska geometriska konstruktioner
+Comment[tr]=Geometik Åžekilleri KeÅŸfedin
+Comment[uk]=ДоÑÐ»Ñ–Ð´Ð¶ÐµÐ½Ð½Ñ Ð³ÐµÐ¾Ð¼ÐµÑ‚Ñ€Ð¸Ñ‡Ð½Ð¸Ñ… конÑтрукцій
+Comment[vi]=Khám phá các phép Dụng Hình há»c
+Comment[zh_CN]=探索几何构造的世界
+Comment[zh_TW]=作出幾何圖形
+Exec=kig %i %m -caption "%c"
+MimeType=application/x-kig;application/x-kgeo;
+Icon=kig
+Type=Application
+DocPath=kig/index.html
+Terminal=false
+Categories=Qt;KDE;Education;Math;
diff --git a/kig/kig/kig.h b/kig/kig/kig.h
new file mode 100644
index 00000000..d6ad9fea
--- /dev/null
+++ b/kig/kig/kig.h
@@ -0,0 +1,148 @@
+// This file is part of Kig, a KDE program for Interactive Geometry...
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_KIG_H
+#define KIG_KIG_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kdeversion.h>
+
+#ifdef KDE_IS_VERSION
+#if KDE_IS_VERSION( 3, 1, 90 )
+#undef KIG_DONT_USE_NEW_KMAINWINDOW_FEATURES
+#else
+#define KIG_DONT_USE_NEW_KMAINWINDOW_FEATURES
+#endif
+#else
+#define KIG_DONT_USE_NEW_KMAINWINDOW_FEATURES
+#endif
+
+#include <kapplication.h>
+#include <kparts/mainwindow.h>
+#include <dcopclient.h>
+
+class KToggleAction;
+class KRecentFilesAction;
+
+/**
+ * This is the application "Shell". It has a menubar, toolbar, and
+ * statusbar but relies on the "Part" to do all the real work.
+ */
+class Kig : public KParts::MainWindow
+{
+ Q_OBJECT
+ public:
+ /**
+ * Default Constructor
+ */
+ Kig();
+
+ /**
+ * Default Destructor
+ */
+ virtual ~Kig();
+
+ public slots:
+ /**
+ * Open file in this window
+ * \param file file to open
+ */
+ void load (const KURL& file);
+
+ /**
+ * this opens the file specified in \p s in a new window
+ *
+ * \param s the url of the file to open
+ */
+ void openURL (const QString& s) { openURL(KURL(s)); }
+ void openURL (const KURL& s);
+
+ protected:
+
+ /**
+ * The user started dragging something onto us...
+ *
+ * \param e
+ */
+ void dragEnterEvent(QDragEnterEvent* e);
+
+ /**
+ * The user dropped something onto us...
+ *
+ * \param e
+ */
+ void dropEvent (QDropEvent* e);
+
+ /**
+ * this is called by the framework before closing the window, to
+ * allow the user to save his changes... returning false cancels the
+ * close request...
+ */
+ bool queryClose();
+
+ /**
+ * This method is called when it is time for the app to save its
+ * properties for session management purposes.
+ */
+ void saveProperties(KConfig *);
+
+ /**
+ * This method is called when this app is restored. The KConfig
+ * object points to the session management config file that was saved
+ * with \ref saveProperties
+ */
+ void readProperties(KConfig *);
+
+ private slots:
+ void fileNew();
+ void fileOpen();
+ // Qt moc doesn't handle ifdef's, so i'm disabling it..
+// #ifdef KIG_DONT_USE_NEW_KMAINWINDOW_FEATURES
+ void optionsShowToolbar();
+ void optionsShowStatusbar();
+// #endif
+// #if KDE_IS_VERSION( 3, 2, 90 )
+ void optionsConfigureKeys();
+// #endif
+ void optionsConfigureToolbars();
+
+ void applyNewToolbarConfig();
+
+ void tipOfDay();
+ void startupTipOfDay();
+
+ private:
+ void setupActions();
+
+ KParts::ReadWritePart *m_part;
+
+//#ifdef KIG_DONT_USE_NEW_KMAINWINDOW_FEATURES
+ KToggleAction *m_toolbarAction;
+ KToggleAction *m_statusbarAction;
+//#endif
+ KRecentFilesAction *m_recentFilesAction;
+
+ KConfig* config;
+
+ static bool kimageioRegistered;
+};
+
+#endif // KIG_KIG_H
diff --git a/kig/kig/kig_commands.cpp b/kig/kig/kig_commands.cpp
new file mode 100644
index 00000000..b9846fa6
--- /dev/null
+++ b/kig/kig/kig_commands.cpp
@@ -0,0 +1,398 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "kig_commands.h"
+#include "kig_commands.moc"
+
+#include "kig_part.h"
+#include "kig_document.h"
+#include "kig_view.h"
+
+#include "../modes/mode.h"
+#include "../objects/object_imp.h"
+#include "../objects/object_drawer.h"
+#include "../misc/calcpaths.h"
+#include "../misc/coordinate_system.h"
+
+#include <vector>
+
+using std::vector;
+using std::max;
+using std::min;
+
+class KigCommand::Private
+{
+public:
+ Private( KigPart& d ) : doc( d ) {}
+ KigPart& doc;
+ vector<KigCommandTask*> tasks;
+};
+
+KigCommand::KigCommand( KigPart& doc, const QString& name )
+ : KNamedCommand(name), d( new Private( doc ) )
+{
+}
+
+KigCommand::~KigCommand()
+{
+ for ( uint i = 0; i < d->tasks.size(); ++i )
+ delete d->tasks[i];
+ delete d;
+}
+
+void KigCommand::execute()
+{
+ for ( uint i = 0; i < d->tasks.size(); ++i )
+ d->tasks[i]->execute( d->doc );
+ d->doc.redrawScreen();
+}
+
+void KigCommand::unexecute()
+{
+ for ( uint i = 0; i < d->tasks.size(); ++i )
+ d->tasks[i]->unexecute( d->doc );
+ d->doc.redrawScreen();
+}
+
+void KigCommand::addTask( KigCommandTask* t )
+{
+ d->tasks.push_back( t );
+}
+
+KigCommand* KigCommand::removeCommand( KigPart& doc, ObjectHolder* o )
+{
+ std::vector<ObjectHolder*> os;
+ os.push_back( o );
+ return removeCommand( doc, os );
+}
+
+KigCommand* KigCommand::addCommand( KigPart& doc, ObjectHolder* o )
+{
+ std::vector<ObjectHolder*> os;
+ os.push_back( o );
+ return addCommand( doc, os );
+}
+
+KigCommand* KigCommand::removeCommand( KigPart& doc, const std::vector<ObjectHolder*>& os )
+{
+ assert( os.size() > 0 );
+ QString text;
+ if ( os.size() == 1 )
+ text = os.back()->imp()->type()->removeAStatement();
+ else
+ text = i18n( "Remove %1 Objects" ).arg( os.size() );
+ KigCommand* ret = new KigCommand( doc, text );
+ ret->addTask( new RemoveObjectsTask( os ) );
+ return ret;
+}
+
+KigCommand* KigCommand::addCommand( KigPart& doc, const std::vector<ObjectHolder*>& os )
+{
+ QString text;
+ if ( os.size() == 1 )
+ text = os.back()->imp()->type()->addAStatement();
+ else
+ text = i18n( "Add %1 Objects" ).arg( os.size() );
+ KigCommand* ret = new KigCommand( doc, text );
+ ret->addTask( new AddObjectsTask( os ) );
+ return ret;
+}
+
+KigCommand* KigCommand::changeCoordSystemCommand( KigPart& doc, CoordinateSystem* s )
+{
+ QString text = CoordinateSystemFactory::setCoordinateSystemStatement( s->id() );
+ KigCommand* ret = new KigCommand( doc, text );
+ ret->addTask( new ChangeCoordSystemTask( s ) );
+ return ret;
+}
+
+KigCommandTask::KigCommandTask()
+{
+}
+
+KigCommandTask::~KigCommandTask()
+{
+}
+
+AddObjectsTask::AddObjectsTask( const std::vector<ObjectHolder*>& os)
+ : KigCommandTask(), undone( true ), mobjs( os )
+{
+}
+
+void AddObjectsTask::execute( KigPart& doc )
+{
+ doc._addObjects( mobjs );
+ undone = false;
+}
+
+void AddObjectsTask::unexecute( KigPart& doc )
+{
+ doc._delObjects( mobjs );
+ undone = true;
+}
+
+AddObjectsTask::~AddObjectsTask()
+{
+ if ( undone )
+ for ( std::vector<ObjectHolder*>::iterator i = mobjs.begin();
+ i != mobjs.end(); ++i )
+ delete *i;
+}
+
+RemoveObjectsTask::RemoveObjectsTask( const std::vector<ObjectHolder*>& os )
+ : AddObjectsTask( os )
+{
+ undone = false;
+}
+
+void RemoveObjectsTask::execute( KigPart& doc )
+{
+ AddObjectsTask::unexecute( doc );
+}
+
+void RemoveObjectsTask::unexecute( KigPart& doc )
+{
+ AddObjectsTask::execute( doc );
+}
+
+ChangeObjectConstCalcerTask::ChangeObjectConstCalcerTask( ObjectConstCalcer* calcer, ObjectImp* newimp )
+ : KigCommandTask(), mcalcer( calcer ), mnewimp( newimp )
+{
+}
+
+void ChangeObjectConstCalcerTask::execute( KigPart& doc )
+{
+ mnewimp = mcalcer->switchImp( mnewimp );
+
+ std::set<ObjectCalcer*> allchildren = getAllChildren( mcalcer.get() );
+ std::vector<ObjectCalcer*> allchildrenvect( allchildren.begin(), allchildren.end() );
+ allchildrenvect = calcPath( allchildrenvect );
+ for ( std::vector<ObjectCalcer*>::iterator i = allchildrenvect.begin();
+ i != allchildrenvect.end(); ++i )
+ ( *i )->calc( doc.document() );
+}
+
+void ChangeObjectConstCalcerTask::unexecute( KigPart& doc )
+{
+ execute( doc );
+}
+
+struct MoveDataStruct
+{
+ ObjectConstCalcer* o;
+ ObjectImp* oldimp;
+ MoveDataStruct( ObjectConstCalcer* io, ObjectImp* oi )
+ : o( io ), oldimp( oi ) { }
+};
+
+class MonitorDataObjects::Private
+{
+public:
+ vector<MoveDataStruct> movedata;
+};
+
+MonitorDataObjects::MonitorDataObjects( const std::vector<ObjectCalcer*>& objs )
+ : d( new Private )
+{
+ monitor( objs );
+}
+
+void MonitorDataObjects::monitor( const std::vector<ObjectCalcer*>& objs )
+{
+ for ( std::vector<ObjectCalcer*>::const_iterator i = objs.begin(); i != objs.end(); ++i )
+ if ( dynamic_cast<ObjectConstCalcer*>( *i ) )
+ {
+ MoveDataStruct n( static_cast<ObjectConstCalcer*>( *i ), (*i)->imp()->copy() );
+ d->movedata.push_back( n );
+ };
+}
+
+void MonitorDataObjects::finish( KigCommand* comm )
+{
+ for ( uint i = 0; i < d->movedata.size(); ++i )
+ {
+ ObjectConstCalcer* o = d->movedata[i].o;
+ if ( ! d->movedata[i].oldimp->equals( *o->imp() ) )
+ {
+ ObjectImp* newimp = o->switchImp( d->movedata[i].oldimp );
+ comm->addTask( new ChangeObjectConstCalcerTask( o, newimp ) );
+ }
+ else
+ delete d->movedata[i].oldimp;
+ };
+ d->movedata.clear();
+}
+
+MonitorDataObjects::~MonitorDataObjects()
+{
+ assert( d->movedata.empty() );
+ delete d;
+}
+
+ChangeCoordSystemTask::ChangeCoordSystemTask( CoordinateSystem* s )
+ : KigCommandTask(), mcs( s )
+{
+}
+
+void ChangeCoordSystemTask::execute( KigPart& doc )
+{
+ mcs = doc.document().switchCoordinateSystem( mcs );
+ std::vector<ObjectCalcer*> calcpath = calcPath( getAllCalcers( doc.document().objects() ) );
+ for ( std::vector<ObjectCalcer*>::iterator i = calcpath.begin(); i != calcpath.end(); ++i )
+ ( *i )->calc( doc.document() );
+ doc.coordSystemChanged( doc.document().coordinateSystem().id() );
+}
+
+void ChangeCoordSystemTask::unexecute( KigPart& doc )
+{
+ execute( doc );
+}
+
+ChangeCoordSystemTask::~ChangeCoordSystemTask()
+{
+ delete mcs;
+}
+
+class ChangeParentsAndTypeTask::Private
+{
+public:
+ ObjectTypeCalcer* o;
+ std::vector<ObjectCalcer::shared_ptr> newparents;
+ const ObjectType* newtype;
+};
+
+ChangeParentsAndTypeTask::~ChangeParentsAndTypeTask()
+{
+ delete d;
+}
+
+ChangeParentsAndTypeTask::ChangeParentsAndTypeTask(
+ ObjectTypeCalcer* o, const std::vector<ObjectCalcer*>& newparents,
+ const ObjectType* newtype )
+ : KigCommandTask(), d( new Private )
+{
+ d->o = o;
+ std::copy( newparents.begin(), newparents.end(),
+ std::back_inserter( d->newparents ) );
+ d->newtype = newtype;
+}
+
+void ChangeParentsAndTypeTask::execute( KigPart& doc )
+{
+ const ObjectType* oldtype = d->o->type();
+ d->o->setType( d->newtype );
+ d->newtype = oldtype;
+
+ std::vector<ObjectCalcer*> oldparentso = d->o->parents();
+ std::vector<ObjectCalcer::shared_ptr> oldparents(
+ oldparentso.begin(), oldparentso.end() );
+ std::vector<ObjectCalcer*> newparents;
+ for ( std::vector<ObjectCalcer::shared_ptr>::iterator i = d->newparents.begin();
+ i != d->newparents.end(); ++i )
+ newparents.push_back( i->get() );
+ d->o->setParents( newparents );
+ d->newparents = oldparents;
+
+ for ( std::vector<ObjectCalcer*>::iterator i = newparents.begin(); i != newparents.end(); ++i )
+ ( *i )->calc( doc.document() );
+ d->o->calc( doc.document() );
+ std::set<ObjectCalcer*> allchildren = getAllChildren( d->o );
+ std::vector<ObjectCalcer*> allchildrenvect( allchildren.begin(), allchildren.end() );
+ allchildrenvect = calcPath( allchildrenvect );
+ for ( std::vector<ObjectCalcer*>::iterator i = allchildrenvect.begin();
+ i != allchildrenvect.end(); ++i )
+ ( *i )->calc( doc.document() );
+}
+
+void ChangeParentsAndTypeTask::unexecute( KigPart& doc )
+{
+ execute( doc );
+}
+
+class KigViewShownRectChangeTask::Private
+{
+public:
+ Private( KigWidget& view, const Rect& r ) : v( view ), rect( r ) { }
+ KigWidget& v;
+ Rect rect;
+};
+
+KigViewShownRectChangeTask::KigViewShownRectChangeTask(
+ KigWidget& v, const Rect& newrect )
+ : KigCommandTask()
+{
+ d = new Private( v, newrect );
+}
+
+KigViewShownRectChangeTask::~KigViewShownRectChangeTask()
+{
+ delete d;
+}
+
+void KigViewShownRectChangeTask::execute( KigPart& doc )
+{
+ Rect oldrect = d->v.showingRect();
+ d->v.setShowingRect( d->rect );
+ doc.mode()->redrawScreen( &d->v );
+ d->v.updateScrollBars();
+ d->rect = oldrect;
+}
+
+void KigViewShownRectChangeTask::unexecute( KigPart& doc )
+{
+ execute( doc );
+}
+
+ChangeObjectDrawerTask::~ChangeObjectDrawerTask()
+{
+ delete mnewdrawer;
+}
+
+ChangeObjectDrawerTask::ChangeObjectDrawerTask(
+ ObjectHolder* holder, ObjectDrawer* newdrawer )
+ : KigCommandTask(), mholder( holder ), mnewdrawer( newdrawer )
+{
+}
+
+void ChangeObjectDrawerTask::execute( KigPart& )
+{
+ mnewdrawer = mholder->switchDrawer( mnewdrawer );
+}
+
+void ChangeObjectDrawerTask::unexecute( KigPart& doc )
+{
+ execute( doc );
+}
+
+MonitorDataObjects::MonitorDataObjects( ObjectCalcer* c )
+ : d( new Private )
+{
+ if ( dynamic_cast<ObjectConstCalcer*>( c ) )
+ {
+ MoveDataStruct n( static_cast<ObjectConstCalcer*>( c ), c->imp()->copy() );
+ d->movedata.push_back( n );
+ };
+}
+
+ChangeObjectConstCalcerTask::~ChangeObjectConstCalcerTask()
+{
+ delete mnewimp;
+}
+
diff --git a/kig/kig/kig_commands.h b/kig/kig/kig_commands.h
new file mode 100644
index 00000000..8e4fd044
--- /dev/null
+++ b/kig/kig/kig_commands.h
@@ -0,0 +1,217 @@
+/*
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+*/
+
+
+#ifndef KIG_COMMANDS_H
+#define KIG_COMMANDS_H
+
+#include <kcommand.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "../objects/object_holder.h"
+
+class KigDocument;
+class KigPart;
+class CoordinateSystem;
+
+class KigCommandTask;
+class KigWidget;
+class Rect;
+
+/**
+ * a KigCommand represents almost every action performed in Kig.
+ * Used mainly in the Undo/Redo stuff...
+ */
+class KigCommand
+ : public QObject, public KNamedCommand
+{
+ Q_OBJECT
+ class Private;
+ Private* d;
+public:
+ KigCommand( KigPart& inDoc, const QString& name );
+ ~KigCommand();
+
+ /**
+ * To avoid confusion, this doesn't add a command to anything, this
+ * creates an AddCommand ;)
+ */
+ static KigCommand* addCommand( KigPart& doc, const std::vector<ObjectHolder*>& os );
+ static KigCommand* addCommand( KigPart& doc, ObjectHolder* os );
+ /**
+ * make sure that when you delete something, you are also deleting
+ * its parents. This class assumes you've done that.
+ * \ref KigDocument::delObjects() takes care of this for you.
+ */
+ static KigCommand* removeCommand( KigPart& doc, const std::vector<ObjectHolder*>& os );
+ static KigCommand* removeCommand( KigPart& doc, ObjectHolder* o );
+
+ static KigCommand* changeCoordSystemCommand( KigPart& doc, CoordinateSystem* s );
+
+ void addTask( KigCommandTask* );
+
+ void execute();
+ void unexecute();
+};
+
+class KigCommandTask
+{
+public:
+ KigCommandTask();
+ virtual ~KigCommandTask();
+
+ virtual void execute( KigPart& doc ) = 0;
+ virtual void unexecute( KigPart& doc ) = 0;
+};
+
+class AddObjectsTask
+ : public KigCommandTask
+{
+public:
+ AddObjectsTask( const std::vector<ObjectHolder*>& os);
+ ~AddObjectsTask ();
+ void execute( KigPart& doc );
+ void unexecute( KigPart& doc );
+protected:
+ bool undone;
+
+ std::vector<ObjectHolder*> mobjs;
+};
+
+class RemoveObjectsTask
+ : public AddObjectsTask
+{
+public:
+ RemoveObjectsTask( const std::vector<ObjectHolder*>& os );
+ void execute( KigPart& );
+ void unexecute( KigPart& );
+};
+
+class ChangeObjectConstCalcerTask
+ : public KigCommandTask
+{
+public:
+ ChangeObjectConstCalcerTask( ObjectConstCalcer* calcer, ObjectImp* newimp );
+ ~ChangeObjectConstCalcerTask();
+
+ void execute( KigPart& );
+ void unexecute( KigPart& );
+protected:
+ ObjectConstCalcer::shared_ptr mcalcer;
+ ObjectImp* mnewimp;
+};
+
+/**
+ * this class monitors a set of DataObjects for changes and returns an
+ * appropriate ChangeObjectImpsCommand if necessary..
+ * E.g. MovingMode wants to move certain objects, so it monitors all
+ * the parents of the explicitly moving objects:
+ * \code
+ * MonitorDataObjects mon( getAllParents( emo ) );
+ * \endcode
+ * It then moves them around, and when it is finished, it asks to add
+ * the KigCommandTasks to a KigCommand, and applies that..
+ * \code
+ * KigCommand* comm = new KigCommand( doc, i18n( "Move Stuff" ) );
+ * mon.finish( comm );
+ * \endcode
+ */
+class MonitorDataObjects
+{
+ class Private;
+ Private* d;
+public:
+ /**
+ * all the DataObjects in \p objs will be watched..
+ */
+ MonitorDataObjects( const std::vector<ObjectCalcer*>& objs );
+ MonitorDataObjects( ObjectCalcer* c );
+ ~MonitorDataObjects();
+
+ /**
+ * add \p objs to the list of objs to be watched, and save their
+ * current imp's..
+ */
+ void monitor( const std::vector<ObjectCalcer*>& objs );
+
+ /**
+ * add the generated KigCommandTasks to the command \p comm ..
+ * monitoring stops after this is called..
+ */
+ void finish( KigCommand* comm );
+};
+
+class ChangeCoordSystemTask
+ : public KigCommandTask
+{
+ CoordinateSystem* mcs;
+public:
+ /**
+ * a command that changes the coordinate-system to \p s ..
+ */
+ ChangeCoordSystemTask( CoordinateSystem* s );
+ ~ChangeCoordSystemTask();
+
+ void execute( KigPart& doc );
+ void unexecute( KigPart& doc );
+};
+
+class ChangeParentsAndTypeTask
+ : public KigCommandTask
+{
+ class Private;
+ Private* d;
+public:
+ ChangeParentsAndTypeTask( ObjectTypeCalcer* o, const std::vector<ObjectCalcer*>& newparents,
+ const ObjectType* newtype );
+ ~ChangeParentsAndTypeTask();
+
+ void execute( KigPart& doc );
+ void unexecute( KigPart& doc );
+};
+
+class KigViewShownRectChangeTask
+ : public KigCommandTask
+{
+ class Private;
+ Private* d;
+public:
+ KigViewShownRectChangeTask( KigWidget& v, const Rect& newrect );
+ ~KigViewShownRectChangeTask();
+
+ void execute( KigPart& doc );
+ void unexecute( KigPart& doc );
+};
+
+class ChangeObjectDrawerTask
+ : public KigCommandTask
+{
+ ObjectHolder* mholder;
+ ObjectDrawer* mnewdrawer;
+public:
+ ChangeObjectDrawerTask( ObjectHolder* holder, ObjectDrawer* newdrawer );
+ ~ChangeObjectDrawerTask();
+
+ void execute( KigPart& doc );
+ void unexecute( KigPart& doc );
+};
+
+#endif
diff --git a/kig/kig/kig_document.cc b/kig/kig/kig_document.cc
new file mode 100644
index 00000000..884b41c5
--- /dev/null
+++ b/kig/kig/kig_document.cc
@@ -0,0 +1,200 @@
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "kig_document.h"
+
+#include "../objects/object_calcer.h"
+#include "../objects/object_holder.h"
+#include "../objects/point_imp.h"
+#include "../objects/polygon_imp.h"
+#include "../misc/coordinate_system.h"
+#include "../misc/rect.h"
+
+#include <assert.h>
+
+KigDocument::KigDocument( std::set<ObjectHolder*> objects, CoordinateSystem* coordsystem,
+ bool showgrid, bool showaxes, bool nv )
+ : mobjects( objects ), mcoordsystem( coordsystem ), mshowgrid( showgrid ),
+ mshowaxes( showaxes ), mnightvision( nv )
+{
+}
+
+const CoordinateSystem& KigDocument::coordinateSystem() const
+{
+ assert( mcoordsystem );
+ return *mcoordsystem;
+}
+
+const std::vector<ObjectHolder*> KigDocument::objects() const
+{
+ return std::vector<ObjectHolder*>( mobjects.begin(), mobjects.end() );
+}
+
+const std::set<ObjectHolder*>& KigDocument::objectsSet() const
+{
+ return mobjects;
+}
+
+void KigDocument::setCoordinateSystem( CoordinateSystem* s )
+{
+ delete switchCoordinateSystem( s );
+}
+
+CoordinateSystem* KigDocument::switchCoordinateSystem( CoordinateSystem* s )
+{
+ CoordinateSystem* ret = mcoordsystem;
+ mcoordsystem = s;
+ return ret;
+}
+
+std::vector<ObjectHolder*> KigDocument::whatAmIOn( const Coordinate& p, const KigWidget& w ) const
+{
+ std::vector<ObjectHolder*> ret;
+ std::vector<ObjectHolder*> curves;
+ std::vector<ObjectHolder*> fatobjects;
+ for ( std::set<ObjectHolder*>::const_iterator i = mobjects.begin();
+ i != mobjects.end(); ++i )
+ {
+ if(!(*i)->contains(p, w, mnightvision)) continue;
+ if ( (*i)->imp()->inherits( PointImp::stype() ) ) ret.push_back( *i );
+ else
+ if ( !(*i)->imp()->inherits( PolygonImp::stype() ) ) curves.push_back( *i );
+ else fatobjects.push_back( *i );
+ };
+ std::copy( curves.begin(), curves.end(), std::back_inserter( ret ) );
+ std::copy( fatobjects.begin(), fatobjects.end(), std::back_inserter( ret ) );
+ return ret;
+}
+
+std::vector<ObjectHolder*> KigDocument::whatIsInHere( const Rect& p, const KigWidget& w )
+{
+ std::vector<ObjectHolder*> ret;
+ std::vector<ObjectHolder*> nonpoints;
+ for ( std::set<ObjectHolder*>::const_iterator i = mobjects.begin();
+ i != mobjects.end(); ++i )
+ {
+ if(! (*i)->inRect( p, w ) ) continue;
+ if ( (*i)->imp()->inherits( PointImp::stype() ) ) ret.push_back( *i );
+ else nonpoints.push_back( *i );
+ };
+ std::copy( nonpoints.begin(), nonpoints.end(), std::back_inserter( ret ) );
+ return ret;
+}
+
+Rect KigDocument::suggestedRect() const
+{
+ bool rectInited = false;
+ Rect r(0.,0.,0.,0.);
+ for ( std::set<ObjectHolder*>::const_iterator i = mobjects.begin();
+ i != mobjects.end(); ++i )
+ {
+ if ( (*i)->shown() )
+ {
+ Rect cr = (*i)->imp()->surroundingRect();
+ if ( ! cr.valid() ) continue;
+ if( !rectInited )
+ {
+ r = cr;
+ rectInited = true;
+ }
+ else
+ r.eat( cr );
+ };
+ };
+
+ if ( ! rectInited )
+ return Rect( -5.5, -5.5, 11., 11. );
+ r.setContains( Coordinate( 0, 0 ) );
+ if( r.width() == 0 ) r.setWidth( 1 );
+ if( r.height() == 0 ) r.setHeight( 1 );
+ Coordinate center = r.center();
+ r *= 2;
+ r.setCenter(center);
+ return r;
+}
+
+void KigDocument::addObject( ObjectHolder* o )
+{
+ mobjects.insert( o );
+}
+
+void KigDocument::addObjects( const std::vector<ObjectHolder*>& os )
+{
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ ( *i )->calc( *this );
+ std::copy( os.begin(), os.end(), std::inserter( mobjects, mobjects.begin() ) );
+}
+
+void KigDocument::delObject( ObjectHolder* o )
+{
+ mobjects.erase( o );
+}
+
+void KigDocument::delObjects( const std::vector<ObjectHolder*>& os )
+{
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ mobjects.erase( *i );
+}
+
+KigDocument::KigDocument()
+ : mcoordsystem( new EuclideanCoords )
+{
+ mshowgrid = true;
+ mshowaxes = true;
+ mnightvision = false;
+}
+
+KigDocument::~KigDocument()
+{
+ typedef std::set<ObjectHolder*> s;
+ for ( s::iterator i = mobjects.begin(); i != mobjects.end(); ++i ) {
+ delete *i;
+ }
+ delete mcoordsystem;
+}
+
+void KigDocument::setGrid( bool showgrid )
+{
+ mshowgrid = showgrid;
+}
+
+const bool KigDocument::grid() const
+{
+ return mshowgrid;
+}
+
+void KigDocument::setAxes( bool showaxes )
+{
+ mshowaxes = showaxes;
+}
+
+void KigDocument::setNightVision( bool nv )
+{
+ mnightvision = nv;
+}
+
+const bool KigDocument::axes() const
+{
+ return mshowaxes;
+}
+
+const bool KigDocument::getNightVision() const
+{
+ return mnightvision;
+}
diff --git a/kig/kig/kig_document.h b/kig/kig/kig_document.h
new file mode 100644
index 00000000..6bcdb623
--- /dev/null
+++ b/kig/kig/kig_document.h
@@ -0,0 +1,137 @@
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_KIG_KIG_DOCUMENT_H
+#define KIG_KIG_KIG_DOCUMENT_H
+
+#include <set>
+#include <vector>
+
+class Coordinate;
+class CoordinateSystem;
+class KigWidget;
+class ObjectHolder;
+class Rect;
+
+/**
+ * KigDocument is the class holding the real data in a Kig document.
+ * It owns a set of Objects, and a CoordinateSystem, which comprise
+ * the entire content of a Kig document.
+ */
+class KigDocument {
+ /**
+ * Here we keep the objects in the document. These are only the
+ * objects that the user is aware of. Other objects exist as well,
+ * but there's no ObjectHolder for them, and they only exist because
+ * some other ObjectCalcer has them as its ancestor.
+ */
+ std::set<ObjectHolder*> mobjects;
+
+ /**
+ * The CoordinateSystem as the user sees it: this has little to do
+ * with the internal coordinates of the objects... It really serves
+ * to translate user coordinates from and to internal coordinates.
+ */
+ CoordinateSystem* mcoordsystem;
+ /**
+ * Whether to show the grid.
+ */
+ bool mshowgrid;
+ /**
+ * Whether to show the axes.
+ */
+ bool mshowaxes;
+ /**
+ * Whether to enable visibility of hidden objects.
+ */
+ bool mnightvision;
+public:
+ KigDocument();
+ KigDocument( std::set<ObjectHolder*> objects, CoordinateSystem* coordsystem,
+ bool showgrid = true, bool showaxes = true, bool nv = false );
+ ~KigDocument();
+
+ const CoordinateSystem& coordinateSystem() const;
+ const bool grid() const;
+ const bool axes() const;
+ const bool getNightVision() const;
+ /**
+ * Get a hold of the objects of this KigDocument.
+ */
+ const std::vector<ObjectHolder*> objects() const;
+ const std::set<ObjectHolder*>& objectsSet() const;
+
+ /**
+ * sets the coordinate system to \p s , and returns the old one..
+ */
+ CoordinateSystem* switchCoordinateSystem( CoordinateSystem* s );
+
+ /**
+ * sets the coordinate system to \p s , and deletes the old one..
+ */
+ void setCoordinateSystem( CoordinateSystem* s );
+
+ /**
+ * set to show/hide the grid.
+ */
+ void setGrid( bool showgrid );
+
+ /**
+ * set to show/hide the grid.
+ */
+ void setAxes( bool showaxes );
+
+ /**
+ * set to enable/disable night-vision (visibility of hidden objects)
+ */
+ void setNightVision( bool nv );
+
+ /**
+ * Return a vector of objects that contain the given point.
+ */
+ std::vector<ObjectHolder*> whatAmIOn( const Coordinate& p, const KigWidget& w ) const;
+
+ /**
+ * Return a vector of objects that are in the given Rect.
+ */
+ std::vector<ObjectHolder*> whatIsInHere( const Rect& p, const KigWidget& );
+
+ /**
+ * Return a rect containing most of the objects, which would be a
+ * fine suggestion to map to the widget...
+ */
+ Rect suggestedRect() const;
+
+ /**
+ * Add the objects \p o to the document.
+ */
+ void addObject( ObjectHolder* oObject );
+ /**
+ * Add the objects \p os to the document.
+ */
+ void addObjects( const std::vector<ObjectHolder*>& os);
+ /**
+ * Remove the object \p o from the document.
+ */
+ void delObject( ObjectHolder* o );
+ /**
+ * Remove the objects \p os from the document.
+ */
+ void delObjects( const std::vector<ObjectHolder*>& os );
+};
+
+#endif
diff --git a/kig/kig/kig_iface.cpp b/kig/kig/kig_iface.cpp
new file mode 100644
index 00000000..1f666a74
--- /dev/null
+++ b/kig/kig/kig_iface.cpp
@@ -0,0 +1,31 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+
+#include "kig_iface.h"
+
+KigIface::KigIface()
+ : DCOPObject("KigIface")
+{
+}
+
+KigIface::~KigIface()
+{
+}
diff --git a/kig/kig/kig_iface.h b/kig/kig/kig_iface.h
new file mode 100644
index 00000000..d3f74e19
--- /dev/null
+++ b/kig/kig/kig_iface.h
@@ -0,0 +1,37 @@
+/*
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+*/
+
+
+#ifndef KIG_IFACE_H
+#define KIG_IFACE_H
+
+#include <dcopobject.h>
+
+class KigIface : virtual public DCOPObject
+{
+ K_DCOP
+public:
+ KigIface();
+ ~KigIface();
+k_dcop:
+ virtual void openURL(const QString& s) = 0;
+};
+
+#endif
diff --git a/kig/kig/kig_part.cpp b/kig/kig/kig_part.cpp
new file mode 100644
index 00000000..163f5429
--- /dev/null
+++ b/kig/kig/kig_part.cpp
@@ -0,0 +1,1041 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "kig_part.h"
+#include "kig_part.moc"
+
+#include "aboutdata.h"
+#include "kig_commands.h"
+#include "kig_document.h"
+#include "kig_view.h"
+
+#include "../filters/exporter.h"
+#include "../filters/filter.h"
+#include "../misc/builtin_stuff.h"
+#include "../misc/calcpaths.h"
+#include "../misc/coordinate_system.h"
+#include "../misc/guiaction.h"
+#include "../misc/kigpainter.h"
+#include "../misc/lists.h"
+#include "../misc/object_constructor.h"
+#include "../misc/screeninfo.h"
+#include "../modes/normal.h"
+#include "../objects/object_drawer.h"
+#include "../objects/point_imp.h"
+
+#include <algorithm>
+#include <functional>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <klocale.h>
+#include <kmainwindow.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kprinter.h>
+#include <kstandarddirs.h>
+#include <kstdaction.h>
+#include <ktoolbar.h>
+#include <kparts/genericfactory.h>
+#include <kdeprint/kprintdialogpage.h>
+
+#include <qcheckbox.h>
+#include <qfile.h>
+#include <qlayout.h>
+#include <qpaintdevicemetrics.h>
+#include <qsizepolicy.h>
+#include <qtimer.h>
+#if QT_VERSION >= 0x030100
+#include <qeventloop.h>
+#endif
+
+using namespace std;
+
+static const QString typesFile = "macros.kigt";
+
+// export this library...
+typedef KParts::GenericFactory<KigPart> KigPartFactory;
+K_EXPORT_COMPONENT_FACTORY ( libkigpart, KigPartFactory )
+
+KAboutData* KigPart::createAboutData()
+{
+ return kigAboutData( "kig", I18N_NOOP( "KigPart" ) );
+}
+
+class SetCoordinateSystemAction
+ : public KSelectAction
+{
+ KigPart& md;
+public:
+ SetCoordinateSystemAction( KigPart& d, KActionCollection* parent );
+ void slotActivated( int index );
+};
+
+SetCoordinateSystemAction::SetCoordinateSystemAction(
+ KigPart& d, KActionCollection* parent )
+ : KSelectAction( i18n( "&Set Coordinate System" ), 0, parent, "settings_set_coordinate_system" ),
+ md( d )
+{
+ setItems( CoordinateSystemFactory::names() );
+ setCurrentItem( md.document().coordinateSystem().id() );
+}
+
+void SetCoordinateSystemAction::slotActivated( int index )
+{
+ CoordinateSystem* sys = CoordinateSystemFactory::build( index );
+ assert( sys );
+ md.history()->addCommand( KigCommand::changeCoordSystemCommand( md, sys ) );
+ setCurrentItem( index );
+}
+
+class KigPrintDialogPage
+ : public KPrintDialogPage
+{
+public:
+ KigPrintDialogPage( QWidget* parent = 0, const char* name = 0 );
+ ~KigPrintDialogPage();
+
+ void getOptions( QMap<QString,QString>& opts, bool );
+ void setOptions( const QMap<QString,QString>& opts );
+ bool isValid( QString& );
+
+private:
+ QCheckBox *showgrid;
+ QCheckBox *showaxes;
+};
+
+KigPrintDialogPage::KigPrintDialogPage( QWidget* parent, const char* name )
+ : KPrintDialogPage( parent, name )
+{
+ setTitle( i18n( "Kig Options" ) );
+
+ QVBoxLayout* vl = new QVBoxLayout( this, 0 , 11 );
+
+ showgrid = new QCheckBox( i18n( "Show grid" ), this );
+ vl->addWidget( showgrid );
+
+ showaxes = new QCheckBox( i18n( "Show axes" ), this );
+ vl->addWidget( showaxes );
+
+ vl->addItem( new QSpacerItem( 10, 10, QSizePolicy::Fixed, QSizePolicy::Expanding ) );
+}
+
+KigPrintDialogPage::~KigPrintDialogPage()
+{
+}
+
+void KigPrintDialogPage::getOptions( QMap< QString, QString >& opts, bool )
+{
+ opts[ "kde-kig-showgrid" ] = QString::number( showgrid->isChecked() );
+ opts[ "kde-kig-showaxes" ] = QString::number( showaxes->isChecked() );
+}
+
+void KigPrintDialogPage::setOptions( const QMap< QString, QString >& opts )
+{
+ QString tmp = opts[ "kde-kig-showgrid" ];
+ bool bt = ( tmp != "0" );
+ showgrid->setChecked( bt );
+ tmp = opts[ "kde-kig-showaxes" ];
+ bt = ( tmp != "0" );
+ showaxes->setChecked( bt );
+}
+
+bool KigPrintDialogPage::isValid( QString& )
+{
+ return true;
+}
+
+KigPart::KigPart( QWidget *parentWidget, const char *,
+ QObject *parent, const char *name,
+ const QStringList& )
+ : KParts::ReadWritePart( parent, name ),
+ mMode( 0 ), mdocument( new KigDocument() )
+{
+ // we need an instance
+ setInstance( KigPartFactory::instance() );
+
+ mMode = new NormalMode( *this );
+
+ // we need a widget, to actually show the document
+ m_widget = new KigView(this, false, parentWidget, "kig_view");
+ // notify the part that this is our internal widget
+ setWidget( m_widget );
+
+ // create our actions...
+ setupActions();
+
+ // set our XML-UI resource file
+ setXMLFile("kigpartui.rc");
+
+ // our types...
+ setupTypes();
+
+ // construct our command history
+ mhistory = new KCommandHistory(actionCollection());
+ mhistory->documentSaved();
+ connect( mhistory, SIGNAL( documentRestored() ), this, SLOT( setUnmodified() ) );
+
+ // we are read-write by default
+ setReadWrite(true);
+
+ setModified (false);
+
+ GUIActionList::instance()->regDoc( this );
+}
+
+void KigPart::setupActions()
+{
+ // save actions..
+ (void) KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
+ (void) KStdAction::save(this, SLOT(fileSave()), actionCollection());
+
+ // print actions
+ (void) KStdAction::print( this, SLOT( filePrint() ), actionCollection() );
+ (void) KStdAction::printPreview( this, SLOT( filePrintPreview() ), actionCollection() );
+
+ // selection actions
+ aSelectAll = KStdAction::selectAll(
+ this, SLOT( slotSelectAll() ), actionCollection() );
+ aDeselectAll = KStdAction::deselect(
+ this, SLOT( slotDeselectAll() ), actionCollection() );
+ aInvertSelection = new KAction(
+ i18n( "Invert Selection" ), "", 0, this,
+ SLOT( slotInvertSelection() ), actionCollection(),
+ "edit_invert_selection" );
+
+ // we need icons...
+ KIconLoader* l = instance()->iconLoader();
+ QPixmap tmp;
+
+ aDeleteObjects = new KAction(
+ i18n("&Delete Objects"), "editdelete", Key_Delete, this,
+ SLOT(deleteObjects()), actionCollection(), "delete_objects");
+ aDeleteObjects->setToolTip(i18n("Delete the selected objects"));
+
+ aCancelConstruction = new KAction(
+ i18n("Cancel Construction"), "stop", Key_Escape, this,
+ SLOT(cancelConstruction()), actionCollection(), "cancel_construction");
+ aCancelConstruction->setToolTip(
+ i18n("Cancel the construction of the object being constructed"));
+ aCancelConstruction->setEnabled(false);
+
+ aShowHidden = new KAction(
+ i18n("U&nhide All"), 0, this, SLOT( showHidden() ),
+ actionCollection(), "edit_unhide_all");
+ aShowHidden->setToolTip(i18n("Show all hidden objects"));
+ aShowHidden->setEnabled( true );
+
+ aNewMacro = new KAction(
+ i18n("&New Macro..."), "gear", 0, this, SLOT(newMacro()),
+ actionCollection(), "macro_action");
+ aNewMacro->setToolTip(i18n("Define a new macro"));
+
+ aConfigureTypes = new KAction(
+ i18n("Manage &Types..."), 0, this, SLOT(editTypes()),
+ actionCollection(), "types_edit");
+ aConfigureTypes->setToolTip(i18n("Manage macro types."));
+
+ KigExportManager::instance()->addMenuAction( this, m_widget->realWidget(),
+ actionCollection() );
+
+ KAction* a = KStdAction::zoomIn( m_widget, SLOT( slotZoomIn() ),
+ actionCollection() );
+ a->setToolTip( i18n( "Zoom in on the document" ) );
+ a->setWhatsThis( i18n( "Zoom in on the document" ) );
+
+ a = KStdAction::zoomOut( m_widget, SLOT( slotZoomOut() ),
+ actionCollection() );
+ a->setToolTip( i18n( "Zoom out of the document" ) );
+ a->setWhatsThis( i18n( "Zoom out of the document" ) );
+
+ a = KStdAction::fitToPage( m_widget, SLOT( slotRecenterScreen() ),
+ actionCollection() );
+ // grr.. why isn't there an icon for this..
+ a->setIconSet( QIconSet( l->loadIcon( "view_fit_to_page", KIcon::Toolbar ) ) );
+ a->setToolTip( i18n( "Recenter the screen on the document" ) );
+ a->setWhatsThis( i18n( "Recenter the screen on the document" ) );
+
+#ifdef KDE_IS_VERSION
+#if KDE_IS_VERSION(3,1,90)
+#define KIG_PART_CPP_STD_FULLSCREEN_ACTION
+#endif
+#endif
+#ifdef KIG_PART_CPP_STD_FULLSCREEN_ACTION
+ a = KStdAction::fullScreen( m_widget, SLOT( toggleFullScreen() ), actionCollection(), (QWidget*)(widget()->parent()),"fullscreen" );
+#else
+ tmp = l->loadIcon( "window_fullscreen", KIcon::Toolbar );
+ a = new KAction(
+ i18n( "Full Screen" ), tmp, CTRL+SHIFT+Key_F,
+ m_widget, SLOT( toggleFullScreen() ),
+ actionCollection(), "fullscreen" );
+#endif
+ a->setToolTip( i18n( "View this document full-screen." ) );
+ a->setWhatsThis( i18n( "View this document full-screen." ) );
+
+ // TODO: an icon for this..
+ a = new KAction(
+ i18n( "&Select Shown Area" ), "viewmagfit", 0, m_widget, SLOT( zoomRect() ),
+ actionCollection(), "view_select_shown_rect" );
+ a->setToolTip( i18n( "Select the area that you want to be shown in the window." ) );
+ a->setWhatsThis( i18n( "Select the area that you want to be shown in the window." ) );
+
+ a = new KAction(
+ i18n( "S&elect Zoom Area" ), "viewmag", 0, m_widget, SLOT( zoomArea() ),
+ actionCollection(), "view_zoom_area" );
+// a->setToolTip( i18n( "Select the area that you want to be shown in the window." ) );
+// a->setWhatsThis( i18n( "Select the area that you want to be shown in the window." ) );
+
+ aToggleGrid = new KToggleAction(
+ i18n( "Show &Grid" ), 0, this, SLOT( toggleGrid() ),
+ actionCollection(), "settings_show_grid" );
+ aToggleGrid->setToolTip( i18n( "Show or hide the grid." ) );
+ aToggleGrid->setChecked( true );
+
+ aToggleAxes = new KToggleAction(
+ i18n( "Show &Axes" ), 0, this, SLOT( toggleAxes() ),
+ actionCollection(), "settings_show_axes" );
+ aToggleAxes->setToolTip( i18n( "Show or hide the axes." ) );
+ aToggleAxes->setChecked( true );
+
+ aToggleNightVision = new KToggleAction(
+ i18n( "Wear Infrared Glasses" ), 0, this, SLOT( toggleNightVision() ),
+ actionCollection(), "settings_toggle_nightvision" );
+ aToggleNightVision->setToolTip( i18n( "Enable/Disable hidden objects visibility." ) );
+ aToggleNightVision->setChecked( false );
+
+ // select coordinate system KActionMenu..
+ aCoordSystem = new SetCoordinateSystemAction( *this, actionCollection() );
+}
+
+void KigPart::setupTypes()
+{
+ setupBuiltinStuff();
+ setupBuiltinMacros();
+ setupMacroTypes();
+ GUIActionList& l = *GUIActionList::instance();
+ typedef GUIActionList::avectype::const_iterator iter;
+ for ( iter i = l.actions().begin(); i != l.actions().end(); ++i )
+ {
+ KigGUIAction* ret = new KigGUIAction( *i, *this, actionCollection() );
+ aActions.push_back( ret );
+ ret->plug( this );
+ };
+}
+
+KigPart::~KigPart()
+{
+ GUIActionList::instance()->unregDoc( this );
+
+ // save our types...
+ saveTypes();
+
+ // objects get deleted automatically, when mobjsref gets
+ // destructed..
+
+ delete_all( aActions.begin(), aActions.end() );
+ aActions.clear();
+
+ // cleanup
+ delete mMode;
+ delete mhistory;
+
+ delete mdocument;
+}
+
+bool KigPart::openFile()
+{
+ QFileInfo fileinfo( m_file );
+ if ( ! fileinfo.exists() )
+ {
+ KMessageBox::sorry( widget(),
+ i18n( "The file \"%1\" you tried to open does not exist. "
+ "Please verify that you entered the correct path." ).arg( m_file ),
+ i18n( "File Not Found" ) );
+ return false;
+ };
+
+ // m_file is always local, so we can use findByPath instead of
+ // findByURL...
+ KMimeType::Ptr mimeType = KMimeType::findByPath ( m_file );
+ kdDebug() << k_funcinfo << "mimetype: " << mimeType->name() << endl;
+ KigFilter* filter = KigFilters::instance()->find( mimeType->name() );
+ if ( !filter )
+ {
+ // we don't support this mime type...
+ KMessageBox::sorry
+ (
+ widget(),
+ i18n( "You tried to open a document of type \"%1\"; unfortunately, "
+ "Kig does not support this format. If you think the format in "
+ "question would be worth implementing support for, you can "
+ "always ask us nicely on mailto:toscano.pino@tiscali.it "
+ "or do the work yourself and send me a patch."
+ ).arg(mimeType->name()),
+ i18n( "Format Not Supported" )
+ );
+ return false;
+ };
+
+ KigDocument* newdoc = filter->load (m_file);
+ if ( !newdoc )
+ {
+ closeURL();
+ m_url = KURL();
+ return false;
+ }
+ delete mdocument;
+ mdocument = newdoc;
+ coordSystemChanged( mdocument->coordinateSystem().id() );
+ aToggleGrid->setChecked( mdocument->grid() );
+ aToggleAxes->setChecked( mdocument->axes() );
+ aToggleNightVision->setChecked( mdocument->getNightVision() );
+
+ setModified(false);
+ mhistory->clear();
+
+ std::vector<ObjectCalcer*> tmp = calcPath( getAllParents( getAllCalcers( document().objects() ) ) );
+ for ( std::vector<ObjectCalcer*>::iterator i = tmp.begin(); i != tmp.end(); ++i )
+ ( *i )->calc( document() );
+ emit recenterScreen();
+
+ redrawScreen();
+
+ return true;
+}
+
+bool KigPart::saveFile()
+{
+ if ( m_file.isEmpty() || m_bTemp ) return internalSaveAs();
+ // mimetype:
+ KMimeType::Ptr mimeType = KMimeType::findByPath ( m_file );
+ if ( mimeType->name() != "application/x-kig" )
+ {
+ // we don't support this mime type...
+ if( KMessageBox::warningYesNo( widget(),
+ i18n( "Kig does not support saving to any other file format than "
+ "its own. Save to Kig's format instead?" ),
+ i18n( "Format Not Supported" ), i18n("Save Kig Format"), KStdGuiItem::cancel() ) == KMessageBox::No )
+ return false;
+ internalSaveAs();
+ };
+
+ if ( KigFilters::instance()->save( document(), m_file ) )
+ {
+ setModified ( false );
+ mhistory->documentSaved();
+ return true;
+ }
+ return false;
+}
+
+void KigPart::addObject(ObjectHolder* o)
+{
+ mhistory->addCommand( KigCommand::addCommand( *this, o ) );
+}
+
+void KigPart::addObjects( const std::vector<ObjectHolder*>& os )
+{
+ mhistory->addCommand( KigCommand::addCommand( *this, os ) );
+}
+
+void KigPart::_addObject( ObjectHolder* o )
+{
+ document().addObject( o );
+ setModified(true);
+}
+
+void KigPart::delObject( ObjectHolder* o )
+{
+ // we delete all children and their children etc. too...
+ std::vector<ObjectHolder*> os;
+ os.push_back( o );
+ delObjects( os );
+}
+
+void KigPart::_delObjects( const std::vector<ObjectHolder*>& o )
+{
+ document().delObjects( o );
+ setModified( true );
+}
+
+void KigPart::_delObject(ObjectHolder* o)
+{
+ document().delObject( o );
+ setModified(true);
+}
+
+void KigPart::setMode( KigMode* m )
+{
+ mMode = m;
+ m->enableActions();
+ redrawScreen();
+}
+
+void KigPart::_addObjects( const std::vector<ObjectHolder*>& os )
+{
+ document().addObjects( os );
+ setModified( true );
+}
+
+void KigPart::deleteObjects()
+{
+ mode()->deleteObjects();
+}
+
+void KigPart::cancelConstruction()
+{
+ mode()->cancelConstruction();
+}
+
+void KigPart::showHidden()
+{
+ mode()->showHidden();
+}
+
+void KigPart::newMacro()
+{
+ mode()->newMacro();
+}
+
+void KigPart::editTypes()
+{
+ mode()->editTypes();
+}
+
+void KigPart::setUnmodified()
+{
+ setModified( false );
+}
+
+KCommandHistory* KigPart::history()
+{
+ return mhistory;
+}
+
+void KigPart::delObjects( const std::vector<ObjectHolder*>& os )
+{
+ if ( os.size() < 1 ) return;
+ std::set<ObjectHolder*> delobjs;
+
+ std::set<ObjectCalcer*> delcalcers = getAllChildren( getAllCalcers( os ) );
+ std::map<ObjectCalcer*, ObjectHolder*> holdermap;
+
+ std::set<ObjectHolder*> curobjs = document().objectsSet();
+
+ for ( std::set<ObjectHolder*>::iterator i = curobjs.begin();
+ i != curobjs.end(); ++i )
+ holdermap[( *i )->calcer()] = *i;
+
+ for ( std::set<ObjectCalcer*>::iterator i = delcalcers.begin();
+ i != delcalcers.end(); ++i )
+ {
+ std::map<ObjectCalcer*, ObjectHolder*>::iterator j = holdermap.find( *i );
+ if ( j != holdermap.end() )
+ delobjs.insert( j->second );
+ }
+
+ assert( delobjs.size() >= os.size() );
+
+ std::vector<ObjectHolder*> delobjsvect( delobjs.begin(), delobjs.end() );
+ mhistory->addCommand( KigCommand::removeCommand( *this, delobjsvect ) );
+}
+
+void KigPart::enableConstructActions( bool enabled )
+{
+ for_each( aActions.begin(), aActions.end(),
+ bind2nd( mem_fun( &KAction::setEnabled ),
+ enabled ) );
+}
+
+void KigPart::unplugActionLists()
+{
+ unplugActionList( "user_conic_types" );
+ unplugActionList( "user_segment_types" );
+ unplugActionList( "user_point_types" );
+ unplugActionList( "user_circle_types" );
+ unplugActionList( "user_line_types" );
+ unplugActionList( "user_other_types" );
+ unplugActionList( "user_types" );
+}
+
+void KigPart::plugActionLists()
+{
+ plugActionList( "user_conic_types", aMNewConic );
+ plugActionList( "user_segment_types", aMNewSegment );
+ plugActionList( "user_point_types", aMNewPoint );
+ plugActionList( "user_circle_types", aMNewCircle );
+ plugActionList( "user_line_types", aMNewLine );
+ plugActionList( "user_other_types", aMNewOther );
+ plugActionList( "user_types", aMNewAll );
+}
+
+void KigPart::emitStatusBarText( const QString& text )
+{
+ emit setStatusBarText( text );
+}
+
+void KigPart::fileSaveAs()
+{
+ internalSaveAs();
+}
+
+void KigPart::fileSave()
+{
+ save();
+}
+
+bool KigPart::internalSaveAs()
+{
+ // this slot is connected to the KStdAction::saveAs action...
+ QString formats = i18n( "*.kig|Kig Documents (*.kig)\n"
+ "*.kigz|Compressed Kig Documents (*.kigz)" );
+
+ // formats += "\n";
+ // formats += KImageIO::pattern( KImageIO::Writing );
+
+ QString file_name = KFileDialog::getSaveFileName(":document", formats );
+ if (file_name.isEmpty()) return false;
+ else if ( QFileInfo( file_name ).exists() )
+ {
+ int ret = KMessageBox::warningContinueCancel( m_widget,
+ i18n( "The file \"%1\" already exists. Do you wish to overwrite it?" )
+ .arg( file_name ), i18n( "Overwrite File?" ), i18n("Overwrite") );
+ if ( ret != KMessageBox::Continue )
+ {
+ return false;
+ }
+ }
+ saveAs(KURL::fromPathOrURL( file_name ));
+ return true;
+}
+
+void KigPart::runMode( KigMode* m )
+{
+ KigMode* prev = mMode;
+
+ setMode( m );
+
+#if QT_VERSION >= 0x030100
+ (void) kapp->eventLoop()->enterLoop();
+#else
+ (void) kapp->enter_loop();
+#endif
+
+ setMode( prev );
+ redrawScreen();
+}
+
+void KigPart::doneMode( KigMode* d )
+{
+ assert( d == mMode );
+ // pretend to use this var..
+ (void)d;
+#if QT_VERSION >= 0x030100
+ kapp->eventLoop()->exitLoop();
+#else
+ kapp->exit_loop();
+#endif
+}
+
+void KigPart::actionRemoved( GUIAction* a, GUIUpdateToken& t )
+{
+ KigGUIAction* rem = 0;
+ for ( std::vector<KigGUIAction*>::iterator i = aActions.begin(); i != aActions.end(); ++i )
+ {
+ if ( (*i)->guiAction() == a )
+ {
+ rem = *i;
+ aActions.erase( i );
+ break;
+ }
+ };
+ assert( rem );
+ aMNewSegment.remove( rem );
+ aMNewConic.remove( rem );
+ aMNewPoint.remove( rem );
+ aMNewCircle.remove( rem );
+ aMNewLine.remove( rem );
+ aMNewOther.remove( rem );
+ aMNewAll.remove( rem );
+ t.push_back( rem );
+}
+
+void KigPart::actionAdded( GUIAction* a, GUIUpdateToken& )
+{
+ KigGUIAction* ret = new KigGUIAction( a, *this, actionCollection() );
+ aActions.push_back( ret );
+ ret->plug( this );
+}
+
+void KigPart::endGUIActionUpdate( GUIUpdateToken& t )
+{
+ unplugActionLists();
+ plugActionLists();
+ delete_all( t.begin(), t.end() );
+ t.clear();
+}
+
+KigPart::GUIUpdateToken KigPart::startGUIActionUpdate()
+{
+ return GUIUpdateToken();
+}
+
+void KigPart::setupMacroTypes()
+{
+ static bool alreadysetup = false;
+ if ( ! alreadysetup )
+ {
+ alreadysetup = true;
+
+ // the user's saved macro types:
+ QStringList dataFiles =
+ KGlobal::dirs()->findAllResources("appdata", "kig-types/*.kigt",
+ true, false );
+ std::vector<Macro*> macros;
+ for ( QStringList::iterator file = dataFiles.begin();
+ file != dataFiles.end(); ++file )
+ {
+ std::vector<Macro*> nmacros;
+ bool ok = MacroList::instance()->load( *file, nmacros, *this );
+ if ( ! ok ) continue;
+ copy( nmacros.begin(), nmacros.end(), back_inserter( macros ) );
+ }
+ MacroList::instance()->add( macros );
+ };
+ // hack: we need to plug the action lists _after_ the gui is
+ // built.. i can't find a better solution than this...
+ QTimer::singleShot( 0, this, SLOT( plugActionLists() ) );
+}
+
+void KigPart::setupBuiltinMacros()
+{
+ static bool alreadysetup = false;
+ if ( ! alreadysetup )
+ {
+ alreadysetup = true;
+ // builtin macro types ( we try to make the user think these are
+ // normal types )..
+ QStringList builtinfiles =
+ KGlobal::dirs()->findAllResources( "appdata", "builtin-macros/*.kigt", true, false );
+ for ( QStringList::iterator file = builtinfiles.begin();
+ file != builtinfiles.end(); ++file )
+ {
+ std::vector<Macro*> macros;
+ bool ok = MacroList::instance()->load( *file, macros, *this );
+ if ( ! ok ) continue;
+ for ( uint i = 0; i < macros.size(); ++i )
+ {
+ ObjectConstructorList* ctors = ObjectConstructorList::instance();
+ GUIActionList* actions = GUIActionList::instance();
+ Macro* macro = macros[i];
+ macro->ctor->setBuiltin( true );
+ ctors->add( macro->ctor );
+ actions->add( macro->action );
+ macro->ctor = 0;
+ macro->action = 0;
+ delete macro;
+ };
+ };
+ };
+}
+
+void KigPart::addWidget( KigWidget* v )
+{
+ mwidgets.push_back( v );
+}
+
+void KigPart::delWidget( KigWidget* v )
+{
+ mwidgets.erase( std::remove( mwidgets.begin(), mwidgets.end(), v ), mwidgets.end() );
+}
+
+void KigPart::filePrintPreview()
+{
+ KPrinter printer;
+ printer.setPreviewOnly( true );
+ doPrint( printer );
+}
+
+void KigPart::filePrint()
+{
+ KPrinter printer;
+ KigPrintDialogPage* kp = new KigPrintDialogPage();
+ printer.addDialogPage( kp );
+ printer.setFullPage( true );
+ printer.setOption( "kde-kig-showgrid", QString::number( document().grid() ) );
+ printer.setOption( "kde-kig-showaxes", QString::number( document().axes() ) );
+ printer.setPageSelection( KPrinter::ApplicationSide );
+ if ( printer.setup( m_widget, i18n("Print Geometry") ) )
+ {
+ doPrint( printer );
+ };
+}
+
+void KigPart::doPrint( KPrinter& printer )
+{
+ QPaintDeviceMetrics metrics( &printer );
+ Rect rect = document().suggestedRect();
+ QRect qrect( 0, 0, metrics.width(), metrics.height() );
+ if ( rect.width() * qrect.height() > rect.height() * qrect.width() )
+ {
+ // qrect is too high..
+ int nh = static_cast<int>( qrect.width() * rect.height() / rect.width() );
+ int rest = qrect.height() - nh;
+ qrect.setTop( qrect.top() - rest / 2 );
+ qrect.setTop( rest / 2 );
+ }
+ else
+ {
+ // qrect is too wide..
+ int nw = static_cast<int>( qrect.height() * rect.width() / rect.height() );
+ int rest = qrect.width() - nw;
+ qrect.setLeft( rest / 2 );
+ qrect.setRight( qrect.right() - rest / 2 );
+ };
+ ScreenInfo si( rect, qrect );
+ KigPainter painter( si, &printer, document() );
+ painter.setWholeWinOverlay();
+ bool sg = true;
+ bool sa = true;
+ if ( !printer.previewOnly() )
+ {
+ sg = ( printer.option( "kde-kig-showgrid" ) != "0" );
+ sa = ( printer.option( "kde-kig-showaxes" ) != "0" );
+ }
+ else
+ {
+ sg = document().grid();
+ sg = document().axes();
+ }
+ painter.drawGrid( document().coordinateSystem(), sg, sa );
+ painter.drawObjects( document().objects(), false );
+}
+
+void KigPart::slotSelectAll()
+{
+ mMode->selectAll();
+}
+
+void KigPart::slotDeselectAll()
+{
+ mMode->deselectAll();
+}
+
+void KigPart::slotInvertSelection()
+{
+ mMode->invertSelection();
+}
+
+void KigPart::hideObjects( const std::vector<ObjectHolder*>& inos )
+{
+ std::vector<ObjectHolder*> os;
+ for (std::vector<ObjectHolder*>::const_iterator i = inos.begin(); i != inos.end(); ++i )
+ {
+ if ( (*i)->shown() )
+ os.push_back( *i );
+ };
+ KigCommand* kc = 0;
+ if ( os.size() == 0 ) return;
+ else if ( os.size() == 1 )
+ kc = new KigCommand( *this, os[0]->imp()->type()->hideAStatement() );
+ else kc = new KigCommand( *this, i18n( "Hide %n Object", "Hide %n Objects", os.size() ) );
+ for ( std::vector<ObjectHolder*>::iterator i = os.begin();
+ i != os.end(); ++i )
+ kc->addTask( new ChangeObjectDrawerTask( *i, ( *i )->drawer()->getCopyShown( false ) ) );
+ mhistory->addCommand( kc );
+}
+
+void KigPart::showObjects( const std::vector<ObjectHolder*>& inos )
+{
+ std::vector<ObjectHolder*> os;
+ for (std::vector<ObjectHolder*>::const_iterator i = inos.begin(); i != inos.end(); ++i )
+ {
+ if ( !(*i)->shown() )
+ os.push_back( *i );
+ };
+ KigCommand* kc = 0;
+ if ( os.size() == 0 ) return;
+ else if ( os.size() == 1 )
+ kc = new KigCommand( *this, os[0]->imp()->type()->showAStatement() );
+ else kc = new KigCommand( *this, i18n( "Show %n Object", "Show %n Objects", os.size() ) );
+ for ( std::vector<ObjectHolder*>::iterator i = os.begin();
+ i != os.end(); ++i )
+ kc->addTask( new ChangeObjectDrawerTask( *i, ( *i )->drawer()->getCopyShown( true ) ) );
+ mhistory->addCommand( kc );
+}
+
+void KigPart::redrawScreen( KigWidget* w )
+{
+ mode()->redrawScreen( w );
+}
+
+void KigPart::redrawScreen()
+{
+ for ( std::vector<KigWidget*>::iterator i = mwidgets.begin();
+ i != mwidgets.end(); ++i )
+ {
+ mode()->redrawScreen( *i );
+ }
+}
+
+const KigDocument& KigPart::document() const
+{
+ return *mdocument;
+}
+
+KigDocument& KigPart::document()
+{
+ return *mdocument;
+}
+
+extern "C" int convertToNative( const KURL& url, const QCString& outfile )
+{
+ kdDebug() << "converting " << url.prettyURL() << " to " << outfile << endl;
+
+ if ( ! url.isLocalFile() )
+ {
+ // TODO
+ kdError() << "--convert-to-native only supports local files for now." << endl;
+ return -1;
+ }
+
+ QString file = url.path();
+
+ QFileInfo fileinfo( file );
+ if ( ! fileinfo.exists() )
+ {
+ kdError() << "The file \"" << file << "\" does not exist" << endl;
+ return -1;
+ };
+
+ KMimeType::Ptr mimeType = KMimeType::findByPath ( file );
+ kdDebug() << k_funcinfo << "mimetype: " << mimeType->name() << endl;
+ KigFilter* filter = KigFilters::instance()->find( mimeType->name() );
+ if ( !filter )
+ {
+ kdError() << "The file \"" << file << "\" is of a filetype not currently supported by Kig." << endl;
+ return -1;
+ };
+
+ KigDocument* doc = filter->load (file);
+ if ( !doc )
+ {
+ kdError() << "Parse error in file \"" << file << "\"." << endl;
+ return -1;
+ }
+
+ std::vector<ObjectCalcer*> tmp = calcPath( getAllParents( getAllCalcers( doc->objects() ) ) );
+ for ( std::vector<ObjectCalcer*>::iterator i = tmp.begin(); i != tmp.end(); ++i )
+ ( *i )->calc( *doc );
+ for ( std::vector<ObjectCalcer*>::iterator i = tmp.begin(); i != tmp.end(); ++i )
+ ( *i )->calc( *doc );
+
+ QString out = ( outfile == "-" ) ? QString::null : outfile;
+ bool success = KigFilters::instance()->save( *doc, out );
+ if ( !success )
+ {
+ kdError() << "something went wrong while saving" << endl;
+ return -1;
+ }
+
+ delete doc;
+
+ return 0;
+}
+
+void KigPart::toggleGrid()
+{
+ bool toshow = !mdocument->grid();
+ aToggleGrid->setChecked( toshow );
+ mdocument->setGrid( toshow );
+
+ redrawScreen();
+}
+
+void KigPart::toggleAxes()
+{
+ bool toshow = !mdocument->axes();
+ aToggleAxes->setChecked( toshow );
+ mdocument->setAxes( toshow );
+
+ redrawScreen();
+}
+
+void KigPart::toggleNightVision()
+{
+ bool nv = !mdocument->getNightVision();
+ aToggleNightVision->setChecked( nv );
+ mdocument->setNightVision( nv );
+
+ redrawScreen();
+}
+
+void KigPart::coordSystemChanged( int id )
+{
+ aCoordSystem->setCurrentItem( id );
+}
+
+void KigPart::saveTypes()
+{
+ QString typesDir = KGlobal::dirs()->saveLocation( "appdata", "kig-types" );
+ if ( typesDir[ typesDir.length() - 1 ] != '/' )
+ typesDir += '/';
+ QString typesFileWithPath = typesDir + typesFile;
+
+ // removing existant types file
+ if ( QFile::exists( typesFileWithPath ) )
+ QFile::remove( typesFileWithPath );
+
+ MacroList* macrolist = MacroList::instance();
+ macrolist->save( macrolist->macros(), typesFileWithPath );
+}
+
+void KigPart::loadTypes()
+{
+ QString typesDir = KGlobal::dirs()->saveLocation( "appdata", "kig-types" );
+ if ( typesDir[ typesDir.length() - 1 ] != '/' )
+ typesDir += '/';
+ QString typesFileWithPath = typesDir + typesFile;
+
+ if ( QFile::exists( typesFileWithPath ) )
+ {
+ std::vector<Macro*> macros;
+ MacroList::instance()->load( typesFileWithPath, macros, *this );
+ MacroList::instance()->add( macros );
+ }
+}
+
+void KigPart::deleteTypes()
+{
+ unplugActionLists();
+ typedef MacroList::vectype vec;
+ MacroList* macrolist = MacroList::instance();
+ const vec& macros = macrolist->macros();
+ for ( vec::const_reverse_iterator i = macros.rbegin(); i != macros.rend(); ++i )
+ {
+ macrolist->remove( *i );
+ }
+ plugActionLists();
+}
diff --git a/kig/kig/kig_part.desktop b/kig/kig/kig_part.desktop
new file mode 100644
index 00000000..cffd6e3d
--- /dev/null
+++ b/kig/kig/kig_part.desktop
@@ -0,0 +1,16 @@
+[Desktop Entry]
+Name=KigPart
+Name[ar]=جزء كيج
+Name[bn]=কিগপারà§à¦Ÿ
+Name[et]=Kigi komponent
+Name[hi]=के-इग-पारà¥à¤Ÿ
+Name[ne]=किग पारà¥à¤Ÿ
+Name[sv]=Kigdel
+Name[ta]=கிகà¯à®ªà®•à¯à®¤à®¿
+Name[ven]=TshipidatshaKig
+Name[zh_CN]=Kig 组件
+MimeType=application/x-kig;application/x-kgeo;
+ServiceTypes=KParts/ReadOnlyPart,KParts/ReadWritePart
+X-KDE-Library=libkigpart
+Type=Service
+Icon=kig
diff --git a/kig/kig/kig_part.h b/kig/kig/kig_part.h
new file mode 100644
index 00000000..2084d0a9
--- /dev/null
+++ b/kig/kig/kig_part.h
@@ -0,0 +1,257 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+
+#ifndef KIGPART_H
+#define KIGPART_H
+
+#include <qptrlist.h>
+
+#include <kparts/part.h>
+
+#include "../objects/common.h"
+
+class KAboutData;
+class KActionMenu;
+class KCommandHistory;
+class KPrinter;
+class KSelectAction;
+class KToolBar;
+class KToggleAction;
+class KURL;
+class QWidget;
+
+class Coordinate;
+class CoordinateSystem;
+class GUIAction;
+class KigGUIAction;
+class KigMode;
+class KigObjectsPopup;
+class KigView;
+class MacroWizardImpl;
+class ObjectHolder;
+class Rect;
+class ScreenInfo;
+
+/**
+ * This is a "Part". It that does all the real work in a KPart
+ * application.
+ * Briefly, it holds the data of the document, and acts as an
+ * interface to shells
+ *
+ * @short Main Part
+ */
+class KigPart : public KParts::ReadWritePart
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ KigPart( QWidget* parentWidget, const char* widgetName,
+ QObject* parent = 0, const char* name = 0,
+ const QStringList& = QStringList()
+ );
+
+ /**
+ * Destructor
+ */
+ virtual ~KigPart();
+
+/*********************** KPart interface *************************/
+
+protected:
+ /**
+ * load our internal document from m_file
+ */
+ virtual bool openFile();
+
+ /**
+ * save our internal document to m_file
+ */
+ virtual bool saveFile();
+
+public:
+ void emitStatusBarText( const QString& text );
+ void redrawScreen();
+ void redrawScreen( KigWidget* w );
+
+public slots:
+ void fileSaveAs();
+ void fileSave();
+
+ void filePrint();
+ void filePrintPreview();
+
+ void slotSelectAll();
+ void slotDeselectAll();
+ void slotInvertSelection();
+
+ void unplugActionLists();
+ void plugActionLists();
+
+ void deleteObjects();
+ void cancelConstruction();
+ void showHidden();
+ void newMacro();
+ void editTypes();
+
+ void toggleGrid();
+ void toggleAxes();
+ void toggleNightVision();
+
+ /**
+ * equivalent to setModified( false ); ( did i mention i don't like
+ * signals/slots for being this inflexible...
+ * this is connected to mhistory->documentRestored();
+ */
+ void setUnmodified();
+
+ /****************** cooperation with stuff ******************/
+public:
+ void addWidget( KigWidget* );
+ void delWidget( KigWidget* );
+
+ KigMode* mode() const { return mMode; }
+ void setMode( KigMode* );
+ void runMode( KigMode* );
+ void doneMode( KigMode* );
+
+ void coordSystemChanged( int );
+
+signals: // these signals are for telling KigView it should do something...
+ /**
+ * emitted when we want to suggest a new size for the view
+ * ( basically after loading a file, and on startup... )
+ */
+ void recenterScreen();
+
+/************** working with our internal document **********/
+public:
+ // guess what these do...
+ // actually, they only add a command object to the history, the real
+ // work is done in _addObject() and _delObject()
+ void addObject(ObjectHolder* inObject);
+ void addObjects( const std::vector<ObjectHolder*>& os );
+ void delObject(ObjectHolder* inObject);
+ void delObjects( const std::vector<ObjectHolder*>& os );
+ void hideObjects( const std::vector<ObjectHolder*>& os );
+ void showObjects( const std::vector<ObjectHolder*>& os );
+
+ void _addObject( ObjectHolder* inObject );
+ void _addObjects( const std::vector<ObjectHolder*>& o);
+ void _delObject( ObjectHolder* inObject );
+ void _delObjects( const std::vector<ObjectHolder*>& o );
+
+/************* internal stuff *************/
+protected:
+ bool internalSaveAs();
+
+public:
+ static KAboutData* createAboutData();
+protected:
+ void setupActions();
+ void setupTypes();
+ void setupBuiltinMacros();
+ void setupMacroTypes();
+
+protected:
+ KigMode* mMode;
+ KSelectAction* aCoordSystem;
+
+ /**
+ * the command history
+ */
+ KCommandHistory* mhistory;
+
+public:
+ // actions: this is an annoying case, didn't really fit into my
+ // model with KigModes.. This is how it works now:
+ // the actions are owned by the Part, because we need them on
+ // constructing the GUI ( actions appearing when you switch modes
+ // would not be nice, imho ). On setting the KigPart mode, we
+ // connect the actions to the current mode, and disconnect them from
+ // the previous mode. Enabling/disabling is done at the same time,
+ // of course..
+ // some MenuActions..
+ QPtrList<KAction> aMNewSegment;
+ QPtrList<KAction> aMNewPoint;
+ QPtrList<KAction> aMNewCircle;
+ QPtrList<KAction> aMNewLine;
+ QPtrList<KAction> aMNewOther;
+ QPtrList<KAction> aMNewAll;
+ QPtrList<KAction> aMNewConic;
+
+
+ KAction* aCancelConstruction;
+ KAction* aSelectAll;
+ KAction* aDeselectAll;
+ KAction* aInvertSelection;
+ KAction* aDeleteObjects;
+ KAction* aNewMacro;
+ KAction* aShowHidden;
+ KAction* aConfigureTypes;
+ KToggleAction* aToggleGrid;
+ KToggleAction* aToggleAxes;
+ KToggleAction* aToggleNightVision;
+ std::vector<KigGUIAction*> aActions;
+
+ /**
+ * the "token" keeps some objects that should be deleted, we only
+ * delete them after we replug the actionLists.. calling these
+ * functions should be done like:
+ * \code
+ * GUIUpdateToken t = doc->startGUIActionUpdate();
+ * doc->action[Added|Removed]( act, t );
+ * ...
+ * doc->endGUIActionUpdate( t );
+ * \endcode
+ */
+ typedef std::vector<KigGUIAction*> GUIUpdateToken;
+ GUIUpdateToken startGUIActionUpdate();
+ void actionAdded( GUIAction* a, GUIUpdateToken& t );
+ void actionRemoved( GUIAction* a, GUIUpdateToken& t );
+ void endGUIActionUpdate( GUIUpdateToken& t );
+
+ KCommandHistory* history();
+
+ void enableConstructActions( bool enabled );
+
+protected:
+ void doPrint( KPrinter& printer );
+
+ std::vector<KigWidget*> mwidgets;
+
+ KigView* m_widget;
+
+ KigDocument* mdocument;
+public:
+ const KigDocument& document() const;
+ KigDocument& document();
+
+/***************** types handling *******************/
+ void saveTypes();
+ void loadTypes();
+ void deleteTypes();
+
+};
+
+#endif // KIGPART_H
+
diff --git a/kig/kig/kig_view.cpp b/kig/kig/kig_view.cpp
new file mode 100644
index 00000000..7d36bc14
--- /dev/null
+++ b/kig/kig/kig_view.cpp
@@ -0,0 +1,593 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "kig_view.h"
+#include "kig_view.moc"
+
+#include "kig_part.h"
+#include "kig_document.h"
+#include "kig_commands.h"
+#include "../misc/coordinate_system.h"
+#include "../misc/kiginputdialog.h"
+#include "../misc/kigpainter.h"
+#include "../modes/mode.h"
+#include "../modes/dragrectmode.h"
+
+#include <qdialog.h>
+#include <qevent.h>
+#include <qwhatsthis.h>
+#include <qlayout.h>
+#include <qscrollbar.h>
+
+#include <kdebug.h>
+#include <kcursor.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kstdaction.h>
+#include <kaction.h>
+#include <kiconloader.h>
+
+#include <cmath>
+#include <algorithm>
+
+kdbgstream& operator<< ( kdbgstream& s, const QPoint& t )
+{
+ s << "x: " << t.x() << " y: " << t.y();
+ return s;
+}
+
+KigWidget::KigWidget( KigPart* part,
+ KigView* view,
+ QWidget* parent,
+ const char* name,
+ bool fullscreen )
+ : QWidget( parent, name,
+ fullscreen ? WStyle_Customize | WStyle_NoBorder : 0 ),
+ mpart( part ),
+ mview( view ),
+ stillPix(size()),
+ curPix(size()),
+ msi( Rect(), rect() ),
+ misfullscreen( fullscreen )
+{
+ part->addWidget(this);
+
+ setFocusPolicy(ClickFocus);
+ setBackgroundMode( Qt::NoBackground );
+ setMouseTracking(true);
+
+ curPix.resize( size() );
+ stillPix.resize( size() );
+}
+
+KigWidget::~KigWidget()
+{
+ mpart->delWidget( this );
+}
+
+void KigWidget::paintEvent(QPaintEvent*)
+{
+ updateEntireWidget();
+}
+
+void KigWidget::mousePressEvent (QMouseEvent* e)
+{
+ if( e->button() & Qt::LeftButton )
+ return mpart->mode()->leftClicked( e, this );
+ if ( e->button() & Qt::MidButton )
+ return mpart->mode()->midClicked( e, this );
+ if ( e->button() & Qt::RightButton )
+ return mpart->mode()->rightClicked( e, this );
+}
+
+void KigWidget::mouseMoveEvent (QMouseEvent* e)
+{
+ if( e->state() & Qt::LeftButton )
+ return mpart->mode()->leftMouseMoved( e, this );
+ if ( e->state() & Qt::MidButton )
+ return mpart->mode()->midMouseMoved( e, this );
+ if ( e->state() & Qt::RightButton )
+ return mpart->mode()->rightMouseMoved( e, this );
+ return mpart->mode()->mouseMoved( e, this );
+}
+
+void KigWidget::mouseReleaseEvent (QMouseEvent* e)
+{
+ if( e->state() & Qt::LeftButton )
+ return mpart->mode()->leftReleased( e, this );
+ if ( e->state() & Qt::MidButton )
+ return mpart->mode()->midReleased( e, this );
+ if ( e->state() & Qt::RightButton )
+ return mpart->mode()->rightReleased( e, this );
+}
+
+void KigWidget::updateWidget( const std::vector<QRect>& overlay )
+{
+#undef SHOW_OVERLAY_RECTS
+#ifdef SHOW_OVERLAY_RECTS
+ QPainter debug (this, this);
+ debug.setPen(Qt::yellow);
+#endif // SHOW_OVERLAY_RECTS
+ // we undo our old changes...
+ for ( std::vector<QRect>::const_iterator i = oldOverlay.begin(); i != oldOverlay.end(); ++i )
+ bitBlt( this, i->topLeft(), &curPix, *i );
+ // we add our new changes...
+ for ( std::vector<QRect>::const_iterator i = overlay.begin(); i != overlay.end(); ++i )
+ {
+ bitBlt( this, i->topLeft(), &curPix, *i );
+#ifdef SHOW_OVERLAY_RECTS
+ debug.drawRect(*i);
+#endif
+ };
+ oldOverlay = overlay;
+}
+
+void KigWidget::updateEntireWidget()
+{
+ std::vector<QRect> overlay;
+ overlay.push_back( QRect( QPoint( 0, 0 ), size() ) );
+ updateWidget( overlay );
+}
+
+void KigWidget::resizeEvent( QResizeEvent* e )
+{
+ QSize osize = e->oldSize();
+ QSize nsize = e->size();
+ Rect orect = msi.shownRect();
+
+ curPix.resize( nsize );
+ stillPix.resize( nsize );
+ msi.setViewRect( rect() );
+
+ Rect nrect( 0., 0.,
+ orect.width() * nsize.width() / osize.width(),
+ orect.height() * nsize.height() / osize.height() );
+ nrect = matchScreenShape( nrect );
+ nrect.setCenter( orect.center() );
+ msi.setShownRect( nrect );
+
+ // horrible hack... We need to somehow differentiate between the
+ // resizeEvents we get on startup, and the ones generated by the
+ // user. The first require recentering the screen, the latter
+ // don't..
+ if ( nsize.width() / osize.width() > 4 ) recenterScreen();
+
+ mpart->redrawScreen( this );
+ updateScrollBars();
+}
+
+void KigWidget::updateCurPix( const std::vector<QRect>& ol )
+{
+ // we make curPix look like stillPix again...
+ for ( std::vector<QRect>::const_iterator i = oldOverlay.begin(); i != oldOverlay.end(); ++i )
+ bitBlt( &curPix, i->topLeft(), &stillPix, *i );
+ for ( std::vector<QRect>::const_iterator i = ol.begin(); i != ol.end(); ++i )
+ bitBlt( &curPix, i->topLeft(), &stillPix, *i );
+
+ // we add ol to oldOverlay, so that part of the widget will be
+ // updated too in updateWidget...
+ std::copy( ol.begin(), ol.end(), std::back_inserter( oldOverlay ) );
+}
+
+void KigWidget::recenterScreen()
+{
+ msi.setShownRect( matchScreenShape( mpart->document().suggestedRect() ) );
+}
+
+Rect KigWidget::matchScreenShape( const Rect& r ) const
+{
+ return r.matchShape( Rect::fromQRect( rect() ) );
+}
+
+void KigWidget::slotZoomIn()
+{
+ Rect nr = msi.shownRect();
+ Coordinate c = nr.center();
+ nr /= 2;
+ nr.setCenter( c );
+ KigCommand* cd =
+ new KigCommand( *mpart,
+ i18n( "Zoom In" ) );
+ cd->addTask( new KigViewShownRectChangeTask( *this, nr ) );
+ mpart->history()->addCommand( cd );
+}
+
+void KigWidget::slotZoomOut()
+{
+ Rect nr = msi.shownRect();
+ Coordinate c = nr.center();
+ nr *= 2;
+ nr.setCenter( c );
+
+ // zooming in is undoable.. I know this isn't really correct,
+ // because the current view doesn't really belong to the document (
+ // althought KGeo and KSeg both save them along, iirc ). However,
+ // undoing a zoom or another operation affecting the window seems a
+ // bit too useful to not be available. Please try to convince me if
+ // you feel otherwise ;-)
+ KigCommand* cd =
+ new KigCommand( *mpart,
+ i18n( "Zoom Out" ) );
+ cd->addTask( new KigViewShownRectChangeTask( *this, nr ) );
+ mpart->history()->addCommand( cd );
+}
+
+void KigWidget::clearStillPix()
+{
+ stillPix.fill(Qt::white);
+ oldOverlay.clear();
+ oldOverlay.push_back ( QRect( QPoint(0,0), size() ) );
+}
+
+void KigWidget::redrawScreen( const std::vector<ObjectHolder*>& selection, bool dos )
+{
+ std::vector<ObjectHolder*> nonselection;
+ std::set<ObjectHolder*> objs = mpart->document().objectsSet();
+ std::set_difference( objs.begin(), objs.end(), selection.begin(), selection.end(),
+ std::back_inserter( nonselection ) );
+
+ // update the screen...
+ clearStillPix();
+ KigPainter p( msi, &stillPix, mpart->document() );
+ p.drawGrid( mpart->document().coordinateSystem(), mpart->document().grid(),
+ mpart->document().axes() );
+ p.drawObjects( selection, true );
+ p.drawObjects( nonselection, false );
+ updateCurPix( p.overlay() );
+ if ( dos ) updateEntireWidget();
+}
+
+const ScreenInfo& KigWidget::screenInfo() const
+{
+ return msi;
+}
+
+const Rect KigWidget::showingRect() const
+{
+ return msi.shownRect();
+}
+
+const Coordinate KigWidget::fromScreen( const QPoint& p )
+{
+ return msi.fromScreen( p );
+}
+
+double KigWidget::pixelWidth() const
+{
+ return msi.pixelWidth();
+}
+
+const Rect KigWidget::fromScreen( const QRect& r )
+{
+ return msi.fromScreen( r );
+}
+
+
+void KigWidget::updateScrollBars()
+{
+ mview->updateScrollBars();
+}
+
+KigView::KigView( KigPart* part,
+ bool fullscreen,
+ QWidget* parent,
+ const char* name )
+ : QWidget( parent, name ),
+ mlayout( 0 ), mrightscroll( 0 ), mbottomscroll( 0 ),
+ mupdatingscrollbars( false ),
+ mrealwidget( 0 ), mpart( part )
+{
+ connect( part, SIGNAL( recenterScreen() ), this, SLOT( slotInternalRecenterScreen() ) );
+
+ mlayout = new QGridLayout( this, 2, 2 );
+ mrightscroll = new QScrollBar( Vertical, this, "Right Scrollbar" );
+ // TODO: make this configurable...
+ mrightscroll->setTracking( true );
+ connect( mrightscroll, SIGNAL( valueChanged( int ) ),
+ this, SLOT( slotRightScrollValueChanged( int ) ) );
+ connect( mrightscroll, SIGNAL( sliderReleased() ),
+ this, SLOT( updateScrollBars() ) );
+ mbottomscroll = new QScrollBar( Horizontal, this, "Bottom Scrollbar" );
+ connect( mbottomscroll, SIGNAL( valueChanged( int ) ),
+ this, SLOT( slotBottomScrollValueChanged( int ) ) );
+ connect( mbottomscroll, SIGNAL( sliderReleased() ),
+ this, SLOT( updateScrollBars() ) );
+ mrealwidget = new KigWidget( part, this, this, "Kig Widget", fullscreen );
+ mlayout->addWidget( mbottomscroll, 1, 0 );
+ mlayout->addWidget( mrealwidget, 0, 0 );
+ mlayout->addWidget( mrightscroll, 0, 1 );
+
+ resize( sizeHint() );
+ mrealwidget->recenterScreen();
+ part->redrawScreen( mrealwidget );
+ updateScrollBars();
+}
+
+void KigView::updateScrollBars()
+{
+ // we update the scrollbars to reflect the new "total size" of the
+ // document... The total size is calced in entireDocumentRect().
+ // ( it is calced as a rect that contains all the points in the
+ // document, and then enlarged a bit, and scaled to match the screen
+ // width/height ratio...
+ // What we do here is tell the scroll bars what they should show as
+ // their total size..
+
+ // see the doc of this variable in the header for this...
+ mupdatingscrollbars = true;
+
+ Rect er = mrealwidget->entireDocumentRect();
+ Rect sr = mrealwidget->screenInfo().shownRect();
+
+ // we define the total rect to be the smallest rect that contains
+ // both er and sr...
+ er |= sr;
+
+ // we need ints, not doubles, so since "pixelwidth == widgetcoord /
+ // internalcoord", we use "widgetcoord/pixelwidth", which would then
+ // equal "internalcoord", which has to be an int ( by definition.. )
+ // i know, i'm a freak to think about these sorts of things... ;)
+ double pw = mrealwidget->screenInfo().pixelWidth();
+
+ // what the scrollbars reflect is the bottom resp. the left side of
+ // the shown rect. This is why the maximum value is not er.top()
+ // (which would be the maximum value of the top of the shownRect),
+ // but er.top() - sr.height(), which is the maximum value the bottom of
+ // the shownRect can reach...
+
+ int rightmin = static_cast<int>( er.bottom() / pw );
+ int rightmax = static_cast<int>( ( er.top() - sr.height() ) / pw );
+
+ mrightscroll->setMinValue( rightmin );
+ mrightscroll->setMaxValue( rightmax );
+ mrightscroll->setLineStep( (int)( sr.height() / pw / 10 ) );
+ mrightscroll->setPageStep( (int)( sr.height() / pw / 1.2 ) );
+
+ // note that since Qt has a coordinate system with the lowest y
+ // values at the top, and we have it the other way around ( i know i
+ // shouldn't have done this.. :( ), we invert the value that the
+ // scrollbar shows. This is inverted again in
+ // slotRightScrollValueChanged()...
+ mrightscroll->setValue( (int) ( rightmin + ( rightmax - ( sr.bottom() / pw ) ) ) );
+
+ mbottomscroll->setMinValue( (int)( er.left() / pw ) );
+ mbottomscroll->setMaxValue( (int)( ( er.right() - sr.width() ) / pw ) );
+ mbottomscroll->setLineStep( (int)( sr.width() / pw / 10 ) );
+ mbottomscroll->setPageStep( (int)( sr.width() / pw / 1.2 ) );
+ mbottomscroll->setValue( (int)( sr.left() / pw ) );
+
+ mupdatingscrollbars = false;
+}
+
+Rect KigWidget::entireDocumentRect() const
+{
+ return matchScreenShape( mpart->document().suggestedRect() );
+}
+
+void KigView::slotRightScrollValueChanged( int v )
+{
+ if ( ! mupdatingscrollbars )
+ {
+ // we invert the inversion that was done in updateScrollBars() (
+ // check the documentation there..; )
+ v = mrightscroll->minValue() + ( mrightscroll->maxValue() - v );
+ double pw = mrealwidget->screenInfo().pixelWidth();
+ double nb = double( v ) * pw;
+ mrealwidget->scrollSetBottom( nb );
+ };
+}
+
+void KigView::slotBottomScrollValueChanged( int v )
+{
+ if ( ! mupdatingscrollbars )
+ {
+ double pw = mrealwidget->screenInfo().pixelWidth();
+ double nl = double( v ) * pw;
+ mrealwidget->scrollSetLeft( nl );
+ };
+}
+
+void KigWidget::scrollSetBottom( double rhs )
+{
+ Rect sr = msi.shownRect();
+ Coordinate bl = sr.bottomLeft();
+ bl.y = rhs;
+ sr.setBottomLeft( bl );
+ msi.setShownRect( sr );
+ mpart->redrawScreen( this );
+}
+
+void KigWidget::scrollSetLeft( double rhs )
+{
+ Rect sr = msi.shownRect();
+ Coordinate bl = sr.bottomLeft();
+ bl.x = rhs;
+ sr.setBottomLeft( bl );
+ msi.setShownRect( sr );
+ mpart->redrawScreen( this );
+}
+
+const ScreenInfo& KigView::screenInfo() const
+{
+ return mrealwidget->screenInfo();
+}
+
+KigView::~KigView()
+{
+}
+
+KigWidget* KigView::realWidget() const
+{
+ return mrealwidget;
+}
+
+const KigDocument& KigWidget::document() const
+{
+ return mpart->document();
+}
+
+QSize KigWidget::sizeHint() const
+{
+ return QSize( 630, 450 );
+}
+
+void KigWidget::wheelEvent( QWheelEvent* e )
+{
+ int delta = e->delta();
+ Qt::Orientation orient = e->orientation();
+ if ( orient == Qt::Vertical )
+ mview->scrollVertical( delta );
+ else
+ mview->scrollHorizontal( delta );
+}
+
+void KigView::scrollHorizontal( int delta )
+{
+ if ( delta >= 0 )
+ for ( int i = 0; i < delta; i += 120 )
+ mbottomscroll->subtractLine();
+ else
+ for ( int i = 0; i >= delta; i -= 120 )
+ mbottomscroll->addLine();
+}
+
+void KigView::scrollVertical( int delta )
+{
+ if ( delta >= 0 )
+ for ( int i = 0; i < delta; i += 120 )
+ mrightscroll->subtractLine();
+ else
+ for ( int i = 0; i >= delta; i -= 120 )
+ mrightscroll->addLine();
+}
+
+bool KigWidget::isFullScreen() const
+{
+ return misfullscreen;
+}
+
+void KigView::slotZoomIn()
+{
+ mrealwidget->slotZoomIn();
+}
+
+void KigView::slotZoomOut()
+{
+ mrealwidget->slotZoomOut();
+}
+
+void KigWidget::slotRecenterScreen()
+{
+ Rect nr = mpart->document().suggestedRect();
+ KigCommand* cd =
+ new KigCommand( *mpart,
+ i18n( "Recenter View" ) );
+
+ cd->addTask( new KigViewShownRectChangeTask( *this, nr ) );
+ mpart->history()->addCommand( cd );
+}
+
+void KigView::toggleFullScreen()
+{
+ mrealwidget->setFullScreen( ! mrealwidget->isFullScreen() );
+ if ( mrealwidget->isFullScreen() )
+ topLevelWidget()->showFullScreen();
+ else
+ topLevelWidget()->showNormal();
+}
+
+void KigWidget::setFullScreen( bool f )
+{
+ misfullscreen = f;
+}
+
+void KigWidget::zoomRect()
+{
+ mpart->emitStatusBarText( i18n( "Select the rectangle that should be shown." ) );
+ DragRectMode d( *mpart, *this );
+ mpart->runMode( &d );
+ if ( ! d.cancelled() )
+ {
+ Rect nr = d.rect();
+ KigCommand* cd =
+ new KigCommand( *mpart,
+ i18n( "Change Shown Part of Screen" ) );
+
+ cd->addTask( new KigViewShownRectChangeTask( *this, nr ) );
+ mpart->history()->addCommand( cd );
+ };
+
+ mpart->redrawScreen( this );
+ updateScrollBars();
+}
+
+void KigView::zoomRect()
+{
+ mrealwidget->zoomRect();
+}
+
+void KigWidget::setShowingRect( const Rect& r )
+{
+ msi.setShownRect( r.matchShape( Rect::fromQRect( rect() ) ) );
+}
+
+void KigView::slotRecenterScreen()
+{
+ mrealwidget->slotRecenterScreen();
+}
+
+void KigView::slotInternalRecenterScreen()
+{
+ mrealwidget->recenterScreen();
+}
+
+void KigWidget::zoomArea()
+{
+// mpart->emitStatusBarText( i18n( "Select the area that should be shown." ) );
+ Rect oldrect = showingRect();
+ Coordinate tl = oldrect.topLeft();
+ Coordinate br = oldrect.bottomRight();
+ bool ok = true;
+ KigInputDialog::getTwoCoordinates( i18n( "Select Zoom Area" ),
+ i18n( "Select the zoom area by entering the coordinates of "
+ "the upper left corner and the lower right corner." ) +
+ QString::fromLatin1("<br>") +
+ mpart->document().coordinateSystem().coordinateFormatNoticeMarkup(),
+ this, &ok, mpart->document(), &tl, &br );
+ if ( ok )
+ {
+ Coordinate nc1( tl.x, br.y );
+ Coordinate nc2( br.x, tl.y );
+ Rect nr( nc1, nc2 );
+ KigCommand* cd = new KigCommand( *mpart, i18n( "Change Shown Part of Screen" ) );
+
+ cd->addTask( new KigViewShownRectChangeTask( *this, nr ) );
+ mpart->history()->addCommand( cd );
+ }
+
+ mpart->redrawScreen( this );
+ updateScrollBars();
+}
+
+void KigView::zoomArea()
+{
+ mrealwidget->zoomArea();
+}
+
diff --git a/kig/kig/kig_view.h b/kig/kig/kig_view.h
new file mode 100644
index 00000000..7970e088
--- /dev/null
+++ b/kig/kig/kig_view.h
@@ -0,0 +1,274 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+
+#ifndef KIG_VIEW_H
+#define KIG_VIEW_H
+
+#include <qwidget.h>
+#include <qpixmap.h>
+
+#include <kparts/part.h>
+
+#include <vector>
+
+#include "../objects/object_holder.h"
+#include "../misc/rect.h"
+#include "../misc/screeninfo.h"
+
+class QGridLayout;
+class QScrollBar;
+
+class KigDocument;
+class KigView;
+
+/**
+ * This class is the real widget showing the document. The other is a
+ * wrapper, that has the scrollbars... I'm not using QScrollView
+ * cause i've been having problems with that, and it's easier to do
+ * the work myself...
+ * Internally, this is basically a dumb class, which is manipulated by
+ * KigMode's. All events are forwarded to them.
+ */
+class KigWidget : public QWidget
+{
+ Q_OBJECT
+
+ KigPart* mpart;
+ KigView* mview;
+
+ // we reimplement these from QWidget to suit our needs
+ void mousePressEvent( QMouseEvent* e );
+ void mouseMoveEvent( QMouseEvent* e );
+ void mouseReleaseEvent( QMouseEvent* e );
+ void paintEvent( QPaintEvent* e );
+ void wheelEvent( QWheelEvent* e );
+ void resizeEvent( QResizeEvent* );
+ QSize sizeHint() const;
+
+ /**
+ * this is called to match a rect's dimensions to the dimensions of
+ * the window before we set mViewRect to it. This is done cause we
+ * always want circles to look like circles etc...
+ */
+ Rect matchScreenShape( const Rect& r ) const;
+
+public:
+ /**
+ * what do the still objects look like
+ * wondering if this is appropriate, maybe it should be part of
+ * MovingMode ?
+ */
+ QPixmap stillPix;
+ /**
+ * temporary, gets bitBlt'd (copied) onto the widget
+ * (to avoid flickering)
+ */
+ QPixmap curPix;
+
+protected:
+ std::vector<QRect> oldOverlay;
+
+ /**
+ * this is a class that maps from our widget coordinates to the
+ * document's coordinates ( and back ).
+ */
+ ScreenInfo msi;
+
+ /**
+ * is this a full-screen widget ?
+ */
+ bool misfullscreen;
+
+public:
+ /**
+ * standard qwidget constructor. if fullscreen is true, we're a
+ * fullscreen widget.
+ */
+ KigWidget( KigPart* doc,
+ KigView* view,
+ QWidget* parent = 0,
+ const char* name = 0,
+ bool fullscreen = false
+ );
+ ~KigWidget();
+
+ bool isFullScreen() const;
+ void setFullScreen( bool f );
+
+ const KigView* view() const {
+ return mview;
+ }
+
+ KigView* view() {
+ return mview;
+ }
+
+ /**
+ * The following are functions used by KigMode's to tell us to draw
+ * stuff...
+ * i tried to optimise the drawing as much as possible, using
+ * much ideas from kgeo
+ * DOUBLE BUFFERING:
+ * we don't draw on the widget directly, we draw on a QPixmap (
+ * curPix ), and bitBlt that onto the widget to avoid flickering.
+ * TRIPLE BUFFERING:
+ * we also currently keep an extra pixmap of what the widget looks
+ * like without objects that are moving... i'm currently wondering
+ * whether this isn't a performance loss rather than a gain, but
+ * well, i haven't done any measurements (yet ?), so for now it
+ * stays in...
+ * OVERLAYS
+ * Another thing: it turns out that working on the pixmaps isn't
+ * that slow, but working on the widget is. So we try to reduce the
+ * amount of work we spend on the widget. (i got this idea from
+ * kgeo, all credits for this go to marc.bartsch@web.de)
+ * on drawing, KigPainter tells us (appendOverlay) for everything it
+ * draws what rects it draws in, so we know on updating the widget (
+ * updateWidget() that the rest is still ok and doesn't need to be
+ * bitBlt'd again on the widget...
+ */
+
+ /**
+ * clear stillPix...
+ */
+ void clearStillPix();
+ /**
+ * update curPix (bitBlt stillPix onto curPix..)
+ */
+ void updateCurPix( const std::vector<QRect>& = std::vector<QRect>());
+
+ /**
+ * this means bitBlting curPix on the actual widget...
+ */
+ void updateWidget( const std::vector<QRect>& = std::vector<QRect>() );
+ void updateEntireWidget();
+
+ /**
+ * Mapping between Internal Coordinate Systems
+ * there are two coordinate systems:
+ * 1 the widget's coordinates: these are simple int's from (0,0) in
+ * the topleft of the widget to size() in the bottomRight...
+ * 2 the document's coordinates: these are the coordinates used by
+ * the KigDocument. Objects only know of their coordinates as
+ * related to this system.
+ * These are mapped by the KigView using the ScreenInfo class.
+ */
+ const Rect showingRect() const;
+ void setShowingRect( const Rect& r );
+
+ const Coordinate fromScreen( const QPoint& p );
+ const Rect fromScreen( const QRect& r );
+ double pixelWidth() const;
+
+ /**
+ * the part of the document we're currently showing
+ * i.e. a rectangle of the document (which has its own coordinate
+ * system) which is mapped onto the widget.
+ */
+ const ScreenInfo& screenInfo() const;
+
+ Rect entireDocumentRect() const;
+
+ void updateScrollBars();
+
+ void scrollSetBottom( double rhs );
+ void scrollSetLeft( double rhs );
+
+ const KigDocument& document() const;
+
+public:
+ /**
+ * this recenters the screen, that is, resets the shown rect to
+ * mpart->document().suggestedRect()..
+ */
+ void recenterScreen();
+ /**
+ * this gets called if the user clicks the recenter screen button.
+ * It adds a KigCommand to the CommandHistory that recenters the
+ * screen..
+ */
+ void slotRecenterScreen();
+
+ // called when the user clicks the appropriate buttons..
+ void slotZoomIn();
+ void slotZoomOut();
+
+ void zoomRect();
+ void zoomArea();
+
+ void redrawScreen( const std::vector<ObjectHolder*>& selection, bool paintOnWidget = true );
+};
+
+/**
+ * This class is a wrapper for KigWidget. It has some actions
+ * that belong here, and not in the part. It also maintains the
+ * scrollbars, but it doesn't manipulate them itself. It forwards
+ * most of its functionality to KigWidget...
+ */
+class KigView
+ : public QWidget
+{
+ Q_OBJECT
+
+ QGridLayout* mlayout;
+ QScrollBar* mrightscroll;
+ QScrollBar* mbottomscroll;
+
+ /**
+ * apparently, QScrollBar also emits its signals when you update it
+ * manually, so we ignore them while we're in \ref updateScrollBars()...
+ */
+ bool mupdatingscrollbars;
+
+ KigWidget* mrealwidget;
+ KigPart* mpart;
+
+public:
+ KigView( KigPart* part,
+ bool fullscreen = false,
+ QWidget* parent = 0,
+ const char* name = 0
+ );
+ ~KigView();
+
+ void setupActions();
+
+ const ScreenInfo& screenInfo() const;
+
+ KigWidget* realWidget() const;
+ void scrollHorizontal( int delta );
+ void scrollVertical( int delta );
+
+public slots:
+ void updateScrollBars();
+ void slotZoomIn();
+ void slotZoomOut();
+ void zoomRect();
+ void zoomArea();
+ void slotInternalRecenterScreen();
+ void slotRecenterScreen();
+ void toggleFullScreen();
+
+private slots:
+ void slotRightScrollValueChanged( int );
+ void slotBottomScrollValueChanged( int );
+};
+#endif
diff --git a/kig/kig/kigpartui.rc b/kig/kig/kigpartui.rc
new file mode 100644
index 00000000..7e594416
--- /dev/null
+++ b/kig/kig/kigpartui.rc
@@ -0,0 +1,288 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kig_part" version="10">
+ <MenuBar>
+ <Menu name="file">
+ <text>&amp;File</text>
+ <Action name="file_save" />
+ <Action name="file_save_as" />
+ <Separator />
+ <Action name="file_print" />
+ <Action name="file_print_preview" />
+ <Separator />
+ <Action name="file_export" />
+ <Separator />
+ </Menu>
+ <Menu name="edit">
+ <text>&amp;Edit</text>
+ <Action name="edit_undo" />
+ <Action name="edit_redo" />
+ <Separator />
+ <Action name="edit_select_all" />
+ <Action name="edit_deselect" />
+ <Action name="edit_invert_selection" />
+ <Separator/>
+ <Action name="edit_unhide_all" />
+ </Menu>
+ <Menu name="view">
+ <text>&amp;View</text>
+ <Action name="view_zoom_in" />
+ <Action name="view_zoom_out" />
+ <Action name="view_fit_to_page" />
+ <Action name="view_select_shown_rect" />
+ <Action name="view_zoom_area" />
+ </Menu>
+ <Menu name="objects">
+ <text>&amp;Objects</text>
+ <Menu name="new_point" icon="point">
+ <text>&amp;Points</text>
+ <Action name="objects_new_normalpoint" />
+ <Action name="objects_new_midpoint" />
+ <Action name="objects_new_intersection" />
+ <Action name="objects_new_point_xy" />
+ <Action name="objects_new_translatedpoint" />
+ <Action name="objects_new_rotatedpoint" />
+ <Action name="objects_new_mirrorpoint" />
+ <ActionList name="user_point_types" />
+ </Menu>
+ <Menu name="new_line" icon="line">
+ <text>&amp;Lines</text>
+ <Action name="objects_new_linettp" />
+ <Action name="objects_new_lineperpend" />
+ <Action name="objects_new_lineparallel" />
+ <Action name="objects_new_ray" />
+ <Action name="objects_new_linebyvector" />
+ <Action name="objects_new_halflinebyvector" />
+ <ActionList name="user_line_types" />
+ </Menu>
+ <Menu name="new_circle" icon="circlebps">
+ <text>&amp;Circles &amp;&amp; Arcs</text>
+ <Action name="objects_new_circlebcp" />
+ <Action name="objects_new_circlebtp" />
+ <Action name="objects_new_circlebps" />
+ <Action name="objects_new_circlebpd" />
+ <Action name="objects_new_circlebcl" />
+ <Action name="objects_new_arcbtp" />
+ <Action name="objects_new_arcbcpa" />
+ <ActionList name="user_circle_types" />
+ </Menu>
+ <Menu name="new_poligon" icon="hexagonbcv">
+ <text>Poly&amp;gons</text>
+ <Action name="objects_new_trianglebtp" />
+ <Action name="objects_new_polygonbnp" />
+ <Action name="objects_new_polygonbcv" />
+ <Action name="objects_new_equitriangle" />
+ <Action name="objects_new_square" />
+ <Action name="objects_new_polygonvertices" />
+ <Action name="objects_new_polygonsides" />
+ <Action name="objects_new_convexhull" />
+ </Menu>
+ <Menu name="new_vector" icon="vector">
+ <text>&amp;Vectors &amp;&amp; Segments</text>
+ <Action name="objects_new_segment" />
+ <Action name="objects_new_segment_axis" />
+ <Action name="objects_new_vector" />
+ <Action name="objects_new_vectorsum" />
+ <Action name="objects_new_vectordifference" />
+ <ActionList name="user_segment_types" />
+ </Menu>
+ <Menu name="new_conic" icon="conicb5p">
+ <text>Co&amp;nics &amp;&amp; Cubics</text>
+ <Action name="objects_new_ellipsebffp" />
+ <Action name="objects_new_hyperbolabffp" />
+ <Action name="objects_new_conicb5p" />
+ <Action name="objects_new_parabolabtp" />
+ <ActionList name="user_conic_types" />
+ <Menu name="new_moreconics" icon="conicsradicalline">
+ <text>More Conics</text>
+ <Action name="objects_new_parabolabdp" />
+ <Action name="objects_new_equilateralhyperbolab4p" />
+ <Action name="objects_new_conicbdfp" />
+ <Action name="objects_new_conicbaap" />
+ <Action name="objects_new_linepolar" />
+ <Action name="objects_new_lineconicasymptotes" />
+ <Action name="objects_new_pointpolar" />
+ <Action name="objects_new_linedirectrix" />
+ <Action name="objects_new_lineconicradical" />
+ </Menu>
+ <Separator />
+ <Menu name="new_cubic">
+ <text>Cu&amp;bics</text>
+ <Action name="objects_new_cubicb9p" />
+ <Action name="objects_new_cubicnodeb6p" />
+ <Action name="objects_new_cubiccuspb4p" />
+ </Menu>
+ </Menu>
+ <Menu name="new_angle" icon="angle">
+ <text>&amp;Angles</text>
+ <Action name="objects_new_angle" />
+ <Action name="objects_new_angle_bisector" />
+ </Menu>
+ <Menu name="new_transformation" icon="centralsymmetry">
+ <text>&amp;Transformations</text>
+ <Action name="objects_new_translation" />
+ <Action name="objects_new_pointreflection" />
+ <Action name="objects_new_linereflection" />
+ <Action name="objects_new_rotation" />
+ <Action name="objects_new_scalingovercenter" />
+ <Action name="objects_new_scalingovercenter2" />
+ <Action name="objects_new_scalingoverline" />
+ <Action name="objects_new_scalingoverline2" />
+ <Action name="objects_new_similitude" />
+ <Action name="objects_new_inversion" />
+ <Action name="objects_new_harmonichomology" />
+ <Action name="objects_new_genericaffinity" />
+ <Action name="objects_new_genericprojectivity" />
+ <Action name="objects_new_castshadow" />
+ <Action name="objects_new_projectiverotation" />
+ </Menu>
+ <Menu name="new_differentialgeometry" icon="tangent">
+ <text>&amp;Differential geometry</text>
+ <Action name="objects_new_tangent" />
+ <Action name="objects_new_centerofcurvature" />
+ <Action name="objects_new_osculatingcircle" />
+ <Action name="objects_new_evolute" />
+ </Menu>
+ <Menu name="new_test" icon="test">
+ <text>T&amp;ests</text>
+ <Action name="objects_new_areparallel" />
+ <Action name="objects_new_areorthogonal" />
+ <Action name="objects_new_arecollinear" />
+ <Action name="objects_new_containstest" />
+ <Action name="objects_new_distancetest" />
+ <Action name="objects_new_vectorequalitytest" />
+ <Action name="objects_new_inpolygontest" />
+ <Action name="objects_new_convexpolygontest" />
+ </Menu>
+ <Menu name="new_other">
+ <text>&amp;Other</text>
+ <Action name="objects_new_locus" />
+ <Action name="objects_new_textlabel" />
+ <Action name="objects_new_measuretransport" />
+ <Action name="objects_new_script_python" />
+ <ActionList name="user_other_types" />
+ </Menu>
+ <Separator />
+ <Action name="delete_objects" />
+ <Action name="cancel_construction" />
+ </Menu>
+ <Menu name="types">
+ <text>&amp;Types</text>
+ <Action name="macro_action" />
+ <Action name="types_edit" />
+ </Menu>
+ <Menu name="settings">
+ <Action name="fullscreen" />
+ <Action name="settings_set_coordinate_system" />
+ <Action name="settings_show_grid" />
+ <Action name="settings_show_axes" />
+ <Action name="settings_toggle_nightvision" />
+ </Menu>
+ </MenuBar>
+ <ToolBar name="mainToolBar">
+ <text>Main Toolbar</text>
+ <Action name="file_save" />
+ <Action name="file_save_as" />
+ <Separator />
+ <Action name="file_print" />
+ <Separator />
+ <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <Separator />
+ <Action name="delete_objects"/>
+ <Action name="cancel_construction"/>
+ <Action name="macro_action"/>
+ </ToolBar>
+ <ToolBar name="points_toolbar" position="left">
+ <text>Points</text>
+ <Action name="objects_new_normalpoint" />
+ <Action name="objects_new_point_xy" />
+ <Action name="objects_new_intersection" />
+ <Action name="objects_new_midpoint" />
+ <Action name="objects_new_mirrorpoint" />
+ <Action name="objects_new_rotatedpoint" />
+ <Action name="objects_new_translatedpoint" />
+ <ActionList name="user_point_types" />
+ </ToolBar>
+ <ToolBar name="line_toolbar" position="left">
+ <text>Lines</text>
+ <Action name="objects_new_linettp" />
+ <Action name="objects_new_ray" />
+ <Action name="objects_new_lineperpend" />
+ <Action name="objects_new_lineparallel" />
+ <Action name="objects_new_linebyvector" />
+ <Action name="objects_new_halflinebyvector" />
+ <ActionList name="user_line_types" />
+ </ToolBar>
+ <ToolBar name="vectseg_toolbar" position="left">
+ <text>Vectors &amp;&amp; Segments</text>
+ <Action name="objects_new_segment" />
+ <Action name="objects_new_segment_axis" />
+ <Action name="objects_new_vector" />
+ <Action name="objects_new_vectorsum" />
+ <ActionList name="user_segment_types" />
+ </ToolBar>
+ <ToolBar name="circle_toolbar" position="left">
+ <text>Circles &amp;&amp; Arcs</text>
+ <Action name="objects_new_circlebcp" />
+ <Action name="objects_new_circlebtp" />
+ <Action name="objects_new_circlebps" />
+ <Action name="objects_new_circlebpd" />
+ <Action name="objects_new_arcbtp" />
+ <ActionList name="user_circle_types" />
+ </ToolBar>
+ <ToolBar name="conic_toolbar" position="left">
+ <text>Conics</text>
+ <Action name="objects_new_ellipsebffp" />
+ <Action name="objects_new_hyperbolabffp" />
+ <Action name="objects_new_parabolabtp" />
+ <Action name="objects_new_conicb5p" />
+ <ActionList name="user_conic_types" />
+ <Action name="objects_new_lineconicradical" />
+ </ToolBar>
+ <ToolBar name="angles_toolbar" position="left">
+ <text>Angles</text>
+ <Action name="objects_new_angle" />
+ <Action name="objects_new_angle_bisector" />
+ </ToolBar>
+ <ToolBar name="transformation_toolbar" position="right">
+ <text>Transformations</text>
+ <Action name="objects_new_translation" />
+ <Action name="objects_new_pointreflection" />
+ <Action name="objects_new_linereflection" />
+ <Action name="objects_new_rotation" />
+ <Action name="objects_new_scalingovercenter" />
+ <Action name="objects_new_scalingoverline" />
+ <Action name="objects_new_similitude" />
+ <Action name="objects_new_inversion" />
+ <Action name="objects_new_harmonichomology" />
+ <Action name="objects_new_genericaffinity" />
+ <Action name="objects_new_genericprojectivity" />
+ </ToolBar>
+ <ToolBar name="tests_toolbar" position="right">
+ <text>Tests</text>
+ <Action name="objects_new_areparallel" />
+ <Action name="objects_new_areorthogonal" />
+ <Action name="objects_new_arecollinear" />
+ <Action name="objects_new_containstest" />
+ <Action name="objects_new_distancetest" />
+ <Action name="objects_new_vectorequalitytest" />
+ <Action name="objects_new_inpolygontest" />
+ <Action name="objects_new_convexpolygontest" />
+ </ToolBar>
+ <ToolBar name="rest_toolbar" position="left">
+ <text>Other Objects</text>
+ <Action name="objects_new_locus" />
+ <Action name="objects_new_textlabel" />
+ <Action name="objects_new_script_python" />
+ <ActionList name="user_other_types" />
+ </ToolBar>
+ <ToolBar name="view_toolbar">
+ <text>View</text>
+ <Action name="view_zoom_in" />
+ <Action name="view_zoom_out" />
+ <Action name="fullscreen" />
+ <Action name="view_fit_to_page" />
+ <Action name="view_select_shown_rect" />
+ <Action name="view_zoom_area" />
+ </ToolBar>
+</kpartgui>
diff --git a/kig/kig/kigui.rc b/kig/kig/kigui.rc
new file mode 100644
index 00000000..db90b0d2
--- /dev/null
+++ b/kig/kig/kigui.rc
@@ -0,0 +1,40 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kig_shell" version="3">
+<MenuBar>
+ <Menu name="file" noMerge="1"><text>&amp;File</text>
+ <Action name="file_new"/>
+ <Action name="file_open"/>
+ <Action name="file_open_recent"/>
+ <Separator />
+ <Merge />
+ <Action name="file_quit"/>
+ </Menu>
+ <Merge />
+ <Menu name="settings" noMerge="1"><text>&amp;Settings</text>
+ <Action name="options_show_toolbar"/>
+ <Merge name="StandardToolBarMenuHandler" />
+ <Action name="options_show_statusbar"/>
+ <Merge />
+ <Separator/>
+ <Action name="options_configure_keybinding"/>
+ <Action name="options_configure_toolbars"/>
+ </Menu>
+ <Menu name="help" noMerge="1"><text>&amp;Help</text>
+ <Action name="help_contents"/>
+ <Action name="help_whats_this"/>
+ <Separator/>
+ <Action name="help_tipofday"/>
+ <Separator/>
+ <Action name="help_report_bug"/>
+ <Separator/>
+ <Action name="help_about_app"/>
+ <Action name="help_about_kde"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar" noMerge="1"><text>Main Toolbar</text>
+ <Action name="file_new"/>
+ <Action name="file_open"/>
+ <Separator/>
+ <Merge />
+</ToolBar>
+</kpartgui>
diff --git a/kig/kig/main.cpp b/kig/kig/main.cpp
new file mode 100644
index 00000000..d0a70404
--- /dev/null
+++ b/kig/kig/main.cpp
@@ -0,0 +1,144 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "kig.h"
+
+#include <kuniqueapplication.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <klibloader.h>
+#include <kdebug.h>
+
+#include "aboutdata.h"
+
+static KCmdLineOptions options[] =
+ {
+ { "c", 0, 0 },
+ { "convert-to-native", I18N_NOOP( "Do not show a GUI. Convert the specified file to the native Kig format. Output goes to stdout unless --outfile is specified." ), 0 },
+ { "o", 0, 0 },
+ { "outfile <file>", I18N_NOOP( "File to output the created native file to. '-' means output to stdout. Default is stdout as well." ), 0 },
+ { "+[URL]", I18N_NOOP( "Document to open" ), 0 },
+ KCmdLineLastOption
+ };
+
+class KigApplication
+ : public KUniqueApplication
+{
+public:
+ KigApplication( bool gui = true );
+ int newInstance();
+ void handleArgs( KCmdLineArgs* args );
+};
+
+KigApplication::KigApplication( bool gui )
+ : KUniqueApplication( gui, gui )
+{
+}
+
+int KigApplication::newInstance()
+{
+ static bool first = true;
+ if (isRestored() && first)
+ {
+ first = false;
+ return 0;
+ }
+ first = false;
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ handleArgs(args);
+ args->clear();
+ return 0;
+}
+
+void KigApplication::handleArgs( KCmdLineArgs* args )
+{
+ if ( args->count() == 0 )
+ {
+ Kig *widget = new Kig;
+ widget->show();
+ }
+ else
+ {
+ for (int i = 0; i < args->count(); i++ )
+ {
+ Kig *widget = new Kig;
+ widget->show();
+ widget->load( args->url( i ) );
+ }
+ }
+}
+
+static int convertToNative( const KURL& file, const QCString& outfile )
+{
+ KigApplication app( false );
+ KLibrary* library = KLibLoader::self()->globalLibrary( "libkigpart" );
+ int ( *converterfunction )( const KURL&, const QCString& );
+ converterfunction = ( int ( * )( const KURL&, const QCString& ) ) library->symbol( "convertToNative" );
+ if ( !converterfunction )
+ {
+ kdError() << "Error: broken Kig installation: different library and application version !" << endl;
+ return -1;
+ }
+ return (*converterfunction)( file, outfile );
+}
+
+int main(int argc, char **argv)
+{
+ KAboutData *about = kigAboutData( "kig", I18N_NOOP("Kig") );
+
+ KCmdLineArgs::init(argc, argv, about);
+ KCmdLineArgs::addCmdLineOptions( options );
+ KigApplication::addCmdLineOptions();
+
+ KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
+ if ( args->isSet( "convert-to-native" ) )
+ {
+ QCString outfile = args->getOption( "outfile" );
+ if ( outfile.isNull() )
+ outfile = "-";
+
+ if ( args->count() == 0 )
+ {
+ kdError() << "Error: --convert-to-native specified without a file to convert." << endl;
+ return -1;
+ }
+ if ( args->count() > 1 )
+ {
+ kdError() << "Error: --convert-to-native specified with more than one file to convert." << endl;
+ return -1;
+ }
+ return convertToNative( args->url( 0 ), outfile );
+ }
+ else
+ {
+ if ( args->isSet( "outfile" ) )
+ {
+ kdError() << "Error: --outfile specified without convert-to-native." << endl;
+ return -1;
+ }
+ KigApplication app;
+
+ // see if we are starting with session management
+ if (app.isRestored()) RESTORE(Kig)
+ return app.exec();
+ }
+}
diff --git a/kig/macros/Makefile.am b/kig/macros/Makefile.am
new file mode 100644
index 00000000..f03caaa0
--- /dev/null
+++ b/kig/macros/Makefile.am
@@ -0,0 +1,11 @@
+builtinmacrodir = $(kde_datadir)/kig/builtin-macros
+builtinmacro_DATA = \
+ circle_by_center_and_line.kigt \
+ circle_by_point_and_diameter.kigt \
+ circle_by_point_and_segment.kigt \
+ equitriangle.kigt \
+ evolute.kigt \
+ osculating_circle.kigt \
+ segment_axis.kigt \
+ square.kigt \
+ vector_difference.kigt
diff --git a/kig/macros/circle_by_center_and_line.kigt b/kig/macros/circle_by_center_and_line.kigt
new file mode 100644
index 00000000..2a02210a
--- /dev/null
+++ b/kig/macros/circle_by_center_and_line.kigt
@@ -0,0 +1,31 @@
+<!DOCTYPE KigMacroFile>
+<KigMacroFile Number="1" Version="0.7.1" >
+ <Macro>
+ <Name>Circle by Center &amp;&amp; Line</Name>
+ <Description>A circle constructed by its center and tangent to a given line</Description>
+ <ActionName>objects_new_circlebcl</ActionName>
+ <IconFileName>circlebcl</IconFileName>
+ <Construction>
+ <input requirement="line" id="1">
+ <UseText>Construct a circle tangent to this line</UseText>
+ <SelectStatement>Select the line that the new circle should be tangent to...</SelectStatement>
+ </input>
+ <input requirement="point" id="2">
+ <UseText>Construct a circle with this center</UseText>
+ <SelectStatement>Select the center of the new circle...</SelectStatement>
+ </input>
+ <intermediate action="calc" type="LinePerpend" id="3" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <intermediate action="calc" type="LineLineIntersection" id="4" >
+ <arg>1</arg>
+ <arg>3</arg>
+ </intermediate>
+ <result action="calc" type="CircleBCP" id="5" >
+ <arg>2</arg>
+ <arg>4</arg>
+ </result>
+ </Construction>
+ </Macro>
+</KigMacroFile>
diff --git a/kig/macros/circle_by_point_and_diameter.kigt b/kig/macros/circle_by_point_and_diameter.kigt
new file mode 100644
index 00000000..afe73a61
--- /dev/null
+++ b/kig/macros/circle_by_point_and_diameter.kigt
@@ -0,0 +1,36 @@
+<!DOCTYPE KigMacroFile>
+<KigMacroFile Number="1" Version="0.9.0" >
+ <Macro>
+ <Name>Circle by Point &amp;&amp; Segment (as the Diameter)</Name>
+ <Description>A circle defined by its center and the length of a segment as the diameter</Description>
+ <ActionName>objects_new_circlebpd</ActionName>
+ <IconFileName>circlebpd</IconFileName>
+ <Construction>
+ <input requirement="point" id="1">
+ <UseText>Construct a circle with this center</UseText>
+ <SelectStatement>Select the center of the new circle...</SelectStatement>
+ </input>
+ <input requirement="segment" id="2">
+ <UseText>Construct a circle with the diameter given by the length of this segment</UseText>
+ <SelectStatement>Select the segment whose length gives the diameter of the new circle...</SelectStatement>
+ </input>
+ <intermediate action="fetch-property" property="end-point-A" id="3" >
+ <arg>2</arg>
+ </intermediate>
+ <intermediate action="fetch-property" property="mid-point" id="4" >
+ <arg>2</arg>
+ </intermediate>
+ <intermediate action="calc" type="SegmentAB" id="5" >
+ <arg>3</arg>
+ <arg>4</arg>
+ </intermediate>
+ <intermediate action="fetch-property" property="length" id="6" >
+ <arg>5</arg>
+ </intermediate>
+ <result action="calc" type="CircleBPR" id="7" >
+ <arg>1</arg>
+ <arg>6</arg>
+ </result>
+ </Construction>
+ </Macro>
+</KigMacroFile>
diff --git a/kig/macros/circle_by_point_and_segment.kigt b/kig/macros/circle_by_point_and_segment.kigt
new file mode 100644
index 00000000..2f72eeb6
--- /dev/null
+++ b/kig/macros/circle_by_point_and_segment.kigt
@@ -0,0 +1,26 @@
+<!DOCTYPE KigMacroFile>
+<KigMacroFile Number="1" Version="0.4.0" >
+ <Macro>
+ <Name>Circle by Point &amp;&amp; Segment (as the Radius)</Name>
+ <Description>A circle defined by its center and the length of a segment as the radius</Description>
+ <ActionName>objects_new_circlebps</ActionName>
+ <IconFileName>circlebps</IconFileName>
+ <Construction>
+ <input requirement="point" id="1">
+ <UseText>Construct a circle with this center</UseText>
+ <SelectStatement>Select the center of the new circle...</SelectStatement>
+ </input>
+ <input requirement="segment" id="2">
+ <UseText>Construct a circle with the radius given by the length of this segment</UseText>
+ <SelectStatement>Select the segment whose length gives the radius of the new circle...</SelectStatement>
+ </input>
+ <intermediate action="fetch-property" property="length" id="3" >
+ <arg>2</arg>
+ </intermediate>
+ <result action="calc" type="CircleBPR" id="4" >
+ <arg>1</arg>
+ <arg>3</arg>
+ </result>
+ </Construction>
+ </Macro>
+</KigMacroFile>
diff --git a/kig/macros/equitriangle.kigt b/kig/macros/equitriangle.kigt
new file mode 100644
index 00000000..efbb702b
--- /dev/null
+++ b/kig/macros/equitriangle.kigt
@@ -0,0 +1,32 @@
+<!DOCTYPE KigMacroFile>
+<KigMacroFile Number="1" Version="0.9.0" >
+ <Macro>
+ <Name>Equilateral Triangle</Name>
+ <Description>Equilateral triangle with given two vertices</Description>
+ <ActionName>objects_new_equitriangle</ActionName>
+ <IconFileName>equitriangle.png</IconFileName>
+ <Construction>
+ <input requirement="point" id="1" />
+ <input requirement="point" id="2" />
+ <intermediate action="calc" type="CircleBCP" id="3" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <intermediate action="calc" type="CircleBCP" id="4" >
+ <arg>2</arg>
+ <arg>1</arg>
+ </intermediate>
+ <intermediate action="push" type="int" id="5" >-1</intermediate>
+ <intermediate action="calc" type="CircleCircleIntersection" id="6" >
+ <arg>3</arg>
+ <arg>4</arg>
+ <arg>5</arg>
+ </intermediate>
+ <result action="calc" type="TriangleB3P" id="7" >
+ <arg>1</arg>
+ <arg>2</arg>
+ <arg>6</arg>
+ </result>
+ </Construction>
+ </Macro>
+</KigMacroFile>
diff --git a/kig/macros/evolute.kigt b/kig/macros/evolute.kigt
new file mode 100644
index 00000000..aa15296e
--- /dev/null
+++ b/kig/macros/evolute.kigt
@@ -0,0 +1,28 @@
+<!DOCTYPE KigMacroFile>
+<KigMacroFile Number="1" Version="0.9.0" >
+ <Macro>
+ <Name>Evolute</Name>
+ <Description>Evolute of a curve</Description>
+ <ActionName>objects_new_evolute</ActionName>
+ <IconFileName>evolute</IconFileName>
+ <Construction>
+ <input requirement="curve" id="1">
+ <UseText>Evolute of this curve</UseText>
+ <SelectStatement>Select the curve...</SelectStatement>
+ </input>
+ <intermediate action="push" type="hierarchy" id="2" >
+ <input requirement="point" id="1" />
+ <input requirement="curve" id="2" />
+ <result action="calc" type="CocCurve" id="3" >
+ <arg>2</arg>
+ <arg>1</arg>
+ </result>
+ </intermediate>
+ <result action="calc" type="Locus" id="3" >
+ <arg>2</arg>
+ <arg>1</arg>
+ <arg>1</arg>
+ </result>
+ </Construction>
+ </Macro>
+</KigMacroFile>
diff --git a/kig/macros/osculating_circle.kigt b/kig/macros/osculating_circle.kigt
new file mode 100644
index 00000000..59ba450a
--- /dev/null
+++ b/kig/macros/osculating_circle.kigt
@@ -0,0 +1,27 @@
+<!DOCTYPE KigMacroFile>
+<KigMacroFile Number="1" Version="0.9.0" >
+ <Macro>
+ <Name>Osculating Circle</Name>
+ <Description>Osculating circle of a curve at a point</Description>
+ <ActionName>objects_new_osculatingcircle</ActionName>
+ <IconFileName>osculatingcircle</IconFileName>
+ <Construction>
+ <input requirement="curve" id="1">
+ <UseText>Osculating circle of this curve</UseText>
+ <SelectStatement>Select the curve...</SelectStatement>
+ </input>
+ <input requirement="point" id="2">
+ <UseText>Osculating circle at this point</UseText>
+ <SelectStatement>Select the point...</SelectStatement>
+ </input>
+ <intermediate action="calc" type="CocCurve" id="3" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <result action="calc" type="CircleBCP" id="4" >
+ <arg>3</arg>
+ <arg>2</arg>
+ </result>
+ </Construction>
+ </Macro>
+</KigMacroFile>
diff --git a/kig/macros/segment_axis.kigt b/kig/macros/segment_axis.kigt
new file mode 100644
index 00000000..e86b90cf
--- /dev/null
+++ b/kig/macros/segment_axis.kigt
@@ -0,0 +1,25 @@
+<!DOCTYPE KigMacroFile>
+<KigMacroFile Number="1" Version="0.6.1" >
+ <Macro>
+ <Name>Segment Axis</Name>
+ <Description>The perpendicular line through a given segment's mid point.</Description>
+ <ActionName>objects_new_segment_axis</ActionName>
+ <IconFileName>segmentaxis</IconFileName>
+ <Construction>
+ <input requirement="segment" id="1">
+ <UseText>Construct the axis of this segment</UseText>
+ <SelectStatement>Select the segment of which you want to draw the axis...</SelectStatement>
+ </input>
+ <intermediate action="fetch-property" property="mid-point" id="2" >
+ <arg>1</arg>
+ </intermediate>
+ <intermediate action="calc" type="Copy" id="3" >
+ <arg>2</arg>
+ </intermediate>
+ <result action="calc" type="LinePerpend" id="4" >
+ <arg>1</arg>
+ <arg>3</arg>
+ </result>
+ </Construction>
+ </Macro>
+</KigMacroFile>
diff --git a/kig/macros/square.kigt b/kig/macros/square.kigt
new file mode 100644
index 00000000..09c500e0
--- /dev/null
+++ b/kig/macros/square.kigt
@@ -0,0 +1,44 @@
+<!DOCTYPE KigMacroFile>
+<KigMacroFile Number="1" Version="0.9.0" >
+ <Macro>
+ <Name>Square</Name>
+ <Description>Square with two given adjacent vertices</Description>
+ <ActionName>objects_new_square</ActionName>
+ <IconFileName>square.png</IconFileName>
+ <Construction>
+ <input requirement="point" id="1" />
+ <input requirement="point" id="2" />
+ <intermediate action="calc" type="SegmentAB" id="3" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <intermediate action="fetch-property" property="mid-point" id="4" >
+ <arg>3</arg>
+ </intermediate>
+ <intermediate action="calc" type="CircleBCP" id="5" >
+ <arg>4</arg>
+ <arg>1</arg>
+ </intermediate>
+ <intermediate action="calc" type="SegmentAB" id="6" >
+ <arg>1</arg>
+ <arg>2</arg>
+ </intermediate>
+ <intermediate action="calc" type="LinePerpend" id="7" >
+ <arg>6</arg>
+ <arg>4</arg>
+ </intermediate>
+ <intermediate action="push" type="int" id="8" >-1</intermediate>
+ <intermediate action="calc" type="ConicLineIntersection" id="9" >
+ <arg>5</arg>
+ <arg>7</arg>
+ <arg>8</arg>
+ </intermediate>
+ <intermediate action="push" type="int" id="10" >4</intermediate>
+ <result action="calc" type="PoligonBCV" id="11" >
+ <arg>9</arg>
+ <arg>1</arg>
+ <arg>10</arg>
+ </result>
+ </Construction>
+ </Macro>
+</KigMacroFile>
diff --git a/kig/macros/vector_difference.kigt b/kig/macros/vector_difference.kigt
new file mode 100644
index 00000000..c1b3be4b
--- /dev/null
+++ b/kig/macros/vector_difference.kigt
@@ -0,0 +1,31 @@
+<!DOCTYPE KigMacroFile>
+<KigMacroFile Number="1" Version="0.9.0" >
+ <Macro>
+ <Name>Vector Difference</Name>
+ <Description>Construct the vector difference of two vectors.</Description>
+ <ActionName>objects_new_vectordifference</ActionName>
+ <IconFileName>vectordifference</IconFileName>
+ <Construction>
+ <input requirement="vector" id="1">
+ <UseText>Construct the vector difference of this vector and another one.</UseText>
+ <SelectStatement>Select the first of the two vectors of which you want to construct the difference...</SelectStatement>
+ </input>
+ <input requirement="vector" id="2">
+ <UseText>Construct the vector difference of the other vector and this one.</UseText>
+ <SelectStatement>Select the other of the two vectors of which you want to construct the difference...</SelectStatement>
+ </input>
+ <input requirement="point" id="3">
+ <UseText>Construct the vector difference starting at this point.</UseText>
+ <SelectStatement>Select the point to construct the difference vector in...</SelectStatement>
+ </input>
+ <intermediate action="fetch-property" property="vector-opposite" id="4" >
+ <arg>2</arg>
+ </intermediate>
+ <result action="calc" type="VectorSum" id="5" >
+ <arg>1</arg>
+ <arg>4</arg>
+ <arg>3</arg>
+ </result>
+ </Construction>
+ </Macro>
+</KigMacroFile>
diff --git a/kig/mimetypes/Makefile.am b/kig/mimetypes/Makefile.am
new file mode 100644
index 00000000..38387bfc
--- /dev/null
+++ b/kig/mimetypes/Makefile.am
@@ -0,0 +1,8 @@
+# mime types...
+kdemime_DATA = x-kig.desktop x-kgeo.desktop x-kseg.desktop x-cabri.desktop x-drgeo.desktop
+kdemimedir=$(kde_mimedir)/application
+
+magicdir = $(kde_confdir)/magic
+magic_DATA = cabri.magic drgeo.magic
+
+KDE_ICON = AUTO
diff --git a/kig/mimetypes/cabri.magic b/kig/mimetypes/cabri.magic
new file mode 100644
index 00000000..fc2e0d5c
--- /dev/null
+++ b/kig/mimetypes/cabri.magic
@@ -0,0 +1 @@
+0 string FIGURE\ CabriII\ vers\. application/x-cabri
diff --git a/kig/mimetypes/cr128-mime-kig_doc.png b/kig/mimetypes/cr128-mime-kig_doc.png
new file mode 100644
index 00000000..0e1feb83
--- /dev/null
+++ b/kig/mimetypes/cr128-mime-kig_doc.png
Binary files differ
diff --git a/kig/mimetypes/cr16-mime-kig_doc.png b/kig/mimetypes/cr16-mime-kig_doc.png
new file mode 100644
index 00000000..f3f2d75b
--- /dev/null
+++ b/kig/mimetypes/cr16-mime-kig_doc.png
Binary files differ
diff --git a/kig/mimetypes/cr22-mime-kig_doc.png b/kig/mimetypes/cr22-mime-kig_doc.png
new file mode 100644
index 00000000..ce7b65cf
--- /dev/null
+++ b/kig/mimetypes/cr22-mime-kig_doc.png
Binary files differ
diff --git a/kig/mimetypes/cr32-mime-kig_doc.png b/kig/mimetypes/cr32-mime-kig_doc.png
new file mode 100644
index 00000000..f80ef2dd
--- /dev/null
+++ b/kig/mimetypes/cr32-mime-kig_doc.png
Binary files differ
diff --git a/kig/mimetypes/cr48-mime-kig_doc.png b/kig/mimetypes/cr48-mime-kig_doc.png
new file mode 100644
index 00000000..b6e039af
--- /dev/null
+++ b/kig/mimetypes/cr48-mime-kig_doc.png
Binary files differ
diff --git a/kig/mimetypes/cr64-mime-kig_doc.png b/kig/mimetypes/cr64-mime-kig_doc.png
new file mode 100644
index 00000000..c2836c88
--- /dev/null
+++ b/kig/mimetypes/cr64-mime-kig_doc.png
Binary files differ
diff --git a/kig/mimetypes/crsc-mime-kig_doc.svgz b/kig/mimetypes/crsc-mime-kig_doc.svgz
new file mode 100644
index 00000000..1a56d017
--- /dev/null
+++ b/kig/mimetypes/crsc-mime-kig_doc.svgz
Binary files differ
diff --git a/kig/mimetypes/drgeo.magic b/kig/mimetypes/drgeo.magic
new file mode 100644
index 00000000..f5fc2a63
--- /dev/null
+++ b/kig/mimetypes/drgeo.magic
@@ -0,0 +1 @@
+0 string \<?xml\ version="1.0"?\>\n\<drgenius\> application/x-drgeo
diff --git a/kig/mimetypes/x-cabri.desktop b/kig/mimetypes/x-cabri.desktop
new file mode 100644
index 00000000..b02d7ac9
--- /dev/null
+++ b/kig/mimetypes/x-cabri.desktop
@@ -0,0 +1,67 @@
+# KDE Config File
+[Desktop Entry]
+MimeType=application/x-cabri
+Icon=kig_doc
+Comment=Cabri Figure
+Comment[af]=Cabri-figuur
+Comment[ar]=شكل كابري
+Comment[be]=Фігура Cabri
+Comment[bg]=Фигура Cabri
+Comment[bn]=কà§à¦¯à¦¾à¦¬à¦°à§€ ছবি
+Comment[bs]=Cabri slika
+Comment[ca]=Figura de cabri
+Comment[cs]=Cabri vzor
+Comment[csb]=Céchùnk Cabri
+Comment[cy]=Ffigur Cabri
+Comment[da]=Cabri figur
+Comment[de]=Cabri-Zeichnung
+Comment[el]=Σχέδιο του Cabri
+Comment[eo]=Cabri figuro
+Comment[es]=Figura de Cabri
+Comment[et]=Cabri kujund
+Comment[eu]=Cabri irudia
+Comment[fa]=Ø´Ú©Ù„ Cabri
+Comment[fi]=Cabri-kaavio
+Comment[fr]=Figure Cabri
+Comment[ga]=Léaráid Cabri
+Comment[gl]=Figura de Cabri
+Comment[hi]=केबरी रूप
+Comment[hr]=Cabri oblik
+Comment[hu]=Cabri ábra
+Comment[is]=Cabri mynd
+Comment[it]=Figura di Cabri
+Comment[ja]=Cabri 図
+Comment[ka]=Cabri ფიგურáƒ
+Comment[km]=រូប​ពន្យល់ Cabri
+Comment[lt]=Cabri figūra
+Comment[lv]=Cabri Figūra
+Comment[mk]=Cabri фигура
+Comment[mn]=Cabri Ð¥ÑлбÑÑ€
+Comment[nb]=Cabri-figur
+Comment[nds]="Cabri"-Figuur
+Comment[ne]=काबà¥à¤°à¥€ आकृति
+Comment[nl]=Cabri-figuur
+Comment[nn]=Cabri-figur
+Comment[pl]=Rysunek Cabri
+Comment[pt]=Figura do Cabri
+Comment[pt_BR]=Figura do Cabri
+Comment[ru]=Фигура Cabri
+Comment[sk]=Cabri vzor
+Comment[sl]=Lik Cabri
+Comment[sr]=Cabri фигура
+Comment[sr@Latn]=Cabri figura
+Comment[sv]=Cabri-figur
+Comment[ta]=கபிரி படமà¯
+Comment[tg]=Фигураи КÑбри
+Comment[tr]=Cabri Figürü
+Comment[uk]=Фігура Cabri
+Comment[ven]=Tshiimo tsha Cabri
+Comment[vi]=Hình Cabri
+Comment[zh_CN]=Cabri 图形
+Comment[zh_TW]=Cabri 圖形
+Type=MimeType
+Patterns=*.fig;*.FIG
+X-KDE-AutoEmbed=false
+[Property::X-KDE-NativeExtension]
+Type=QString
+Value=.FIG
diff --git a/kig/mimetypes/x-drgeo.desktop b/kig/mimetypes/x-drgeo.desktop
new file mode 100644
index 00000000..7a19faf7
--- /dev/null
+++ b/kig/mimetypes/x-drgeo.desktop
@@ -0,0 +1,62 @@
+# KDE Config File
+[Desktop Entry]
+MimeType=application/x-drgeo
+Icon=kig_doc
+Comment=Dr. Geo Figure
+Comment[af]=Dr. Geo-figuur
+Comment[be]=Фігура Dr. Geo
+Comment[bg]=Фигура Dr. Geo
+Comment[bn]=ড. জিও ছবি
+Comment[bs]=Dr. Geo slika
+Comment[ca]=Figura de Dr. Geo
+Comment[cs]=Dr. Geo
+Comment[csb]=Céchùnk Dr Geo
+Comment[cy]=Ffigur Dr. Geo
+Comment[da]=Dr. Geo-figur
+Comment[de]=Dr. Geo-Zeichnung
+Comment[el]=Σχέδιο του Dr. Geo
+Comment[eo]=Dr. Geo figuro
+Comment[es]=Figura de Dr. Geo
+Comment[et]=Dr. Geo kujund
+Comment[eu]=Dr. Geo irudia
+Comment[fa]=شکل دکتر جیو
+Comment[fi]=Dr. Geo -kaavio
+Comment[fr]=Figure Dr. Geo
+Comment[ga]=Léaráid Dr. Geo
+Comment[gl]=Figura de Dr. Geo
+Comment[hi]=डॉ. जिओ आकार
+Comment[hu]=Dr. Geo-ábra
+Comment[is]=Dr. Geo mynd
+Comment[it]=Figura di Dr. Geo
+Comment[ja]=Dr. Geo 図
+Comment[ka]=Dr. Geo ფიგურáƒ
+Comment[km]=រូប​ពន្យល់ Dr. Geo
+Comment[lt]=Dr. Geo figūra
+Comment[ms]=Figure Dr. Geo
+Comment[nb]=Dr. Geo-figur
+Comment[nds]="Dr. Geo"-Figuur
+Comment[ne]=डा. जिव फिगर
+Comment[nl]=Dr. Geo-figuur
+Comment[nn]=Dr. Geo-figur
+Comment[pl]=Rysunek Dr. Geo
+Comment[pt]=Figura do Dr. Geo
+Comment[pt_BR]=Figura do Dr.Geo
+Comment[ru]=Фигура Dr. Geo
+Comment[sk]=Obrázok Dr. Geo
+Comment[sl]=Lik Dr. Geo
+Comment[sr]=Dr. Geo Ñлика
+Comment[sr@Latn]=Dr. Geo slika
+Comment[sv]=Dr. Geo-figur
+Comment[ta]= டா. ஜியோ படமà¯
+Comment[tg]=Фигураи геометрӣ
+Comment[tr]=Dr. Geo Figürü
+Comment[uk]=Фігура Dr. Geo
+Comment[vi]=Tiến sÄ© Hình Hình há»c
+Comment[zh_CN]=Dr. Geo 图形
+Comment[zh_TW]=Dr. Geo 圖形
+Type=MimeType
+Patterns=*.fgeo
+X-KDE-AutoEmbed=false
+[Property::X-KDE-NativeExtension]
+Type=QString
+Value=.fgeo
diff --git a/kig/mimetypes/x-kgeo.desktop b/kig/mimetypes/x-kgeo.desktop
new file mode 100644
index 00000000..5fb0b12d
--- /dev/null
+++ b/kig/mimetypes/x-kgeo.desktop
@@ -0,0 +1,69 @@
+# KDE Config File
+[Desktop Entry]
+MimeType=application/x-kgeo
+Icon=kig_doc
+Comment=KGeo Figure
+Comment[af]=KGeo-figuur
+Comment[ar]=شكل هندسي ك
+Comment[be]=Фігура KGeo
+Comment[bg]=Фигура KGeo
+Comment[bn]=কে-জিও ছবি
+Comment[br]=Skeudenn KGeo
+Comment[bs]=KGeo slika
+Comment[ca]=Figura de KGeo
+Comment[cs]=KGeo vzor
+Comment[csb]=Céchùnk KGeo
+Comment[cy]=Ffigur KGeo
+Comment[da]=KGeo figur
+Comment[de]=KGeo-Zeichnung
+Comment[el]=Σχέδιο του KGeo
+Comment[eo]=KGeo figuro
+Comment[es]=Figura de KGeo
+Comment[et]=KGeo kujund
+Comment[eu]=KGeo irudia
+Comment[fi]=KGeo-kaavio
+Comment[fr]=Figure KGeo
+Comment[ga]=Léaráid KGeo
+Comment[gl]=Figura de KGeo
+Comment[hi]=के-जिओ रूप
+Comment[hr]=KGeo oblik
+Comment[hu]=KGeo ábra
+Comment[is]=KGeo mynd
+Comment[it]=Figura di KGeo
+Comment[ja]=KGeo 図
+Comment[ka]=KGeo ფიგურáƒ
+Comment[km]=រូប​ពន្យល់ KGeo
+Comment[lt]=KGeo figūra
+Comment[lv]=KGeo Figūra
+Comment[mk]=KGeo фигура
+Comment[mn]=КГео Ð¥ÑлбÑÑ€
+Comment[nb]=KGeo-figur
+Comment[nds]="KGeo"-Figuur
+Comment[ne]=केडीई जिव फिगर
+Comment[nl]=KGeo-figuur
+Comment[nn]=KGeo-figur
+Comment[pa]=KGeo ਸ਼ਕਲਾਂ
+Comment[pl]=Rysunek KGeo
+Comment[pt]=Figura do KGeo
+Comment[pt_BR]=Figura do KGeo
+Comment[ru]=Фигура KGeo
+Comment[sk]=KGeo vzor
+Comment[sl]=Lik KGeo
+Comment[sr]=KGeo фигура
+Comment[sr@Latn]=KGeo figura
+Comment[sv]=Kgeo-figur
+Comment[ta]=கேஜியோ படமà¯
+Comment[tg]=Фигураи KGeo
+Comment[tr]=KGeo Figürü
+Comment[uk]=Фігура KGeo
+Comment[ven]=Tshiimo tsha KGeo
+Comment[vi]=Hình KGeo
+Comment[xh]=Umfanekiso we KGeo
+Comment[zh_CN]=KGeo 图形
+Comment[zh_TW]=KGeo 圖形
+Type=MimeType
+Patterns=*.kgeo;
+X-KDE-AutoEmbed=false
+[Property::X-KDE-NativeExtension]
+Type=QString
+Value=.kgeo
diff --git a/kig/mimetypes/x-kig.desktop b/kig/mimetypes/x-kig.desktop
new file mode 100644
index 00000000..95fcce4c
--- /dev/null
+++ b/kig/mimetypes/x-kig.desktop
@@ -0,0 +1,69 @@
+# KDE Config File
+[Desktop Entry]
+MimeType=application/x-kig
+Icon=kig_doc
+Comment=Kig Figure
+Comment[af]=Kig-figuur
+Comment[ar]=شكل لكيج
+Comment[be]=Фігура Kig
+Comment[bg]=Фигура Kig
+Comment[bn]=কিগ ছবি
+Comment[br]=Skeudenn Kig
+Comment[bs]=Kig datoteka
+Comment[ca]=Figura de Kig
+Comment[cs]=Kig vzor
+Comment[csb]=Céchùnk Kig
+Comment[cy]=Ffigur Kig
+Comment[da]=Kig figur
+Comment[de]=Kig-Zeichnung
+Comment[el]=Σχέδιο του Kig
+Comment[eo]=Kig figuro
+Comment[es]=Figura de Kig
+Comment[et]=Kigi kujund
+Comment[eu]=Kig irudia
+Comment[fa]=Ø´Ú©Ù„ Kig
+Comment[fi]=Kig-kaavio
+Comment[fr]=Figure Kig
+Comment[ga]=Léaráid Kig
+Comment[gl]=Figura de Kig
+Comment[hi]=के-इग रूप
+Comment[hr]=Kig oblik
+Comment[hu]=Kig ábra
+Comment[is]=Kig mynd
+Comment[it]=Figura di Kig
+Comment[ja]=Kig 図
+Comment[ka]=Kig ფიგურáƒ
+Comment[km]=រូប​ពន្យល់ Kig
+Comment[lt]=Kig figūra
+Comment[lv]=Kig Figūra
+Comment[mk]=Kig фигура
+Comment[mn]=Kig Ð¥ÑлбÑÑ€
+Comment[nb]=Kig-figur
+Comment[nds]="Kig"-Figuur
+Comment[ne]=किग फिगर
+Comment[nl]=Kig-figuur
+Comment[nn]=Kig-figur
+Comment[pl]=Rysunek Kig
+Comment[pt]=Figura do Kig
+Comment[pt_BR]=Figura do Kig
+Comment[ru]=Фигура Kig
+Comment[sk]=Kig vzor
+Comment[sl]=Lik Kig
+Comment[sr]=Kig фигура
+Comment[sr@Latn]=Kig figura
+Comment[sv]=Kig-figur
+Comment[ta]=கிக௠படமà¯
+Comment[tg]=Фигураи Kig
+Comment[tr]=Kig Figürü
+Comment[uk]=Фігура Kig
+Comment[ven]=Tshiimo tsha Kig
+Comment[vi]=Hình Kig
+Comment[xh]=Kig Inani
+Comment[zh_CN]=Kig 图形
+Comment[zh_TW]=Kig 圖形
+Type=MimeType
+Patterns=*.kig;*.kigz;
+X-KDE-AutoEmbed=false
+[Property::X-KDE-NativeExtension]
+Type=QString
+Value=.kig;*.kigz
diff --git a/kig/mimetypes/x-kseg.desktop b/kig/mimetypes/x-kseg.desktop
new file mode 100644
index 00000000..daac2747
--- /dev/null
+++ b/kig/mimetypes/x-kseg.desktop
@@ -0,0 +1,68 @@
+# KDE Config File
+[Desktop Entry]
+MimeType=application/x-kseg
+Icon=kig_doc
+Comment=KSeg Document
+Comment[af]=KSeg Dokument
+Comment[ar]=مستند قسم ك
+Comment[be]=Дакумент KSeg
+Comment[bg]=Документ на KSeg
+Comment[bn]=কে-সেগ ডকà§à¦®à§‡à¦¨à§à¦Ÿ
+Comment[br]=Teul KSeg
+Comment[bs]=KSeg dokument
+Comment[ca]=Document de KSeg
+Comment[cs]=Dokument KSeg
+Comment[csb]=Dokùment KSeg
+Comment[cy]=Dogfen KSeg
+Comment[da]=KSeg-dokument
+Comment[de]=KSeg-Dokument
+Comment[el]=ΈγγÏαφο KSeg
+Comment[eo]=KSeg dokumento
+Comment[es]=Documento de KSeg
+Comment[et]=KSegi dokument
+Comment[eu]=KSeg dokumentua
+Comment[fa]=سند KSeg
+Comment[fi]=KSeg-asiakirja
+Comment[fr]=Document KSeg
+Comment[ga]=Cáipéis KSeg
+Comment[gl]=Documento de KSeg
+Comment[he]=מסמך KSeg
+Comment[hi]=के-सेग दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼
+Comment[hr]=KSeg dokument
+Comment[hu]=KSeg dokumentum
+Comment[is]=KSeg skjal
+Comment[it]=Documento KSeg
+Comment[ja]=KSeg ドキュメント
+Comment[ka]=KSeg დáƒáƒ™áƒ£áƒ›áƒ”ნტი
+Comment[km]=ឯកសារ KSeg
+Comment[lt]=KSeg dokumentas
+Comment[lv]=KSeg Dokuments
+Comment[mk]=KSeg документ
+Comment[ms]=Dokumen KSeg
+Comment[nb]=KSeg-dokument
+Comment[nds]=KSeg-Dokment
+Comment[ne]=केडीई सेग कागजात
+Comment[nl]=KSeg-document
+Comment[nn]=KSeg-dokument
+Comment[pl]=Dokument KSeg
+Comment[pt]=Documento do KSeg
+Comment[pt_BR]=Documento do KSeg
+Comment[ru]=Документ KSeg
+Comment[sk]=Dokument KSeg
+Comment[sl]=Dokument KSeg
+Comment[sr]=Kseg документ
+Comment[sr@Latn]=Kseg dokument
+Comment[sv]=Kseg-dokument
+Comment[ta]=கேசக௠ஆவணமà¯
+Comment[tg]=Ҳуҷҷати KSeg
+Comment[tr]=KSeg Belgesi
+Comment[uk]=Документ KSeg
+Comment[vi]=Tài liệu KSeg
+Comment[zh_CN]=KSeg 文档
+Comment[zh_TW]=KSeg 文件
+Type=MimeType
+Patterns=*.seg;
+X-KDE-AutoEmbed=false
+[Property::X-KDE-NativeExtension]
+Type=QString
+Value=.seg
diff --git a/kig/misc/Makefile.am b/kig/misc/Makefile.am
new file mode 100644
index 00000000..d97d7989
--- /dev/null
+++ b/kig/misc/Makefile.am
@@ -0,0 +1,50 @@
+INCLUDES=$(all_includes)
+noinst_LTLIBRARIES=libmisc.la
+noinst_HEADERS = \
+ argsparser.h \
+ builtin_stuff.h \
+ calcpaths.h \
+ common.h \
+ conic-common.h \
+ coordinate.h \
+ coordinate_system.h \
+ cubic-common.h \
+ goniometry.h \
+ guiaction.h \
+ kigfiledialog.h \
+ kiginputdialog.h \
+ kignumerics.h \
+ kigpainter.h \
+ kigtransform.h \
+ lists.h \
+ object_constructor.h \
+ object_hierarchy.h \
+ rect.h \
+ screeninfo.h \
+ special_constructors.h
+
+libmisc_la_SOURCES = \
+ argsparser.cpp \
+ builtin_stuff.cc \
+ calcpaths.cc \
+ common.cpp \
+ conic-common.cpp \
+ coordinate.cpp \
+ coordinate_system.cpp \
+ cubic-common.cc \
+ goniometry.cc \
+ guiaction.cc \
+ kigfiledialog.cc \
+ kiginputdialog.cc \
+ kignumerics.cpp \
+ kigpainter.cpp \
+ kigtransform.cpp \
+ lists.cc \
+ object_constructor.cc \
+ object_hierarchy.cc \
+ rect.cc \
+ screeninfo.cc \
+ special_constructors.cc
+
+libmisc_la_LIBADD=-lm
+METASOURCES=AUTO
diff --git a/kig/misc/argsparser.cpp b/kig/misc/argsparser.cpp
new file mode 100644
index 00000000..c2387970
--- /dev/null
+++ b/kig/misc/argsparser.cpp
@@ -0,0 +1,267 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "argsparser.h"
+
+#include "../objects/object_imp.h"
+#include "../objects/object_holder.h"
+
+#include <cassert>
+#include <algorithm>
+#include <kdebug.h>
+
+void ArgsParser::initialize( const struct spec* args, int n )
+{
+ std::vector<spec> vect( args, args + n );
+ initialize( vect );
+}
+
+ArgsParser::ArgsParser()
+{
+}
+
+ArgsParser::ArgsParser( const std::vector<spec>& args )
+{
+ initialize( args );
+}
+
+void ArgsParser::initialize( const std::vector<spec>& args )
+{
+ margs = args;
+}
+
+ArgsParser::ArgsParser( const spec* args, int n )
+{
+ initialize( args, n );
+}
+
+static bool hasimp( const ObjectCalcer& o, const ObjectImpType* imptype )
+{
+ return o.imp()->inherits( imptype );
+}
+
+static bool hasimp( const ObjectImp& o, const ObjectImpType* imptype )
+{
+ return o.inherits( imptype );
+}
+
+static bool isvalid( const ObjectImp& o )
+{
+ return o.valid();
+}
+
+static bool isvalid( const ObjectCalcer& o )
+{
+ return o.imp()->valid();
+}
+
+// we use a template method that is used for both Objects and Args to
+// not have to write the same thing twice..
+template <class Collection>
+static int check( const Collection& c, const std::vector<ArgsParser::spec>& margs )
+{
+ std::vector<bool> found( margs.size() );
+
+ for ( typename Collection::const_iterator o = c.begin(); o != c.end(); ++o )
+ {
+ for ( uint i = 0; i < margs.size(); ++i )
+ {
+ if ( hasimp( **o, margs[i].type ) && !found[i] )
+ {
+ // object o is of a type that we're looking for
+ found[i] = true;
+ goto matched;
+ };
+ };
+ return ArgsParser::Invalid;
+ matched:
+ ;
+ };
+ for( uint i = 0; i < margs.size(); ++i )
+ if ( !found[i] ) return ArgsParser::Valid;
+ return ArgsParser::Complete;
+}
+
+int ArgsParser::check( const Args& os ) const
+{
+ return ::check( os, margs );
+}
+
+int ArgsParser::check( const std::vector<ObjectCalcer*>& os ) const
+{
+ return ::check( os, margs );
+}
+
+template <typename Collection>
+static Collection parse( const Collection& os,
+ const std::vector<ArgsParser::spec> margs )
+{
+ Collection ret( margs.size(), static_cast<typename Collection::value_type>( 0 ) );
+
+ for ( typename Collection::const_iterator o = os.begin(); o != os.end(); ++o )
+ {
+ for( uint i = 0; i < margs.size(); ++i )
+ if ( hasimp( **o, margs[i].type ) && ret[i] == 0 )
+ {
+ // object o is of a type that we're looking for
+ ret[i] = *o;
+ goto added;
+ }
+ added:
+ ;
+ };
+ // remove 0's from the output..
+ ret.erase(
+ std::remove( ret.begin(), ret.end(),
+ static_cast<typename Collection::value_type>( 0 ) ),
+ ret.end() );
+ return ret;
+}
+
+Args ArgsParser::parse( const Args& os ) const
+{
+ return ::parse( os, margs );
+}
+
+std::vector<ObjectCalcer*> ArgsParser::parse( const std::vector<ObjectCalcer*>& os ) const
+{
+ return ::parse( os, margs );
+}
+
+ArgsParser ArgsParser::without( const ObjectImpType* type ) const
+{
+ std::vector<spec> ret;
+ ret.reserve( margs.size() - 1 );
+ for ( uint i = 0; i < margs.size(); ++i )
+ if ( margs[i].type != type )
+ ret.push_back( margs[i] );
+ return ArgsParser( ret );
+}
+
+ArgsParser::spec ArgsParser::findSpec( const ObjectImp* obj, const Args& parents ) const
+{
+ spec ret;
+ ret.type = 0;
+
+ std::vector<bool> found( margs.size(), false );
+
+ for ( Args::const_iterator o = parents.begin();
+ o != parents.end(); ++o )
+ {
+ for ( uint i = 0; i < margs.size(); ++i )
+ {
+ if ( (*o)->inherits( margs[i].type ) && !found[i] )
+ {
+ // object o is of a type that we're looking for
+ found[i] = true;
+ if ( *o == obj ) return margs[i];
+ // i know that "goto's are *evil*", but they're very useful
+ // and completely harmless if you use them as better "break;"
+ // statements.. trust me ;)
+ goto matched;
+ };
+ };
+ matched:
+ ;
+ };
+ kdDebug() << k_funcinfo << "no proper spec found :(" << endl;
+ return ret;
+}
+
+const ObjectImpType* ArgsParser::impRequirement(
+ const ObjectImp* o, const Args& parents ) const
+{
+ spec s = findSpec( o, parents );
+ return s.type;
+}
+
+std::string ArgsParser::usetext( const ObjectImp* obj, const Args& sel ) const
+{
+ spec s = findSpec( obj, sel );
+ return s.usetext;
+}
+
+template<typename Collection>
+static bool checkArgs( const Collection& os, uint min, const std::vector<ArgsParser::spec>& argsspec )
+{
+ assert( os.size() <= argsspec.size() );
+ if( os.size() < min ) return false;
+ uint checknum = os.size();
+ for ( uint i = 0; i < checknum; ++i )
+ {
+ if( !isvalid( *os[i] ) ) return false;
+ if( !hasimp( *os[i], argsspec[i].type ) ) return false;
+ }
+ return true;
+}
+
+bool ArgsParser::checkArgs( const Args& os ) const
+{
+ return checkArgs( os, margs.size() );
+}
+
+bool ArgsParser::checkArgs( const Args& os, uint min ) const
+{
+ return ::checkArgs( os, min, margs );
+}
+
+bool ArgsParser::checkArgs( const std::vector<ObjectCalcer*>& os ) const
+{
+ return checkArgs( os, margs.size() );
+}
+
+bool ArgsParser::checkArgs( const std::vector<ObjectCalcer*>& os, uint minobjects ) const
+{
+ return ::checkArgs( os, minobjects, margs );
+}
+
+ArgsParser::~ArgsParser()
+{
+}
+
+bool ArgsParser::isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const
+{
+ spec s = findSpec( o, parents );
+ return s.onOrThrough;
+}
+
+std::string ArgsParser::selectStatement( const Args& selection ) const
+{
+ std::vector<bool> found( margs.size(), false );
+
+ for ( Args::const_iterator o = selection.begin();
+ o != selection.end(); ++o )
+ {
+ for ( uint i = 0; i < margs.size(); ++i )
+ {
+ if ( (*o)->inherits( margs[i].type ) && !found[i] )
+ {
+ // object o is of a type that we're looking for
+ found[i] = true;
+ break;
+ }
+ }
+ }
+ for ( uint i = 0; i < margs.size(); ++i )
+ {
+ if ( !found[i] )
+ return margs[i].selectstat;
+ }
+ kdDebug() << k_funcinfo << "no proper select statement found :(" << endl;
+ return 0;
+}
+
diff --git a/kig/misc/argsparser.h b/kig/misc/argsparser.h
new file mode 100644
index 00000000..001d9359
--- /dev/null
+++ b/kig/misc/argsparser.h
@@ -0,0 +1,187 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MISC_ARGSPARSER_H
+#define KIG_MISC_ARGSPARSER_H
+
+#include "../objects/common.h"
+
+#include <string>
+
+class ObjectImpType;
+
+/**
+ * This class is meant to take care of checking the types of the
+ * parents to ObjectCalcer's, and to put them in the correct order.
+ * An ObjectType should construct an ArgsParser with a specification
+ * of the arguments it wants. This specification is given as an array
+ * of ArgsParser::spec structs. This struct contains a pointer to an
+ * ObjectImpType ( which is the type you want the argument to have ),
+ * a string ( which is an I18N_NOOP'd string describing what you will
+ * be using the argument for ) and a boolean ( which says whether the
+ * constructed object is by construction on the curve argument ( if
+ * the constructed object is a point ), or whether the constructed
+ * object is by construction through the point argument ( if the
+ * constructed object is a curve ) ).
+ *
+ * An ObjectType using an ArgsParser to take care of the various
+ * things that it can handle ( impRequirement, the sortArgs functions
+ * and the isDefinedOnOrThrough stuff ), should inherit from
+ * ArgsParserObjectType, which takes care of calling the ArgsParser
+ * for these things... It also allows you to use a convenient
+ * ObjectConstructor for your type.
+ *
+ * E.g., let's see what CircleBCPType has for its arguments spec:
+ * here's some code:
+ * \code
+ * static const ArgsParser::spec argsspecTranslation[] =
+ * {
+ * { ObjectImp::stype(), I18N_NOOP("Translate this object"), false },
+ * { VectorImp::stype(), I18N_NOOP("Translate by this vector"), false }
+ * };
+ *
+ * TranslatedType::TranslatedType()
+ * : ArgsParserObjectType( "Translation", argsspecTranslation, 2 )
+ * {
+ * }
+ *
+ * ObjectImp* TranslatedType::calc( const Args& args, const KigDocument& ) const
+ * {
+ * if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+ *
+ * Coordinate dir = static_cast<const VectorImp*>( args[1] )->dir();
+ * Transformation t = Transformation::translation( dir );
+ *
+ * return args[0]->transform( t );
+ * }
+ * \endcode
+ *
+ * As you can see above, the argsspec can be declared right in the
+ * cpp-file. The usetexts explain to the user what the argument in
+ * question will be used for. The boolean says that in this case, the
+ * constructed object is not by construction on or through one of its
+ * arguments. In the constructor, you simply call the
+ * ArgsParserObjectType with the argsspec struct you defined, and the
+ * number of arguments in the argsspec ( in this case 2 ).
+ *
+ * In the calc function, you can rely on the arguments already being
+ * in the correct order ( the same order as you put them in in the
+ * arguments spec. You should use the checkArgs function to check if
+ * all the arguments are valid, and if they aren't return a
+ * InvalidImp. All objects can always become invalid ( e.g. an
+ * intersection point of two non-intersecting conics can become valid
+ * again when the conics move ), and you should always check for this.
+ *
+ * An interesting to note here is that the first argument is of a more
+ * general type than the second. A VectorImp is *also* an ObjectImp.
+ * In general, when this happens, you should put the more general type
+ * first, as in general this produces the results that the user
+ * expects. I have no formal proof for this, just talking from
+ * experience. It might be that you experience different things, but
+ * unless you're sure of the results, put the more general type first.
+ *
+ * This class uses a pretty basic algorithm for doing the parsing (
+ * e.g. if a match fails in one order, it does not try a different
+ * order, which could perhaps be necessary in the case of having more
+ * general argument types in the same argument spec ). However, the
+ * current algorithm works in all the situation where I've tested it,
+ * and I don't feel the need to change it. Feel free to do so if you
+ * like, but even if you do, I'm not sure if I will include it in
+ * mainline Kig.
+ */
+class ArgsParser
+{
+public:
+ /**
+ * this are some enum values that we return from some functions.
+ */
+ enum { Invalid = 0, Valid = 1, Complete = 2 };
+ struct spec { const ObjectImpType* type; std::string usetext; std::string selectstat; bool onOrThrough;};
+private:
+ /**
+ * the args spec..
+ */
+ std::vector<spec> margs;
+
+ spec findSpec( const ObjectImp* o, const Args& parents ) const;
+public:
+ ArgsParser( const struct spec* args, int n );
+ ArgsParser( const std::vector<spec>& args );
+ ArgsParser();
+ ~ArgsParser();
+
+ void initialize( const std::vector<spec>& args );
+ void initialize( const struct spec* args, int n );
+
+ /**
+ * returns a new ArgsParser that wants the same args, except for the
+ * ones of the given type..
+ */
+ ArgsParser without( const ObjectImpType* type ) const;
+ // checks if os matches the argument list this parser should parse..
+ int check( const Args& os ) const;
+ int check( const std::vector<ObjectCalcer*>& os ) const;
+ /**
+ * returns the usetext for the argument that o would be used for,
+ * if sel were used as parents..
+ * \p o should be in \p sel ...
+ */
+ std::string usetext( const ObjectImp* o, const Args& sel ) const;
+
+ /**
+ * returns the select statement for the next selectable argument
+ * when the given args are selected.
+ */
+ std::string selectStatement( const Args& sel ) const;
+
+ // this reorders the objects or args so that they are in the same
+ // order as the requested arguments..
+ Args parse( const Args& os ) const;
+ std::vector<ObjectCalcer*> parse( const std::vector<ObjectCalcer*>& os ) const;
+
+ /**
+ * returns the minimal ObjectImp ID that \p o needs to inherit in order
+ * to be useful.. \p o should be part of \p parents .
+ */
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+
+ /**
+ * Supposing that \p parents would be given as parents, this function
+ * returns whether the returned ObjectImp will be, by construction,
+ * on \p o ( if \p o is a curve ), or through \p o ( if \p o is a point ).
+ */
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+
+ // Checks the args according to this args specification. If the
+ // objects should never have occurred, then an assertion failure
+ // will happen, if one of the args is invalid, then false will be
+ // returned, if all is fine, then true is returned..
+ // assert that the objects are of the right types, and in the right
+ // order as what would be returned by parse( os ).. If minobjects
+ // is provided, then not all objects are needed, and it is enough if
+ // at least minobjects are available.. Use this for object types
+ // that can calc a temporary example object using less than the
+ // required args. These args need to be at the end of argsspec +
+ // anyobjsspec. If minobjects is not provided, then it is assumed
+ // that all args are necessary.
+ bool checkArgs( const std::vector<ObjectCalcer*>& os ) const;
+ bool checkArgs( const std::vector<ObjectCalcer*>& os, uint minobjects ) const;
+ bool checkArgs( const Args& os ) const;
+ bool checkArgs( const Args& os, uint minobjects ) const;
+};
+
+#endif
diff --git a/kig/misc/boost_intrusive_pointer.hpp b/kig/misc/boost_intrusive_pointer.hpp
new file mode 100644
index 00000000..a278e736
--- /dev/null
+++ b/kig/misc/boost_intrusive_pointer.hpp
@@ -0,0 +1,256 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+
+
+// This code comes from the boost::intrusive_ptr. I adapted it to
+// suit my needs ( no dependencies on other boost libs, change the
+// namespace to avoid conflicts,
+
+#ifndef MYBOOST_INTRUSIVE_PTR_HPP_INCLUDED
+#define MYBOOST_INTRUSIVE_PTR_HPP_INCLUDED
+
+//
+// intrusive_ptr.hpp
+//
+// Copyright (c) 2001, 2002 Peter Dimov
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+// See http://www.boost.org/libs/smart_ptr/intrusive_ptr.html for documentation.
+//
+
+#include <functional> // for std::less
+#include <iosfwd> // for std::basic_ostream
+
+
+namespace myboost
+{
+
+//
+// intrusive_ptr
+//
+// A smart pointer that uses intrusive reference counting.
+//
+// Relies on unqualified calls to
+//
+// void intrusive_ptr_add_ref(T * p);
+// void intrusive_ptr_release(T * p);
+//
+// (p != 0)
+//
+// The object is responsible for destroying itself.
+//
+
+template<class T> class intrusive_ptr
+{
+private:
+
+ typedef intrusive_ptr this_type;
+
+public:
+
+ typedef T element_type;
+
+ intrusive_ptr(): p_(0)
+ {
+ }
+
+ intrusive_ptr(T * p, bool add_ref = true): p_(p)
+ {
+ if(p_ != 0 && add_ref) intrusive_ptr_add_ref(p_);
+ }
+
+#if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES)
+
+ template<class U> intrusive_ptr(intrusive_ptr<U> const & rhs): p_(rhs.get())
+ {
+ if(p_ != 0) intrusive_ptr_add_ref(p_);
+ }
+
+#endif
+
+ intrusive_ptr(intrusive_ptr const & rhs): p_(rhs.p_)
+ {
+ if(p_ != 0) intrusive_ptr_add_ref(p_);
+ }
+
+ ~intrusive_ptr()
+ {
+ if(p_ != 0) intrusive_ptr_release(p_);
+ }
+
+#if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES)
+
+ template<class U> intrusive_ptr & operator=(intrusive_ptr<U> const & rhs)
+ {
+ this_type(rhs).swap(*this);
+ return *this;
+ }
+
+#endif
+
+ intrusive_ptr & operator=(intrusive_ptr const & rhs)
+ {
+ this_type(rhs).swap(*this);
+ return *this;
+ }
+
+ intrusive_ptr & operator=(T * rhs)
+ {
+ this_type(rhs).swap(*this);
+ return *this;
+ }
+
+ T * get() const
+ {
+ return p_;
+ }
+
+ T & operator*() const
+ {
+ return *p_;
+ }
+
+ T * operator->() const
+ {
+ return p_;
+ }
+
+ typedef T * (intrusive_ptr::*unspecified_bool_type) () const;
+
+ operator unspecified_bool_type () const
+ {
+ return p_ == 0? 0: &intrusive_ptr::get;
+ }
+
+ // operator! is a Borland-specific workaround
+ bool operator! () const
+ {
+ return p_ == 0;
+ }
+
+ void swap(intrusive_ptr & rhs)
+ {
+ T * tmp = p_;
+ p_ = rhs.p_;
+ rhs.p_ = tmp;
+ }
+
+private:
+
+ T * p_;
+};
+
+template<class T, class U> inline bool operator==(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b)
+{
+ return a.get() == b.get();
+}
+
+template<class T, class U> inline bool operator!=(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b)
+{
+ return a.get() != b.get();
+}
+
+template<class T> inline bool operator==(intrusive_ptr<T> const & a, T * b)
+{
+ return a.get() == b;
+}
+
+template<class T> inline bool operator!=(intrusive_ptr<T> const & a, T * b)
+{
+ return a.get() != b;
+}
+
+template<class T> inline bool operator==(T * a, intrusive_ptr<T> const & b)
+{
+ return a == b.get();
+}
+
+template<class T> inline bool operator!=(T * a, intrusive_ptr<T> const & b)
+{
+ return a != b.get();
+}
+
+#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
+
+// Resolve the ambiguity between our op!= and the one in rel_ops
+
+template<class T> inline bool operator!=(intrusive_ptr<T> const & a, intrusive_ptr<T> const & b)
+{
+ return a.get() != b.get();
+}
+
+#endif
+
+template<class T> inline bool operator<(intrusive_ptr<T> const & a, intrusive_ptr<T> const & b)
+{
+ return std::less<T *>()(a.get(), b.get());
+}
+
+template<class T> void swap(intrusive_ptr<T> & lhs, intrusive_ptr<T> & rhs)
+{
+ lhs.swap(rhs);
+}
+
+// mem_fn support
+
+template<class T> T * get_pointer(intrusive_ptr<T> const & p)
+{
+ return p.get();
+}
+
+template<class T, class U> intrusive_ptr<T> static_pointer_cast(intrusive_ptr<U> const & p)
+{
+ return static_cast<T *>(p.get());
+}
+
+template<class T, class U> intrusive_ptr<T> dynamic_pointer_cast(intrusive_ptr<U> const & p)
+{
+ return dynamic_cast<T *>(p.get());
+}
+
+// operator<<
+
+#if defined(__GNUC__) && (__GNUC__ < 3)
+
+template<class Y> std::ostream & operator<< (std::ostream & os, intrusive_ptr<Y> const & p)
+{
+ os << p.get();
+ return os;
+}
+
+#else
+
+template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, intrusive_ptr<Y> const & p)
+{
+ os << p.get();
+ return os;
+}
+
+#endif
+
+} // namespace myboost
+
+#ifdef BOOST_MSVC
+# pragma warning(pop)
+#endif
+
+#endif // #ifndef MYBOOST_INTRUSIVE_PTR_HPP_INCLUDED
diff --git a/kig/misc/builtin_stuff.cc b/kig/misc/builtin_stuff.cc
new file mode 100644
index 00000000..e162e7ac
--- /dev/null
+++ b/kig/misc/builtin_stuff.cc
@@ -0,0 +1,596 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "builtin_stuff.h"
+
+#include <config.h>
+
+#include "object_constructor.h"
+#include "lists.h"
+#include "special_constructors.h"
+#include "guiaction.h"
+
+#include "../objects/angle_type.h"
+#include "../objects/arc_type.h"
+#include "../objects/circle_type.h"
+#include "../objects/conic_types.h"
+#include "../objects/cubic_type.h"
+#include "../objects/intersection_types.h"
+#include "../objects/inversion_type.h"
+#include "../objects/line_imp.h"
+#include "../objects/line_type.h"
+#include "../objects/object_imp.h"
+#include "../objects/other_imp.h"
+#include "../objects/other_type.h"
+#include "../objects/point_type.h"
+#include "../objects/tests_type.h"
+#include "../objects/transform_types.h"
+#include "../objects/vector_type.h"
+#include "../objects/polygon_type.h"
+
+#include <klocale.h>
+
+void setupBuiltinStuff()
+{
+ static bool done = false;
+ if ( ! done )
+ {
+ ObjectConstructorList* ctors = ObjectConstructorList::instance();
+ GUIActionList* actions = GUIActionList::instance();
+ ObjectConstructor* c = 0;
+
+ // segment...
+ c = new SimpleObjectTypeConstructor(
+ SegmentABType::instance(), I18N_NOOP( "Segment" ),
+ I18N_NOOP( "A segment constructed from its start and end point" ),
+ "segment" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_segment", Qt::Key_S ) );
+
+ // line by two points..
+ c = new SimpleObjectTypeConstructor(
+ LineABType::instance(), I18N_NOOP( "Line by Two Points" ),
+ I18N_NOOP( "A line constructed through two points"), "line" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_linettp", Qt::Key_L ) );
+
+ // ray by two points..
+ c = new SimpleObjectTypeConstructor(
+ RayABType::instance(), I18N_NOOP( "Half-Line" ),
+ I18N_NOOP( "A half-line by its start point, and another point somewhere on it." ),
+ "ray" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_ray", Qt::Key_R ) );
+
+ // perpendicular line
+ c = new SimpleObjectTypeConstructor(
+ LinePerpendLPType::instance(), I18N_NOOP( "Perpendicular" ),
+ I18N_NOOP( "A line constructed through a point, perpendicular to another line or segment." ),
+ "perpendicular" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_lineperpend" ) );
+
+ // parallel line
+ c = new SimpleObjectTypeConstructor(
+ LineParallelLPType::instance(), I18N_NOOP( "Parallel" ),
+ I18N_NOOP( "A line constructed through a point, and parallel to another line or segment" ),
+ "parallel" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_lineparallel" ) );
+
+ // circle
+ c = new SimpleObjectTypeConstructor(
+ CircleBCPType::instance(), I18N_NOOP( "Circle by Center && Point" ),
+ I18N_NOOP( "A circle constructed by its center and a point that pertains to it" ),
+ "circlebcp" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_circlebcp", Qt::Key_C ) );
+
+ c = new SimpleObjectTypeConstructor(
+ CircleBTPType::instance(), I18N_NOOP( "Circle by Three Points" ),
+ I18N_NOOP( "A circle constructed through three points" ),
+ "circlebtp" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_circlebtp" ) );
+
+ // declare this object static to this function, so it gets deleted
+ // at the end of the program, without us having to wonder about
+ // deleting it.. We don't want to register this
+ // object-constructor, because that way, "construct the bisector"
+ // would appear twice in the angle popup menu: once as the generic
+ // construct a property stuff, and once because of this ctor..
+ // we only register the guiaction, cause it makes sense to have a
+ // toolbar icon for this..
+ static PropertyObjectConstructor anglebisectionctor(
+ AngleImp::stype(),
+ I18N_NOOP( "Construct Bisector of This Angle" ),
+ I18N_NOOP( "Select the angle you want to construct the bisector of..." ),
+ I18N_NOOP( "Angle Bisector" ),
+ I18N_NOOP( "The bisector of an angle" ),
+ "angle_bisector",
+ "angle-bisector" );
+ actions->add( new ConstructibleAction( &anglebisectionctor, "objects_new_angle_bisector" ) );
+
+ // conic stuff
+ c = new SimpleObjectTypeConstructor(
+ ConicB5PType::instance(), I18N_NOOP( "Conic by Five Points" ),
+ I18N_NOOP( "A conic constructed through five points" ),
+ "conicb5p" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_conicb5p" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ ConicBAAPType::instance(),
+ I18N_NOOP( "Hyperbola by Asymptotes && Point" ),
+ I18N_NOOP( "A hyperbola with given asymptotes through a point" ),
+ "conicbaap" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_conicbaap" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ EllipseBFFPType::instance(),
+ I18N_NOOP( "Ellipse by Focuses && Point" ), // focuses is used in preference to foci
+ I18N_NOOP( "An ellipse constructed by its focuses and a point that pertains to it" ),
+ "ellipsebffp" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_ellipsebffp" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ HyperbolaBFFPType::instance(),
+ I18N_NOOP( "Hyperbola by Focuses && Point" ), // focuses is used in preference to foci
+ I18N_NOOP( "A hyperbola constructed by its focuses and a point that pertains to it" ),
+ "hyperbolabffp" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_hyperbolabffp" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ ConicBDFPType::instance(),
+ I18N_NOOP( "Conic by Directrix, Focus && Point" ),
+ I18N_NOOP( "A conic with given directrix and focus, through a point" ),
+ "conicbdfp" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_conicbdfp" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ ParabolaBTPType::instance(),
+ I18N_NOOP( "Vertical Parabola by Three Points" ),
+ I18N_NOOP( "A vertical parabola constructed through three points" ),
+ "parabolabtp" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_parabolabtp" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ CubicB9PType::instance(),
+ I18N_NOOP( "Cubic Curve by Nine Points" ),
+ I18N_NOOP( "A cubic curve constructed through nine points" ),
+ "cubicb9p" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_cubicb9p" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ ConicPolarPointType::instance(),
+ I18N_NOOP( "Polar Point of a Line" ),
+ I18N_NOOP( "The polar point of a line with respect to a conic." ),
+ "polarpoint" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_pointpolar" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ ConicPolarLineType::instance(),
+ I18N_NOOP( "Polar Line of a Point" ),
+ I18N_NOOP( "The polar line of a point with respect to a conic." ),
+ "polarline" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_linepolar" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ CubicNodeB6PType::instance(),
+ I18N_NOOP( "Cubic Curve with Node by Six Points" ),
+ I18N_NOOP( "A cubic curve with a nodal point at the origin through six points" ),
+ "cubicnodeb6p" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_cubicnodeb6p" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ CubicCuspB4PType::instance(),
+ I18N_NOOP( "Cubic Curve with Cusp by Four Points" ),
+ I18N_NOOP( "A cubic curve with a horizontal cusp at the origin through four points" ),
+ "cubiccuspb4p" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_cubiccuspb4p" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ ConicDirectrixType::instance(),
+ I18N_NOOP( "Directrix of a Conic" ),
+ I18N_NOOP( "The directrix line of a conic." ),
+ "directrix" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_linedirectrix" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ AngleType::instance(),
+ I18N_NOOP( "Angle by Three Points" ),
+ I18N_NOOP( "An angle defined by three points" ),
+ "angle" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_angle", Qt::Key_A ) );
+
+ c = new SimpleObjectTypeConstructor(
+ EquilateralHyperbolaB4PType::instance(),
+ I18N_NOOP( "Equilateral Hyperbola by Four Points" ),
+ I18N_NOOP( "An equilateral hyperbola constructed through four points" ),
+ "equilateralhyperbolab4p" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_equilateralhyperbolab4p" ) );
+
+ {
+ // now for the Mid Point action. It does both the mid point of
+ // a segment, and the mid point of two points. The midpoint of
+ // two segments just shows the mid point property, and therefore
+ // doesn't need to be added to the ctors, because there are
+ // already facilities to construct an object's properties..
+ // therefore, we add only an mpotp to the ctors, and add the
+ // merged constructor only to the actions..
+ ctors->add( new MidPointOfTwoPointsConstructor() );
+
+ ObjectConstructor* mpotp = new MidPointOfTwoPointsConstructor();
+ ObjectConstructor* mpos = new PropertyObjectConstructor(
+ SegmentImp::stype(), I18N_NOOP( "Construct the midpoint of this segment" ),
+ "", "", "", "", "mid-point" );
+
+ // make this a static object, so it gets deleted at the end of
+ // the program.
+ static MergeObjectConstructor m(
+ I18N_NOOP( "Mid Point" ),
+ I18N_NOOP( "The midpoint of a segment or two other points" ),
+ "bisection" );
+ m.merge( mpotp );
+ m.merge( mpos );
+ actions->add( new ConstructibleAction( &m, "objects_new_midpoint", Qt::Key_M ) );
+ };
+
+ c = new SimpleObjectTypeConstructor(
+ VectorType::instance(),
+ I18N_NOOP( "Vector" ),
+ I18N_NOOP( "Construct a vector from two given points." ),
+ "vector" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_vector", Qt::Key_V ) );
+
+ c = new SimpleObjectTypeConstructor(
+ VectorSumType::instance(),
+ I18N_NOOP( "Vector Sum" ),
+ I18N_NOOP( "Construct the vector sum of two vectors." ),
+ "vectorsum" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_vectorsum", 0 ) );
+
+ c = new SimpleObjectTypeConstructor(
+ LineByVectorType::instance(),
+ I18N_NOOP( "Line by Vector" ),
+ I18N_NOOP( "Construct the line by a given vector though a given point." ),
+ "linebyvector" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_linebyvector", 0 ) );
+
+ c = new SimpleObjectTypeConstructor(
+ HalflineByVectorType::instance(),
+ I18N_NOOP( "Half-Line by Vector" ),
+ I18N_NOOP( "Construct the half-line by a given vector starting at given point." ),
+ "halflinebyvector" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_halflinebyvector", 0 ) );
+
+ c = new SimpleObjectTypeConstructor(
+ ArcBTPType::instance(),
+ I18N_NOOP( "Arc by Three Points" ),
+ I18N_NOOP( "Construct an arc through three points." ),
+ "arc" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_arcbtp" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ ArcBCPAType::instance(),
+ I18N_NOOP( "Arc by Center, Angle && Point" ),
+ I18N_NOOP( "Construct an arc by its center and a given angle, "
+ "starting at a given point" ),
+ "arcbcpa" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_arcbcpa" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ ParabolaBDPType::instance(),
+ I18N_NOOP( "Parabola by Directrix && Focus" ),
+ I18N_NOOP( "A parabola defined by its directrix and focus" ),
+ "parabolabdp" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_parabolabdp" ) );
+
+ // Transformation stuff..
+ c = new InversionConstructor();
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_inversion" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ TranslatedType::instance(),
+ I18N_NOOP( "Translate" ),
+ I18N_NOOP( "The translation of an object by a vector" ),
+ "translation" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_translation" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ PointReflectionType::instance(),
+ I18N_NOOP( "Reflect in Point" ),
+ I18N_NOOP( "An object reflected in a point" ),
+ "centralsymmetry" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_pointreflection" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ LineReflectionType::instance(),
+ I18N_NOOP( "Reflect in Line" ),
+ I18N_NOOP( "An object reflected in a line" ),
+ "mirrorpoint" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_linereflection" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ RotationType::instance(),
+ I18N_NOOP( "Rotate" ),
+ I18N_NOOP( "An object rotated by an angle around a point" ),
+ "rotation" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_rotation" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ ScalingOverCenterType::instance(),
+ I18N_NOOP( "Scale" ),
+ I18N_NOOP( "Scale an object over a point, by the ratio given by the length of a segment" ),
+ "scale" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_scalingovercenter" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ ScalingOverLineType::instance(),
+ I18N_NOOP( "Scale over Line" ),
+ I18N_NOOP( "An object scaled over a line, by the ratio given by the length of a segment" ),
+ "stretch" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_scalingoverline" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ ScalingOverCenter2Type::instance(),
+ I18N_NOOP( "Scale (ratio given by two segments)" ),
+ I18N_NOOP( "Scale an object over a point, by the ratio given by the length of two segments" ),
+ "scale" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_scalingovercenter2" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ ScalingOverLine2Type::instance(),
+ I18N_NOOP( "Scale over Line (ratio given by two segments)" ),
+ I18N_NOOP( "An object scaled over a line, by the ratio given by the length of two segments" ),
+ "stretch" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_scalingoverline2" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ SimilitudeType::instance(),
+ I18N_NOOP( "Apply Similitude" ),
+ I18N_NOOP( "Apply a similitude to an object ( the sequence of a scaling and rotation around a center )" ),
+ "similitude" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_similitude" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ HarmonicHomologyType::instance(),
+ I18N_NOOP( "Harmonic Homology" ),
+ I18N_NOOP( "The harmonic homology with a given center and a given axis (this is a projective transformation)" ),
+ "harmonichomology" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_harmonichomology" ) );
+
+ c = new GenericAffinityConstructor();
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_genericaffinity" ) );
+
+ c = new GenericProjectivityConstructor();
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_genericprojectivity" ) );
+
+ c = new SimpleObjectTypeConstructor(
+ CastShadowType::instance(),
+ I18N_NOOP( "Draw Projective Shadow" ),
+ I18N_NOOP( "The shadow of an object with a given light source and projection plane (indicated by a line)" ),
+ "castshadow" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_castshadow" ) );
+
+// c = new SimpleObjectTypeConstructor(
+// ProjectiveRotationType::instance(),
+// I18N_NOOP( "Rotate Projectively" ),
+// I18N_NOOP( "An object projectively rotated by an angle and a half-line" ),
+// "projectiverotation" );
+// ctors->add( c );
+// actions->add( new ConstructibleAction( c, "objects_new_projectiverotation" ) );
+
+ c = new MultiObjectTypeConstructor(
+ ConicAsymptoteType::instance(),
+ I18N_NOOP( "Asymptotes of a Hyperbola" ),
+ I18N_NOOP( "The two asymptotes of a hyperbola." ),
+ "conicasymptotes", -1, 1 );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_lineconicasymptotes" ) );
+
+ c = new ConicRadicalConstructor();
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_lineconicradical") );
+
+ /* ----------- start polygons --------- */
+
+ c = new SimpleObjectTypeConstructor(
+ TriangleB3PType::instance(),
+ I18N_NOOP( "Triangle by Its Vertices" ),
+ I18N_NOOP( "Construct a triangle given its three vertices." ),
+ "triangle" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_trianglebtp" ) );
+
+ c = new PolygonBNPTypeConstructor();
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_polygonbnp" ));
+
+ c = new PolygonBCVConstructor();
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_polygonbcv" ) );
+
+ c = new PolygonVertexTypeConstructor();
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_polygonvertices" ));
+
+ c = new PolygonSideTypeConstructor();
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_polygonsides" ));
+
+ c = new SimpleObjectTypeConstructor(
+ ConvexHullType::instance(), I18N_NOOP( "Convex Hull" ),
+ I18N_NOOP( "A polygon that corresponds to the convex hull of another polygon" ),
+ "convexhull" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_convexhull" ) );
+
+ /* ----------- end polygons --------- */
+
+ c = new LocusConstructor();
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_locus" ) );
+
+ // tests
+ c = new TestConstructor(
+ AreParallelType::instance(),
+ I18N_NOOP( "Parallel Test" ),
+ I18N_NOOP( "Test whether two given lines are parallel" ),
+ "testparallel" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_areparallel" ) );
+
+ c = new TestConstructor(
+ AreOrthogonalType::instance(),
+ I18N_NOOP( "Orthogonal Test" ),
+ I18N_NOOP( "Test whether two given lines are orthogonal" ),
+ "testorthogonal" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_areorthogonal" ) );
+
+ c = new TestConstructor(
+ AreCollinearType::instance(),
+ I18N_NOOP( "Collinear Test" ),
+ I18N_NOOP( "Test whether three given points are collinear" ),
+ "testcollinear" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_arecollinear" ) );
+
+ c = new TestConstructor(
+ ContainsTestType::instance(),
+ I18N_NOOP( "Contains Test" ),
+ I18N_NOOP( "Test whether a given curve contains a given point" ),
+ "testcontains" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_containstest" ) );
+
+ c = new TestConstructor(
+ InPolygonTestType::instance(),
+ I18N_NOOP( "In Polygon Test" ),
+ I18N_NOOP( "Test whether a given polygon contains a given point" ),
+ "test" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_inpolygontest" ) );
+
+ c = new TestConstructor(
+ ConvexPolygonTestType::instance(),
+ I18N_NOOP( "Convex Polygon Test" ),
+ I18N_NOOP( "Test whether a given polygon is convex" ),
+ "test" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_convexpolygontest" ) );
+
+ c = new TestConstructor(
+ SameDistanceType::instance(),
+ I18N_NOOP( "Distance Test" ),
+ I18N_NOOP( "Test whether a given point have the same distance from a given point "
+ "and from another given point" ),
+ "testdistance" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_distancetest" ) );
+
+ c = new TestConstructor(
+ VectorEqualityTestType::instance(),
+ I18N_NOOP( "Vector Equality Test" ),
+ I18N_NOOP( "Test whether two vectors are equal" ),
+ "test" );
+// "testequal" );
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_vectorequalitytest" ) );
+
+ c = new MeasureTransportConstructor();
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_measuretransport" ));
+
+// c = new SimpleObjectTypeConstructor(
+// MeasureTransportType::instance(),
+// I18N_NOOP( "Measure Transport" ),
+// I18N_NOOP( "Transport the measure of a segment or arc over a line or circle." ),
+// "measuretransport" );
+// ctors->add( c );
+// actions->add( new ConstructibleAction( c, "objects_new_measuretransport" ) );
+
+ // the generic intersection constructor..
+ c = new GenericIntersectionConstructor();
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_intersection", Qt::Key_I ) );
+
+ // the generic tangent constructor
+ c = new TangentConstructor();
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_tangent", Qt::Key_T ) );
+
+ // the generic center of curvature constructor
+ c = new CocConstructor();
+ ctors->add( c );
+ actions->add( new ConstructibleAction( c, "objects_new_centerofcurvature" ) );
+
+ actions->add( new ConstructPointAction( "objects_new_normalpoint" ) );
+ actions->add( new ConstructTextLabelAction( "objects_new_textlabel" ) );
+ actions->add( new AddFixedPointAction( "objects_new_point_xy" ) );
+
+#ifdef KIG_ENABLE_PYTHON_SCRIPTING
+#include "../scripting/script-common.h"
+ actions->add( new NewScriptAction(
+ I18N_NOOP( "Python Script" ),
+ I18N_NOOP( "Construct a new Python script." ),
+ "objects_new_script_python",
+ ScriptType::Python ) );
+#endif
+
+#if 0
+ actions->add( new TestAction( "test_stuff" ) );
+#endif
+ };
+
+ done = true;
+}
diff --git a/kig/misc/builtin_stuff.h b/kig/misc/builtin_stuff.h
new file mode 100644
index 00000000..198886fe
--- /dev/null
+++ b/kig/misc/builtin_stuff.h
@@ -0,0 +1,23 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MISC_BUILTIN_STUFF_H
+#define KIG_MISC_BUILTIN_STUFF_H
+
+void setupBuiltinStuff();
+
+#endif
diff --git a/kig/misc/calcpaths.cc b/kig/misc/calcpaths.cc
new file mode 100644
index 00000000..1532715b
--- /dev/null
+++ b/kig/misc/calcpaths.cc
@@ -0,0 +1,303 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "calcpaths.h"
+
+#include "../objects/object_calcer.h"
+#include "../objects/object_imp.h"
+
+#include <algorithm>
+
+// mp:
+// The previous algorithm by Dominique had an exponential complexity
+// for some constructions (e.g. a sequence of "n" triangles each inscribed
+// into the previous).
+// The new version is directly taken from a book of Alan Bertossi
+// "Algoritmi e strutture dati"
+
+// temporarily disabling the new algorithm due to the freeze:
+// I previously misunderstood the semantics of this function
+// and thought that the os vector had to be completed with all
+// the subtree generated by it. On the contrary, the os vector
+// contains *all* the objects that we want, we only have to
+// reorder them. Now it *should* work, however we postpone
+// activating this to a more proper moment
+
+// to deactivate the new algorithm change "define" into "undef"
+
+#define NEWCALCPATH
+#ifdef NEWCALCPATH
+void localdfs( ObjectCalcer* obj,
+ std::vector<ObjectCalcer*>& visited,
+ std::vector<ObjectCalcer*>& all);
+
+std::vector<ObjectCalcer*> calcPath( const std::vector<ObjectCalcer*>& os )
+{
+ // "all" is the Objects var we're building, in reverse ordering
+ std::vector<ObjectCalcer*> visited;
+ std::vector<ObjectCalcer*> all;
+
+ for ( std::vector<ObjectCalcer*>::const_iterator i = os.begin(); i != os.end(); ++i )
+ {
+ if ( std::find( visited.begin(), visited.end(), *i ) == visited.end() )
+ {
+ localdfs( *i, visited, all );
+ }
+ }
+
+ // now, we need to remove all objects that are not in os
+ // (forgot to do this in previous fix :-( )
+ std::vector<ObjectCalcer*> ret;
+ for ( std::vector<ObjectCalcer*>::reverse_iterator i = all.rbegin(); i != all.rend(); ++i )
+ {
+ // we only add objects that appear in os
+ if ( std::find( os.begin(), os.end(), *i ) != os.end() ) ret.push_back( *i );
+ };
+ return ret;
+}
+
+void localdfs( ObjectCalcer* obj,
+ std::vector<ObjectCalcer*>& visited,
+ std::vector<ObjectCalcer*>& all)
+{
+ visited.push_back( obj );
+ const std::vector<ObjectCalcer*> o = obj->children();
+ for ( std::vector<ObjectCalcer*>::const_iterator i = o.begin(); i != o.end(); ++i )
+ {
+ if ( std::find( visited.begin(), visited.end(), *i ) == visited.end() )
+ localdfs( *i, visited, all );
+ }
+ all.push_back( obj );
+}
+
+// old calcPath commented out...
+
+#else
+// these first two functions were written before i read stuff about
+// graph theory and algorithms, so i'm sure they're far from optimal.
+// However, they seem to work fine, and i don't think there's a real
+// need for optimisation here..
+std::vector<ObjectCalcer*> calcPath( const std::vector<ObjectCalcer*>& os )
+{
+ // this is a little experiment of mine, i don't know if it is the
+ // fastest way to do it, but it seems logical to me...
+
+ // the general idea here:
+ // first we build a new Objects variable. For every object in os,
+ // we put all of its children at the end of it, and we do the same
+ // for the ones we add..
+
+ // "all" is the Objects var we're building...
+ std::vector<ObjectCalcer*> all = os;
+ // tmp is the var containing the objects we're iterating over. The
+ // first time around this is the os variable, the next time, this
+ // contains the variables we added in the first round...
+ std::vector<ObjectCalcer*> tmp = os;
+ // tmp2 is a temporary var. During a round, it receives all the
+ // variables we add ( to "all" ) in that round, and at the end of
+ // the round, it is assigned to tmp.
+ std::vector<ObjectCalcer*> tmp2;
+ while ( ! tmp.empty() )
+ {
+ for ( std::vector<ObjectCalcer*>::const_iterator i = tmp.begin(); i != tmp.end(); ++i )
+ {
+ const std::vector<ObjectCalcer*> o = (*i)->children();
+ std::copy( o.begin(), o.end(), std::back_inserter( all ) );
+ std::copy( o.begin(), o.end(), std::back_inserter( tmp2 ) );
+ };
+ tmp = tmp2;
+ tmp2.clear();
+ };
+
+ // now we know that if all objects appear at least once after all of
+ // their parents. So, we take all, and of every object, we remove
+ // every reference except the last one...
+ std::vector<ObjectCalcer*> ret;
+ ret.reserve( os.size() );
+ for ( std::vector<ObjectCalcer*>::reverse_iterator i = all.rbegin(); i != all.rend(); ++i )
+ {
+ // we only add objects that appear in os and only if they are not
+ // already in ret..
+ if ( std::find( ret.begin(), ret.end(), *i ) == ret.end() &&
+ std::find( os.begin(), os.end(), *i ) != os.end() ) ret.push_back( *i );
+ };
+ std::reverse( ret.begin(), ret.end() );
+ return ret;
+}
+#endif
+
+bool addBranch( const std::vector<ObjectCalcer*>& o, const ObjectCalcer* to, std::vector<ObjectCalcer*>& ret )
+{
+ bool rb = false;
+ for ( std::vector<ObjectCalcer*>::const_iterator i = o.begin(); i != o.end(); ++i )
+ {
+ if ( *i == to )
+ rb = true;
+ else
+ if ( addBranch( (*i)->children(), to, ret ) )
+ {
+ rb = true;
+ ret.push_back( *i );
+ };
+ };
+ return rb;
+}
+
+std::vector<ObjectCalcer*> calcPath( const std::vector<ObjectCalcer*>& from, const ObjectCalcer* to )
+{
+ std::vector<ObjectCalcer*> all;
+
+ for ( std::vector<ObjectCalcer*>::const_iterator i = from.begin(); i != from.end(); ++i )
+ {
+ (void) addBranch( (*i)->children(), to, all );
+ };
+
+ std::vector<ObjectCalcer*> ret;
+ for ( std::vector<ObjectCalcer*>::iterator i = all.begin(); i != all.end(); ++i )
+ {
+ if ( std::find( ret.begin(), ret.end(), *i ) == ret.end() )
+ ret.push_back( *i );
+ };
+ return std::vector<ObjectCalcer*>( ret.rbegin(), ret.rend() );
+}
+
+static void addNonCache( ObjectCalcer* o, std::vector<ObjectCalcer*>& ret )
+{
+ if ( ! o->imp()->isCache() )
+ if ( std::find( ret.begin(), ret.end(), o ) == ret.end() )
+ ret.push_back( o );
+ else
+ {
+ std::vector<ObjectCalcer*> parents = o->parents();
+ for ( uint i = 0; i < parents.size(); ++i )
+ addNonCache( parents[i], ret );
+ };
+}
+
+static bool visit( const ObjectCalcer* o, const std::vector<ObjectCalcer*>& from, std::vector<ObjectCalcer*>& ret )
+{
+ // this function returns true if the visited object depends on one
+ // of the objects in from. If we encounter objects that are on the
+ // side of the tree path ( they do not depend on from themselves,
+ // but their direct children do ), then we add them to ret.
+ if ( std::find( from.begin(), from.end(), o ) != from.end() ) return true;
+
+ std::vector<bool> deps( o->parents().size(), false );
+ bool somedepend = false;
+ bool alldepend = true;
+ std::vector<ObjectCalcer*> parents = o->parents();
+ for ( uint i = 0; i < parents.size(); ++i )
+ {
+ bool v = visit( parents[i], from, ret );
+ somedepend |= v;
+ alldepend &= v;
+ deps[i] = v;
+ };
+ if ( somedepend && ! alldepend )
+ {
+ for ( uint i = 0; i < deps.size(); ++i )
+ if ( ! deps[i] )
+ addNonCache( parents[i], ret );
+ };
+
+ return somedepend;
+}
+
+std::vector<ObjectCalcer*> sideOfTreePath( const std::vector<ObjectCalcer*>& from, const ObjectCalcer* to )
+{
+ std::vector<ObjectCalcer*> ret;
+ visit( to, from, ret );
+ return ret;
+}
+
+std::vector<ObjectCalcer*> getAllParents( const std::vector<ObjectCalcer*>& objs )
+{
+ using namespace std;
+ std::set<ObjectCalcer*> ret( objs.begin(),objs.end() );
+ std::set<ObjectCalcer*> cur = ret;
+ while ( ! cur.empty() )
+ {
+ std::set<ObjectCalcer*> next;
+ for ( std::set<ObjectCalcer*>::const_iterator i = cur.begin(); i != cur.end(); ++i )
+ {
+ std::vector<ObjectCalcer*> parents = (*i)->parents();
+ next.insert( parents.begin(), parents.end() );
+ };
+
+ ret.insert( next.begin(), next.end() );
+ cur = next;
+ };
+ return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
+}
+
+std::vector<ObjectCalcer*> getAllParents( ObjectCalcer* obj )
+{
+ std::vector<ObjectCalcer*> objs;
+ objs.push_back( obj );
+ return getAllParents( objs );
+}
+
+bool isChild( const ObjectCalcer* o, const std::vector<ObjectCalcer*>& os )
+{
+ std::vector<ObjectCalcer*> parents = o->parents();
+ std::set<ObjectCalcer*> cur( parents.begin(), parents.end() );
+ while ( ! cur.empty() )
+ {
+ std::set<ObjectCalcer*> next;
+ for ( std::set<ObjectCalcer*>::const_iterator i = cur.begin(); i != cur.end(); ++i )
+ {
+ if ( std::find( os.begin(), os.end(), *i ) != os.end() ) return true;
+ std::vector<ObjectCalcer*> parents = (*i)->parents();
+ next.insert( parents.begin(), parents.end() );
+ };
+ cur = next;
+ };
+ return false;
+}
+
+std::set<ObjectCalcer*> getAllChildren( ObjectCalcer* obj )
+{
+ std::vector<ObjectCalcer*> objs;
+ objs.push_back( obj );
+ return getAllChildren( objs );
+}
+
+std::set<ObjectCalcer*> getAllChildren( const std::vector<ObjectCalcer*> objs )
+{
+ std::set<ObjectCalcer*> ret;
+ // objects to iterate over...
+ std::set<ObjectCalcer*> cur( objs.begin(), objs.end() );
+ while( !cur.empty() )
+ {
+ // contains the objects to iterate over the next time around...
+ std::set<ObjectCalcer*> next;
+ for( std::set<ObjectCalcer*>::iterator i = cur.begin();
+ i != cur.end(); ++i )
+ {
+ ret.insert( *i );
+ std::vector<ObjectCalcer*> children = (*i)->children();
+ next.insert( children.begin(), children.end() );
+ };
+ cur = next;
+ };
+ return ret;
+}
+
+bool isPointOnCurve( const ObjectCalcer* point, const ObjectCalcer* curve )
+{
+ return point->isDefinedOnOrThrough( curve ) || curve->isDefinedOnOrThrough( point );
+}
diff --git a/kig/misc/calcpaths.h b/kig/misc/calcpaths.h
new file mode 100644
index 00000000..620558a3
--- /dev/null
+++ b/kig/misc/calcpaths.h
@@ -0,0 +1,88 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MISC_CALCPATHS_H
+#define KIG_MISC_CALCPATHS_H
+
+#include "../objects/common.h"
+
+/**
+ * This function sorts \p os such that they're in the right order for
+ * calc()-ing. This means that child objects must appear after their
+ * parents ( for you graph people, this is just a topological sort.. )
+ */
+std::vector<ObjectCalcer*> calcPath( const std::vector<ObjectCalcer*>& os );
+
+/**
+ * This is a different function for more or less the same purpose. It
+ * takes a few Objects, which are considered to have been calced
+ * already. Then, it puts the necessary part of their children in the
+ * right order, so that calc()-ing correctly updates all of their data
+ * ( they're calc'ed in the right order, i mean... ). The objects in
+ * from are normally not included in the output, unless they appear
+ * somewhere in the middle of the calc-path towards to...
+ */
+std::vector<ObjectCalcer*> calcPath( const std::vector<ObjectCalcer*>& from, const ObjectCalcer* to );
+
+/**
+ * This function returns all objects on the side of the path through
+ * the dependency tree from from down to to. This means that we look
+ * for any objects that don't depend on any of the objects in from
+ * themselves, but of which one of the direct children does. We need
+ * this function for Locus stuff...
+ */
+std::vector<ObjectCalcer*> sideOfTreePath( const std::vector<ObjectCalcer*>& from, const ObjectCalcer* to );
+
+/**
+ * This function returns all objects above the \p given in the
+ * dependency graph. The \p given objects are also included
+ * themselves..
+ */
+std::vector<ObjectCalcer*> getAllParents( const std::vector<ObjectCalcer*>& objs );
+/**
+ * \overload
+ */
+std::vector<ObjectCalcer*> getAllParents( ObjectCalcer* obj );
+
+/**
+ * This function returns all objects below the objects in \p objs in the
+ * dependency graphy. The objects in \p objs are also included
+ * themselves..
+ */
+std::set<ObjectCalcer*> getAllChildren( const std::vector<ObjectCalcer*> objs );
+
+/**
+ * \overload
+ */
+std::set<ObjectCalcer*> getAllChildren( ObjectCalcer* obj );
+
+/**
+ * Returns true if \p o is a descendant of any of the objects in \p os..
+ */
+bool isChild( const ObjectCalcer* o, const std::vector<ObjectCalcer*>& os );
+
+/**
+ * Return true if the given \p point is ( by construction ) on the given
+ * \p curve. This means that it is either a constrained point on the
+ * curve, or the curve is constructed through the point, or the point
+ * is an intersection point of the curve with another curve.
+ * Note that it is assumed that the given point is in fact a point and the
+ * given curve is in fact a curve.
+ */
+bool isPointOnCurve( const ObjectCalcer* point, const ObjectCalcer* curve );
+
+#endif
diff --git a/kig/misc/common.cpp b/kig/misc/common.cpp
new file mode 100644
index 00000000..fccd384f
--- /dev/null
+++ b/kig/misc/common.cpp
@@ -0,0 +1,520 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "common.h"
+
+#include "../kig/kig_view.h"
+#include "../objects/object_imp.h"
+
+#include <cmath>
+
+#include <kdebug.h>
+#include <knumvalidator.h>
+#include <klocale.h>
+#if KDE_IS_VERSION( 3, 1, 90 )
+#include <kinputdialog.h>
+#else
+#include <klineeditdlg.h>
+#endif
+
+Coordinate calcPointOnPerpend( const LineData& l, const Coordinate& t )
+{
+ return calcPointOnPerpend( l.b - l.a, t );
+}
+
+Coordinate calcPointOnPerpend( const Coordinate& dir, const Coordinate& t )
+{
+ return t + ( dir ).orthogonal();
+}
+
+Coordinate calcPointOnParallel( const LineData& l, const Coordinate& t )
+{
+ return calcPointOnParallel( l.b - l.a, t );
+}
+
+Coordinate calcPointOnParallel( const Coordinate& dir, const Coordinate& t )
+{
+ return t + dir*5;
+}
+
+Coordinate calcIntersectionPoint( const LineData& l1, const LineData& l2 )
+{
+ const Coordinate& pa = l1.a;
+ const Coordinate& pb = l1.b;
+ const Coordinate& pc = l2.a;
+ const Coordinate& pd = l2.b;
+
+ double
+ xab = pb.x - pa.x,
+ xdc = pd.x - pc.x,
+ xac = pc.x - pa.x,
+ yab = pb.y - pa.y,
+ ydc = pd.y - pc.y,
+ yac = pc.y - pa.y;
+
+ double det = xab*ydc - xdc*yab;
+ double detn = xac*ydc - xdc*yac;
+
+ // test for parallelism
+ if ( fabs (det) < 1e-6 ) return Coordinate::invalidCoord();
+ double t = detn/det;
+
+ return pa + t*(pb - pa);
+}
+
+void calcBorderPoints( Coordinate& p1, Coordinate& p2, const Rect& r )
+{
+ calcBorderPoints( p1.x, p1.y, p2.x, p2.y, r );
+}
+
+const LineData calcBorderPoints( const LineData& l, const Rect& r )
+{
+ LineData ret( l );
+ calcBorderPoints( ret.a.x, ret.a.y, ret.b.x, ret.b.y, r );
+ return ret;
+}
+
+void calcBorderPoints( double& xa, double& ya, double& xb, double& yb, const Rect& r )
+{
+ // we calc where the line through a(xa,ya) and b(xb,yb) intersects with r:
+ double left = (r.left()-xa)*(yb-ya)/(xb-xa)+ya;
+ double right = (r.right()-xa)*(yb-ya)/(xb-xa)+ya;
+ double top = (r.top()-ya)*(xb-xa)/(yb-ya)+xa;
+ double bottom = (r.bottom()-ya)*(xb-xa)/(yb-ya)+xa;
+
+ // now we go looking for valid points
+ int novp = 0; // number of valid points we have already found
+
+ if (!(top < r.left() || top > r.right())) {
+ // the line intersects with the top side of the rect.
+ ++novp;
+ xa = top; ya = r.top();
+ };
+ if (!(left < r.bottom() || left > r.top())) {
+ // the line intersects with the left side of the rect.
+ if (novp++) { xb = r.left(); yb=left; }
+ else { xa = r.left(); ya=left; };
+ };
+ if (!(right < r.bottom() || right > r.top())) {
+ // the line intersects with the right side of the rect.
+ if (novp++) { xb = r.right(); yb=right; }
+ else { xa = r.right(); ya=right; };
+ };
+ if (!(bottom < r.left() || bottom > r.right())) {
+ // the line intersects with the bottom side of the rect.
+ ++novp;
+ xb = bottom; yb = r.bottom();
+ };
+ if (novp < 2) {
+ // line is completely outside of the window...
+ xa = ya = xb = yb = 0;
+ };
+}
+
+void calcRayBorderPoints( const Coordinate& a, Coordinate& b, const Rect& r )
+{
+ calcRayBorderPoints( a.x, a.y, b.x, b.y, r );
+}
+
+void calcRayBorderPoints( const double xa, const double ya, double& xb,
+ double& yb, const Rect& r )
+{
+ // we calc where the line through a(xa,ya) and b(xb,yb) intersects with r:
+ double left = (r.left()-xa)*(yb-ya)/(xb-xa)+ya;
+ double right = (r.right()-xa)*(yb-ya)/(xb-xa)+ya;
+ double top = (r.top()-ya)*(xb-xa)/(yb-ya)+xa;
+ double bottom = (r.bottom()-ya)*(xb-xa)/(yb-ya)+xa;
+
+ // now we see which we can use...
+ if(
+ // the ray intersects with the top side of the rect..
+ top >= r.left() && top <= r.right()
+ // and b is above a
+ && yb > ya )
+ {
+ xb = top;
+ yb = r.top();
+ return;
+ };
+ if(
+ // the ray intersects with the left side of the rect...
+ left >= r.bottom() && left <= r.top()
+ // and b is on the left of a..
+ && xb < xa )
+ {
+ xb = r.left();
+ yb=left;
+ return;
+ };
+ if (
+ // the ray intersects with the right side of the rect...
+ right >= r.bottom() && right <= r.top()
+ // and b is to the right of a..
+ && xb > xa )
+ {
+ xb = r.right();
+ yb=right;
+ return;
+ };
+ if(
+ // the ray intersects with the bottom side of the rect...
+ bottom >= r.left() && bottom <= r.right()
+ // and b is under a..
+ && yb < ya ) {
+ xb = bottom;
+ yb = r.bottom();
+ return;
+ };
+ kdError() << k_funcinfo << "damn" << endl;
+}
+
+bool isOnLine( const Coordinate& o, const Coordinate& a,
+ const Coordinate& b, const double fault )
+{
+ double x1 = a.x;
+ double y1 = a.y;
+ double x2 = b.x;
+ double y2 = b.y;
+
+ // check your math theory ( homogeneous coördinates ) for this
+ double tmp = fabs( o.x * (y1-y2) + o.y*(x2-x1) + (x1*y2-y1*x2) );
+ return tmp < ( fault * (b-a).length());
+ // if o is on the line ( if the determinant of the matrix
+ // |---|---|---|
+ // | x | y | z |
+ // |---|---|---|
+ // | x1| y1| z1|
+ // |---|---|---|
+ // | x2| y2| z2|
+ // |---|---|---|
+ // equals 0, then p(x,y,z) is on the line containing points
+ // p1(x1,y1,z1) and p2 here, we're working with normal coords, no
+ // homogeneous ones, so all z's equal 1
+}
+
+bool isOnSegment( const Coordinate& o, const Coordinate& a,
+ const Coordinate& b, const double fault )
+{
+ return isOnLine( o, a, b, fault )
+ // not too far to the right
+ && (o.x - kigMax(a.x,b.x) < fault )
+ // not too far to the left
+ && ( kigMin (a.x, b.x) - o.x < fault )
+ // not too high
+ && ( kigMin (a.y, b.y) - o.y < fault )
+ // not too low
+ && ( o.y - kigMax (a.y, b.y) < fault );
+}
+
+bool isOnRay( const Coordinate& o, const Coordinate& a,
+ const Coordinate& b, const double fault )
+{
+ return isOnLine( o, a, b, fault )
+ // not too far in front of a horizontally..
+// && ( a.x - b.x < fault ) == ( a.x - o.x < fault )
+ && ( ( a.x < b.x ) ? ( a.x - o.x < fault ) : ( a.x - o.x > -fault ) )
+ // not too far in front of a vertically..
+// && ( a.y - b.y < fault ) == ( a.y - o.y < fault );
+ && ( ( a.y < b.y ) ? ( a.y - o.y < fault ) : ( a.y - o.y > -fault ) );
+}
+
+bool isOnArc( const Coordinate& o, const Coordinate& c, const double r,
+ const double sa, const double a, const double fault )
+{
+ if ( fabs( ( c - o ).length() - r ) > fault )
+ return false;
+ Coordinate d = o - c;
+ double angle = atan2( d.y, d.x );
+
+ if ( angle < sa ) angle += 2 * M_PI;
+ return angle - sa - a < 1e-4;
+}
+
+const Coordinate calcMirrorPoint( const LineData& l,
+ const Coordinate& p )
+{
+ Coordinate m =
+ calcIntersectionPoint( l,
+ LineData( p,
+ calcPointOnPerpend( l, p )
+ )
+ );
+ return 2*m - p;
+}
+
+const Coordinate calcCircleLineIntersect( const Coordinate& c,
+ const double sqr,
+ const LineData& l,
+ int side )
+{
+ Coordinate proj = calcPointProjection( c, l );
+ Coordinate hvec = proj - c;
+ Coordinate lvec = -l.dir();
+
+ double sqdist = hvec.squareLength();
+ double sql = sqr - sqdist;
+ if ( sql < 0.0 )
+ return Coordinate::invalidCoord();
+ else
+ {
+ double l = sqrt( sql );
+ lvec = lvec.normalize( l );
+ lvec *= side;
+
+ return proj + lvec;
+ };
+}
+
+const Coordinate calcArcLineIntersect( const Coordinate& c, const double sqr,
+ const double sa, const double angle,
+ const LineData& l, int side )
+{
+ const Coordinate possiblepoint = calcCircleLineIntersect( c, sqr, l, side );
+ if ( isOnArc( possiblepoint, c, sqrt( sqr ), sa, angle, test_threshold ) )
+ return possiblepoint;
+ else return Coordinate::invalidCoord();
+}
+
+const Coordinate calcPointProjection( const Coordinate& p,
+ const LineData& l )
+{
+ Coordinate orth = l.dir().orthogonal();
+ return p + orth.normalize( calcDistancePointLine( p, l ) );
+}
+
+double calcDistancePointLine( const Coordinate& p,
+ const LineData& l )
+{
+ double xa = l.a.x;
+ double ya = l.a.y;
+ double xb = l.b.x;
+ double yb = l.b.y;
+ double x = p.x;
+ double y = p.y;
+ double norm = l.dir().length();
+ return ( yb * x - ya * x - xb * y + xa * y + xb * ya - yb * xa ) / norm;
+}
+
+Coordinate calcRotatedPoint( const Coordinate& a, const Coordinate& c, const double arc )
+{
+ // we take a point p on a line through c and parallel with the
+ // X-axis..
+ Coordinate p( c.x + 5, c.y );
+ // we then calc the arc that ac forms with cp...
+ Coordinate d = a - c;
+ d = d.normalize();
+ double aarc = std::acos( d.x );
+ if ( d.y < 0 ) aarc = 2*M_PI - aarc;
+
+ // we now take the sum of the two arcs to find the arc between
+ // pc and ca
+ double asum = aarc + arc;
+
+ Coordinate ret( std::cos( asum ), std::sin( asum ) );
+ ret = ret.normalize( ( a -c ).length() );
+ return ret + c;
+}
+
+Coordinate calcCircleRadicalStartPoint( const Coordinate& ca, const Coordinate& cb,
+ double sqra, double sqrb )
+{
+ Coordinate direc = cb - ca;
+ Coordinate m = (ca + cb)/2;
+
+ double dsq = direc.squareLength();
+ double lambda = dsq == 0.0 ? 0.0
+ : (sqra - sqrb) / (2*dsq);
+
+ direc *= lambda;
+ return m + direc;
+}
+
+double getDoubleFromUser( const QString& caption, const QString& label, double value,
+ QWidget* parent, bool* ok, double min, double max, int decimals )
+{
+#ifdef KIG_USE_KDOUBLEVALIDATOR
+ KDoubleValidator vtor( min, max, decimals, 0, 0 );
+#else
+ KFloatValidator vtor( min, max, (QWidget*) 0, 0 );
+#endif
+#if KDE_IS_VERSION( 3, 1, 90 )
+ QString input = KInputDialog::getText(
+ caption, label, KGlobal::locale()->formatNumber( value, decimals ),
+ ok, parent, "getDoubleFromUserDialog", &vtor );
+#else
+ QString input =
+ KLineEditDlg::getText( caption, label,
+ KGlobal::locale()->formatNumber( value, decimals ),
+ ok, parent, &vtor );
+#endif
+
+ bool myok = true;
+ double ret = KGlobal::locale()->readNumber( input, &myok );
+ if ( ! myok )
+ ret = input.toDouble( & myok );
+ if ( ok ) *ok = myok;
+ return ret;
+}
+
+const Coordinate calcCenter(
+ const Coordinate& a, const Coordinate& b, const Coordinate& c )
+{
+ // this algorithm is written by my brother, Christophe Devriese
+ // <oelewapperke@ulyssis.org> ...
+ // I don't get it myself :)
+
+ double xdo = b.x-a.x;
+ double ydo = b.y-a.y;
+
+ double xao = c.x-a.x;
+ double yao = c.y-a.y;
+
+ double a2 = xdo*xdo + ydo*ydo;
+ double b2 = xao*xao + yao*yao;
+
+ double numerator = (xdo * yao - xao * ydo);
+ if ( numerator == 0 )
+ {
+ // problem: xdo * yao == xao * ydo <=> xdo/ydo == xao / yao
+ // this means that the lines ac and ab have the same direction,
+ // which means they're the same line..
+ // FIXME: i would normally throw an error here, but KDE doesn't
+ // use exceptions, so i'm returning a bogus point :(
+ return a.invalidCoord();
+ /* return (a+c)/2; */
+ };
+ double denominator = 0.5 / numerator;
+
+ double centerx = a.x - (ydo * b2 - yao * a2) * denominator;
+ double centery = a.y + (xdo * b2 - xao * a2) * denominator;
+
+ return Coordinate(centerx, centery);
+}
+
+bool lineInRect( const Rect& r, const Coordinate& a, const Coordinate& b,
+ const int width, const ObjectImp* imp, const KigWidget& w )
+{
+ double miss = w.screenInfo().normalMiss( width );
+
+//mp: the following test didn't work for vertical segments;
+// fortunately the ieee floating point standard allows us to avoid
+// the test altogether, since it would produce an infinity value that
+// makes the final r.contains to fail
+// in any case the corresponding test for a.y - b.y was missing.
+
+// if ( fabs( a.x - b.x ) <= 1e-7 )
+// {
+// // too small to be useful..
+// return r.contains( Coordinate( a.x, r.center().y ), miss );
+// }
+
+// in case we have a segment we need also to check for the case when
+// the segment is entirely contained in the rect, in which case the
+// final tests all fail.
+// it is ok to just check for the midpoint in the rect since:
+// - if we have a segment completely contained in the rect this is true
+// - if the midpoint is in the rect than returning true is safe (also
+// in the cases where we have a ray or a line)
+
+ if ( r.contains( 0.5*( a + b ), miss ) ) return true;
+
+ Coordinate dir = b - a;
+ double m = dir.y / dir.x;
+ double lefty = a.y + m * ( r.left() - a.x );
+ double righty = a.y + m * ( r.right() - a.x );
+ double minv = dir.x / dir.y;
+ double bottomx = a.x + minv * ( r.bottom() - a.y );
+ double topx = a.x + minv * ( r.top() - a.y );
+
+ // these are the intersections between the line, and the lines
+ // defined by the sides of the rectangle.
+ Coordinate leftint( r.left(), lefty );
+ Coordinate rightint( r.right(), righty );
+ Coordinate bottomint( bottomx, r.bottom() );
+ Coordinate topint( topx, r.top() );
+
+ // For each intersection, we now check if we contain the
+ // intersection ( this might not be the case for a segment, when the
+ // intersection is not between the begin and end point.. ) and if
+ // the rect contains the intersection.. If it does, we have a winner..
+ return
+ ( imp->contains( leftint, width, w ) && r.contains( leftint, miss ) ) ||
+ ( imp->contains( rightint, width, w ) && r.contains( rightint, miss ) ) ||
+ ( imp->contains( bottomint, width, w ) && r.contains( bottomint, miss ) ) ||
+ ( imp->contains( topint, width, w ) && r.contains( topint, miss ) );
+}
+
+bool operator==( const LineData& l, const LineData& r )
+{
+ return l.a == r.a && l.b == r.b;
+}
+
+bool LineData::isParallelTo( const LineData& l ) const
+{
+ const Coordinate& p1 = a;
+ const Coordinate& p2 = b;
+ const Coordinate& p3 = l.a;
+ const Coordinate& p4 = l.b;
+
+ double dx1 = p2.x - p1.x;
+ double dy1 = p2.y - p1.y;
+ double dx2 = p4.x - p3.x;
+ double dy2 = p4.y - p3.y;
+
+ return isSingular( dx1, dy1, dx2, dy2 );
+}
+
+bool LineData::isOrthogonalTo( const LineData& l ) const
+{
+ const Coordinate& p1 = a;
+ const Coordinate& p2 = b;
+ const Coordinate& p3 = l.a;
+ const Coordinate& p4 = l.b;
+
+ double dx1 = p2.x - p1.x;
+ double dy1 = p2.y - p1.y;
+ double dx2 = p4.x - p3.x;
+ double dy2 = p4.y - p3.y;
+
+ return isSingular( dx1, dy1, -dy2, dx2 );
+}
+
+bool areCollinear( const Coordinate& p1,
+ const Coordinate& p2, const Coordinate& p3 )
+{
+ return isSingular( p2.x - p1.x, p2.y - p1.y, p3.x - p1.x, p3.y - p1.y );
+}
+
+bool isSingular( const double& a, const double& b,
+ const double& c, const double& d )
+{
+ double det = a*d - b*c;
+ double norm1 = std::fabs(a) + std::fabs(b);
+ double norm2 = std::fabs(c) + std::fabs(d);
+
+/*
+ * test must be done relative to the magnitude of the two
+ * row (or column) vectors!
+ */
+ return ( std::fabs(det) < test_threshold*norm1*norm2 );
+}
+
+const double double_inf = HUGE_VAL;
+const double test_threshold = 1e-6;
diff --git a/kig/misc/common.h b/kig/misc/common.h
new file mode 100644
index 00000000..77a1faa2
--- /dev/null
+++ b/kig/misc/common.h
@@ -0,0 +1,291 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+
+#ifndef KIG_MISC_COMMON_H
+#define KIG_MISC_COMMON_H
+
+#include "coordinate.h"
+#include "rect.h"
+
+#include <qrect.h>
+#include <kdeversion.h>
+
+#include <vector>
+#include <assert.h>
+
+#ifdef KDE_IS_VERSION
+#if KDE_IS_VERSION( 3, 1, 0 )
+#define KIG_USE_KDOUBLEVALIDATOR
+#else
+#undef KIG_USE_KDOUBLEVALIDATOR
+#endif
+#else
+#undef KIG_USE_KDOUBLEVALIDATOR
+#endif
+
+class ObjectImp;
+class KigWidget;
+
+extern const double double_inf;
+
+/**
+ * Here, we define some algorithms which we need in
+ * various places...
+ */
+
+double getDoubleFromUser( const QString& caption, const QString& label, double value,
+ QWidget* parent, bool* ok, double min, double max, int decimals );
+
+/**
+ * Simple class representing a line. Used by various functions in Kig.
+ */
+class LineData {
+public:
+ /**
+ * \ifnot creating-python-scripting-doc
+ * Default constructor. Sets a and b to the origin.
+ * \endif
+ */
+ LineData() : a(), b() {}
+ /**
+ * Constructor. Sets a and b to the given Coordinates.
+ */
+ LineData( const Coordinate& na, const Coordinate& nb ) : a( na ), b( nb ) {}
+ /**
+ * One point on the line.
+ */
+ Coordinate a;
+ /**
+ * Another point on the line.
+ */
+ Coordinate b;
+ /**
+ * The direction of the line. Equivalent to b - a.
+ */
+ const Coordinate dir() const { return b - a; }
+ /**
+ * The length from a to b.
+ */
+ double length() const { return ( b - a ).length(); }
+
+ /**
+ * Return true if this line is parallel to l.
+ */
+ bool isParallelTo( const LineData& l ) const;
+
+ /**
+ * Return true if this line is orthogonal to l.
+ */
+ bool isOrthogonalTo( const LineData& l ) const;
+};
+
+/**
+ * Equality. Tests two LineData's for equality.
+ */
+bool operator==( const LineData& l, const LineData& r );
+
+/**
+ * This calcs the rotation of point a around point c by arc arc. Arc
+ * is in radians, in the range 0 < arc < 2*pi ...
+ */
+Coordinate calcRotatedPoint( const Coordinate& a, const Coordinate& c, const double arc );
+
+/**
+ * this returns a point, so that the line through point t
+ * and the point returned is perpendicular to the line l.
+ */
+Coordinate calcPointOnPerpend( const LineData& l, const Coordinate& t );
+
+/**
+ * this returns a point, so that the line through point t and the
+ * point returned is perpendicular to the direction given in dir...
+ */
+Coordinate calcPointOnPerpend( const Coordinate& dir, const Coordinate& t );
+
+/**
+ * this returns a point, so that the line through point t
+ * and the point returned is parallel with the line l
+ */
+Coordinate calcPointOnParallel( const LineData& l, const Coordinate& t );
+
+/**
+ * this returns a point, so that the line through point t
+ * and the point returned is parallel with the direction given in dir...
+ */
+Coordinate calcPointOnParallel( const Coordinate& dir, const Coordinate& t );
+
+
+/**
+ * this calcs the point where the lines l and m intersect...
+ */
+Coordinate calcIntersectionPoint( const LineData& l, const LineData& m );
+
+/**
+ * this calcs the intersection points of the circle with center c and
+ * radius sqrt( r ), and the line l. As a circle and a
+ * line have two intersection points, side tells us which one we
+ * need... It should be 1 or -1. If the line and the circle have no
+ * intersection, valid is set to false, otherwise to true...
+ * Note that sqr is the _square_ of the radius. We do this to avoid
+ * rounding errors...
+ */
+const Coordinate calcCircleLineIntersect( const Coordinate& c,
+ const double sqr,
+ const LineData& l,
+ int side );
+
+/**
+ * this calcs the intersection points of the arc with center c,
+ * radius sqrt( r ), start angle sa and angle angle, and the line l.
+ * As a arc and a line can have max two intersection points, side
+ * tells us which one we need... It should be 1 or -1. If the line
+ * and the arc have no intersection, valid is set to false, otherwise
+ * to true... Note that sqr is the _square_ of the radius. We do
+ * this to avoid rounding errors...
+ */
+const Coordinate calcArcLineIntersect( const Coordinate& c, const double sqr,
+ const double sa, const double angle,
+ const LineData& l, int side );
+
+/**
+ * this calculates the perpendicular projection of point p on line
+ * ab...
+ */
+const Coordinate calcPointProjection( const Coordinate& p,
+ const LineData& l );
+
+/**
+ * calc the distance of point p to the line through a and b...
+ */
+double calcDistancePointLine( const Coordinate& p,
+ const LineData& l );
+
+/**
+ * this sets p1 and p2 to p1' and p2' so that p1'p2' is the same line
+ * as p1p2, and so that p1' and p2' are on the border of the Rect...
+ */
+void calcBorderPoints( Coordinate& p1, Coordinate& p2, const Rect& r );
+/**
+ * overload...
+ */
+void calcBorderPoints( double& xa, double& xb, double& ya, double& yb, const Rect& r);
+/**
+ * cleaner overload, intended to replace the above two...
+ */
+const LineData calcBorderPoints( const LineData& l, const Rect& r );
+
+/**
+ * this does the same as the above function, but only for b..
+ */
+void calcRayBorderPoints( const Coordinate& a, Coordinate& b, const Rect& r );
+
+/**
+ * This function calculates the center of the circle going through the
+ * three given points..
+ */
+const Coordinate calcCenter(
+ const Coordinate& a, const Coordinate& b, const Coordinate& c );
+
+/**
+ * overload...
+ */
+void calcRayBorderPoints( const double xa, const double xb, double& ya,
+ double& yb, const Rect& r );
+
+/**
+ * calc the mirror point of p over the line l
+ */
+const Coordinate calcMirrorPoint( const LineData& l,
+ const Coordinate& p );
+
+/**
+ * test collinearity of three points
+ */
+bool areCollinear( const Coordinate& p1, const Coordinate& p2,
+ const Coordinate& p3 );
+
+/**
+ * test if a 2x2 matrix is singular (relatively to the
+ * norm of the two row vectors)
+ */
+bool isSingular( const double& a, const double& b,
+ const double& c, const double& d );
+
+/**
+ * is o on the line defined by point a and point b ?
+ * fault is the allowed difference...
+ */
+bool isOnLine( const Coordinate& o, const Coordinate& a,
+ const Coordinate& b, const double fault );
+
+/**
+ * is o on the segment defined by point a and point b ?
+ * this calls isOnLine(), but also checks if o is "between" a and b...
+ * fault is the allowed difference...
+ */
+bool isOnSegment( const Coordinate& o, const Coordinate& a,
+ const Coordinate& b, const double fault );
+
+bool isOnRay( const Coordinate& o, const Coordinate& a,
+ const Coordinate& b, const double fault );
+
+bool isOnArc( const Coordinate& o, const Coordinate& c, const double r,
+ const double sa, const double a, const double fault );
+
+Coordinate calcCircleRadicalStartPoint( const Coordinate& ca,
+ const Coordinate& cb,
+ double sqra, double sqrb );
+
+/**
+ * Is the line, segment, ray or vector inside r ? We need the imp to
+ * distinguish between rays, lines, segments or whatever.. ( we use
+ * their contains functions actually.. )
+ */
+bool lineInRect( const Rect& r, const Coordinate& a, const Coordinate& b,
+ const int width, const ObjectImp* imp, const KigWidget& w );
+
+template <typename T>
+T kigMin( const T& a, const T& b )
+{
+ return a < b ? a : b;
+}
+
+template <typename T>
+T kigMax( const T& a, const T& b )
+{
+ return a > b ? a : b;
+}
+
+template <typename T>
+T kigAbs( const T& a )
+{
+ return a >= 0 ? a : -a;
+}
+
+template <typename T>
+int kigSgn( const T& a )
+{
+ return a == 0 ? 0 : a > 0 ? +1 : -1;
+}
+
+extern const double test_threshold;
+
+#endif
diff --git a/kig/misc/conic-common.cpp b/kig/misc/conic-common.cpp
new file mode 100644
index 00000000..3dde7449
--- /dev/null
+++ b/kig/misc/conic-common.cpp
@@ -0,0 +1,888 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include <config.h>
+
+#include "conic-common.h"
+
+#include "common.h"
+#include "kigtransform.h"
+
+#include <cmath>
+#include <algorithm>
+
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+
+ConicCartesianData::ConicCartesianData(
+ const ConicPolarData& polardata
+ )
+{
+ double ec = polardata.ecostheta0;
+ double es = polardata.esintheta0;
+ double p = polardata.pdimen;
+ double fx = polardata.focus1.x;
+ double fy = polardata.focus1.y;
+
+ double a = 1 - ec*ec;
+ double b = 1 - es*es;
+ double c = - 2*ec*es;
+ double d = - 2*p*ec;
+ double e = - 2*p*es;
+ double f = - p*p;
+
+ f += a*fx*fx + b*fy*fy + c*fx*fy - d*fx - e*fy;
+ d -= 2*a*fx + c*fy;
+ e -= 2*b*fy + c*fx;
+
+ coeffs[0] = a;
+ coeffs[1] = b;
+ coeffs[2] = c;
+ coeffs[3] = d;
+ coeffs[4] = e;
+ coeffs[5] = f;
+}
+
+ConicPolarData::ConicPolarData( const ConicCartesianData& cartdata )
+{
+ double a = cartdata.coeffs[0];
+ double b = cartdata.coeffs[1];
+ double c = cartdata.coeffs[2];
+ double d = cartdata.coeffs[3];
+ double e = cartdata.coeffs[4];
+ double f = cartdata.coeffs[5];
+
+ // 1. Compute theta (tilt of conic)
+ double theta = std::atan2(c, b - a)/2;
+
+ // now I should possibly add pi/2...
+ double costheta = std::cos(theta);
+ double sintheta = std::sin(theta);
+ // compute new coefficients (c should now be zero)
+ double aa = a*costheta*costheta + b*sintheta*sintheta - c*sintheta*costheta;
+ double bb = a*sintheta*sintheta + b*costheta*costheta + c*sintheta*costheta;
+ if (aa*bb < 0)
+ { // we have a hyperbola we need to check the correct orientation
+ double dd = d*costheta - e*sintheta;
+ double ee = d*sintheta + e*costheta;
+ double xc = - dd / ( 2*aa );
+ double yc = - ee / ( 2*bb );
+ double ff = f + aa*xc*xc + bb*yc*yc + dd*xc + ee*yc;
+ if (ff*aa > 0) // wrong orientation
+ {
+ if (theta > 0) theta -= M_PI/2;
+ else theta += M_PI/2;
+ costheta = cos(theta);
+ sintheta = sin(theta);
+ aa = a*costheta*costheta + b*sintheta*sintheta - c*sintheta*costheta;
+ bb = a*sintheta*sintheta + b*costheta*costheta + c*sintheta*costheta;
+ }
+ }
+ else
+ {
+ if ( std::fabs (bb) < std::fabs (aa) )
+ {
+ if (theta > 0) theta -= M_PI/2;
+ else theta += M_PI/2;
+ costheta = cos(theta);
+ sintheta = sin(theta);
+ aa = a*costheta*costheta + b*sintheta*sintheta - c*sintheta*costheta;
+ bb = a*sintheta*sintheta + b*costheta*costheta + c*sintheta*costheta;
+ }
+ }
+
+ double cc = 2*(a - b)*sintheta*costheta +
+ c*(costheta*costheta - sintheta*sintheta);
+ // cc should be zero!!! cout << "cc = " << cc << "\n";
+ double dd = d*costheta - e*sintheta;
+ double ee = d*sintheta + e*costheta;
+
+ a = aa;
+ b = bb;
+ c = cc;
+ d = dd;
+ e = ee;
+
+ // now b cannot be zero (otherwise conic is degenerate)
+ a /= b;
+ c /= b;
+ d /= b;
+ e /= b;
+ f /= b;
+ b = 1.0;
+
+ // 2. compute y coordinate of focuses
+
+ double yf = - e/2;
+
+ // new values:
+ f += yf*yf + e*yf;
+ e += 2*yf; // this should be zero!
+
+ // now: a > 0 -> ellipse
+ // a = 0 -> parabula
+ // a < 0 -> hyperbola
+
+ double eccentricity = sqrt(1.0 - a);
+
+ double sqrtdiscrim = sqrt(d*d - 4*a*f);
+ if (d < 0.0) sqrtdiscrim = -sqrtdiscrim;
+ double xf = (4*a*f - 4*f - d*d)/(d + eccentricity*sqrtdiscrim) / 2;
+
+ // 3. the focus needs to be rotated back into position
+ focus1.x = xf*costheta + yf*sintheta;
+ focus1.y = -xf*sintheta + yf*costheta;
+
+ // 4. final touch: the pdimen
+ pdimen = -sqrtdiscrim/2;
+
+ ecostheta0 = eccentricity*costheta;
+ esintheta0 = -eccentricity*sintheta;
+ if ( pdimen < 0)
+ {
+ pdimen = -pdimen;
+ ecostheta0 = -ecostheta0;
+ esintheta0 = -esintheta0;
+ }
+}
+
+const ConicCartesianData calcConicThroughPoints (
+ const std::vector<Coordinate>& points,
+ const LinearConstraints c1,
+ const LinearConstraints c2,
+ const LinearConstraints c3,
+ const LinearConstraints c4,
+ const LinearConstraints c5 )
+{
+ assert( 0 < points.size() && points.size() <= 5 );
+ // points is a vector of up to 5 points through which the conic is
+ // constrained.
+ // this routine should compute the coefficients in the cartesian equation
+ // a x^2 + b y^2 + c xy + d x + e y + f = 0
+ // they are defined up to a multiplicative factor.
+ // since we don't know (in advance) which one of them is nonzero, we
+ // simply keep all 6 parameters, obtaining a 5x6 linear system which
+ // we solve using gaussian elimination with complete pivoting
+ // If there are too few, then we choose some cool way to fill in the
+ // empty parts in the matrix according to the LinearConstraints
+ // given..
+
+ // 5 rows, 6 columns..
+ double row0[6];
+ double row1[6];
+ double row2[6];
+ double row3[6];
+ double row4[6];
+ double *matrix[5] = {row0, row1, row2, row3, row4};
+ double solution[6];
+ int scambio[6];
+ LinearConstraints constraints[] = {c1, c2, c3, c4, c5};
+
+ int numpoints = points.size();
+ int numconstraints = 5;
+
+ // fill in the matrix elements
+ for ( int i = 0; i < numpoints; ++i )
+ {
+ double xi = points[i].x;
+ double yi = points[i].y;
+ matrix[i][0] = xi*xi;
+ matrix[i][1] = yi*yi;
+ matrix[i][2] = xi*yi;
+ matrix[i][3] = xi;
+ matrix[i][4] = yi;
+ matrix[i][5] = 1.0;
+ }
+
+ for ( int i = 0; i < numconstraints; i++ )
+ {
+ if (numpoints >= 5) break; // don't add constraints if we have enough
+ for (int j = 0; j < 6; ++j) matrix[numpoints][j] = 0.0;
+ // force the symmetry axes to be
+ // parallel to the coordinate system (zero tilt): c = 0
+ if (constraints[i] == zerotilt) matrix[numpoints][2] = 1.0;
+ // force a parabula (if zerotilt): b = 0
+ if (constraints[i] == parabolaifzt) matrix[numpoints][1] = 1.0;
+ // force a circle (if zerotilt): a = b
+ if (constraints[i] == circleifzt) {
+ matrix[numpoints][0] = 1.0;
+ matrix[numpoints][1] = -1.0; }
+ // force an equilateral hyperbola: a + b = 0
+ if (constraints[i] == equilateral) {
+ matrix[numpoints][0] = 1.0;
+ matrix[numpoints][1] = 1.0; }
+ // force symmetry about y-axis: d = 0
+ if (constraints[i] == ysymmetry) matrix[numpoints][3] = 1.0;
+ // force symmetry about x-axis: e = 0
+ if (constraints[i] == xsymmetry) matrix[numpoints][4] = 1.0;
+
+ if (constraints[i] != noconstraint) ++numpoints;
+ }
+
+ if ( ! GaussianElimination( matrix, numpoints, 6, scambio ) )
+ return ConicCartesianData::invalidData();
+ // fine della fase di eliminazione
+ BackwardSubstitution( matrix, numpoints, 6, scambio, solution );
+
+ // now solution should contain the correct coefficients..
+ return ConicCartesianData( solution );
+}
+
+const ConicPolarData calcConicBFFP(
+ const std::vector<Coordinate>& args,
+ int type )
+{
+ assert( args.size() >= 2 && args.size() <= 3 );
+ assert( type == 1 || type == -1 );
+
+ ConicPolarData ret;
+
+ Coordinate f1 = args[0];
+ Coordinate f2 = args[1];
+ Coordinate d;
+ double eccentricity, d1, d2, dl;
+
+ Coordinate f2f1 = f2 - f1;
+ double f2f1l = f2f1.length();
+ ret.ecostheta0 = f2f1.x / f2f1l;
+ ret.esintheta0 = f2f1.y / f2f1l;
+
+ if ( args.size() == 3 )
+ {
+ d = args[2];
+ d1 = ( d - f1 ).length();
+ d2 = ( d - f2 ).length();
+ dl = fabs( d1 + type * d2 );
+ eccentricity = f2f1l/dl;
+ }
+ else
+ {
+ if ( type > 0 ) eccentricity = 0.7; else eccentricity = 2.0;
+ dl = f2f1l/eccentricity;
+ }
+
+ double rhomax = (dl + f2f1l) /2.0;
+
+ ret.ecostheta0 *= eccentricity;
+ ret.esintheta0 *= eccentricity;
+ ret.pdimen = type*(1 - eccentricity)*rhomax;
+ ret.focus1 = type == 1 ? f1 : f2;
+ return ret;
+}
+
+const LineData calcConicPolarLine (
+ const ConicCartesianData& data,
+ const Coordinate& cpole,
+ bool& valid )
+{
+ double x = cpole.x;
+ double y = cpole.y;
+ double a = data.coeffs[0];
+ double b = data.coeffs[1];
+ double c = data.coeffs[2];
+ double d = data.coeffs[3];
+ double e = data.coeffs[4];
+ double f = data.coeffs[5];
+
+ double alpha = 2*a*x + c*y + d;
+ double beta = c*x + 2*b*y + e;
+ double gamma = d*x + e*y + 2*f;
+
+ double normsq = alpha*alpha + beta*beta;
+
+ if (normsq < 1e-10) // line at infinity
+ {
+ valid = false;
+ return LineData();
+ }
+ valid = true;
+
+ Coordinate reta = -gamma/normsq * Coordinate (alpha, beta);
+ Coordinate retb = reta + Coordinate (-beta, alpha);
+ return LineData( reta, retb );
+}
+
+const Coordinate calcConicPolarPoint (
+ const ConicCartesianData& data,
+ const LineData& polar )
+{
+ Coordinate p1 = polar.a;
+ Coordinate p2 = polar.b;
+
+ double alpha = p2.y - p1.y;
+ double beta = p1.x - p2.x;
+ double gamma = p1.y*p2.x - p1.x*p2.y;
+
+ double a11 = data.coeffs[0];
+ double a22 = data.coeffs[1];
+ double a12 = data.coeffs[2]/2.0;
+ double a13 = data.coeffs[3]/2.0;
+ double a23 = data.coeffs[4]/2.0;
+ double a33 = data.coeffs[5];
+
+// double detA = a11*a22*a33 - a11*a23*a23 - a22*a13*a13 - a33*a12*a12 +
+// 2*a12*a23*a13;
+
+ double a11inv = a22*a33 - a23*a23;
+ double a22inv = a11*a33 - a13*a13;
+ double a33inv = a11*a22 - a12*a12;
+ double a12inv = a23*a13 - a12*a33;
+ double a23inv = a12*a13 - a23*a11;
+ double a13inv = a12*a23 - a13*a22;
+
+ double x = a11inv*alpha + a12inv*beta + a13inv*gamma;
+ double y = a12inv*alpha + a22inv*beta + a23inv*gamma;
+ double z = a13inv*alpha + a23inv*beta + a33inv*gamma;
+
+ if (fabs(z) < 1e-10) // point at infinity
+ {
+ return Coordinate::invalidCoord();
+ }
+
+ x /= z;
+ y /= z;
+ return Coordinate (x, y);
+}
+
+const Coordinate calcConicLineIntersect( const ConicCartesianData& c,
+ const LineData& l,
+ double knownparam,
+ int which )
+{
+ assert( which == 1 || which == -1 || which == 0 );
+
+ double aa = c.coeffs[0];
+ double bb = c.coeffs[1];
+ double cc = c.coeffs[2];
+ double dd = c.coeffs[3];
+ double ee = c.coeffs[4];
+ double ff = c.coeffs[5];
+
+ double x = l.a.x;
+ double y = l.a.y;
+ double dx = l.b.x - l.a.x;
+ double dy = l.b.y - l.a.y;
+
+ double aaa = aa*dx*dx + bb*dy*dy + cc*dx*dy;
+ double bbb = 2*aa*x*dx + 2*bb*y*dy + cc*x*dy + cc*y*dx + dd*dx + ee*dy;
+ double ccc = aa*x*x + bb*y*y + cc*x*y + dd*x + ee*y + ff;
+
+ double t;
+ if ( which == 0 ) /* i.e. we have a known intersection */
+ {
+ t = - bbb/aaa - knownparam;
+ return l.a + t*(l.b - l.a);
+ }
+
+ double discrim = bbb*bbb - 4*aaa*ccc;
+ if (discrim < 0.0)
+ {
+ return Coordinate::invalidCoord();
+ }
+ else
+ {
+ if ( which*bbb > 0 )
+ {
+ t = bbb + which*sqrt(discrim);
+ t = - 2*ccc/t;
+ } else {
+ t = -bbb + which*sqrt(discrim);
+ t /= 2*aaa;
+ }
+
+ return l.a + t*(l.b - l.a);
+ }
+}
+
+ConicPolarData::ConicPolarData(
+ const Coordinate& f, double d,
+ double ec, double es )
+ : focus1( f ), pdimen( d ), ecostheta0( ec ), esintheta0( es )
+{
+}
+
+ConicPolarData::ConicPolarData()
+ : focus1(), pdimen( 0 ), ecostheta0( 0 ), esintheta0( 0 )
+{
+}
+
+const ConicPolarData calcConicBDFP(
+ const LineData& directrix,
+ const Coordinate& cfocus,
+ const Coordinate& cpoint )
+{
+ ConicPolarData ret;
+
+ Coordinate ba = directrix.dir();
+ double bal = ba.length();
+ ret.ecostheta0 = -ba.y / bal;
+ ret.esintheta0 = ba.x / bal;
+
+ Coordinate pa = cpoint - directrix.a;
+
+ double distpf = (cpoint - cfocus).length();
+ double distpd = ( pa.y*ba.x - pa.x*ba.y)/bal;
+
+ double eccentricity = distpf/distpd;
+ ret.ecostheta0 *= eccentricity;
+ ret.esintheta0 *= eccentricity;
+
+ Coordinate fa = cfocus - directrix.a;
+ ret.pdimen = ( fa.y*ba.x - fa.x*ba.y )/bal;
+ ret.pdimen *= eccentricity;
+ ret.focus1 = cfocus;
+
+ return ret;
+}
+
+ConicCartesianData::ConicCartesianData( const double incoeffs[6] )
+{
+ std::copy( incoeffs, incoeffs + 6, coeffs );
+}
+
+const LineData calcConicAsymptote(
+ const ConicCartesianData data,
+ int which, bool &valid )
+{
+ assert( which == -1 || which == 1 );
+
+ LineData ret;
+ double a=data.coeffs[0];
+ double b=data.coeffs[1];
+ double c=data.coeffs[2];
+ double d=data.coeffs[3];
+ double e=data.coeffs[4];
+
+ double normabc = a*a + b*b + c*c;
+ double delta = c*c - 4*a*b;
+ if (fabs(delta) < 1e-6*normabc) { valid = false; return ret; }
+
+ double yc = (2*a*e - c*d)/delta;
+ double xc = (2*b*d - c*e)/delta;
+ // let c be nonnegative; we no longer need d, e, f.
+ if (c < 0)
+ {
+ c *= -1;
+ a *= -1;
+ b *= -1;
+ }
+
+ if ( delta < 0 )
+ {
+ valid = false;
+ return ret;
+ }
+
+ double sqrtdelta = sqrt(delta);
+ Coordinate displacement;
+ if (which > 0)
+ displacement = Coordinate(-2*b, c + sqrtdelta);
+ else
+ displacement = Coordinate(c + sqrtdelta, -2*a);
+ ret.a = Coordinate(xc, yc);
+ ret.b = ret.a + displacement;
+ return ret;
+}
+
+const ConicCartesianData calcConicByAsymptotes(
+ const LineData& line1,
+ const LineData& line2,
+ const Coordinate& p )
+{
+ Coordinate p1 = line1.a;
+ Coordinate p2 = line1.b;
+ double x = p.x;
+ double y = p.y;
+
+ double c1 = p1.x*p2.y - p2.x*p1.y;
+ double b1 = p2.x - p1.x;
+ double a1 = p1.y - p2.y;
+
+ p1 = line2.a;
+ p2 = line2.b;
+
+ double c2 = p1.x*p2.y - p2.x*p1.y;
+ double b2 = p2.x - p1.x;
+ double a2 = p1.y - p2.y;
+
+ double a = a1*a2;
+ double b = b1*b2;
+ double c = a1*b2 + a2*b1;
+ double d = a1*c2 + a2*c1;
+ double e = b1*c2 + c1*b2;
+
+ double f = a*x*x + b*y*y + c*x*y + d*x + e*y;
+ f = -f;
+
+ return ConicCartesianData( a, b, c, d, e, f );
+}
+
+const LineData calcConicRadical( const ConicCartesianData& cequation1,
+ const ConicCartesianData& cequation2,
+ int which, int zeroindex, bool& valid )
+{
+ assert( which == 1 || which == -1 );
+ assert( 0 < zeroindex && zeroindex < 4 );
+ LineData ret;
+ valid = true;
+
+ double a = cequation1.coeffs[0];
+ double b = cequation1.coeffs[1];
+ double c = cequation1.coeffs[2];
+ double d = cequation1.coeffs[3];
+ double e = cequation1.coeffs[4];
+ double f = cequation1.coeffs[5];
+
+ double a2 = cequation2.coeffs[0];
+ double b2 = cequation2.coeffs[1];
+ double c2 = cequation2.coeffs[2];
+ double d2 = cequation2.coeffs[3];
+ double e2 = cequation2.coeffs[4];
+ double f2 = cequation2.coeffs[5];
+
+// background: the family of conics c + lambda*c2 has members that
+// degenerate into a union of two lines. The values of lambda giving
+// such degenerate conics is the solution of a third degree equation.
+// The coefficients of such equation are given by:
+// (Thanks to Dominique Devriese for the suggestion of this approach)
+// domi: (And thanks to Maurizio for implementing it :)
+
+ double df = 4*a*b*f - a*e*e - b*d*d - c*c*f + c*d*e;
+ double cf = 4*a2*b*f + 4*a*b2*f + 4*a*b*f2
+ - 2*a*e*e2 - 2*b*d*d2 - 2*f*c*c2
+ - a2*e*e - b2*d*d - f2*c*c
+ + c2*d*e + c*d2*e + c*d*e2;
+ double bf = 4*a*b2*f2 + 4*a2*b*f2 + 4*a2*b2*f
+ - 2*a2*e2*e - 2*b2*d2*d - 2*f2*c2*c
+ - a*e2*e2 - b*d2*d2 - f*c2*c2
+ + c*d2*e2 + c2*d*e2 + c2*d2*e;
+ double af = 4*a2*b2*f2 - a2*e2*e2 - b2*d2*d2 - c2*c2*f2 + c2*d2*e2;
+
+// assume both conics are nondegenerate, renormalize so that af = 1
+
+ df /= af;
+ cf /= af;
+ bf /= af;
+ af = 1.0; // not needed, just for consistency
+
+// computing the coefficients of the Sturm sequence
+
+ double p1a = 2*bf*bf - 6*cf;
+ double p1b = bf*cf - 9*df;
+ double p0a = cf*p1a*p1a + p1b*(3*p1b - 2*bf*p1a);
+ double fval, fpval, lambda;
+
+ if (p0a < 0 && p1a < 0)
+ {
+ // -+-- ---+
+ valid = false;
+ return ret;
+ }
+
+ lambda = -bf/3.0; //inflection point
+ double displace = 1.0;
+ if (p1a > 0) // with two stationary points
+ {
+ displace += sqrt(p1a); // should be enough. The important
+ // thing is that it is larger than the
+ // semidistance between the stationary points
+ }
+ // compute the value at the inflection point using Horner scheme
+ fval = bf + lambda; // b + x
+ fval = cf + lambda*fval; // c + xb + xx
+ fval = df + lambda*fval; // d + xc + xxb + xxx
+
+ if (fabs(p0a) < 1e-7)
+ { // this is the case if we intersect two vertical parabulas!
+ p0a = 1e-7; // fall back to the one zero case
+ }
+ if (p0a < 0)
+ {
+ // we have three roots..
+ // we select the one we want ( defined by mzeroindex.. )
+ lambda += ( 2 - zeroindex )* displace;
+ }
+ else
+ {
+ // we have just one root
+ if( zeroindex > 1 ) // cannot find second and third root
+ {
+ valid = false;
+ return ret;
+ }
+
+ if (fval > 0) // zero on the left
+ {
+ lambda -= displace;
+ } else { // zero on the right
+ lambda += displace;
+ }
+
+ // p0a = 0 means we have a root with multiplicity two
+ }
+
+//
+// find a root of af*lambda^3 + bf*lambda^2 + cf*lambda + df = 0
+// (use a Newton method starting from lambda = 0. Hope...)
+//
+
+ double delta;
+
+ int iterations = 0;
+ const int maxiterations = 30;
+ while (iterations++ < maxiterations) // using Newton, iterations should be very few
+ {
+ // compute value of function and polinomial
+ fval = fpval = af;
+ fval = bf + lambda*fval; // b + xa
+ fpval = fval + lambda*fpval; // b + 2xa
+ fval = cf + lambda*fval; // c + xb + xxa
+ fpval = fval + lambda*fpval; // c + 2xb + 3xxa
+ fval = df + lambda*fval; // d + xc + xxb + xxxa
+
+ delta = fval/fpval;
+ lambda -= delta;
+ if (fabs(delta) < 1e-6) break;
+ }
+ if (iterations >= maxiterations) { valid = false; return ret; }
+
+ // now we have the degenerate conic: a, b, c, d, e, f
+
+ a += lambda*a2;
+ b += lambda*b2;
+ c += lambda*c2;
+ d += lambda*d2;
+ e += lambda*e2;
+ f += lambda*f2;
+
+ // domi:
+ // this is the determinant of the matrix of the new conic. It
+ // should be zero, for the new conic to be degenerate.
+ df = 4*a*b*f - a*e*e - b*d*d - c*c*f + c*d*e;
+
+ //lets work in homogeneous coordinates...
+
+ double dis1 = e*e - 4*b*f;
+ double maxval = fabs(dis1);
+ int maxind = 1;
+ double dis2 = d*d - 4*a*f;
+ if (fabs(dis2) > maxval)
+ {
+ maxval = fabs(dis2);
+ maxind = 2;
+ }
+ double dis3 = c*c - 4*a*b;
+ if (fabs(dis3) > maxval)
+ {
+ maxval = fabs(dis3);
+ maxind = 3;
+ }
+ // one of these must be nonzero (otherwise the matrix is ...)
+ // exchange elements so that the largest is the determinant of the
+ // first 2x2 minor
+ double temp;
+ switch (maxind)
+ {
+ case 1: // exchange 1 <-> 3
+ temp = a; a = f; f = temp;
+ temp = c; c = e; e = temp;
+ temp = dis1; dis1 = dis3; dis3 = temp;
+ break;
+
+ case 2: // exchange 2 <-> 3
+ temp = b; b = f; f = temp;
+ temp = c; c = d; d = temp;
+ temp = dis2; dis2 = dis3; dis3 = temp;
+ break;
+ }
+
+ // domi:
+ // this is the negative of the determinant of the top left of the
+ // matrix. If it is 0, then the conic is a parabola, if it is < 0,
+ // then the conic is an ellipse, if positive, the conic is a
+ // hyperbola. In this case, it should be positive, since we have a
+ // degenerate conic, which is a degenerate case of a hyperbola..
+ // note that it is negative if there is no valid conic to be
+ // found ( e.g. not enough intersections.. )
+ // double discrim = c*c - 4*a*b;
+
+ if (dis3 < 0)
+ {
+ // domi:
+ // i would put an assertion here, but well, i guess it doesn't
+ // really matter, and this prevents crashes if the math i still
+ // recall from high school happens to be wrong :)
+ valid = false;
+ return ret;
+ };
+
+ double r[3]; // direction of the null space
+ r[0] = 2*b*d - c*e;
+ r[1] = 2*a*e - c*d;
+ r[2] = dis3;
+
+ // now remember the switch:
+ switch (maxind)
+ {
+ case 1: // exchange 1 <-> 3
+ temp = a; a = f; f = temp;
+ temp = c; c = e; e = temp;
+ temp = dis1; dis1 = dis3; dis3 = temp;
+ temp = r[0]; r[0] = r[2]; r[2] = temp;
+ break;
+
+ case 2: // exchange 2 <-> 3
+ temp = b; b = f; f = temp;
+ temp = c; c = d; d = temp;
+ temp = dis2; dis2 = dis3; dis3 = temp;
+ temp = r[1]; r[1] = r[2]; r[2] = temp;
+ break;
+ }
+
+ // Computing a Householder reflection transformation that
+ // maps r onto [0, 0, k]
+
+ double w[3];
+ double rnormsq = r[0]*r[0] + r[1]*r[1] + r[2]*r[2];
+ double k = sqrt( rnormsq );
+ if ( k*r[2] < 0) k = -k;
+ double wnorm = sqrt( 2*rnormsq + 2*k*r[2] );
+ w[0] = r[0]/wnorm;
+ w[1] = r[1]/wnorm;
+ w[2] = (r[2] + k)/wnorm;
+
+ // matrix transformation using Householder matrix, the resulting
+ // matrix is zero on third row and column
+ // [q0,q1,q2]^t = A w
+ // alpha = w^t A w
+ double q0 = a*w[0] + c*w[1]/2 + d*w[2]/2;
+ double q1 = b*w[1] + c*w[0]/2 + e*w[2]/2;
+ double alpha = a*w[0]*w[0] + b*w[1]*w[1] + c*w[0]*w[1] +
+ d*w[0]*w[2] + e*w[1]*w[2] + f*w[2]*w[2];
+ double a00 = a - 4*w[0]*q0 + 4*w[0]*w[0]*alpha;
+ double a11 = b - 4*w[1]*q1 + 4*w[1]*w[1]*alpha;
+ double a01 = c/2 - 2*w[1]*q0 - 2*w[0]*q1 + 4*w[0]*w[1]*alpha;
+
+ double dis = a01*a01 - a00*a11;
+ assert ( dis >= 0 );
+ double sqrtdis = sqrt( dis );
+ double px, py;
+ if ( which*a01 > 0 )
+ {
+ px = a01 + which*sqrtdis;
+ py = a11;
+ } else {
+ px = a00;
+ py = a01 - which*sqrtdis;
+ }
+ double p[3]; // vector orthogonal to one of the two planes
+ double pscalw = w[0]*px + w[1]*py;
+ p[0] = px - 2*pscalw*w[0];
+ p[1] = py - 2*pscalw*w[1];
+ p[2] = - 2*pscalw*w[2];
+
+ // "r" is the solution of the equation A*(x,y,z) = (0,0,0) where
+ // A is the matrix of the degenerate conic. This is what we
+ // called in the conic theory we saw in high school a "double
+ // point". It has the unique property that any line going through
+ // it is a "polar line" of the conic at hand. It only exists for
+ // degenerate conics. It has another unique property that if you
+ // take any other point on the conic, then the line between it and
+ // the double point is part of the conic.
+ // this is what we use here: we find the double point ( ret.a
+ // ), and then find another points on the conic.
+
+ ret.a = -p[2]/(p[0]*p[0] + p[1]*p[1]) * Coordinate (p[0],p[1]);
+ ret.b = ret.a + Coordinate (-p[1],p[0]);
+ valid = true;
+
+ return ret;
+}
+
+const ConicCartesianData calcConicTransformation (
+ const ConicCartesianData& data, const Transformation& t, bool& valid )
+{
+ double a[3][3];
+ double b[3][3];
+
+ a[1][1] = data.coeffs[0];
+ a[2][2] = data.coeffs[1];
+ a[1][2] = a[2][1] = data.coeffs[2]/2;
+ a[0][1] = a[1][0] = data.coeffs[3]/2;
+ a[0][2] = a[2][0] = data.coeffs[4]/2;
+ a[0][0] = data.coeffs[5];
+
+ Transformation ti = t.inverse( valid );
+ if ( ! valid ) return ConicCartesianData();
+
+ double supnorm = 0.0;
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ b[i][j] = 0.;
+ for (int ii = 0; ii < 3; ii++)
+ {
+ for (int jj = 0; jj < 3; jj++)
+ {
+ b[i][j] += a[ii][jj]*ti.data( ii, i )*ti.data( jj, j );
+ }
+ }
+ if ( std::fabs( b[i][j] ) > supnorm ) supnorm = std::fabs( b[i][j] );
+ }
+ }
+
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ b[i][j] /= supnorm;
+ }
+ }
+
+ return ConicCartesianData ( b[1][1], b[2][2], b[1][2] + b[2][1],
+ b[0][1] + b[1][0], b[0][2] + b[2][0], b[0][0] );
+}
+
+ConicCartesianData::ConicCartesianData()
+{
+}
+
+bool operator==( const ConicPolarData& lhs, const ConicPolarData& rhs )
+{
+ return lhs.focus1 == rhs.focus1 &&
+ lhs.pdimen == rhs.pdimen &&
+ lhs.ecostheta0 == rhs.ecostheta0 &&
+ lhs.esintheta0 == rhs.esintheta0;
+}
+
+ConicCartesianData ConicCartesianData::invalidData()
+{
+ ConicCartesianData ret;
+ ret.coeffs[0] = double_inf;
+ return ret;
+}
+
+bool ConicCartesianData::valid() const
+{
+ return finite( coeffs[0] );
+}
+
diff --git a/kig/misc/conic-common.h b/kig/misc/conic-common.h
new file mode 100644
index 00000000..bcad5b6b
--- /dev/null
+++ b/kig/misc/conic-common.h
@@ -0,0 +1,278 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#ifndef KIG_MISC_CONIC_COMMON_H
+#define KIG_MISC_CONIC_COMMON_H
+
+#include "coordinate.h"
+#include <vector>
+#include "kignumerics.h"
+
+class ConicPolarData;
+class Transformation;
+class LineData;
+
+/**
+ * Cartesian Conic Data. This class represents an equation of a conic
+ * in the form "ax^2 + by^2 + cxy + dx + ey + f = 0".
+ * \internal The coefficients are stored in the order a - f.
+ */
+class ConicCartesianData
+{
+public:
+ double coeffs[6];
+ ConicCartesianData();
+ /**
+ * Construct a ConicCartesianData from a ConicPolarData.
+ * Construct a ConicCartesianData that is the cartesian
+ * representation of the conic represented by d.
+ */
+ explicit ConicCartesianData( const ConicPolarData& d );
+ /**
+ * Construct a ConicCartesianData from its coefficients
+ * Construct a ConicCartesianData using the coefficients a through f
+ * from the equation "ax^2 + by^2 + cxy + dx + ey + f = 0"
+ */
+ ConicCartesianData( double a, double b, double c,
+ double d, double e, double f )
+ {
+ coeffs[0] = a;
+ coeffs[1] = b;
+ coeffs[2] = c;
+ coeffs[3] = d;
+ coeffs[4] = e;
+ coeffs[5] = f;
+ }
+ ConicCartesianData( const double incoeffs[6] );
+
+ /**
+ * Invalid conic.
+ * Return a ConicCartesianData representing an invalid conic.
+ * \see valid()
+ */
+ static ConicCartesianData invalidData();
+ /**
+ * Test validity.
+ * Return whether this is a valid conic.
+ * \see invalidData()
+ */
+ bool valid() const;
+};
+
+/**
+ * This class represents an equation of a conic in the form
+ * \f$ \rho(\theta) = \frac{p}{1 - e \cos\theta}\f$. focus and the
+ * ecostheta stuff represent the coordinate system in which the
+ * equation yields the good result..
+ */
+class ConicPolarData
+{
+public:
+ /**
+ * Construct a ConicPolarData from a ConicCartesianData.
+ *
+ * Construct a ConicPolarData that is the polar
+ * representation of the conic represented by d.
+ */
+ explicit ConicPolarData( const ConicCartesianData& data );
+ explicit ConicPolarData();
+ /**
+ * Construct a ConicPolarData using the parameters from the equation
+ * \f$ \rho(\theta) = \frac{p}{1 - e \cos\theta}\f$
+ */
+ ConicPolarData( const Coordinate& focus1, double dimen,
+ double ecostheta0, double esintheta0 );
+
+ /**
+ * The first focus of this conic.
+ */
+ Coordinate focus1;
+ /**
+ * The pdimen value from the polar equation.
+ */
+ double pdimen;
+ /**
+ * The ecostheta0 value from the polar equation.
+ */
+ double ecostheta0;
+ /**
+ * The esintheta0 value from the polar equation.
+ */
+ double esintheta0;
+};
+
+bool operator==( const ConicPolarData& lhs, const ConicPolarData& rhs );
+
+/**
+ * These are the constraint values that can be passed to the
+ * calcConicThroughPoints function. Their meaning is as follows:
+ * noconstraint: no additional points will be calculated.
+ * zerotilt: force the symmetry axes to be parallel to the coordinate
+ * system ( zero tilt ).
+ * parabolaifzt: the returned conic should be a parabola ( if used in
+ * combination with zerotilt )
+ * circleifzt: the returned conic should be a circle ( if used in
+ * combination with zerotilt )
+ * equilateral: the returned conic should be equilateral
+ * ysymmetry: the returned conic should be symmetric over the Y-axis.
+ * xsymmetry: the returned conic should be symmetric over the X-axis.
+ */
+enum LinearConstraints {
+ noconstraint, zerotilt, parabolaifzt, circleifzt,
+ equilateral, ysymmetry, xsymmetry
+};
+
+/**
+ * Calculate a conic through a given set of points. points should
+ * contain at least one, and at most five points. If there are five
+ * points, then the conic is completely defined. If there are less,
+ * then additional points will be calculated according to the
+ * constraints given. See above for the various constraints.
+ *
+ * An invalid ConicCartesianData is returned if there is no conic
+ * through the given set of points, or if not enough constraints are
+ * given for a conic to be calculated.
+ */
+const ConicCartesianData calcConicThroughPoints (
+ const std::vector<Coordinate>& points,
+ const LinearConstraints c1 = noconstraint,
+ const LinearConstraints c2 = noconstraint,
+ const LinearConstraints c3 = noconstraint,
+ const LinearConstraints c4 = noconstraint,
+ const LinearConstraints c5 = noconstraint);
+
+/**
+ * This function is used by ConicBFFP. It calcs the polar equation
+ * for a hyperbola ( type == -1 ) or ellipse ( type == 1 ) with
+ * focuses args[0] and args[1], and with args[2] on the edge of the
+ * conic. args.size() should be two or three. If it is two, the two
+ * points are taken to be the focuses, and a third point is chosen in
+ * a sensible way..
+ */
+const ConicPolarData calcConicBFFP(
+ const std::vector<Coordinate>& args,
+ int type );
+
+/**
+ * function used by ConicBDFP. It calcs the conic with directrix d,
+ * focus f, and point p on the conic..
+ */
+const ConicPolarData calcConicBDFP(
+ const LineData& d, const Coordinate& f, const Coordinate& p );
+
+/**
+ * This calcs the hyperbola defined by its two asymptotes line1 and
+ * line2, and a point p on the edge.
+ */
+const ConicCartesianData calcConicByAsymptotes(
+ const LineData& line1,
+ const LineData& line2,
+ const Coordinate& p );
+
+/**
+ * This function calculates the polar line of the point cpole with
+ * respect to the given conic data. As the last argument, you should
+ * pass a reference to a boolean. This boolean will be set to true if
+ * the returned LineData is valid, and to false if the returned line
+ * is not valid. The latter condition only occurs if a "line at
+ * infinity" would have had to be returned.
+ */
+const LineData calcConicPolarLine (
+ const ConicCartesianData& data,
+ const Coordinate& cpole,
+ bool& valid );
+
+/**
+ * This function calculates the polar point of the line polar with
+ * respect to the given conic data. As the last argument, you should
+ * pass a reference to a boolean. This boolean will be set to true if
+ * the returned LineData is valid, and to false if the returned line
+ * is not valid. The latter condition only occurs if a "point at
+ * infinity" would have had to be returned.
+ */
+const Coordinate calcConicPolarPoint (
+ const ConicCartesianData& data,
+ const LineData& polar );
+
+/**
+ * This function calculates the intersection of a given line ( l ) and
+ * a given conic ( c ). A line and a conic have two intersections in
+ * general, and as such, which should be set to -1 or 1 depending on
+ * which intersection you want. As the last argument, you should pass
+ * a reference to a boolean. This boolean will be set to true if the
+ * returned point is valid, and to false if the returned point is not
+ * valid. The latter condition only occurs if the given conic and
+ * line do not have the specified intersection.
+ *
+ * knownparam is something special: If you already know one
+ * intersection of the line and the conic, and you want the other one,
+ * then you should set which to 0, knownparam to the curve parameter
+ * of the point you already know ( i.e. the value returned by
+ * conicimp->getParam( otherpoint ) ).
+ */
+const Coordinate calcConicLineIntersect( const ConicCartesianData& c,
+ const LineData& l,
+ double knownparam,
+ int which );
+
+/**
+ * This function calculates the asymptote of the given conic ( data ).
+ * A conic has two asymptotes in general, so which should be set to +1
+ * or -1 depending on which asymptote you want. As the last argument,
+ * you should pass a reference to a boolean. This boolean will be set
+ * to true if the returned line is valid, and to false if the returned
+ * line is not valid. The latter condition only occurs if the given
+ * conic does not have the specified asymptote.
+ */
+const LineData calcConicAsymptote(
+ const ConicCartesianData data,
+ int which, bool &valid );
+
+/**
+ * This function calculates the radical line of two conics. A radical
+ * line is the line that goes through two of the intersections of two
+ * conics. Since two conics have up to four intersections in general,
+ * there are three sets of two radical lines. zeroindex specifies
+ * which set of radical lines you want ( set it to 1, 2 or 3 ), and
+ * which is set to -1 or +1 depending on which of the two radical
+ * lines in the set you want. As the last argument, you should pass a
+ * reference to a boolean. This boolean will be set to true if the
+ * returned line is valid, and to false if the returned line is not
+ * valid. The latter condition only occurs if the given conics do not
+ * have the specified radical line.
+ */
+const LineData calcConicRadical( const ConicCartesianData& cequation1,
+ const ConicCartesianData& cequation2,
+ int which, int zeroindex, bool& valid );
+
+/**
+ * This calculates the image of the given conic ( data ) through the
+ * given transformation ( t ). As the last argument, you should pass
+ * a reference to a boolean. This boolean will be set to true if the
+ * returned line is valid, and to false if the returned line is not
+ * valid. The latter condition only occurs if the given
+ * transformation is singular, and as such, the transformation of the
+ * conic cannot be calculated.
+ */
+const ConicCartesianData calcConicTransformation (
+ const ConicCartesianData& data,
+ const Transformation& t, bool& valid );
+
+#endif // KIG_MISC_CONIC_COMMON_H
diff --git a/kig/misc/coordinate.cpp b/kig/misc/coordinate.cpp
new file mode 100644
index 00000000..13501bc9
--- /dev/null
+++ b/kig/misc/coordinate.cpp
@@ -0,0 +1,184 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "coordinate.h"
+
+#include <qglobal.h>
+#include <cmath>
+#include <kdebug.h>
+
+#include "common.h"
+
+using namespace std;
+
+Coordinate Coordinate::fromQPoint( const QPoint& p )
+{
+ return Coordinate( p.x(), p.y() );
+}
+
+kdbgstream& operator<<( kdbgstream& s, const Coordinate& t )
+{
+ s << "x: " << t.x << " y: " << t.y << endl;
+ return s;
+}
+
+const Coordinate operator+ ( const Coordinate& a, const Coordinate& b )
+{
+ return Coordinate ( a.x + b.x, a.y + b.y );
+}
+
+const Coordinate operator- ( const Coordinate& a, const Coordinate& b )
+{
+ return Coordinate ( a.x - b.x, a.y - b.y );
+}
+
+const Coordinate operator* ( const Coordinate& a, double r )
+{
+ return Coordinate ( r*a.x, r*a.y );
+}
+
+const Coordinate operator* ( double r, const Coordinate& a )
+{
+ return Coordinate ( r*a.x, r*a.y );
+}
+
+const Coordinate operator/ ( const Coordinate& a, double r )
+{
+ return Coordinate ( a.x/r, a.y/r );
+}
+
+bool operator==( const Coordinate& a, const Coordinate& b )
+{
+ return a.x == b.x && a.y == b.y;
+}
+
+bool operator!=( const Coordinate& a, const Coordinate& b )
+{
+ return !operator==( a, b );
+}
+
+Coordinate::Coordinate()
+ : x(0),
+ y(0)
+{
+}
+
+Coordinate::Coordinate( double nx, double ny )
+ : x( nx ),
+ y( ny )
+{
+}
+
+Coordinate::Coordinate( const Coordinate& p )
+ : x( p.x ),
+ y( p.y )
+{
+}
+
+const Coordinate Coordinate::operator-() const
+{
+ return Coordinate ( -x, -y );
+}
+
+Coordinate& Coordinate::operator=( const Coordinate& p )
+{
+ x = p.x;
+ y = p.y;
+ return *this;
+}
+
+Coordinate& Coordinate::operator+=( const Coordinate& p )
+{
+ x += p.x;
+ y += p.y;
+ return *this;
+}
+
+Coordinate& Coordinate::operator-=( const Coordinate& p )
+{
+ x -= p.x;
+ y -= p.y;
+ return *this;
+}
+
+Coordinate& Coordinate::operator*=( double r )
+{
+ x *= r;
+ y *= r;
+ return *this;
+}
+
+Coordinate& Coordinate::operator*=( int r )
+{
+ x *= r;
+ y *= r;
+ return *this;
+}
+
+Coordinate& Coordinate::operator/=( double r )
+{
+ x /= r;
+ y /= r;
+ return *this;
+}
+
+double Coordinate::distance( const Coordinate& p ) const
+{
+ return (p - *this).length();
+}
+
+double Coordinate::length() const
+{
+ return sqrt(x*x+y*y);
+}
+
+const Coordinate Coordinate::orthogonal() const
+{
+ return Coordinate( -y, x );
+}
+
+const Coordinate Coordinate::normalize( double l ) const
+{
+ double oldlength = length();
+ return ( *this * l ) / oldlength;
+}
+
+const Coordinate Coordinate::round() const
+{
+ return Coordinate( qRound( x ), qRound( y ) );
+}
+
+QPoint Coordinate::toQPoint() const
+{
+ Coordinate t = round();
+ return QPoint( (int) t.x, (int) t.y );
+}
+
+Coordinate Coordinate::invalidCoord()
+{
+ return Coordinate( double_inf, double_inf );
+}
+
+bool Coordinate::valid() const
+{
+ return abs( x ) != double_inf && abs( y ) != double_inf;
+}
+
+double operator*( const Coordinate& a, const Coordinate& b )
+{
+ return a.x * b.x + a.y * b.y;
+}
diff --git a/kig/misc/coordinate.h b/kig/misc/coordinate.h
new file mode 100644
index 00000000..a56edb76
--- /dev/null
+++ b/kig/misc/coordinate.h
@@ -0,0 +1,169 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+
+#ifndef KIG_MISC_COORDINATE_H
+#define KIG_MISC_COORDINATE_H
+
+class QPoint;
+class kdbgstream;
+
+/**
+ * The Coordinate class is the basic class representing a 2D location
+ * by its x and y components. It has all relevant arithmetic
+ * operators properly defined, and should be straightforward to use..
+ */
+class Coordinate
+{
+public:
+ static Coordinate fromQPoint( const QPoint& p );
+
+ /** Constructor. Construct a new Coordinate, with a given x and y
+ * value.
+ */
+ Coordinate( double x, double y );
+ /** Copy Constructor. Construct a new Coordinate, and give it the
+ * same value as p.
+ */
+ Coordinate( const Coordinate& p );
+ /**
+ * \ifnot creating-python-scripting-doc
+ * \brief Default Constructor
+ *
+ * Constructs a new Coordinate, with x and y initialized to 0.
+ * \endif
+ */
+ Coordinate();
+ ~Coordinate() {}
+
+ /** Create an invalid Coordinate. This is a special value of a
+ * Coordinate that signals that something went wrong..
+ *
+ * \see Coordinate::valid
+ *
+ * \internal We represent an invalid coordinate by setting x or y to
+ * positive or negative infinity. This is handy, since it doesn't
+ * require us to adapt most of the functions, it doesn't need extra
+ * space, and most of the times that we should get an invalid coord,
+ * we get one automatically..
+ */
+ static Coordinate invalidCoord();
+ /** Return whether this is a valid Coordinate.
+ * \see Coordinate::invalidCoord
+ */
+ bool valid() const;
+
+ /** Distance to another Coordinate.
+ */
+ double distance ( const Coordinate& p ) const;
+ /** Length. Returns the length or norm of this coordinate.
+ * I.e. return the distance from this Coordinate to the origin.
+ * \see squareLength
+ */
+ double length () const;
+ /** Square length. Equivalent to the square of \ref length, but a
+ * bit more efficient because no square root has to be calculated.
+ * \see length
+ */
+ inline double squareLength() const;
+ /** Inverse. Returns the inverse of this Coordinate.
+ */
+ const Coordinate operator- () const;
+ /** Orthogonal. Returns a vector which is orthogonal on this vector.
+ * This relation always holds:
+ * <pre>
+ * Coordinate a = ...;
+ * assert( a*a.orthogonal() ) == 0;
+ * </pre>
+ */
+ const Coordinate orthogonal() const;
+ /** Round. Returns this coordinate, rounded to the nearest integral
+ * values.
+ */
+ const Coordinate round() const;
+ /** Normalize. This sets the length to length, while keeping the
+ * x/y ratio untouched...
+ */
+ const Coordinate normalize( double length = 1 ) const;
+ QPoint toQPoint() const;
+
+ Coordinate& operator= ( const Coordinate& c );
+ /** Add. Add c to this Coordinate
+ */
+ Coordinate& operator+= ( const Coordinate& c );
+ /** Subtract. Subtract c from this Coordinate
+ */
+ Coordinate& operator-= ( const Coordinate& c );
+ /** Scale. Scales this Coordinate by a factor r
+ */
+ Coordinate& operator*= ( double r );
+ /** Scale. Scales this Coordinate by a factor r
+ */
+ Coordinate& operator*= ( int r );
+ /** Scale. Scales this Coordinate by a factor 1/r
+ */
+ Coordinate& operator/= ( double r );
+public:
+ /** X Component. The X Component of this Coordinate.
+ */
+ double x;
+ /** Y Component. The Y Component of this Coordinate.
+ */
+ double y;
+
+ friend kdbgstream& operator<<( kdbgstream& s, const Coordinate& t );
+ /** Add. Returns the sum of a and b.
+ */
+ friend const Coordinate operator+ ( const Coordinate& a, const Coordinate& b );
+ /** Subtract. Returns the difference between a and b.
+ */
+ friend const Coordinate operator- ( const Coordinate& a, const Coordinate& b );
+ /** Scale. Returns this a, scaled by a factor of r.
+ */
+ friend const Coordinate operator* ( const Coordinate& a, double r );
+ /** Scale. Returns a, scaled by a factor of 1/r.
+ */
+ friend const Coordinate operator/ ( const Coordinate& a, double r );
+ /** Scalar Product. Returns the scalar product of a and b.
+ */
+ friend double operator*( const Coordinate& a, const Coordinate& b );
+ /** Equal. Tests two Coordinates for equality.
+ */
+ friend bool operator==( const Coordinate&, const Coordinate& );
+ /** Not Equal. Tests two Coordinates for inequality.
+ */
+ friend bool operator!=( const Coordinate&, const Coordinate& );
+};
+
+const Coordinate operator/ ( const Coordinate& a, double r );
+kdbgstream& operator<<( kdbgstream& s, const Coordinate& t );
+const Coordinate operator+ ( const Coordinate& a, const Coordinate& b );
+const Coordinate operator- ( const Coordinate& a, const Coordinate& b );
+const Coordinate operator* ( const Coordinate& a, double r );
+const Coordinate operator* ( double r, const Coordinate& a );
+double operator*( const Coordinate& a, const Coordinate& b );
+
+double Coordinate::squareLength() const
+{
+ return x*x+y*y;
+}
+
+#endif
+
diff --git a/kig/misc/coordinate_system.cpp b/kig/misc/coordinate_system.cpp
new file mode 100644
index 00000000..dd5181c2
--- /dev/null
+++ b/kig/misc/coordinate_system.cpp
@@ -0,0 +1,720 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "coordinate_system.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+
+#include "common.h"
+#include "coordinate.h"
+#include "goniometry.h"
+#include "kigpainter.h"
+
+#include <qpainter.h>
+#include <qregexp.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <knumvalidator.h>
+
+#include <string>
+#include <math.h>
+
+class CoordinateValidator
+ : public QValidator
+{
+ bool mpolar;
+#ifdef KIG_USE_KDOUBLEVALIDATOR
+ KDoubleValidator mdv;
+#else
+ KFloatValidator mdv;
+#endif
+ mutable QRegExp mre;
+public:
+ CoordinateValidator( bool polar );
+ ~CoordinateValidator();
+ State validate ( QString & input, int & pos ) const;
+ void fixup ( QString & input ) const;
+};
+
+
+CoordinateValidator::CoordinateValidator( bool polar )
+ : QValidator( 0, 0 ), mpolar( polar ), mdv( 0, 0 ),
+ mre( polar ? "\\(? ?([0-9.,+-]+); ?([0-9.,+-]+) ?°? ?\\)?"
+ : "\\(? ?([0-9.,+-]+); ?([0-9.,+-]+) ?\\)?" )
+{
+}
+
+CoordinateValidator::~CoordinateValidator()
+{
+}
+
+QValidator::State CoordinateValidator::validate( QString & input, int & pos ) const
+{
+ QString tinput = input;
+ if ( tinput[tinput.length() - 1 ] == ')' ) tinput.truncate( tinput.length() - 1 );
+ if ( mpolar )
+ {
+ if ( tinput[tinput.length() - 1 ] == ' ' ) tinput.truncate( tinput.length() - 1 );
+ if ( tinput[tinput.length() - 1 ] == '°' ) tinput.truncate( tinput.length() - 1 );
+ };
+ if( tinput[tinput.length() - 1 ] == ' ' ) tinput.truncate( tinput.length() - 1 );
+ if ( tinput[0] == '(' ) tinput = tinput.mid( 1 );
+ if( tinput[0] == ' ' ) tinput = tinput.mid( 1 );
+ int scp = tinput.find( ';' );
+ if ( scp == -1 ) return mdv.validate( tinput, pos ) == Invalid ? Invalid : Valid;
+ else
+ {
+ QString p1 = tinput.left( scp );
+ QString p2 = tinput.mid( scp + 1 );
+
+ State ret = Acceptable;
+
+ int boguspos = 0;
+ ret = kigMin( ret, mdv.validate( p1, boguspos ) );
+
+ boguspos = 0;
+ ret = kigMin( ret, mdv.validate( p2, boguspos ) );
+
+ return ret;
+ };
+}
+
+void CoordinateValidator::fixup( QString & input ) const
+{
+ int nsc = input.contains( ';' );
+ if ( nsc > 1 )
+ {
+ // where is the second ';'
+ int i = input.find( ';' );
+ i = input.find( ';', i );
+ input = input.left( i );
+ };
+ // now the string has at most one semicolon left..
+ int sc = input.find( ';' );
+ if ( sc == -1 )
+ {
+ sc = input.length();
+ KLocale* l = KGlobal::locale();
+ if ( mpolar )
+ input.append( QString::fromLatin1( ";" ) + l->positiveSign() +
+ QString::fromLatin1( "0°" ) );
+ else
+ input.append( QString::fromLatin1( ";" ) + l->positiveSign() +
+ QString::fromLatin1( "0" ) + l->decimalSymbol() +
+ QString::fromLatin1( "0" ) );
+ };
+ mre.exactMatch( input );
+ QString ds1 = mre.cap( 1 );
+ mdv.fixup( ds1 );
+ QString ds2 = mre.cap( 2 );
+ mdv.fixup( ds2 );
+ input = ds1 + QString::fromLatin1( "; " ) + ds2;
+}
+
+EuclideanCoords::EuclideanCoords()
+{
+}
+
+QString EuclideanCoords::fromScreen( const Coordinate& p, const KigDocument& d ) const
+{
+ // i used to use the widget size here, but that's no good idea,
+ // since an object isn't asked to recalc every time the widget size
+ // changes.. might be a good idea to do that, but well, maybe some
+ // other time :)
+ Rect sr = d.suggestedRect();
+ double m = kigMax( sr.width(), sr.height() );
+ int l = kigMax( 0, (int) ( 3 - log10( m ) ) );
+ QString xs = KGlobal::locale()->formatNumber( p.x, l );
+ QString ys = KGlobal::locale()->formatNumber( p.y, l );
+ return QString::fromLatin1( "( %1; %2 )" ).arg( xs ).arg( ys );
+}
+
+Coordinate EuclideanCoords::toScreen(const QString& s, bool& ok) const
+{
+ QRegExp r( "\\(? ?([0-9.,+-]+); ?([0-9.,+-]+) ?\\)?" );
+ ok = ( r.search(s) == 0 );
+ if (ok)
+ {
+ QString xs = r.cap(1);
+ QString ys = r.cap(2);
+ KLocale* l = KGlobal::locale();
+ double x = l->readNumber( xs, &ok );
+ if ( ! ok ) x = xs.toDouble( &ok );
+ if ( ! ok ) return Coordinate();
+ double y = l->readNumber( ys, &ok );
+ if ( ! ok ) y = ys.toDouble( &ok );
+ if ( ! ok ) return Coordinate();
+ return Coordinate( x, y );
+ }
+ return Coordinate();
+}
+
+/**
+ * copied and adapted from a ( public domain ) function i found in the
+ * first Graphics Gems book. Credits to Paul S. Heckbert, who wrote
+ * the "Nice number for graph labels" gem.
+ * find a "nice" number approximately equal to x. We look for
+ * 1, 2 or 5, multiplied by a power of 10.
+ */
+static double nicenum( double x, bool round )
+{
+ int exp = (int) log10( x );
+ double f = x/pow( 10., exp );
+ double nf;
+ if ( round )
+ {
+ if ( f < 1.5 ) nf = 1.;
+ else if ( f < 3. ) nf = 2.;
+ else if ( f < 7. ) nf = 5.;
+ else nf = 10.;
+ }
+ else
+ {
+ if ( f <= 1. ) nf = 1.;
+ else if ( f <= 2. ) nf = 2.;
+ else if ( f <= 5. ) nf = 5.;
+ else nf = 10.;
+ };
+ return nf * pow( 10., exp );
+}
+
+void EuclideanCoords::drawGrid( KigPainter& p, bool showgrid, bool showaxes ) const
+{
+ p.setWholeWinOverlay();
+
+ // this instruction in not necessary, but there is a little
+ // optimization when there are no grid and no axes.
+ if ( !( showgrid || showaxes ) )
+ return;
+
+ // this function is inspired upon ( public domain ) code from the
+ // first Graphics Gems book. Credits to Paul S. Heckbert, who wrote
+ // the "Nice number for graph labels" gem.
+
+ const double hmax = ceil( p.window().right() );
+ const double hmin = floor( p.window().left() );
+ const double vmax = ceil( p.window().top() );
+ const double vmin = floor( p.window().bottom() );
+
+ // the number of intervals we would like to have:
+ // we try to have one of them per 40 pixels or so..
+ const int ntick = static_cast<int>(
+ kigMax( hmax - hmin, vmax - vmin ) / p.pixelWidth() / 40. ) + 1;
+
+ double hrange = nicenum( hmax - hmin, false );
+ double vrange = nicenum( vmax - vmin, false );
+ const double newrange = kigMin( hrange, vrange );
+ hrange = newrange;
+ vrange = newrange;
+
+ const double hd = nicenum( hrange / ( ntick - 1 ), true );
+ const double vd = nicenum( vrange / ( ntick - 1 ), true );
+
+ const double hgraphmin = ceil( hmin / hd) * hd;
+ const double hgraphmax = floor( hmax / hd ) * hd;
+ const double vgraphmin = ceil( vmin / vd ) * vd;
+ const double vgraphmax = floor( vmax / vd ) * vd;
+
+ const int hnfrac = kigMax( (int) - floor( log10( hd ) ), 0 );
+ const int vnfrac = kigMax( (int) - floor( log10( vd ) ), 0 );
+
+ /****** the grid lines ******/
+ if ( showgrid )
+ {
+ p.setPen( QPen( lightGray, 0, DotLine ) );
+ // vertical lines...
+ for ( double i = hgraphmin; i <= hgraphmax + hd/2; i += hd )
+ p.drawSegment( Coordinate( i, vgraphmin ),
+ Coordinate( i, vgraphmax ) );
+ // horizontal lines...
+ for ( double i = vgraphmin; i <= vgraphmax + vd/2; i += vd )
+ p.drawSegment( Coordinate( hgraphmin, i ),
+ Coordinate( hgraphmax, i ) );
+ }
+
+ /****** the axes ******/
+ if ( showaxes )
+ {
+ p.setPen( QPen( Qt::gray, 1, Qt::SolidLine ) );
+ // x axis
+ p.drawSegment( Coordinate( hmin, 0 ), Coordinate( hmax, 0 ) );
+ // y axis
+ p.drawSegment( Coordinate( 0, vmin ), Coordinate( 0, vmax ) );
+
+ /****** the numbers ******/
+
+ // x axis
+ for( double i = hgraphmin; i <= hgraphmax + hd / 2; i += hd )
+ {
+ // we skip 0 since that would look stupid... (the axes going
+ // through the 0 etc. )
+ if( fabs( i ) < 1e-8 ) continue;
+
+ p.drawText(
+ Rect( Coordinate( i, 0 ), hd, -2*vd ).normalized(),
+ KGlobal::locale()->formatNumber( i, hnfrac ),
+ AlignLeft | AlignTop
+ );
+ };
+ // y axis...
+ for ( double i = vgraphmin; i <= vgraphmax + vd/2; i += vd )
+ {
+ if( fabs( i ) < 1e-8 ) continue;
+ p.drawText ( Rect( Coordinate( 0, i ), 2*hd, vd ).normalized(),
+ KGlobal::locale()->formatNumber( i, vnfrac ),
+ AlignBottom | AlignLeft
+ );
+ };
+ // arrows on the ends of the axes...
+ p.setPen( QPen( Qt::gray, 1, Qt::SolidLine ) );
+ p.setBrush( QBrush( Qt::gray ) );
+ std::vector<Coordinate> a;
+
+ // the arrow on the right end of the X axis...
+ a.reserve( 3 );
+ double u = p.pixelWidth();
+ a.push_back( Coordinate( hmax - 6 * u, -3 * u) );
+ a.push_back( Coordinate( hmax, 0 ) );
+ a.push_back( Coordinate( hmax - 6 * u, 3 * u ) );
+ p.drawArea( a );
+// p.drawPolygon( a, true );
+
+ // the arrow on the top end of the Y axis...
+ a.clear();
+ a.reserve( 3 );
+ a.push_back( Coordinate( 3 * u, vmax - 6 * u ) );
+ a.push_back( Coordinate( 0, vmax ) );
+ a.push_back( Coordinate( -3 * u, vmax - 6 * u ) );
+ p.drawArea( a );
+// p.drawPolygon( a, true );
+ }; // if( showaxes )
+}
+
+QString EuclideanCoords::coordinateFormatNotice() const
+{
+ return i18n( "Enter coordinates in the following format: \"x;y\",\n"
+ "where x is the x coordinate, and y is the y coordinate." );
+}
+
+QString EuclideanCoords::coordinateFormatNoticeMarkup() const
+{
+ return i18n( "Enter coordinates in the following format: <b>\"x;y\"</b>, "
+ "where x is the x coordinate, and y is the y coordinate." );
+}
+
+EuclideanCoords::~EuclideanCoords()
+{
+}
+
+CoordinateSystem::~CoordinateSystem()
+{
+}
+
+CoordinateSystem::CoordinateSystem()
+{
+}
+
+PolarCoords::PolarCoords()
+{
+}
+
+PolarCoords::~PolarCoords()
+{
+}
+
+QString PolarCoords::fromScreen( const Coordinate& pt, const KigDocument& d ) const
+{
+ Rect sr = d.suggestedRect();
+ double m = kigMax( sr.width(), sr.height() );
+ int l = kigMax( 0, (int) ( 3 - log10( m ) ) );
+
+ double r = pt.length();
+ double theta = Goniometry::convert( atan2( pt.y, pt.x ), Goniometry::Rad, Goniometry::Deg );
+
+ QString rs = KGlobal::locale()->formatNumber( r, l );
+ QString ts = KGlobal::locale()->formatNumber( theta, 0 );
+
+ return QString::fromLatin1("( %1; %2° )").arg( rs ).arg( ts );
+}
+
+QString PolarCoords::coordinateFormatNotice() const
+{
+ // \xCE\xB8 is utf8 for the greek theta sign..
+ return i18n( "Enter coordinates in the following format: \"r; \xCE\xB8°\",\n"
+ "where r and \xCE\xB8 are the polar coordinates." );
+}
+
+QString PolarCoords::coordinateFormatNoticeMarkup() const
+{
+ // \xCE\xB8 is utf8 for the greek theta sign..
+ return i18n( "Enter coordinates in the following format: <b>\"r; \xCE\xB8°\"</b>, "
+ "where r and \xCE\xB8 are the polar coordinates." );
+}
+
+Coordinate PolarCoords::toScreen(const QString& s, bool& ok) const
+{
+ QRegExp regexp("\\(? ?([0-9.,+-]+); ?([0-9.,+-]+) ?°? ?\\)?" );
+ ok = ( regexp.search( s ) == 0 );
+ if (ok)
+ {
+ QString rs = regexp.cap( 1 );
+ double r = KGlobal::locale()->readNumber( rs, &ok );
+ if ( ! ok ) r = rs.toDouble( &ok );
+ if ( ! ok ) return Coordinate();
+ QString ts = regexp.cap( 2 );
+ double theta = KGlobal::locale()->readNumber( ts, &ok );
+ if ( ! ok ) theta = ts.toDouble( &ok );
+ if ( ! ok ) return Coordinate();
+ theta *= M_PI;
+ theta /= 180;
+ return Coordinate( cos( theta ) * r, sin( theta ) * r );
+ }
+ else return Coordinate();
+}
+
+void PolarCoords::drawGrid( KigPainter& p, bool showgrid, bool showaxes ) const
+{
+ p.setWholeWinOverlay();
+
+ // this instruction in not necessary, but there is a little
+ // optimization when there are no grid and no axes.
+ if ( !( showgrid || showaxes ) )
+ return;
+
+ // we multiply by sqrt( 2 ) cause we don't want to miss circles in
+ // the corners, that intersect with the axes outside of the
+ // screen..
+
+ const double hmax = M_SQRT2*p.window().right();
+ const double hmin = M_SQRT2*p.window().left();
+ const double vmax = M_SQRT2*p.window().top();
+ const double vmin = M_SQRT2*p.window().bottom();
+
+ // the intervals:
+ // we try to have one of them per 40 pixels or so..
+ const int ntick = static_cast<int>(
+ kigMax( hmax - hmin, vmax - vmin ) / p.pixelWidth() / 40 ) + 1;
+
+ const double hrange = nicenum( hmax - hmin, false );
+ const double vrange = nicenum( vmax - vmin, false );
+
+ const double hd = nicenum( hrange / ( ntick - 1 ), true );
+ const double vd = nicenum( vrange / ( ntick - 1 ), true );
+
+ const double hgraphmin = floor( hmin / hd) * hd;
+ const double hgraphmax = ceil( hmax / hd ) * hd;
+ const double vgraphmin = floor( vmin / vd ) * vd;
+ const double vgraphmax = ceil( vmax / vd ) * vd;
+
+ const int hnfrac = kigMax( (int) - floor( log10( hd ) ), 0 );
+ const int vnfrac = kigMax( (int) - floor( log10( vd ) ), 0 );
+ const int nfrac = kigMax( hnfrac, vnfrac );
+
+ /****** the grid lines ******/
+ if ( showgrid )
+ {
+ double d = kigMin( hd, vd );
+ double begin = kigMin( kigAbs( hgraphmin ), kigAbs( vgraphmin ) );
+ if ( kigSgn( hgraphmin ) != kigSgn( hgraphmax ) && kigSgn( vgraphmin ) != kigSgn( vgraphmax ) )
+ begin = d;
+ double end = kigMax( hgraphmax, vgraphmax );
+
+ // we also want the circles that don't fit entirely in the
+ // screen..
+ Coordinate c( 0, 0 );
+ p.setPen( QPen( lightGray, 0, DotLine ) );
+ for ( double i = begin; i <= end + d / 2; i += d )
+ drawGridLine( p, c, fabs( i ) );
+ }
+
+ /****** the axes ******/
+ if ( showaxes )
+ {
+ p.setPen( QPen( Qt::gray, 1, Qt::SolidLine ) );
+ // x axis
+ p.drawSegment( Coordinate( hmin, 0 ), Coordinate( hmax, 0 ) );
+ // y axis
+ p.drawSegment( Coordinate( 0, vmin ), Coordinate( 0, vmax ) );
+
+ /****** the numbers ******/
+
+ // x axis
+ for( double i = hgraphmin; i <= hgraphmax + hd / 2; i += hd )
+ {
+ // we skip 0 since that would look stupid... (the axes going
+ // through the 0 etc. )
+ if( fabs( i ) < 1e-8 ) continue;
+
+ QString is = KGlobal::locale()->formatNumber( fabs( i ), nfrac );
+ p.drawText(
+ Rect( Coordinate( i, 0 ), hd, -2*vd ).normalized(),
+ is, AlignLeft | AlignTop );
+ };
+ // y axis...
+ for ( double i = vgraphmin; i <= vgraphmax + vd / 2; i += vd )
+ {
+ if( fabs( i ) < 1e-8 ) continue;
+
+ QString is = KGlobal::locale()->formatNumber( fabs( i ), nfrac );
+
+ p.drawText ( Rect( Coordinate( 0, i ), hd, vd ).normalized(),
+ is, AlignBottom | AlignLeft
+ );
+ };
+ // arrows on the ends of the axes...
+ p.setPen( QPen( Qt::gray, 1, Qt::SolidLine ) );
+ p.setBrush( QBrush( Qt::gray ) );
+ std::vector<Coordinate> a;
+
+ // the arrow on the right end of the X axis...
+ a.reserve( 3 );
+ double u = p.pixelWidth();
+ a.push_back( Coordinate( hmax - 6 * u, -3 * u) );
+ a.push_back( Coordinate( hmax, 0 ) );
+ a.push_back( Coordinate( hmax - 6 * u, 3 * u ) );
+// p.drawPolygon( a, true );
+ p.drawArea( a );
+
+ // the arrow on the top end of the Y axis...
+ a.clear();
+ a.reserve( 3 );
+ a.push_back( Coordinate( 3 * u, vmax - 6 * u ) );
+ a.push_back( Coordinate( 0, vmax ) );
+ a.push_back( Coordinate( -3 * u, vmax - 6 * u ) );
+// p.drawPolygon( a, true );
+ p.drawArea( a );
+ }; // if( showaxes )
+}
+
+QValidator* EuclideanCoords::coordinateValidator() const
+{
+ return new CoordinateValidator( false );
+}
+
+QValidator* PolarCoords::coordinateValidator() const
+{
+ return new CoordinateValidator( true );
+}
+
+QStringList CoordinateSystemFactory::names()
+{
+ QStringList ret;
+ ret << i18n( "&Euclidean" )
+ << i18n( "&Polar" );
+ return ret;
+}
+
+CoordinateSystem* CoordinateSystemFactory::build( int which )
+{
+ if ( which == Euclidean )
+ return new EuclideanCoords;
+ else if ( which == Polar )
+ return new PolarCoords;
+ else return 0;
+}
+
+static const char euclideanTypeString[] = "Euclidean";
+static const char polarTypeString[] = "Polar";
+
+CoordinateSystem* CoordinateSystemFactory::build( const char* type )
+{
+ if ( std::string( euclideanTypeString ) == type )
+ return new EuclideanCoords;
+ if ( std::string( polarTypeString ) == type )
+ return new PolarCoords;
+ else return 0;
+}
+
+const char* EuclideanCoords::type() const
+{
+ return euclideanTypeString;
+}
+
+const char* PolarCoords::type() const
+{
+ return polarTypeString;
+}
+
+int EuclideanCoords::id() const
+{
+ return CoordinateSystemFactory::Euclidean;
+}
+
+int PolarCoords::id() const
+{
+ return CoordinateSystemFactory::Polar;
+}
+
+QString CoordinateSystemFactory::setCoordinateSystemStatement( int id )
+{
+ switch( id )
+ {
+ case Euclidean:
+ return i18n( "Set Euclidean Coordinate System" );
+ case Polar:
+ return i18n( "Set Polar Coordinate System" );
+ default:
+ assert( false );
+ return QString::null;
+ }
+}
+
+Coordinate EuclideanCoords::snapToGrid( const Coordinate& c,
+ const KigWidget& w ) const
+{
+ Rect rect = w.showingRect();
+ // we recalc the interval stuff since there is no way to cache it..
+
+ // this function is again inspired upon ( public domain ) code from
+ // the first Graphics Gems book. Credits to Paul S. Heckbert, who
+ // wrote the "Nice number for graph labels" gem.
+
+ const double hmax = rect.right();
+ const double hmin = rect.left();
+ const double vmax = rect.top();
+ const double vmin = rect.bottom();
+
+ // the number of intervals we would like to have:
+ // we try to have one of them per 40 pixels or so..
+ const int ntick = static_cast<int>(
+ kigMax( hmax - hmin, vmax - vmin ) / w.pixelWidth() / 40. ) + 1;
+
+ const double hrange = nicenum( hmax - hmin, false );
+ const double vrange = nicenum( vmax - vmin, false );
+
+ const double hd = nicenum( hrange / ( ntick - 1 ), true );
+ const double vd = nicenum( vrange / ( ntick - 1 ), true );
+
+ const double hgraphmin = ceil( hmin / hd) * hd;
+ const double vgraphmin = ceil( vmin / vd ) * vd;
+
+ const double nx = qRound( ( c.x - hgraphmin ) / hd ) * hd + hgraphmin;
+ const double ny = qRound( ( c.y - vgraphmin ) / vd ) * vd + vgraphmin;
+ return Coordinate( nx, ny );
+}
+
+Coordinate PolarCoords::snapToGrid( const Coordinate& c,
+ const KigWidget& w ) const
+{
+ // we reuse the drawGrid code to find
+
+ // we multiply by sqrt( 2 ) cause we don't want to miss circles in
+ // the corners, that intersect with the axes outside of the
+ // screen..
+
+ Rect r = w.showingRect();
+
+ const double hmax = M_SQRT2 * r.right();
+ const double hmin = M_SQRT2 * r.left();
+ const double vmax = M_SQRT2 * r.top();
+ const double vmin = M_SQRT2 * r.bottom();
+
+ // the intervals:
+ // we try to have one of them per 40 pixels or so..
+ const int ntick = static_cast<int>(
+ kigMax( hmax - hmin, vmax - vmin ) / w.pixelWidth() / 40 ) + 1;
+
+ const double hrange = nicenum( hmax - hmin, false );
+ const double vrange = nicenum( vmax - vmin, false );
+
+ const double hd = nicenum( hrange / ( ntick - 1 ), true );
+ const double vd = nicenum( vrange / ( ntick - 1 ), true );
+
+ double d = kigMin( hd, vd );
+
+ double dist = c.length();
+ double ndist = qRound( dist / d ) * d;
+ return c.normalize( ndist );
+}
+
+void PolarCoords::drawGridLine( KigPainter& p, const Coordinate& c,
+ double r ) const
+{
+ Rect rect = p.window();
+
+ struct iterdata_t
+ {
+ int xd;
+ int yd;
+ Coordinate ( Rect::*point )() const;
+ Coordinate ( Rect::*oppositepoint )() const;
+ double horizAngle;
+ double vertAngle;
+ };
+
+ static const iterdata_t iterdata[] =
+ {
+ { +1, +1, &Rect::topRight, &Rect::bottomLeft, 0, M_PI/2 },
+ { -1, +1, &Rect::topLeft, &Rect::bottomRight, M_PI, M_PI / 2 },
+ { -1, -1, &Rect::bottomLeft, &Rect::topRight, M_PI, 3*M_PI/2 },
+ { +1, -1, &Rect::bottomRight, &Rect::topLeft, 2*M_PI, 3*M_PI/2 }
+ };
+ for ( int i = 0; i < 4; ++i )
+ {
+ int xd = iterdata[i].xd;
+ int yd = iterdata[i].yd;
+ Coordinate point = ( rect.*iterdata[i].point )();
+ Coordinate opppoint = ( rect.*iterdata[i].oppositepoint )();
+ double horizangle = iterdata[i].horizAngle;
+ double vertangle = iterdata[i].vertAngle;
+
+ if ( ( c.x - point.x )*xd > 0 || ( c.y - point.y )*yd > 0 )
+ continue;
+ if ( ( c.x - opppoint.x )*-xd > r || ( c.y - opppoint.y )*-yd > r )
+ continue;
+
+ int posdir = xd*yd;
+ double hd = ( point.x - c.x )*xd;
+ assert( hd >= 0 );
+ if ( hd < r )
+ {
+ double anglediff = acos( hd/r );
+ horizangle += posdir * anglediff;
+ }
+
+ hd = ( c.x - opppoint.x )*-xd;
+ if ( hd >= 0 )
+ {
+ double anglediff = asin( hd/r );
+ vertangle -= posdir * anglediff;
+ }
+
+ double vd = ( point.y - c.y )*yd;
+ assert( vd >= 0 );
+ if ( vd < r )
+ {
+ double anglediff = acos( vd/r );
+ vertangle -= posdir * anglediff;
+ }
+
+ vd = ( c.y - opppoint.y ) * -xd;
+ if ( vd >= 0 )
+ {
+ double anglediff = asin( hd/r );
+ horizangle += posdir * anglediff;
+ }
+
+ p.drawArc( c, r, kigMin( horizangle, vertangle ), kigMax( horizangle, vertangle ) );
+ }
+// p.drawCircle( c, r );
+}
diff --git a/kig/misc/coordinate_system.h b/kig/misc/coordinate_system.h
new file mode 100644
index 00000000..af426909
--- /dev/null
+++ b/kig/misc/coordinate_system.h
@@ -0,0 +1,134 @@
+/*
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+*/
+
+#ifndef KIG_MISC_COORDINATE_SYSTEM_H
+#define KIG_MISC_COORDINATE_SYSTEM_H
+
+#include <qnamespace.h>
+
+class KigPainter;
+class KigDocument;
+class KigWidget;
+class CoordinateSystem;
+class QValidator;
+class Coordinate;
+class QString;
+class QStringList;
+class QWidget;
+
+/**
+ * a factory to build a CoordinateSystem and a small handle to the
+ * existant CoordinateSystem's...
+ */
+class CoordinateSystemFactory
+{
+public:
+ enum { Euclidean = 0, Polar = 1 };
+
+ static QStringList names();
+ static QString setCoordinateSystemStatement( int id );
+ static CoordinateSystem* build( int which );
+ static CoordinateSystem* build( const char* type );
+};
+
+/**
+ * a CoordinateSystem is what the user sees: it is kept by KigPart to
+ * show the user a grid, and to show the coordinates of points... it
+ * allows for weird CoordinateSystem's like homogeneous or
+ * projective...
+ * internally, it does nothing, it could almost have been an ordinary
+ * Object..., mapping coordinates from and to the screen to and from
+ * the internal coordinates is done elsewhere ( KigPainter and
+ * KigWidget... )
+ */
+class CoordinateSystem
+ : public Qt
+{
+public:
+ CoordinateSystem();
+ virtual ~CoordinateSystem();
+
+ virtual QString fromScreen ( const Coordinate& pt, const KigDocument& w ) const = 0;
+ /**
+ * This returns a notice to say in which format coordinates should
+ * be entered. This should be something like:
+ * i18n( "Enter coordinates in the following form: \"(x,y)\", where
+ * x is the x coordinate, and y is the y coordinate." );
+ */
+ virtual QString coordinateFormatNotice() const = 0;
+ /**
+ * Like \ref coordinateFormatNotice(), but with HTML tags useful to
+ * have a rich text...
+ */
+ virtual QString coordinateFormatNoticeMarkup() const = 0;
+ virtual Coordinate toScreen (const QString& pt, bool& ok) const = 0;
+ virtual void drawGrid ( KigPainter& p, bool showgrid = true,
+ bool showaxes = true ) const = 0;
+ virtual QValidator* coordinateValidator() const = 0;
+ virtual Coordinate snapToGrid( const Coordinate& c,
+ const KigWidget& w ) const = 0;
+
+ virtual const char* type() const = 0;
+ virtual int id() const = 0;
+};
+
+class EuclideanCoords
+ : public CoordinateSystem
+{
+public:
+ EuclideanCoords();
+ ~EuclideanCoords();
+ QString fromScreen( const Coordinate& pt, const KigDocument& w ) const;
+ QString coordinateFormatNotice() const;
+ QString coordinateFormatNoticeMarkup() const;
+ Coordinate toScreen (const QString& pt, bool& ok) const;
+ void drawGrid ( KigPainter& p, bool showgrid = true,
+ bool showaxes = true ) const;
+ QValidator* coordinateValidator() const;
+ Coordinate snapToGrid( const Coordinate& c,
+ const KigWidget& w ) const;
+
+ const char* type() const;
+ int id() const;
+};
+
+class PolarCoords
+ : public CoordinateSystem
+{
+ void drawGridLine( KigPainter& p, const Coordinate& center,
+ double radius ) const;
+public:
+ PolarCoords();
+ ~PolarCoords();
+ QString fromScreen( const Coordinate& pt, const KigDocument& w ) const;
+ QString coordinateFormatNotice() const;
+ QString coordinateFormatNoticeMarkup() const;
+ Coordinate toScreen (const QString& pt, bool& ok) const;
+ void drawGrid ( KigPainter& p, bool showgrid = true,
+ bool showaxes = true ) const;
+ QValidator* coordinateValidator() const;
+ Coordinate snapToGrid( const Coordinate& c,
+ const KigWidget& w ) const;
+
+ const char* type() const;
+ int id() const;
+};
+
+#endif
diff --git a/kig/misc/cubic-common.cc b/kig/misc/cubic-common.cc
new file mode 100644
index 00000000..029f1194
--- /dev/null
+++ b/kig/misc/cubic-common.cc
@@ -0,0 +1,527 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include <config.h>
+
+#include "cubic-common.h"
+#include "kignumerics.h"
+#include "kigtransform.h"
+
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+
+/*
+ * coefficients of the cartesian equation for cubics
+ */
+
+CubicCartesianData::CubicCartesianData()
+{
+ std::fill( coeffs, coeffs + 10, 0 );
+}
+
+CubicCartesianData::CubicCartesianData(
+ const double incoeffs[10] )
+{
+ std::copy( incoeffs, incoeffs + 10, coeffs );
+}
+
+const CubicCartesianData calcCubicThroughPoints (
+ const std::vector<Coordinate>& points )
+{
+ // points is a vector of at most 9 points through which the cubic is
+ // constrained.
+ // this routine should compute the coefficients in the cartesian equation
+ // they are defined up to a multiplicative factor.
+ // since we don't know (in advance) which one of them is nonzero, we
+ // simply keep all 10 parameters, obtaining a 9x10 linear system which
+ // we solve using gaussian elimination with complete pivoting
+ // If there are too few, then we choose some cool way to fill in the
+ // empty parts in the matrix according to the LinearConstraints
+ // given..
+
+ // 9 rows, 10 columns..
+ double row0[10];
+ double row1[10];
+ double row2[10];
+ double row3[10];
+ double row4[10];
+ double row5[10];
+ double row6[10];
+ double row7[10];
+ double row8[10];
+ double *matrix[9] = {row0, row1, row2, row3, row4, row5, row6, row7, row8};
+ double solution[10];
+ int scambio[10];
+
+ int numpoints = points.size();
+ int numconstraints = 9;
+
+ // fill in the matrix elements
+ for ( int i = 0; i < numpoints; ++i )
+ {
+ double xi = points[i].x;
+ double yi = points[i].y;
+ matrix[i][0] = 1.0;
+ matrix[i][1] = xi;
+ matrix[i][2] = yi;
+ matrix[i][3] = xi*xi;
+ matrix[i][4] = xi*yi;
+ matrix[i][5] = yi*yi;
+ matrix[i][6] = xi*xi*xi;
+ matrix[i][7] = xi*xi*yi;
+ matrix[i][8] = xi*yi*yi;
+ matrix[i][9] = yi*yi*yi;
+ }
+
+ for ( int i = 0; i < numconstraints; i++ )
+ {
+ if (numpoints >= 9) break; // don't add constraints if we have enough
+ for (int j = 0; j < 10; ++j) matrix[numpoints][j] = 0.0;
+ bool addedconstraint = true;
+ switch (i)
+ {
+ case 0:
+ matrix[numpoints][7] = 1.0;
+ matrix[numpoints][8] = -1.0;
+ break;
+ case 1:
+ matrix[numpoints][7] = 1.0;
+ break;
+ case 2:
+ matrix[numpoints][9] = 1.0;
+ break;
+ case 3:
+ matrix[numpoints][4] = 1.0;
+ break;
+ case 4:
+ matrix[numpoints][5] = 1.0;
+ break;
+ case 5:
+ matrix[numpoints][3] = 1.0;
+ break;
+ case 6:
+ matrix[numpoints][1] = 1.0;
+ break;
+
+ default:
+ addedconstraint = false;
+ break;
+ }
+
+ if (addedconstraint) ++numpoints;
+ }
+
+ if ( ! GaussianElimination( matrix, numpoints, 10, scambio ) )
+ return CubicCartesianData::invalidData();
+ // fine della fase di eliminazione
+ BackwardSubstitution( matrix, numpoints, 10, scambio, solution );
+
+ // now solution should contain the correct coefficients..
+ return CubicCartesianData( solution );
+}
+
+const CubicCartesianData calcCubicCuspThroughPoints (
+ const std::vector<Coordinate>& points )
+{
+ // points is a vector of at most 4 points through which the cubic is
+ // constrained. Moreover the cubic is required to have a cusp at the
+ // origin.
+
+ // 9 rows, 10 columns..
+ double row0[10];
+ double row1[10];
+ double row2[10];
+ double row3[10];
+ double row4[10];
+ double row5[10];
+ double row6[10];
+ double row7[10];
+ double row8[10];
+ double *matrix[9] = {row0, row1, row2, row3, row4, row5, row6, row7, row8};
+ double solution[10];
+ int scambio[10];
+
+ int numpoints = points.size();
+ int numconstraints = 9;
+
+ // fill in the matrix elements
+ for ( int i = 0; i < numpoints; ++i )
+ {
+ double xi = points[i].x;
+ double yi = points[i].y;
+ matrix[i][0] = 1.0;
+ matrix[i][1] = xi;
+ matrix[i][2] = yi;
+ matrix[i][3] = xi*xi;
+ matrix[i][4] = xi*yi;
+ matrix[i][5] = yi*yi;
+ matrix[i][6] = xi*xi*xi;
+ matrix[i][7] = xi*xi*yi;
+ matrix[i][8] = xi*yi*yi;
+ matrix[i][9] = yi*yi*yi;
+ }
+
+ for ( int i = 0; i < numconstraints; i++ )
+ {
+ if (numpoints >= 9) break; // don't add constraints if we have enough
+ for (int j = 0; j < 10; ++j) matrix[numpoints][j] = 0.0;
+ bool addedconstraint = true;
+ switch (i)
+ {
+ case 0:
+ matrix[numpoints][0] = 1.0; // through the origin
+ break;
+ case 1:
+ matrix[numpoints][1] = 1.0;
+ break;
+ case 2:
+ matrix[numpoints][2] = 1.0; // no first degree term
+ break;
+ case 3:
+ matrix[numpoints][3] = 1.0; // a011 (x^2 coeff) = 0
+ break;
+ case 4:
+ matrix[numpoints][4] = 1.0; // a012 (xy coeff) = 0
+ break;
+ case 5:
+ matrix[numpoints][7] = 1.0;
+ matrix[numpoints][8] = -1.0;
+ break;
+ case 6:
+ matrix[numpoints][7] = 1.0;
+ break;
+ case 7:
+ matrix[numpoints][9] = 1.0;
+ break;
+ case 8:
+ matrix[numpoints][6] = 1.0;
+ break;
+
+ default:
+ addedconstraint = false;
+ break;
+ }
+
+ if (addedconstraint) ++numpoints;
+ }
+
+ if ( ! GaussianElimination( matrix, numpoints, 10, scambio ) )
+ return CubicCartesianData::invalidData();
+ // fine della fase di eliminazione
+ BackwardSubstitution( matrix, numpoints, 10, scambio, solution );
+
+ // now solution should contain the correct coefficients..
+ return CubicCartesianData( solution );
+}
+
+const CubicCartesianData calcCubicNodeThroughPoints (
+ const std::vector<Coordinate>& points )
+{
+ // points is a vector of at most 6 points through which the cubic is
+ // constrained. Moreover the cubic is required to have a node at the
+ // origin.
+
+ // 9 rows, 10 columns..
+ double row0[10];
+ double row1[10];
+ double row2[10];
+ double row3[10];
+ double row4[10];
+ double row5[10];
+ double row6[10];
+ double row7[10];
+ double row8[10];
+ double *matrix[9] = {row0, row1, row2, row3, row4, row5, row6, row7, row8};
+ double solution[10];
+ int scambio[10];
+
+ int numpoints = points.size();
+ int numconstraints = 9;
+
+ // fill in the matrix elements
+ for ( int i = 0; i < numpoints; ++i )
+ {
+ double xi = points[i].x;
+ double yi = points[i].y;
+ matrix[i][0] = 1.0;
+ matrix[i][1] = xi;
+ matrix[i][2] = yi;
+ matrix[i][3] = xi*xi;
+ matrix[i][4] = xi*yi;
+ matrix[i][5] = yi*yi;
+ matrix[i][6] = xi*xi*xi;
+ matrix[i][7] = xi*xi*yi;
+ matrix[i][8] = xi*yi*yi;
+ matrix[i][9] = yi*yi*yi;
+ }
+
+ for ( int i = 0; i < numconstraints; i++ )
+ {
+ if (numpoints >= 9) break; // don't add constraints if we have enough
+ for (int j = 0; j < 10; ++j) matrix[numpoints][j] = 0.0;
+ bool addedconstraint = true;
+ switch (i)
+ {
+ case 0:
+ matrix[numpoints][0] = 1.0;
+ break;
+ case 1:
+ matrix[numpoints][1] = 1.0;
+ break;
+ case 2:
+ matrix[numpoints][2] = 1.0;
+ break;
+ case 3:
+ matrix[numpoints][7] = 1.0;
+ matrix[numpoints][8] = -1.0;
+ break;
+ case 4:
+ matrix[numpoints][7] = 1.0;
+ break;
+ case 5:
+ matrix[numpoints][9] = 1.0;
+ break;
+ case 6:
+ matrix[numpoints][4] = 1.0;
+ break;
+ case 7:
+ matrix[numpoints][5] = 1.0;
+ break;
+ case 8:
+ matrix[numpoints][3] = 1.0;
+ break;
+
+ default:
+ addedconstraint = false;
+ break;
+ }
+
+ if (addedconstraint) ++numpoints;
+ }
+
+ if ( ! GaussianElimination( matrix, numpoints, 10, scambio ) )
+ return CubicCartesianData::invalidData();
+ // fine della fase di eliminazione
+ BackwardSubstitution( matrix, numpoints, 10, scambio, solution );
+
+ // now solution should contain the correct coefficients..
+ return CubicCartesianData( solution );
+}
+
+/*
+ * computation of the y value corresponding to some x value
+ */
+
+double calcCubicYvalue ( double x, double ymin, double ymax, int root,
+ CubicCartesianData data, bool& valid,
+ int &numroots )
+{
+ valid = true;
+
+ // compute the third degree polinomial:
+ double a000 = data.coeffs[0];
+ double a001 = data.coeffs[1];
+ double a002 = data.coeffs[2];
+ double a011 = data.coeffs[3];
+ double a012 = data.coeffs[4];
+ double a022 = data.coeffs[5];
+ double a111 = data.coeffs[6];
+ double a112 = data.coeffs[7];
+ double a122 = data.coeffs[8];
+ double a222 = data.coeffs[9];
+
+ // first the y^3 coefficient, it coming only from a222:
+ double a = a222;
+ // next the y^2 coefficient (from a122 and a022):
+ double b = a122*x + a022;
+ // next the y coefficient (from a112, a012 and a002):
+ double c = a112*x*x + a012*x + a002;
+ // finally the constant coefficient (from a111, a011, a001 and a000):
+ double d = a111*x*x*x + a011*x*x + a001*x + a000;
+
+ return calcCubicRoot ( ymin, ymax, a, b, c, d, root, valid, numroots );
+}
+
+const Coordinate calcCubicLineIntersect( const CubicCartesianData& cu,
+ const LineData& l,
+ int root, bool& valid )
+{
+ assert( root == 1 || root == 2 || root == 3 );
+
+ double a, b, c, d;
+ calcCubicLineRestriction ( cu, l.a, l.b-l.a, a, b, c, d );
+ int numroots;
+ double param =
+ calcCubicRoot ( -1e10, 1e10, a, b, c, d, root, valid, numroots );
+ return l.a + param*(l.b - l.a);
+}
+
+/*
+ * calculate the cubic polynomial resulting from the restriction
+ * of a cubic to a line (defined by two "Coordinates": a point and a
+ * direction)
+ */
+
+void calcCubicLineRestriction ( CubicCartesianData data,
+ Coordinate p, Coordinate v,
+ double& a, double& b, double& c, double& d )
+{
+ a = b = c = d = 0;
+
+ double a000 = data.coeffs[0];
+ double a001 = data.coeffs[1];
+ double a002 = data.coeffs[2];
+ double a011 = data.coeffs[3];
+ double a012 = data.coeffs[4];
+ double a022 = data.coeffs[5];
+ double a111 = data.coeffs[6];
+ double a112 = data.coeffs[7];
+ double a122 = data.coeffs[8];
+ double a222 = data.coeffs[9];
+
+ // zero degree term
+ d += a000;
+
+ // first degree terms
+ d += a001*p.x + a002*p.y;
+ c += a001*v.x + a002*v.y;
+
+ // second degree terms
+ d += a011*p.x*p.x + a012*p.x*p.y + a022*p.y*p.y;
+ c += 2*a011*p.x*v.x + a012*(p.x*v.y + v.x*p.y) + 2*a022*p.y*v.y;
+ b += a011*v.x*v.x + a012*v.x*v.y + a022*v.y*v.y;
+
+ // third degree terms: a111 x^3 + a222 y^3
+ d += a111*p.x*p.x*p.x + a222*p.y*p.y*p.y;
+ c += 3*(a111*p.x*p.x*v.x + a222*p.y*p.y*v.y);
+ b += 3*(a111*p.x*v.x*v.x + a222*p.y*v.y*v.y);
+ a += a111*v.x*v.x*v.x + a222*v.y*v.y*v.y;
+
+ // third degree terms: a112 x^2 y + a122 x y^2
+ d += a112*p.x*p.x*p.y + a122*p.x*p.y*p.y;
+ c += a112*(p.x*p.x*v.y + 2*p.x*v.x*p.y) + a122*(v.x*p.y*p.y + 2*p.x*p.y*v.y);
+ b += a112*(v.x*v.x*p.y + 2*v.x*p.x*v.y) + a122*(p.x*v.y*v.y + 2*v.x*v.y*p.y);
+ a += a112*v.x*v.x*v.y + a122*v.x*v.y*v.y;
+}
+
+
+const CubicCartesianData calcCubicTransformation (
+ const CubicCartesianData& data,
+ const Transformation& t, bool& valid )
+{
+ double a[3][3][3];
+ double b[3][3][3];
+ CubicCartesianData dataout;
+
+ int icount = 0;
+ for (int i=0; i < 3; i++)
+ {
+ for (int j=i; j < 3; j++)
+ {
+ for (int k=j; k < 3; k++)
+ {
+ a[i][j][k] = data.coeffs[icount++];
+ if ( i < k )
+ {
+ if ( i == j ) // case aiik
+ {
+ a[i][i][k] /= 3.;
+ a[i][k][i] = a[k][i][i] = a[i][i][k];
+ }
+ else if ( j == k ) // case aijj
+ {
+ a[i][j][j] /= 3.;
+ a[j][i][j] = a[j][j][i] = a[i][j][j];
+ }
+ else // case aijk (i<j<k)
+ {
+ a[i][j][k] /= 6.;
+ a[i][k][j] = a[j][i][k] = a[j][k][i] =
+ a[k][i][j] = a[k][j][i] = a[i][j][k];
+ }
+ }
+ }
+ }
+ }
+
+ Transformation ti = t.inverse( valid );
+ if ( ! valid ) return dataout;
+
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ for (int k = 0; k < 3; k++)
+ {
+ b[i][j][k] = 0.;
+ for (int ii = 0; ii < 3; ii++)
+ {
+ for (int jj = 0; jj < 3; jj++)
+ {
+ for (int kk = 0; kk < 3; kk++)
+ {
+ b[i][j][k] += a[ii][jj][kk]*ti.data( ii, i )*ti.data( jj, j )*ti.data( kk, k );
+ }
+ }
+ }
+ }
+ }
+ }
+
+// assert (fabs(b[0][1][2] - b[1][2][0]) < 1e-8); // test a couple of cases
+// assert (fabs(b[0][1][1] - b[1][1][0]) < 1e-8);
+
+ // apparently, the above assertions are wrong ( due to rounding
+ // errors, Maurizio and I hope :) ), so since the symmetry is not
+ // present, we just take the sum of the parts of the matrix elements
+ // that should be symmetric, instead of taking one of them, and
+ // multiplying it..
+
+ dataout.coeffs[0] = b[0][0][0];
+ dataout.coeffs[1] = b[0][0][1] + b[0][1][0] + b[1][0][0];
+ dataout.coeffs[2] = b[0][0][2] + b[0][2][0] + b[2][0][0];
+ dataout.coeffs[3] = b[0][1][1] + b[1][0][1] + b[1][1][0];
+ dataout.coeffs[4] = b[0][1][2] + b[0][2][1] + b[1][2][0] + b[1][0][2] + b[2][1][0] + b[2][0][1];
+ dataout.coeffs[5] = b[0][2][2] + b[2][0][2] + b[2][2][0];
+ dataout.coeffs[6] = b[1][1][1];
+ dataout.coeffs[7] = b[1][1][2] + b[1][2][1] + b[2][1][1];
+ dataout.coeffs[8] = b[1][2][2] + b[2][1][2] + b[2][2][1];
+ dataout.coeffs[9] = b[2][2][2];
+
+ return dataout;
+}
+
+bool operator==( const CubicCartesianData& lhs, const CubicCartesianData& rhs )
+{
+ for ( int i = 0; i < 10; ++i )
+ if ( lhs.coeffs[i] != rhs.coeffs[i] )
+ return false;
+ return true;
+}
+
+CubicCartesianData CubicCartesianData::invalidData()
+{
+ CubicCartesianData ret;
+ ret.coeffs[0] = double_inf;
+ return ret;
+}
+
+bool CubicCartesianData::valid() const
+{
+ return finite( coeffs[0] );
+}
diff --git a/kig/misc/cubic-common.h b/kig/misc/cubic-common.h
new file mode 100644
index 00000000..8fbcd1a2
--- /dev/null
+++ b/kig/misc/cubic-common.h
@@ -0,0 +1,120 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MISC_CUBIC_COMMON_H
+#define KIG_MISC_CUBIC_COMMON_H
+
+#include "common.h"
+
+class Transformation;
+
+/**
+ * This class represents an equation of a cubic in the form
+ * \f$ a_{ijk} x_i x_j x_k = 0 \f$ (in homogeneous coordinates,
+ * \f$ i,j,k = 0,1,2 \f$), \f$ i <= j <= k \f$.
+ * The coefficients are stored in lessicografic order.
+ */
+class CubicCartesianData
+{
+public:
+ double coeffs[10];
+ /**
+ * \ifnot creating-python-scripting-doc
+ * \brief Default Constructor
+ *
+ * Constructs a new CubicCartesianData, with all the coeffs
+ * initialized to 0.
+ * \endif
+ */
+ explicit CubicCartesianData();
+ /**
+ * Constructor. Construct a new CubicCartesianData, with the given
+ * values as coeffs.
+ */
+ CubicCartesianData( double a000, double a001, double a002,
+ double a011, double a012, double a022,
+ double a111, double a112, double a122,
+ double a222 )
+ {
+ coeffs[0] = a000;
+ coeffs[1] = a001;
+ coeffs[2] = a002;
+ coeffs[3] = a011;
+ coeffs[4] = a012;
+ coeffs[5] = a022;
+ coeffs[6] = a111;
+ coeffs[7] = a112;
+ coeffs[8] = a122;
+ coeffs[9] = a222;
+ }
+ CubicCartesianData( const double incoeffs[10] );
+
+ /**
+ * Create an invalid CubicCartesianData. This is a special state of a
+ * CubicCartesianData that signals that something went wrong..
+ *
+ * \see CubicCartesianData::valid
+ *
+ * \internal We represent an invalid CubicCartesianData by setting all
+ * the coeffs to positive or negative infinity. This is handy, since
+ * it doesn't require us to adapt most of the functions, it doesn't
+ * need extra space, and most of the times that we should get an
+ * invalid CubicCartesianData, we get one automatically..
+ */
+ static CubicCartesianData invalidData();
+ /**
+ * Return whether this is a valid CubicCartesianData.
+ *
+ * \see CubicCartesianData::invalidData
+ */
+ bool valid() const;
+};
+
+bool operator==( const CubicCartesianData& lhs, const CubicCartesianData& rhs );
+
+/**
+ * This function calcs a cartesian cubic equation such that the
+ * given points are on the cubic. There can be at most 9 and at
+ * least 2 point. If there are less than 9, than the coefficients
+ * will be chosen to 1.0 if possible
+ */
+const CubicCartesianData calcCubicThroughPoints (
+ const std::vector<Coordinate>& points );
+
+const CubicCartesianData calcCubicCuspThroughPoints (
+ const std::vector<Coordinate>& points );
+
+const CubicCartesianData calcCubicNodeThroughPoints (
+ const std::vector<Coordinate>& points );
+
+double calcCubicYvalue ( double x, double ymin, double ymax,
+ int root, CubicCartesianData data,
+ bool& valid, int& numroots );
+
+const Coordinate calcCubicLineIntersect( const CubicCartesianData& c,
+ const LineData& l,
+ int root, bool& valid );
+
+void calcCubicLineRestriction ( CubicCartesianData data,
+ Coordinate p1, Coordinate dir,
+ double& a, double& b, double& c, double& d );
+
+const CubicCartesianData calcCubicTransformation (
+ const CubicCartesianData& data,
+ const Transformation& t, bool& valid );
+
+#endif
diff --git a/kig/misc/goniometry.cc b/kig/misc/goniometry.cc
new file mode 100644
index 00000000..13d72fdb
--- /dev/null
+++ b/kig/misc/goniometry.cc
@@ -0,0 +1,137 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+ Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+
+#include "goniometry.h"
+
+#include <qstringlist.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <cmath>
+
+Goniometry::Goniometry()
+{
+ mvalue = 0.0;
+ msys = Rad;
+}
+
+Goniometry::Goniometry( double value, Goniometry::System system )
+{
+ mvalue = value;
+ msys = system;
+}
+
+Goniometry::~Goniometry()
+{
+}
+
+void Goniometry::setValue( double value )
+{
+ mvalue = value;
+}
+
+const double Goniometry::value() const
+{
+ return mvalue;
+}
+
+void Goniometry::setSystem( Goniometry::System system )
+{
+ msys = system;
+}
+
+void Goniometry::convertTo( Goniometry::System system )
+{
+ mvalue = convert( mvalue, msys, system );
+ msys = system;
+}
+
+const Goniometry::System Goniometry::system() const
+{
+ return msys;
+}
+
+double Goniometry::getValue( Goniometry::System system )
+{
+ return convert( mvalue, msys, system );
+}
+
+Goniometry& Goniometry::operator=( const Goniometry& g )
+{
+ mvalue = g.value();
+ msys = g.system();
+ return *this;
+}
+
+double Goniometry::convert( const double angle, const Goniometry::System from, const Goniometry::System to )
+{
+ switch( from )
+ {
+ case Deg:
+ {
+ if ( to == Rad )
+ return angle * M_PI / 180;
+ if ( to == Grad )
+ return angle * 10 / 9;
+ break;
+ }
+ case Rad:
+ {
+ if ( to == Deg )
+ return angle * 180 / M_PI;
+ if ( to == Grad )
+ return angle * 200 / M_PI;
+ break;
+ }
+ case Grad:
+ {
+ if ( to == Deg )
+ return angle * 9 / 10;
+ if ( to == Rad )
+ return angle * M_PI / 200;
+ break;
+ }
+ }
+ return angle;
+}
+
+QStringList Goniometry::systemList()
+{
+ QStringList sl;
+ sl << i18n( "Translators: Degrees", "Deg" );
+ sl << i18n( "Translators: Radians", "Rad" );
+ sl << i18n( "Translators: Gradians", "Grad" );
+ return sl;
+}
+
+Goniometry::System Goniometry::intToSystem( const int index )
+{
+ if( index == 0 )
+ return Deg;
+ else if( index == 1 )
+ return Rad;
+ else if( index == 2 )
+ return Grad;
+ kdDebug() << "No goniometric system with index " << index << endl;
+ return Rad;
+}
diff --git a/kig/misc/goniometry.h b/kig/misc/goniometry.h
new file mode 100644
index 00000000..eae84ced
--- /dev/null
+++ b/kig/misc/goniometry.h
@@ -0,0 +1,72 @@
+// This file is part of Kig, a KDE program for Interactive Geometry...
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MISC_GONIOMETRY_H
+#define KIG_MISC_GONIOMETRY_H
+
+#include <qstringlist.h>
+
+/**
+ * Manage an angle and convert it from/to other goniometric systems.
+ */
+class Goniometry
+{
+public:
+ enum System { Deg, Rad, Grad };
+ Goniometry();
+ Goniometry( double value, Goniometry::System system );
+ ~Goniometry();
+ void setValue( double value );
+ const double value() const;
+ /**
+ * Set the system of the current angle to \p system, but it doesn't
+ * convert the value to the new system.
+ *
+ * \see convertTo()
+ */
+ void setSystem( Goniometry::System system );
+ /**
+ * Set the system of the current angle to \p system and convert the
+ * value to the new system using \ref convert().
+ *
+ * \see setSystem()
+ */
+ void convertTo( Goniometry::System system );
+ const Goniometry::System system() const;
+ double getValue( Goniometry::System system );
+ /**
+ * The most useful method of this class: convert the specified
+ * \p angle from the system \p from to the system \p to.
+ */
+ static double convert( const double angle, const Goniometry::System from, const Goniometry::System to );
+ /**
+ * Get a list of the supported goniometric systems.
+ */
+ static QStringList systemList();
+ static Goniometry::System intToSystem( const int index );
+
+ Goniometry& operator= ( const Goniometry& g );
+
+private:
+ double mvalue;
+ typedef Goniometry::System goniosys;
+ goniosys msys;
+};
+
+#endif
diff --git a/kig/misc/guiaction.cc b/kig/misc/guiaction.cc
new file mode 100644
index 00000000..d4be4ded
--- /dev/null
+++ b/kig/misc/guiaction.cc
@@ -0,0 +1,367 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "guiaction.h"
+#include "guiaction.moc"
+
+#include "coordinate_system.h"
+#include "coordinate.h"
+#include "object_constructor.h"
+
+#include "../kig/kig_part.h"
+#include "../kig/kig_document.h"
+#include "../misc/kiginputdialog.h"
+#include "../modes/construct_mode.h"
+#include "../modes/label.h"
+#include "../objects/object_holder.h"
+#include "../objects/object_factory.h"
+#include "../objects/bogus_imp.h"
+
+#include <kiconloader.h>
+#include <klocale.h>
+
+#include <qregexp.h>
+
+int GUIAction::shortcut() const
+{
+ return 0;
+}
+
+GUIAction::~GUIAction()
+{
+}
+
+ConstructibleAction::~ConstructibleAction()
+{
+}
+
+ConstructibleAction::ConstructibleAction(
+ ObjectConstructor* ctor,
+ const QCString& actionname,
+ int shortcut )
+ : GUIAction(), mctor( ctor ), mactionname( actionname ), mshortcut( shortcut )
+{
+}
+
+QString ConstructibleAction::description() const
+{
+ return mctor->description();
+}
+
+QCString ConstructibleAction::iconFileName() const
+{
+ return mctor->iconFileName();
+}
+
+QString ConstructibleAction::descriptiveName() const
+{
+ return mctor->descriptiveName();
+}
+
+void ConstructibleAction::act( KigPart& d )
+{
+ BaseConstructMode* m = mctor->constructMode( d );
+ d.runMode( m );
+ delete m;
+}
+
+KigGUIAction::KigGUIAction( GUIAction* act,
+ KigPart& doc,
+ QObject* parent )
+ : KAction( act->descriptiveName(),
+ doc.instance()->iconLoader()->loadIcon(
+ act->iconFileName(), KIcon::Toolbar, 0, KIcon::DefaultState, 0L, true ),
+ act->shortcut(),
+ 0, 0, // no slot connection
+ parent, act->actionName() ),
+ mact( act ),
+ mdoc( doc )
+{
+ setWhatsThis( act->description() );
+ QString tooltip = act->descriptiveName();
+ tooltip.replace( QRegExp( "&&" ), "&" );
+ setToolTip( tooltip );
+}
+
+void KigGUIAction::slotActivated()
+{
+ mact->act( mdoc );
+}
+
+const char* ConstructibleAction::actionName() const
+{
+ return mactionname;
+}
+
+ConstructPointAction::~ConstructPointAction()
+{
+}
+
+QString ConstructPointAction::description() const
+{
+ return i18n(
+ "A normal point, i.e. one that is either independent or attached "
+ "to a line, circle, segment."
+ );
+}
+
+QCString ConstructPointAction::iconFileName() const
+{
+ return "point";
+}
+
+QString ConstructPointAction::descriptiveName() const
+{
+ return i18n("Point");
+}
+
+const char* ConstructPointAction::actionName() const
+{
+ return mactionname;
+}
+
+int ConstructPointAction::shortcut() const
+{
+ return Qt::Key_P;
+}
+
+void ConstructPointAction::act( KigPart& d )
+{
+ PointConstructMode m( d );
+ d.runMode( &m );
+}
+
+ConstructPointAction::ConstructPointAction( const char* actionname )
+ : mactionname( actionname )
+{
+}
+
+GUIAction* KigGUIAction::guiAction()
+{
+ return mact;
+}
+
+void KigGUIAction::plug( KigPart* doc )
+{
+ mact->plug( doc, this );
+}
+
+void ConstructibleAction::plug( KigPart* doc, KigGUIAction* kact )
+{
+ mctor->plug( doc, kact );
+}
+
+QString ConstructTextLabelAction::description() const
+{
+ return i18n( "Construct a text label." );
+}
+
+QCString ConstructTextLabelAction::iconFileName() const
+{
+ return "kig_text";
+}
+
+QString ConstructTextLabelAction::descriptiveName() const
+{
+ return i18n( "Text Label" );
+}
+
+const char* ConstructTextLabelAction::actionName() const
+{
+ return mactionname;
+}
+
+void ConstructTextLabelAction::act( KigPart& d )
+{
+ TextLabelConstructionMode m( d );
+ d.runMode( &m );
+}
+
+ConstructTextLabelAction::ConstructTextLabelAction( const char* actionname )
+ : mactionname( actionname )
+{
+}
+
+QString AddFixedPointAction::description() const
+{
+ return i18n( "Construct a Point by its Coordinates" );
+}
+
+QCString AddFixedPointAction::iconFileName() const
+{
+ return "pointxy";
+}
+
+QString AddFixedPointAction::descriptiveName() const
+{
+ return i18n( "Point by Coordinates" );
+}
+
+const char* AddFixedPointAction::actionName() const
+{
+ return mactionname;
+}
+
+void AddFixedPointAction::act( KigPart& doc )
+{
+ bool ok;
+ Coordinate c = Coordinate::invalidCoord();
+ KigInputDialog::getCoordinate(
+ i18n( "Fixed Point" ),
+ i18n( "Enter the coordinates for the new point." ) +
+ QString::fromLatin1( "<br>" ) +
+ doc.document().coordinateSystem().coordinateFormatNoticeMarkup(),
+ doc.widget(), &ok, doc.document(), &c );
+ if ( ! ok ) return;
+ ObjectHolder* p = ObjectFactory::instance()->fixedPoint( c );
+ p->calc( doc.document() );
+ doc.addObject( p );
+}
+
+AddFixedPointAction::AddFixedPointAction( const char* actionname )
+ : mactionname( actionname )
+{
+}
+
+AddFixedPointAction::~AddFixedPointAction()
+{
+}
+
+void GUIAction::plug( KigPart*, KigGUIAction* )
+{
+}
+
+int ConstructibleAction::shortcut() const
+{
+ return mshortcut;
+}
+
+int ConstructTextLabelAction::shortcut() const
+{
+ return Qt::Key_B;
+}
+
+int AddFixedPointAction::shortcut() const
+{
+ return Qt::Key_F;
+}
+
+#if 0
+TestAction::TestAction( const char* actionname )
+ : mactionname( actionname )
+{
+}
+
+TestAction::~TestAction()
+{
+}
+
+QString TestAction::description() const
+{
+ return QString::fromLatin1( "Test stuff !!!" );
+}
+
+QCString TestAction::iconFileName() const
+{
+ return "new";
+}
+
+QString TestAction::descriptiveName() const
+{
+ return QString::fromLatin1( "Test stuff !!!" );
+}
+
+const char* TestAction::actionName() const
+{
+ return mactionname;
+}
+
+void TestAction::act( KigPart& doc )
+{
+ const char* script =
+ "def calc( a ):\n\treturn Point( a.coordinate() + Coordinate( 2, 0 ) )\n";
+ Object* constantpoint = ObjectFactory::instance()->fixedPoint( Coordinate( -1, -1 ) );
+ constantpoint->calc( doc );
+
+ Object* codeobject = new DataObject( new StringImp( QString::fromLatin1( script ) ) );
+ Object* compiledcode = new RealObject( PythonCompileType::instance(), Objects( codeobject ) );
+ compiledcode->calc( doc );
+
+ Objects args( compiledcode );
+ args.push_back( constantpoint );
+ Object* scriptobject = new RealObject( PythonExecuteType::instance(), args );
+ scriptobject->calc( doc );
+
+ doc.addObject( constantpoint );
+ doc.addObject( scriptobject );
+}
+
+#endif // if 0 ( TestAction )
+
+#ifdef KIG_ENABLE_PYTHON_SCRIPTING
+#include "../scripting/python_type.h"
+#include "../scripting/script_mode.h"
+
+NewScriptAction::NewScriptAction( const char* descname, const char* description,
+ const char* actionname, const ScriptType::Type type,
+ const char* icon )
+ : GUIAction(), mactionname( actionname ), mdescname( descname ),
+ mdescription( description ), micon( icon ), mtype( type )
+{
+ if ( QString( micon ).isEmpty() )
+ {
+ micon = ScriptType::icon( type );
+ }
+}
+
+NewScriptAction::~NewScriptAction()
+{
+}
+
+QString NewScriptAction::description() const
+{
+ return i18n( mdescription );
+}
+
+QCString NewScriptAction::iconFileName() const
+{
+ return micon;
+}
+
+QString NewScriptAction::descriptiveName() const
+{
+ return i18n( mdescname );
+}
+
+const char* NewScriptAction::actionName() const
+{
+ return mactionname;
+}
+
+void NewScriptAction::act( KigPart& doc )
+{
+ ScriptCreationMode m( doc );
+ m.setScriptType( mtype );
+ doc.runMode( &m );
+}
+
+int NewScriptAction::shortcut() const
+{
+ return 0;
+}
+
+#endif // if KIG_ENABLE_PYTHON_SCRIPTING ( NewScriptAction )
diff --git a/kig/misc/guiaction.h b/kig/misc/guiaction.h
new file mode 100644
index 00000000..c188a492
--- /dev/null
+++ b/kig/misc/guiaction.h
@@ -0,0 +1,174 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MISC_GUIACTION_H
+#define KIG_MISC_GUIACTION_H
+
+#include <config.h>
+
+#ifdef KIG_ENABLE_PYTHON_SCRIPTING
+#include "../scripting/script-common.h"
+#endif
+
+#include <qstring.h>
+#include <qcstring.h>
+#include <kaction.h>
+
+class GUIAction;
+class KigPart;
+
+class KigGUIAction
+ : public KAction
+{
+ Q_OBJECT
+ GUIAction* mact;
+ KigPart& mdoc;
+public:
+ KigGUIAction( GUIAction* act,
+ KigPart& doc,
+ QObject* parent );
+ void slotActivated();
+
+ GUIAction* guiAction();
+
+ void plug( KigPart* doc );
+};
+
+class GUIAction
+{
+public:
+ virtual ~GUIAction();
+
+ virtual QString description() const = 0;
+ virtual QCString iconFileName() const = 0;
+ virtual QString descriptiveName() const = 0;
+ virtual const char* actionName() const = 0;
+ virtual int shortcut() const = 0;
+ virtual void act( KigPart& ) = 0;
+
+ virtual void plug( KigPart* doc, KigGUIAction* kact );
+};
+
+class ObjectConstructor;
+
+class ConstructibleAction
+ : public GUIAction
+{
+ ObjectConstructor* mctor;
+ QCString mactionname;
+ int mshortcut;
+public:
+ ConstructibleAction( ObjectConstructor* ctor, const QCString& actionname,
+ int shortcut = 0 );
+ ~ConstructibleAction();
+ QString description() const;
+ QCString iconFileName() const;
+ QString descriptiveName() const;
+ const char* actionName() const;
+ int shortcut() const;
+ void act( KigPart& );
+ void plug( KigPart* doc, KigGUIAction* kact );
+};
+
+class ConstructPointAction
+ : public GUIAction
+{
+ const char* mactionname;
+public:
+ ConstructPointAction( const char* actionname );
+ ~ConstructPointAction();
+
+ QString description() const;
+ QCString iconFileName() const;
+ QString descriptiveName() const;
+ const char* actionName() const;
+ int shortcut() const;
+ void act( KigPart& );
+};
+
+class ConstructTextLabelAction
+ : public GUIAction
+{
+ const char* mactionname;
+public:
+ ConstructTextLabelAction( const char* actionname );
+
+ QString description() const;
+ QCString iconFileName() const;
+ QString descriptiveName() const;
+ const char* actionName() const;
+ int shortcut() const;
+ void act( KigPart& );
+};
+
+class AddFixedPointAction
+ : public GUIAction
+{
+ const char* mactionname;
+public:
+ AddFixedPointAction( const char* actionname );
+ ~AddFixedPointAction();
+ QString description() const;
+ QCString iconFileName() const;
+ QString descriptiveName() const;
+ const char* actionName() const;
+ int shortcut() const;
+ void act( KigPart& );
+};
+
+#if 0
+class TestAction
+ : public GUIAction
+{
+ const char* mactionname;
+public:
+ TestAction( const char* actionname );
+ ~TestAction();
+ QString description() const;
+ QCString iconFileName() const;
+ QString descriptiveName() const;
+ const char* actionName() const;
+ void act( KigPart& );
+};
+#endif
+
+#ifdef KIG_ENABLE_PYTHON_SCRIPTING
+
+class NewScriptAction
+ : public GUIAction
+{
+ const char* mactionname;
+ const char* mdescname;
+ const char* mdescription;
+ const char* micon;
+ const ScriptType::Type mtype;
+public:
+ NewScriptAction( const char* descname, const char* description,
+ const char* actionname, const ScriptType::Type type,
+ const char* icon = "" );
+ ~NewScriptAction();
+ QString description() const;
+ QCString iconFileName() const;
+ QString descriptiveName() const;
+ const char* actionName() const;
+ void act( KigPart& );
+ int shortcut() const;
+};
+
+#endif // KIG_ENABLE_PYTHON_SCRIPTING
+
+#endif
diff --git a/kig/misc/kigfiledialog.cc b/kig/misc/kigfiledialog.cc
new file mode 100644
index 00000000..6b8d8cb4
--- /dev/null
+++ b/kig/misc/kigfiledialog.cc
@@ -0,0 +1,81 @@
+// Copyright (C) 2005 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+// USA
+
+#include "kigfiledialog.h"
+#include "kigfiledialog.moc"
+
+#include <qfile.h>
+#include <qpoint.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+KigFileDialog::KigFileDialog( const QString& startDir, const QString& filter,
+ const QString& caption, QWidget* parent )
+ : KFileDialog( startDir, filter, parent, "kigfiledialog", true ),
+ mow( 0L )
+{
+ setCaption( caption );
+ setOperationMode( Saving );
+ setMode( KFile::File | KFile::LocalOnly );
+ moptcaption = i18n( "Options" );
+}
+
+void KigFileDialog::setOptionsWidget( QWidget* w )
+{
+ mow = w;
+}
+
+void KigFileDialog::accept()
+{
+ // i know this is an ugly hack, but i hadn't found other ways to get
+ // the selected file name _before_ the dialog is accept()'ed or
+ // reject()'ed... in every case, below we make sure to accept() or
+ // reject()...
+ setResult( QDialog::Accepted );
+
+ QString sFile = selectedFile();
+ if ( QFile::exists( sFile ) )
+ {
+ int ret = KMessageBox::warningContinueCancel( this,
+ i18n( "The file \"%1\" already exists. Do you wish to overwrite it?" )
+ .arg( sFile ), i18n( "Overwrite File?" ), i18n("Overwrite") );
+ if ( ret != KMessageBox::Continue )
+ {
+ KFileDialog::reject();
+ return;
+ }
+ }
+ if ( mow )
+ {
+ KDialogBase* optdlg = new KDialogBase(
+ this, "optdlg", true, moptcaption, Cancel|Ok, Cancel, true );
+ mow->reparent( optdlg, QPoint() );
+ optdlg->setMainWidget( mow );
+ optdlg->exec() == QDialog::Accepted ? KFileDialog::accept() : KFileDialog::reject();
+ }
+ else
+ KFileDialog::accept();
+}
+
+void KigFileDialog::setOptionCaption( const QString& caption )
+{
+ if ( caption.isEmpty() )
+ return;
+
+ moptcaption = caption;
+}
diff --git a/kig/misc/kigfiledialog.h b/kig/misc/kigfiledialog.h
new file mode 100644
index 00000000..0337236d
--- /dev/null
+++ b/kig/misc/kigfiledialog.h
@@ -0,0 +1,77 @@
+// Copyright (C) 2005 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+// USA
+
+#ifndef KIG_MISC_KIGFILEDIALOG_H
+#define KIG_MISC_KIGFILEDIALOG_H
+
+#include <kfiledialog.h>
+
+/**
+ * This file dialog is pretty like KFileDialog, but allow us to make an option
+ * widget popup to the user.
+ */
+class KigFileDialog
+ : public KFileDialog
+{
+ Q_OBJECT
+
+private:
+ /**
+ * Options widget
+ */
+ QWidget* mow;
+
+ QString moptcaption;
+
+public:
+ /**
+ * Construct a new KigFileDialog.
+ *
+ * \param startDir the start dir of the file dialog. Consult the
+ * documentation of KFileDialog for more help about this
+ * \param filter the filter for the file dialog
+ * \param caption the caption of this file dialog
+ * \param parent the parent for this file dialog
+ */
+ KigFileDialog( const QString& startDir, const QString& filter,
+ const QString& caption, QWidget *parent );
+
+ /**
+ * Use this to set the widget containing the options of eg an export filter.
+ * The option widget will be popped up in a dialog right after the user
+ * presses OK and before the dialog is closed.
+ *
+ * You can construct the option widget with no parent, as it will be
+ * reparented.
+ *
+ * \param w the option widget
+ */
+ void setOptionsWidget( QWidget* w );
+
+ /**
+ * Set the caption of the option dialog
+ *
+ * \param caption the caption of the option dialog
+ */
+ void setOptionCaption( const QString& caption );
+
+protected slots:
+ virtual void accept();
+
+};
+
+#endif
diff --git a/kig/misc/kiginputdialog.cc b/kig/misc/kiginputdialog.cc
new file mode 100644
index 00000000..8a2c38e5
--- /dev/null
+++ b/kig/misc/kiginputdialog.cc
@@ -0,0 +1,283 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2005 Pino Toscano <toscano.pino@tiscali.it>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "kiginputdialog.h"
+#include "kiginputdialog.moc"
+
+#include "coordinate.h"
+#include "coordinate_system.h"
+#include "goniometry.h"
+
+#include "../kig/kig_document.h"
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qvalidator.h>
+#include <qwhatsthis.h>
+
+#include <kcombobox.h>
+#include <kdebug.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <ktextedit.h>
+
+class KigInputDialogPrivate
+{
+public:
+ KigInputDialogPrivate();
+
+ QLabel* m_label;
+ KLineEdit* m_lineEditFirst;
+ KLineEdit* m_lineEditSecond;
+ KComboBox* m_comboBox;
+ KTextEdit* m_textEdit;
+
+ Coordinate m_coord1;
+ Coordinate m_coord2;
+ KigDocument m_doc;
+ QValidator* m_vtor;
+ Goniometry m_gonio;
+ bool m_gonioIsNum;
+};
+
+KigInputDialogPrivate::KigInputDialogPrivate()
+ : m_label( 0L ), m_lineEditFirst( 0L ), m_lineEditSecond( 0L ), m_comboBox( 0L ),
+ m_textEdit( 0L )
+{
+}
+
+KigInputDialog::KigInputDialog( const QString& caption, const QString& label,
+ QWidget* parent, const KigDocument& doc, Coordinate* c1, Coordinate* c2 )
+ : KDialogBase( parent, "kigdialog", true, caption, Ok|Cancel, Cancel, true ),
+ d( new KigInputDialogPrivate() )
+{
+ d->m_coord1 = c1 ? Coordinate( *c1 ) : Coordinate::invalidCoord();
+ d->m_coord2 = c2 ? Coordinate( *c2 ) : Coordinate::invalidCoord();
+ d->m_doc = doc;
+ d->m_vtor = d->m_doc.coordinateSystem().coordinateValidator();
+
+ int deltay = 0;
+ bool ok = false;
+
+ QFrame* frame = makeMainWidget();
+ QVBoxLayout* mainlay = new QVBoxLayout( frame, 0, spacingHint() );
+ mainlay->activate();
+
+ d->m_textEdit = new KTextEdit( frame );
+ d->m_textEdit->setText( label );
+ d->m_textEdit->setReadOnly( true );
+ d->m_textEdit->setFocusPolicy( NoFocus );
+// d->m_textEdit->setAlignment( d->m_textEdit->alignment() | Qt::WordBreak );
+ d->m_textEdit->setFrameStyle( QFrame::NoFrame );
+ mainlay->addWidget( d->m_textEdit );
+
+ d->m_lineEditFirst = new KLineEdit( frame );
+// d->m_lineEditFirst->setValidator( d->m_vtor );
+ if ( d->m_coord1.valid() )
+ {
+ d->m_lineEditFirst->setText( d->m_doc.coordinateSystem().fromScreen( d->m_coord1, d->m_doc ) );
+ ok = true;
+ }
+ mainlay->addWidget( d->m_lineEditFirst );
+
+ connect( d->m_lineEditFirst, SIGNAL(textChanged(const QString&)),
+ this, SLOT(slotCoordsChanged(const QString&)) );
+
+ if ( d->m_coord2.valid() )
+ {
+ d->m_lineEditSecond = new KLineEdit( frame );
+// d->m_lineEditSecond->setValidator( d->m_vtor );
+ d->m_lineEditSecond->setText( d->m_doc.coordinateSystem().fromScreen( d->m_coord2, d->m_doc ) );
+ mainlay->addWidget( d->m_lineEditSecond );
+
+ connect( d->m_lineEditSecond, SIGNAL(textChanged(const QString&)),
+ this, SLOT(slotCoordsChanged(const QString&)) );
+
+ deltay += d->m_lineEditSecond->height() + spacingHint();
+ }
+
+ resize( 400, 160 + deltay );
+
+ d->m_lineEditFirst->setFocus();
+
+ enableButtonOK( ok );
+}
+
+KigInputDialog::KigInputDialog( QWidget* parent, const Goniometry& g )
+ : KDialogBase( parent, "kigdialog", true, i18n( "Set Angle Size" ), Ok|Cancel, Cancel, true ),
+ d( new KigInputDialogPrivate() )
+{
+ d->m_gonio = g;
+ d->m_gonioIsNum = true;
+
+ QFrame* frame = makeMainWidget();
+ QVBoxLayout* mainlay = new QVBoxLayout( frame, 0, spacingHint() );
+ mainlay->activate();
+
+ d->m_label = new QLabel( frame );
+ d->m_label->setText( i18n( "Insert the new size of this angle:" ) );
+ mainlay->addWidget( d->m_label );
+
+ QHBoxLayout* horlay = new QHBoxLayout( 0, 0, spacingHint() );
+ horlay->activate();
+
+ d->m_lineEditFirst = new KLineEdit( frame );
+ d->m_lineEditFirst->setText( QString::number( d->m_gonio.value() ) );
+ QWhatsThis::add(
+ d->m_lineEditFirst,
+ i18n( "Use this edit field to modify the size of this angle." ) );
+ horlay->addWidget( d->m_lineEditFirst );
+
+ d->m_comboBox = new KComboBox( frame );
+ d->m_comboBox->insertStringList( Goniometry::systemList() );
+ d->m_comboBox->setCurrentItem( d->m_gonio.system() );
+ QWhatsThis::add(
+ d->m_comboBox,
+ i18n( "Choose from this list the goniometric unit you want to use to "
+ "modify the size of this angle.<br>\n"
+ "If you switch to another unit, the value in the edit field on "
+ "the left will be converted to the new selected unit." ) );
+ horlay->addWidget( d->m_comboBox );
+
+ mainlay->addLayout( horlay );
+
+ connect( d->m_lineEditFirst, SIGNAL(textChanged(const QString&)),
+ this, SLOT(slotGonioTextChanged(const QString&)) );
+ connect( d->m_comboBox, SIGNAL(activated(int)),
+ this, SLOT(slotGonioSystemChanged(int)) );
+
+ resize( 350, 100 );
+
+ d->m_lineEditFirst->setFocus();
+}
+
+void KigInputDialog::keyPressEvent( QKeyEvent* e )
+{
+ if ( ( e->key() == Qt::Key_Return ) && ( e->state() == 0 ) )
+ {
+ if ( actionButton( Ok )->isEnabled() )
+ {
+ actionButton( Ok )->animateClick();
+ e->accept();
+ return;
+ }
+ }
+ else if ( ( e->key() == Qt::Key_Escape ) && ( e->state() == 0 ) )
+ {
+ actionButton( Cancel )->animateClick();
+ e->accept();
+ return;
+ }
+
+}
+
+void KigInputDialog::slotCoordsChanged( const QString& )
+{
+ int p = 0;
+ QString t = d->m_lineEditFirst->text();
+ bool ok = d->m_vtor->validate( t, p ) == QValidator::Acceptable;
+ if ( ok )
+ d->m_coord1 = d->m_doc.coordinateSystem().toScreen( t, ok );
+ if ( d->m_lineEditSecond )
+ {
+ p = 0;
+ t = d->m_lineEditSecond->text();
+ ok &= d->m_vtor->validate( t, p ) == QValidator::Acceptable;
+ if ( ok )
+ d->m_coord2 = d->m_doc.coordinateSystem().toScreen( t, ok );
+ }
+
+ enableButtonOK( ok );
+}
+
+void KigInputDialog::slotGonioSystemChanged( int index )
+{
+ if ( d->m_gonioIsNum )
+ {
+ Goniometry::System newsys = Goniometry::intToSystem( index );
+ d->m_gonio.convertTo( newsys );
+ d->m_lineEditFirst->setText( QString::number( d->m_gonio.value() ) );
+ }
+}
+
+void KigInputDialog::slotGonioTextChanged( const QString& txt )
+{
+ if ( txt.isNull() )
+ d->m_gonioIsNum = false;
+ else
+ {
+ double v = txt.toDouble( &(d->m_gonioIsNum) );
+ d->m_gonio.setValue( v );
+ }
+ enableButtonOK( d->m_gonioIsNum );
+}
+
+
+Coordinate KigInputDialog::coordinateFirst() const
+{
+ return d->m_coord1;
+}
+
+Coordinate KigInputDialog::coordinateSecond() const
+{
+ return d->m_coord2;
+}
+
+Goniometry KigInputDialog::goniometry() const
+{
+ return d->m_gonio;
+}
+
+void KigInputDialog::getCoordinate( const QString& caption, const QString& label,
+ QWidget* parent, bool* ok, const KigDocument& doc, Coordinate* cvalue )
+{
+ getTwoCoordinates( caption, label, parent, ok, doc, cvalue, 0 );
+}
+
+void KigInputDialog::getTwoCoordinates( const QString& caption, const QString& label,
+ QWidget* parent, bool* ok, const KigDocument& doc, Coordinate* cvalue,
+ Coordinate* cvalue2 )
+{
+ KigInputDialog dlg( caption, label, parent, doc, cvalue, cvalue2 );
+
+ *ok = ( dlg.exec() == Accepted );
+
+ if ( *ok )
+ {
+ Coordinate a = dlg.coordinateFirst();
+ *cvalue = a;
+ if ( cvalue2 )
+ {
+ Coordinate b = dlg.coordinateSecond();
+ *cvalue2 = b;
+ }
+ }
+
+}
+
+Goniometry KigInputDialog::getAngle( QWidget* parent, bool* ok, const Goniometry& g )
+{
+ KigInputDialog dlg( parent, g );
+
+ *ok = ( dlg.exec() == Accepted );
+
+ return dlg.goniometry();
+}
diff --git a/kig/misc/kiginputdialog.h b/kig/misc/kiginputdialog.h
new file mode 100644
index 00000000..afdd303d
--- /dev/null
+++ b/kig/misc/kiginputdialog.h
@@ -0,0 +1,123 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2005 Pino Toscano <toscano.pino@tiscali.it>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#ifndef KIG_MISC_KIGINPUTDIALOG_H
+#define KIG_MISC_KIGINPUTDIALOG_H
+
+class QString;
+class Coordinate;
+class Goniometry;
+class KigDocument;
+class KigInputDialogPrivate;
+
+#include <kdialogbase.h>
+
+/**
+ * The KigInputDialog class provides easy ways of interaction with the user.
+ * For example, it provides a flexible way to get one or two coordinates at
+ * once.
+ *
+ * It provides several static convenience functions: getCoordinate(),
+ * getTwoCoordinates(), getAngle().
+ */
+class KigInputDialog
+ : KDialogBase
+{
+Q_OBJECT
+
+public:
+
+private:
+ KigInputDialog( const QString& caption, const QString& label, QWidget* parent,
+ const KigDocument& doc, Coordinate* c1, Coordinate* c2 );
+ KigInputDialog( QWidget* parent, const Goniometry& g );
+
+ virtual void keyPressEvent( QKeyEvent* e );
+
+ KigInputDialogPrivate* const d;
+ friend class KInputDialogPrivate;
+
+ Coordinate coordinateFirst() const;
+ Coordinate coordinateSecond() const;
+ Goniometry goniometry() const;
+
+private slots:
+ void slotCoordsChanged( const QString& );
+ void slotGonioSystemChanged( int index );
+ void slotGonioTextChanged( const QString& txt );
+
+public:
+ /**
+ * Static convenience function to get a Coordinate from the user.
+ *
+ * \param caption caption of the dialog
+ * \param label text of the label of the dialog
+ * \param parent parent of the dialog widget
+ * \param ok it will be set to true if the user pressed Ok after inserting a
+ * well-formatted Coordinate
+ * \param doc the actual Kig document
+ * \param cvalue a pointer to a Coordinate class. If the user inserted
+ * successfully a new Coordinate, the value will be stored
+ * here. If this points to a valid Coordinate, then it will be
+ * displayed as initial value of the correspondenting text edit
+ */
+ static void getCoordinate( const QString& caption, const QString& label,
+ QWidget* parent, bool* ok, const KigDocument& doc, Coordinate* cvalue );
+
+ /**
+ * Static convenience function to get two Coordinates at once from the user.
+ *
+ * \param caption caption of the dialog
+ * \param label text of the label of the dialog
+ * \param parent parent of the dialog widget
+ * \param ok it will be set to true if the user pressed Ok after inserting
+ * well-formatted Coordinates
+ * \param doc the actual Kig document
+ * \param cvalue a pointer to a Coordinate class. If the user inserted
+ * successfully new Coordinates, the value of the first
+ * Coordinate will be stored here. If this points to a valid
+ * Coordinate, then it will be displayed as initial value of
+ * the text edit representing the first Coordinate.
+ * \param cvalue2 a pointer to a Coordinate class. If the user inserted
+ * successfully new Coordinates, the value of the second
+ * Coordinate will be stored here. If this points to a valid
+ * Coordinate, then it will be displayed as initial value of
+ * the text edit representing the second Coordinate.
+ */
+ static void getTwoCoordinates( const QString& caption, const QString& label,
+ QWidget* parent, bool* ok, const KigDocument& doc, Coordinate* cvalue,
+ Coordinate* cvalue2 );
+
+ /**
+ * Static convenience function to get an angle incapsulated in a Goniometry
+ * class.
+ *
+ * \param parent parent of the dialog widget
+ * \param ok it will be set to true if the user pressed Ok after inserting a
+ * well-formatted angle
+ * \param g the Goniometry class containing the original angle we are going
+ * to modify.
+ *
+ * \return a Goniometry class containing the new angle
+ */
+ static Goniometry getAngle( QWidget* parent, bool* ok, const Goniometry& g );
+};
+
+#endif
diff --git a/kig/misc/kignumerics.cpp b/kig/misc/kignumerics.cpp
new file mode 100644
index 00000000..4711d058
--- /dev/null
+++ b/kig/misc/kignumerics.cpp
@@ -0,0 +1,389 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "kignumerics.h"
+#include "common.h"
+
+/*
+ * compute one of the roots of a cubic polynomial
+ * if xmin << 0 or xmax >> 0 then autocompute a bound for all the
+ * roots
+ */
+
+double calcCubicRoot ( double xmin, double xmax, double a,
+ double b, double c, double d, int root, bool& valid, int& numroots )
+{
+ // renormalize: positive a and infinity norm = 1
+
+ double infnorm = fabs(a);
+ if ( infnorm < fabs(b) ) infnorm = fabs(b);
+ if ( infnorm < fabs(c) ) infnorm = fabs(c);
+ if ( infnorm < fabs(d) ) infnorm = fabs(d);
+ if ( a < 0 ) infnorm = -infnorm;
+ a /= infnorm;
+ b /= infnorm;
+ c /= infnorm;
+ d /= infnorm;
+
+ const double small = 1e-7;
+ valid = false;
+ if ( fabs(a) < small )
+ {
+ if ( fabs(b) < small )
+ {
+ if ( fabs(c) < small )
+ { // degree = 0;
+ numroots = 0;
+ return 0.0;
+ }
+ // degree = 1
+ double rootval = -d/c;
+ numroots = 1;
+ if ( rootval < xmin || xmax < rootval ) numroots--;
+ if ( root > numroots ) return 0.0;
+ valid = true;
+ return rootval;
+ }
+ // degree = 2
+ if ( b < 0 ) { b = -b; c = -c; d = -d; }
+ double discrim = c*c - 4*b*d;
+ numroots = 2;
+ if ( discrim < 0 )
+ {
+ numroots = 0;
+ return 0.0;
+ }
+ discrim = sqrt(discrim)/(2*fabs(b));
+ double rootmiddle = -c/(2*b);
+ if ( rootmiddle - discrim < xmin ) numroots--;
+ if ( rootmiddle + discrim > xmax ) numroots--;
+ if ( rootmiddle + discrim < xmin ) numroots--;
+ if ( rootmiddle - discrim > xmax ) numroots--;
+ if ( root > numroots ) return 0.0;
+ valid = true;
+ if ( root == 2 || rootmiddle - discrim < xmin ) return rootmiddle + discrim;
+ return rootmiddle - discrim;
+ }
+
+ if ( xmin < -1e8 || xmax > 1e8 )
+ {
+
+ // compute a bound for all the real roots:
+
+ xmax = fabs(d/a);
+ if ( fabs(c/a) + 1 > xmax ) xmax = fabs(c/a) + 1;
+ if ( fabs(b/a) + 1 > xmax ) xmax = fabs(b/a) + 1;
+ xmin = -xmax;
+ }
+
+ // computing the coefficients of the Sturm sequence
+ double p1a = 2*b*b - 6*a*c;
+ double p1b = b*c - 9*a*d;
+ double p0a = c*p1a*p1a + p1b*(3*a*p1b - 2*b*p1a);
+
+ int varbottom = calcCubicVariations (xmin, a, b, c, d, p1a, p1b, p0a);
+ int vartop = calcCubicVariations (xmax, a, b, c, d, p1a, p1b, p0a);
+ numroots = vartop - varbottom;
+ valid = false;
+ if (root <= varbottom || root > vartop ) return 0.0;
+
+ valid = true;
+
+ // now use bisection to separate the required root
+ double dx = (xmax - xmin)/2;
+ while ( vartop - varbottom > 1 )
+ {
+ if ( fabs( dx ) < 1e-8 ) return (xmin + xmax)/2;
+ double xmiddle = xmin + dx;
+ int varmiddle = calcCubicVariations (xmiddle, a, b, c, d, p1a, p1b, p0a);
+ if ( varmiddle < root ) // I am below
+ {
+ xmin = xmiddle;
+ varbottom = varmiddle;
+ } else {
+ xmax = xmiddle;
+ vartop = varmiddle;
+ }
+ dx /= 2;
+ }
+
+ /*
+ * now [xmin, xmax] enclose a single root, try using Newton
+ */
+ if ( vartop - varbottom == 1 )
+ {
+ double fval1 = a; // double check...
+ double fval2 = a;
+ fval1 = b + xmin*fval1;
+ fval2 = b + xmax*fval2;
+ fval1 = c + xmin*fval1;
+ fval2 = c + xmax*fval2;
+ fval1 = d + xmin*fval1;
+ fval2 = d + xmax*fval2;
+ assert ( fval1 * fval2 <= 0 );
+ return calcCubicRootwithNewton ( xmin, xmax, a, b, c, d, 1e-8 );
+ }
+ else // probably a double root here!
+ return ( xmin + xmax )/2;
+}
+
+/*
+ * computation of the number of sign changes in the sturm sequence for
+ * a third degree polynomial at x. This number counts the number of
+ * roots of the polynomial on the left of point x.
+ *
+ * a, b, c, d: coefficients of the third degree polynomial (a*x^3 + ...)
+ *
+ * the second degree polynomial in the sturm sequence is just minus the
+ * derivative, so we don't need to compute it.
+ *
+ * p1a*x + p1b: is the third (first degree) polynomial in the sturm sequence.
+ *
+ * p0a: is the (constant) fourth polynomial of the sturm sequence.
+ */
+
+int calcCubicVariations (double x, double a, double b, double c,
+ double d, double p1a, double p1b, double p0a)
+{
+ double fval, fpval;
+ fval = fpval = a;
+ fval = b + x*fval;
+ fpval = fval + x*fpval;
+ fval = c + x*fval;
+ fpval = fval + x*fpval;
+ fval = d + x*fval;
+
+ double f1val = p1a*x + p1b;
+
+ bool f3pos = fval >= 0;
+ bool f2pos = fpval <= 0;
+ bool f1pos = f1val >= 0;
+ bool f0pos = p0a >= 0;
+
+ int variations = 0;
+ if ( f3pos != f2pos ) variations++;
+ if ( f2pos != f1pos ) variations++;
+ if ( f1pos != f0pos ) variations++;
+ return variations;
+}
+
+/*
+ * use newton to solve a third degree equation with already isolated
+ * root
+ */
+
+inline void calcCubicDerivatives ( double x, double a, double b, double c,
+ double d, double& fval, double& fpval, double& fppval )
+{
+ fval = fpval = fppval = a;
+ fval = b + x*fval;
+ fpval = fval + x*fpval;
+ fppval = fpval + x*fppval; // this is really half the second derivative
+ fval = c + x*fval;
+ fpval = fval + x*fpval;
+ fval = d + x*fval;
+}
+
+double calcCubicRootwithNewton ( double xmin, double xmax, double a,
+ double b, double c, double d, double tol )
+{
+ double fval, fpval, fppval;
+
+ double fval1, fval2, fpval1, fpval2, fppval1, fppval2;
+ calcCubicDerivatives ( xmin, a, b, c, d, fval1, fpval1, fppval1 );
+ calcCubicDerivatives ( xmax, a, b, c, d, fval2, fpval2, fppval2 );
+ assert ( fval1 * fval2 <= 0 );
+
+ assert ( xmax > xmin );
+ while ( xmax - xmin > tol )
+ {
+ // compute the values of function, derivative and second derivative:
+ assert ( fval1 * fval2 <= 0 );
+ if ( fppval1 * fppval2 < 0 || fpval1 * fpval2 < 0 )
+ {
+ double xmiddle = (xmin + xmax)/2;
+ calcCubicDerivatives ( xmiddle, a, b, c, d, fval, fpval, fppval );
+ if ( fval1*fval <= 0 )
+ {
+ xmax = xmiddle;
+ fval2 = fval;
+ fpval2 = fpval;
+ fppval2 = fppval;
+ } else {
+ xmin = xmiddle;
+ fval1 = fval;
+ fpval1 = fpval;
+ fppval1 = fppval;
+ }
+ } else
+ {
+ // now we have first and second derivative of constant sign, we
+ // can start with Newton from the Fourier point.
+ double x = xmin;
+ if ( fval2*fppval2 > 0 ) x = xmax;
+ double p = 1.0;
+ int iterations = 0;
+ while ( fabs(p) > tol && iterations++ < 100 )
+ {
+ calcCubicDerivatives ( x, a, b, c, d, fval, fpval, fppval );
+ p = fval/fpval;
+ x -= p;
+ }
+ if( iterations >= 100 )
+ {
+ // Newton scheme did not converge..
+ // we should end up with an invalid Coordinate
+ return double_inf;
+ };
+ return x;
+ }
+ }
+
+ // we cannot apply Newton, (perhaps we are at an inflection point)
+
+ return (xmin + xmax)/2;
+}
+
+/*
+ * This function computes the LU factorization of a mxn matrix, with
+ * m typically less then n. This is done with complete pivoting; the
+ * exchanges in columns are recorded in the integer vector "exchange"
+ */
+bool GaussianElimination( double *matrix[], int numrows,
+ int numcols, int exchange[] )
+{
+ // start gaussian elimination
+ for ( int k = 0; k < numrows; ++k )
+ {
+ // ricerca elemento di modulo massimo
+ double maxval = -double_inf;
+ int imax = k;
+ int jmax = k;
+ for( int i = k; i < numrows; ++i )
+ {
+ for( int j = k; j < numcols; ++j )
+ {
+ if (fabs(matrix[i][j]) > maxval)
+ {
+ maxval = fabs(matrix[i][j]);
+ imax = i;
+ jmax = j;
+ }
+ }
+ }
+
+ // row exchange
+ if ( imax != k )
+ for( int j = k; j < numcols; ++j )
+ {
+ double t = matrix[k][j];
+ matrix[k][j] = matrix[imax][j];
+ matrix[imax][j] = t;
+ }
+
+ // column exchange
+ if ( jmax != k )
+ for( int i = 0; i < numrows; ++i )
+ {
+ double t = matrix[i][k];
+ matrix[i][k] = matrix[i][jmax];
+ matrix[i][jmax] = t;
+ }
+
+ // remember this column exchange at step k
+ exchange[k] = jmax;
+
+ // we can't usefully eliminate a singular matrix..
+ if ( maxval == 0. ) return false;
+
+ // ciclo sulle righe
+ for( int i = k+1; i < numrows; ++i)
+ {
+ double mik = matrix[i][k]/matrix[k][k];
+ matrix[i][k] = mik; //ricorda il moltiplicatore... (not necessary)
+ // ciclo sulle colonne
+ for( int j = k+1; j < numcols; ++j )
+ {
+ matrix[i][j] -= mik*matrix[k][j];
+ }
+ }
+ }
+ return true;
+}
+
+/*
+ * solve an undetermined homogeneous triangular system. the matrix is nonzero
+ * on its diagonal. The last unknown(s) are chosen to be 1. The
+ * vector "exchange" contains exchanges to be performed on the
+ * final solution components.
+ */
+
+void BackwardSubstitution( double *matrix[], int numrows, int numcols,
+ int exchange[], double solution[] )
+{
+ // the system is homogeneous and underdetermined, the last unknown(s)
+ // are chosen = 1
+ for ( int j = numrows; j < numcols; ++j )
+ {
+ solution[j] = 1.0; // other choices are possible here
+ };
+
+ for( int k = numrows - 1; k >= 0; --k )
+ {
+ // backward substitution
+ solution[k] = 0.0;
+ for ( int j = k+1; j < numcols; ++j)
+ {
+ solution[k] -= matrix[k][j]*solution[j];
+ }
+ solution[k] /= matrix[k][k];
+ }
+
+ // ultima fase: riordinamento incognite
+
+ for( int k = numrows - 1; k >= 0; --k )
+ {
+ int jmax = exchange[k];
+ double t = solution[k];
+ solution[k] = solution[jmax];
+ solution[jmax] = t;
+ }
+}
+
+bool Invert3by3matrix ( const double m[3][3], double inv[3][3] )
+{
+ double det = m[0][0]*(m[1][1]*m[2][2] - m[1][2]*m[2][1]) -
+ m[0][1]*(m[1][0]*m[2][2] - m[1][2]*m[2][0]) +
+ m[0][2]*(m[1][0]*m[2][1] - m[1][1]*m[2][0]);
+ if (det == 0) return false;
+
+ for (int i=0; i < 3; i++)
+ {
+ for (int j=0; j < 3; j++)
+ {
+ int i1 = (i+1)%3;
+ int i2 = (i+2)%3;
+ int j1 = (j+1)%3;
+ int j2 = (j+2)%3;
+ inv[j][i] = (m[i1][j1]*m[i2][j2] - m[i1][j2]*m[i2][j1])/det;
+ }
+ }
+ return true;
+}
diff --git a/kig/misc/kignumerics.h b/kig/misc/kignumerics.h
new file mode 100644
index 00000000..7beef59f
--- /dev/null
+++ b/kig/misc/kignumerics.h
@@ -0,0 +1,47 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#ifndef KIG_MISC_KIGNUMERICS_H
+#define KIG_MISC_KIGNUMERICS_H
+
+#include <cmath>
+
+double calcCubicRoot ( double xmin, double xmax, double a,
+ double b, double c, double d, int root, bool& valid, int& numroots );
+
+int calcCubicVariations (double x, double a, double b, double c,
+ double d, double p1a, double p1b, double p0a);
+
+double calcCubicRootwithNewton ( double ymin, double ymax, double a,
+ double b, double c, double d, double tol );
+
+/**
+ * Gaussian Elimination. We return false if the matrix is singular,
+ * and can't be usefully eliminated..
+ */
+bool GaussianElimination( double *matrix[], int numrows, int numcols,
+ int scambio[] );
+
+void BackwardSubstitution( double *matrix[], int numrows, int numcols,
+ int scambio[], double solution[] );
+
+bool Invert3by3matrix ( const double m[3][3], double inv[3][3] );
+
+#endif // KIG_MISC_KIGNUMERICS_H
diff --git a/kig/misc/kigpainter.cpp b/kig/misc/kigpainter.cpp
new file mode 100644
index 00000000..e2b2f440
--- /dev/null
+++ b/kig/misc/kigpainter.cpp
@@ -0,0 +1,953 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002-2003 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "kigpainter.h"
+
+#include "../kig/kig_view.h"
+#include "../kig/kig_document.h"
+#include "../misc/goniometry.h"
+#include "../objects/object_holder.h"
+#include "../objects/curve_imp.h"
+#include "../objects/point_imp.h"
+#include "object_hierarchy.h"
+#include "common.h"
+#include "conic-common.h"
+#include "cubic-common.h"
+#include "coordinate_system.h"
+
+#include <qpen.h>
+
+#include <cmath>
+#include <stack>
+#include <functional>
+#include <algorithm>
+
+KigPainter::KigPainter( const ScreenInfo& si, QPaintDevice* device,
+ const KigDocument& doc, bool no )
+ : mP ( device ),
+ color( Qt::blue ),
+ style( Qt::SolidLine ),
+ pointstyle( 0 ),
+ width( -1 ),
+ brushStyle( Qt::NoBrush ),
+ brushColor( Qt::blue ),
+ mdoc( doc ),
+ msi( si ),
+ mNeedOverlay( no ),
+ overlayenlarge( 0 )
+{
+ mP.setBackgroundColor( Qt::white );
+}
+
+KigPainter::~KigPainter()
+{
+}
+
+void KigPainter::drawRect( const Rect& r )
+{
+ Rect rt = r.normalized();
+ QRect qr = toScreen(rt);
+ qr.normalize();
+ mP.drawRect(qr);
+ if( mNeedOverlay ) mOverlay.push_back( qr );
+}
+
+void KigPainter::drawRect( const QRect& r )
+{
+ mP.drawRect(r);
+ if( mNeedOverlay ) mOverlay.push_back( r );
+}
+
+void KigPainter::drawCircle( const Coordinate& center, const double radius )
+{
+ Coordinate bottomLeft = center - Coordinate(radius, radius);
+ Coordinate topRight = center + Coordinate(radius, radius);
+ Rect r( bottomLeft, topRight );
+ QRect qr = toScreen( r );
+ mP.drawEllipse ( qr );
+ if( mNeedOverlay ) circleOverlay( center, radius );
+}
+
+void KigPainter::drawSegment( const Coordinate& from, const Coordinate& to )
+{
+ QPoint tF = toScreen(from), tT = toScreen(to);
+ mP.drawLine( tF, tT );
+ if( mNeedOverlay ) segmentOverlay( from, to );
+}
+
+void KigPainter::drawFatPoint( const Coordinate& p )
+{
+ int twidth = width == -1 ? 5 : width;
+ mP.setPen( QPen( color, 1, style ) );
+ switch ( pointstyle )
+ {
+ case 0:
+ {
+ double radius = twidth * pixelWidth();
+ setBrushStyle( Qt::SolidPattern );
+ Coordinate rad( radius, radius );
+ rad /= 2;
+ Coordinate tl = p - rad;
+ Coordinate br = p + rad;
+ Rect r( tl, br );
+ QRect qr = toScreen( r );
+ mP.drawEllipse( qr );
+ if( mNeedOverlay ) mOverlay.push_back( qr );
+ break;
+ }
+ case 1:
+ {
+ double radius = twidth * pixelWidth();
+ setBrushStyle( Qt::NoBrush );
+ Coordinate rad( radius, radius );
+ rad /= 2;
+ Coordinate tl = p - rad;
+ Coordinate br = p + rad;
+ Rect r( tl, br );
+ QRect qr = toScreen( r );
+ mP.drawEllipse( qr );
+ if( mNeedOverlay ) mOverlay.push_back( qr );
+ break;
+ }
+ case 2:
+ {
+ double radius = twidth * pixelWidth();
+ Coordinate rad( radius, radius );
+ rad /= 2;
+ Coordinate tl = p - rad;
+ Coordinate br = p + rad;
+ Rect r( tl, br );
+ QRect qr = toScreen( r );
+ mP.drawRect( qr );
+ mP.fillRect( qr, QBrush( color, Qt::SolidPattern ) );
+ if( mNeedOverlay ) mOverlay.push_back( qr );
+ break;
+ }
+ case 3:
+ {
+ double radius = twidth * pixelWidth();
+ Coordinate rad( radius, radius );
+ rad /= 2;
+ Coordinate tl = p - rad;
+ Coordinate br = p + rad;
+ Rect r( tl, br );
+ QRect qr = toScreen( r );
+ mP.drawRect( qr );
+ if( mNeedOverlay ) mOverlay.push_back( qr );
+ break;
+ }
+ case 4:
+ {
+ double radius = twidth * pixelWidth();
+ Coordinate rad( radius, radius );
+ rad /= 2;
+ Coordinate tl = p - rad;
+ Coordinate br = p + rad;
+ Rect r( tl, br );
+ QRect qr = toScreen( r );
+ mP.setPen( QPen( color, 2 ) );
+ mP.drawLine( qr.topLeft(), qr.bottomRight() );
+ mP.drawLine( qr.topRight(), qr.bottomLeft() );
+ if( mNeedOverlay ) mOverlay.push_back( qr );
+ break;
+ }
+ }
+ mP.setPen( QPen( color, twidth, style ) );
+}
+
+void KigPainter::drawPoint( const Coordinate& p )
+{
+ mP.drawPoint( toScreen(p) );
+ if( mNeedOverlay ) pointOverlay( p );
+}
+
+void KigPainter::drawLine( const Coordinate& p1, const Coordinate& p2 )
+{
+ drawLine( LineData( p1, p2 ) );
+}
+
+void KigPainter::drawText( const Rect p, const QString s, int textFlags, int len )
+{
+ QRect t = toScreen(p);
+ int tf = textFlags;
+ t.moveBy( 2, 2 );
+ t.setWidth( t.width() - 4 );
+ t.setHeight( t.height() - 4 );
+ mP.drawText( t, tf, s, len );
+ if( mNeedOverlay ) textOverlay( t, s, tf, len );
+}
+
+void KigPainter::textOverlay( const QRect& r, const QString s, int textFlags, int len )
+{
+ // kdDebug() << Rect::fromQRect( mP.boundingRect( r, textFlags, s, len ) ) << endl;
+ QRect newr( mP.boundingRect( r, textFlags, s, len ) );
+ newr.setWidth( newr.width() + 4 );
+ newr.setHeight( newr.height() + 4 );
+ mOverlay.push_back( newr );
+}
+
+const Rect KigPainter::boundingRect( const Rect& r, const QString s,
+ int f, int l ) const
+{
+ QRect qr = mP.boundingRect( toScreen( r ), f, s, l );
+ qr.setWidth( qr.width() + 4 );
+ qr.setHeight( qr.height() + 4 );
+ return fromScreen( qr );
+}
+
+void KigPainter::setColor( const QColor& c )
+{
+ color = c;
+ mP.setPen( QPen( color, width == -1 ? 1 : width, style ) );
+}
+
+void KigPainter::setStyle( const PenStyle c )
+{
+ style = c;
+ mP.setPen( QPen( color, width == -1 ? 1 : width, style ) );
+}
+
+void KigPainter::setWidth( const int c )
+{
+ width = c;
+ if (c > 0) overlayenlarge = c - 1;
+ mP.setPen( QPen( color, width == -1 ? 1 : width, style ) );
+}
+
+void KigPainter::setPointStyle( const int p )
+{
+ pointstyle = p;
+}
+
+void KigPainter::setPen( const QPen& p )
+{
+ color = p.color();
+ width = p.width();
+ style = p.style();
+ mP.setPen(p);
+}
+
+void KigPainter::setBrush( const QBrush& b )
+{
+ brushStyle = b.style();
+ brushColor = b.color();
+ mP.setBrush( b );
+}
+
+void KigPainter::setBrushStyle( const BrushStyle c )
+{
+ brushStyle = c;
+ mP.setBrush( QBrush( brushColor, brushStyle ) );
+}
+
+void KigPainter::setBrushColor( const QColor& c )
+{
+ brushColor = c;
+ mP.setBrush( QBrush( brushColor, brushStyle ) );
+}
+
+bool KigPainter::getNightVision( ) const
+{
+ return mdoc.getNightVision();
+}
+
+QColor KigPainter::getColor() const
+{
+ return color;
+}
+
+/*
+static void setContains( QRect& r, const QPoint& p )
+{
+ if ( r.left() > p.x() ) r.setLeft( p.x() );
+ if ( r.right() < p.x() ) r.setRight( p.x() );
+ // this is correct, i think. In qt the bottom has the highest y
+ // coord...
+ if ( r.bottom() > p.y() ) r.setBottom( p.y() );
+ if ( r.top() < p.y() ) r.setTop( p.y() );
+}
+*/
+
+void KigPainter::drawPolygon( const std::vector<QPoint>& pts,
+ bool winding, int index, int npoints )
+{
+ QPen oldpen = mP.pen();
+ QBrush oldbrush = mP.brush();
+ setBrush( QBrush( color, Dense4Pattern ) );
+ setPen( Qt::NoPen );
+ // i know this isn't really fast, but i blame it all on Qt with its
+ // stupid container classes... what's wrong with the STL ?
+ QPointArray t( pts.size() );
+ int c = 0;
+ for( std::vector<QPoint>::const_iterator i = pts.begin(); i != pts.end(); ++i )
+ {
+ t.putPoints( c++, 1, i->x(), i->y() );
+ };
+ mP.drawPolygon( t, winding, index, npoints );
+ setPen( oldpen );
+ setBrush( oldbrush );
+ if( mNeedOverlay ) mOverlay.push_back( t.boundingRect() );
+}
+
+void KigPainter::drawArea( const std::vector<Coordinate>& pts, bool border )
+{
+ QPen oldpen = mP.pen();
+ QBrush oldbrush = mP.brush();
+ setBrush( QBrush( color, SolidPattern ) );
+ if ( border )
+ setPen( QPen( color, width == -1 ? 1 : width ) );
+ else
+ setPen( Qt::NoPen );
+ QPointArray t( pts.size() );
+ int c = 0;
+ for( std::vector<Coordinate>::const_iterator i = pts.begin(); i != pts.end(); ++i )
+ {
+ QPoint p = toScreen( *i );
+ t.putPoints( c++, 1, p.x(), p.y() );
+ }
+ mP.drawPolygon( t );
+ setPen( oldpen );
+ setBrush( oldbrush );
+ if( mNeedOverlay ) mOverlay.push_back( t.boundingRect() );
+}
+
+Rect KigPainter::window()
+{
+ return msi.shownRect();
+}
+
+void KigPainter::circleOverlayRecurse( const Coordinate& centre,
+ double radiussq,
+ const Rect& cr )
+{
+ Rect currentRect = cr.normalized();
+
+ if( !currentRect.intersects( window() ) ) return;
+
+ // this code is an adaptation of Marc Bartsch's code, from KGeo
+ Coordinate tl = currentRect.topLeft();
+ Coordinate br = currentRect.bottomRight();
+ Coordinate tr = currentRect.topRight();
+ Coordinate bl = currentRect.bottomLeft();
+ Coordinate c = currentRect.center();
+
+ // mp: we compute the minimum and maximum distance from the center
+ // of the circle and this rect
+ double distxmin = 0, distxmax = 0, distymin = 0, distymax = 0;
+ if ( centre.x >= tr.x ) distxmin = centre.x - tr.x;
+ if ( centre.x <= bl.x ) distxmin = bl.x - centre.x;
+ if ( centre.y >= tr.y ) distymin = centre.y - tr.y;
+ if ( centre.y <= bl.y ) distymin = bl.y - centre.y;
+ distxmax = fabs(centre.x - c.x) + currentRect.width()/2;
+ distymax = fabs(centre.y - c.y) + currentRect.height()/2;
+ // this should take into account the thickness of the line...
+ distxmin -= pixelWidth();
+ if (distxmin < 0) distxmin = 0;
+ distxmax += pixelWidth();
+ distymin -= pixelWidth();
+ if (distymin < 0) distymin = 0;
+ distymax += pixelWidth();
+ double distminsq = distxmin*distxmin + distymin*distymin;
+ double distmaxsq = distxmax*distxmax + distymax*distymax;
+
+ // if the circle doesn't touch this rect, we return
+ // too far from the centre
+ if (distminsq > radiussq) return;
+
+ // too near to the centre
+ if (distmaxsq < radiussq) return;
+
+ // the rect contains some of the circle
+ // -> if it's small enough, we keep it
+ if( currentRect.width() < overlayRectSize() ) {
+ mOverlay.push_back( toScreenEnlarge( currentRect) );
+ } else {
+ // this func works recursive: we subdivide the current rect, and if
+ // it is of a good size, we keep it, otherwise we handle it again
+ double width = currentRect.width() / 2;
+ double height = currentRect.height() / 2;
+ Rect r1 ( c, -width, -height);
+ r1.normalize();
+ circleOverlayRecurse(centre, radiussq, r1);
+ Rect r2 ( c, width, -height);
+ r2.normalize();
+ circleOverlayRecurse(centre, radiussq, r2);
+ Rect r3 ( c, -width, height);
+ r3.normalize();
+ circleOverlayRecurse(centre, radiussq, r3);
+ Rect r4 ( c, width, height);
+ r4.normalize();
+ circleOverlayRecurse(centre, radiussq, r4);
+ };
+}
+
+void KigPainter::circleOverlay( const Coordinate& centre, double radius )
+{
+ double t = radius + pixelWidth();
+ Coordinate r( t, t );
+ Coordinate bottomLeft = centre - r;
+ Coordinate topRight = centre + r;
+ Rect rect( bottomLeft, topRight );
+ circleOverlayRecurse ( centre , radius*radius, rect );
+}
+
+void KigPainter::segmentOverlay( const Coordinate& p1, const Coordinate& p2 )
+{
+ // this code is based upon what Marc Bartsch wrote for KGeo
+
+ // some stuff we may need:
+ Coordinate p3 = p2 - p1;
+ Rect border = window();
+// double length = p3.length();
+ // mp: using the l-infinity distance is more natural here
+ double length = fabs(p3.x);
+ if ( fabs( p3.y ) > length ) length = fabs( p3.y );
+ if ( length < pixelWidth() )
+ {
+ // hopefully prevent SIGZERO's
+ mOverlay.push_back( toScreen( Rect( p1, p2 ) ) );
+ return;
+ };
+ p3 *= overlayRectSize();
+ p3 /= length;
+
+ int counter = 0;
+
+ Rect r(p1, p2);
+ r.normalize();
+
+ for (;;) {
+ Rect tR( Coordinate( 0, 0 ), overlayRectSize(), overlayRectSize() );
+ Coordinate tP = p1+p3*counter;
+ tR.setCenter(tP);
+ if (!tR.intersects(r))
+ {
+ //kdDebug()<< "stopped after "<< counter << " passes." << endl;
+ break;
+ }
+ if (tR.intersects(border)) mOverlay.push_back( toScreenEnlarge( tR ) );
+ if (++counter > 100)
+ {
+ kdDebug()<< k_funcinfo << "counter got too big :( " << endl;
+ break;
+ }
+ }
+}
+
+double KigPainter::overlayRectSize()
+{
+ return 20 * pixelWidth();
+}
+
+void KigPainter::pointOverlay( const Coordinate& p1 )
+{
+ Rect r( p1, 3*pixelWidth(), 3*pixelWidth());
+ r.setCenter( p1 );
+ mOverlay.push_back( toScreen( r) );
+}
+
+double KigPainter::pixelWidth()
+{
+ return msi.pixelWidth();
+}
+
+void KigPainter::setWholeWinOverlay()
+{
+ mOverlay.clear();
+ mOverlay.push_back( mP.viewport() );
+ // don't accept any more overlay's...
+ mNeedOverlay = false;
+}
+
+QPoint KigPainter::toScreen( const Coordinate p ) const
+{
+ return msi.toScreen( p );
+}
+
+void KigPainter::drawGrid( const CoordinateSystem& c, bool showGrid, bool showAxes )
+{
+ c.drawGrid( *this, showGrid, showAxes );
+ setWholeWinOverlay();
+}
+
+void KigPainter::drawObject( const ObjectHolder* o, bool ss )
+{
+ o->draw( *this, ss );
+}
+
+void KigPainter::drawObjects( const std::vector<ObjectHolder*>& os, bool sel )
+{
+ drawObjects( os.begin(), os.end(), sel );
+}
+
+void KigPainter::drawFilledRect( const QRect& r )
+{
+ QPen pen( Qt::black, 1, Qt::DotLine );
+ setPen( pen );
+ setBrush( QBrush( Qt::cyan, Dense6Pattern ) );
+ drawRect( r.normalize() );
+}
+
+void KigPainter::drawTextStd( const QPoint& p, const QString& s )
+{
+ if ( s.isNull() ) return;
+ // tf = text formatting flags
+ int tf = AlignLeft | AlignTop | DontClip | WordBreak;
+ // we need the rect where we're going to paint text
+ setPen(QPen(Qt::blue, 1, SolidLine));
+ setBrush(Qt::NoBrush);
+ drawText( Rect(
+ msi.fromScreen(p), window().bottomRight()
+ ).normalized(), s, tf );
+
+}
+
+QRect KigPainter::toScreen( const Rect r ) const
+{
+ return msi.toScreen( r );
+}
+
+QRect KigPainter::toScreenEnlarge( const Rect r ) const
+{
+ if ( overlayenlarge == 0 ) return msi.toScreen( r );
+
+ QRect qr = msi.toScreen( r );
+ qr.moveBy ( -overlayenlarge, -overlayenlarge );
+ int w = qr.width();
+ int h = qr.height();
+ qr.setWidth (w + 2*overlayenlarge);
+ qr.setHeight (h + 2*overlayenlarge);
+ return qr;
+}
+
+void KigPainter::drawSimpleText( const Coordinate& c, const QString s )
+{
+ int tf = AlignLeft | AlignTop | DontClip | WordBreak;
+ drawText( c, s, tf);
+}
+
+void KigPainter::drawText( const Coordinate p, const QString s,
+ int textFlags, int len )
+{
+ drawText( Rect( p, mP.window().right(), mP.window().top() ),
+ s, textFlags, len );
+}
+const Rect KigPainter::simpleBoundingRect( const Coordinate& c, const QString s )
+{
+ int tf = AlignLeft | AlignTop | DontClip | WordBreak;
+ return boundingRect( c, s, tf );
+}
+
+const Rect KigPainter::boundingRect( const Coordinate& c, const QString s,
+ int f, int l ) const
+{
+ return boundingRect( Rect( c, mP.window().right(), mP.window().top() ),
+ s, f, l );
+}
+
+Coordinate KigPainter::fromScreen( const QPoint& p ) const
+{
+ return msi.fromScreen( p );
+}
+
+Rect KigPainter::fromScreen( const QRect& r ) const
+{
+ return msi.fromScreen( r );
+}
+
+void KigPainter::drawRay( const Coordinate& a, const Coordinate& b )
+{
+ Coordinate tb = b;
+ calcRayBorderPoints( a, tb, window() );
+ drawSegment( a, tb );
+}
+
+typedef std::pair<double,Coordinate> coordparampair;
+
+struct workitem
+{
+ workitem( coordparampair f, coordparampair s, Rect *o) :
+ first(f), second(s), overlay(o) {}
+ coordparampair first;
+ coordparampair second;
+ Rect *overlay;
+};
+
+void KigPainter::drawLine( const LineData& d )
+{
+ if ( d.a != d.b )
+ {
+ LineData l = calcBorderPoints( d, window() );
+ drawSegment( l.a, l.b );
+ }
+}
+
+void KigPainter::drawSegment( const LineData& d )
+{
+ drawSegment( d.a, d.b );
+}
+
+void KigPainter::drawRay( const LineData& d )
+{
+ drawRay( d.a, d.b );
+}
+
+void KigPainter::drawAngle( const Coordinate& cpoint, const double dstartangle,
+ const double dangle )
+{
+ // convert to 16th of degrees...
+ const int startangle = static_cast<int>( Goniometry::convert( 16 * dstartangle, Goniometry::Rad, Goniometry::Deg ) );
+ const int angle = static_cast<int>( Goniometry::convert( 16 * dangle, Goniometry::Rad, Goniometry::Deg ) );
+
+ QPoint point = toScreen( cpoint );
+
+// int radius = mP.window().width() / 5;
+ int radius = 50;
+ QRect surroundingRect( 0, 0, radius*2, radius*2 );
+ surroundingRect.moveCenter( point );
+
+ mP.drawArc( surroundingRect, startangle, angle );
+
+ // now for the arrow...
+ QPoint end( static_cast<int>( point.x() + radius * cos( dstartangle + dangle ) ),
+ static_cast<int>( point.y() - radius * sin( dstartangle + dangle ) ) );
+ QPoint vect = (end - point);
+ double vectlen = sqrt( float( vect.x() * vect.x() + vect.y() * vect.y() ) );
+ QPoint orthvect( -vect.y(), vect.x() );
+ vect = vect * 6 / vectlen;
+ orthvect = orthvect * 6 / vectlen;
+
+ QPointArray arrow( 3 );
+ arrow.setPoint( 0, end );
+ arrow.setPoint( 1, end + orthvect + vect );
+ arrow.setPoint( 2, end + orthvect - vect );
+// std::vector<QPoint> arrow;
+// arrow.push_back( end );
+// arrow.push_back( end + orthvect + vect );
+// arrow.push_back( end + orthvect - vect );
+
+ setBrushStyle( Qt::SolidPattern );
+// drawPolygon( arrow );
+ mP.drawPolygon( arrow, false, 0, -1 );
+
+// if ( mNeedOverlay ) mOverlay.push_back( toScreen( r ) );
+ setWholeWinOverlay(); //mp: ugly! why not compute a correct overlay?
+ // mOverlay.push_back( arrow.boundingRect() );
+}
+
+void KigPainter::drawPolygon( const std::vector<Coordinate>& pts,
+ bool winding, int index, int npoints )
+{
+ using namespace std;
+ vector<QPoint> points;
+ for ( uint i = 0; i < pts.size(); ++i )
+ points.push_back( toScreen( pts[i] ) );
+ drawPolygon( points, winding, index, npoints );
+}
+
+void KigPainter::drawVector( const Coordinate& a, const Coordinate& b )
+{
+ // bugfix...
+ if ( a == b ) return;
+ // the segment
+ drawSegment( a, b );
+ // the arrows...
+ Coordinate dir = b - a;
+ Coordinate perp( dir.y, -dir.x );
+ double length = perp.length();
+ perp *= 10* pixelWidth();
+ perp /= length;
+ dir *= 10 * pixelWidth();
+ dir /= length;
+ Coordinate c = b - dir + perp;
+ Coordinate d = b - dir - perp;
+ // draw the arrow lines with a normal style
+ mP.setPen( QPen( color, width == -1 ? 1 : width, Qt::SolidLine ) );
+ drawSegment( b, c );
+ drawSegment( b, d );
+ // setting again the original style
+ mP.setPen( QPen( color, width == -1 ? 1 : width, style ) );
+}
+
+/* *** this function is commented out ***
+inline Coordinate locusGetCoord( double p, const CurveImp* curve, const ObjectHierarchy& h,
+ bool& valid, const KigDocument& doc )
+{
+ Coordinate pt = curve->getPoint( p, valid, doc );
+ if ( ! valid ) return Coordinate();
+ PointImp pimp( pt );
+ Args args;
+ args.push_back( &pimp );
+ std::vector<ObjectImp*> calced = h.calc( args, doc );
+ assert( calced.size() == 1 );
+ ObjectImp* o = calced.front();
+ Coordinate ret;
+ if ( o->inherits( ObjectImp::ID_PointImp ) )
+ {
+ valid = true;
+ ret = static_cast<PointImp*>( o )->coordinate();
+ }
+ else
+ valid = false;
+ delete o;
+ return ret;
+};
+*/
+
+class CurveImpPointCalcer
+{
+ const CurveImp* curve;
+public:
+ CurveImpPointCalcer( const CurveImp* c )
+ : curve( c )
+ {
+ }
+ static const double endinterval;
+ inline const Coordinate getPoint( double param, const KigDocument& d ) const {
+ return curve->getPoint( param, d );
+ }
+};
+
+const double CurveImpPointCalcer::endinterval = 1.;
+
+void KigPainter::drawCurve( const CurveImp* curve )
+{
+ // we manage our own overlay
+ bool tNeedOverlay = mNeedOverlay;
+ mNeedOverlay = false;
+
+ QPen pen = mP.pen();
+
+ // this stack contains pairs of Coordinates ( parameter intervals )
+ // that we still need to process:
+ std::stack<workitem> workstack;
+ // mp: this stack contains all the generated overlays:
+ // the strategy for generating the overlay structure is the same
+ // recursive-like used to draw the segments: a new rectangle is
+ // generated whenever the length of a segment becomes lower than
+ // overlayRectSize(), or if the segment would be drawn anyway
+ // to avoid strange things from happening we impose that the distance
+ // in parameter space be less than a threshold before generating
+ // any overlay.
+ //
+ // The third parameter in workitem is a pointer into a stack of
+ // all generated rectangles (in real coordinate space); if 0
+ // there is no rectangles associated to that segment yet.
+ //
+ // Using the final mOverlay stack would be much more efficient, but
+ // 1. needs transformations into window space
+ // 2. would be more difficult to drop rectangles not intersecting
+ // the window.
+ std::stack<Rect> overlaystack;
+
+ // mp: the original version in which an initial set of 20 intervals
+ // were pushed onto the stack is replaced by a single interval and
+ // by forcing subdivision till h < hmax (with more or less the same
+ // final result).
+ // First push the [0,1] interval into the stack:
+
+ Coordinate coo1 = curve->getPoint( 0., mdoc );
+ Coordinate coo2 = curve->getPoint( 1., mdoc );
+ workstack.push( workitem(
+ coordparampair( 0., coo1 ),
+ coordparampair( 1., coo2 ),
+ 0 ) );
+
+ // maxlength is the square of the maximum size that we allow
+ // between two points..
+ double maxlength = 1.5 * pixelWidth();
+ maxlength *= maxlength;
+ // error squared is required to be less that sigma (half pixel)
+ double sigma = maxlength/4;
+ // distance between two parameter values cannot be too small
+ double hmin = 3e-5;
+ // distance between two parameter values cannot be too large
+ double hmax = 1./40;
+ double hmaxoverlay = 1./8;
+
+ int count = 1; // the number of segments we've already
+ // visited...
+ static const int maxnumberofpoints = 1000;
+
+ const Rect& sr = window();
+
+ // what this algorithm does is approximating the curve with a set of
+ // segments. we don't draw the individual segments, but use
+ // QPainter::drawPolyline() so that the line styles work properly.
+ // Possibly there are performance advantages as well ? this array
+ // is a buffer of the polyline approximation of the part of the
+ // curve that we are currently processing.
+ QPointArray curpolyline( 1000 );
+ int curpolylinenextfree = 0;
+
+ // we don't use recursion, but a stack based approach for efficiency
+ // concerns...
+ while ( ! workstack.empty() && count < maxnumberofpoints )
+ {
+ workitem curitem = workstack.top();
+ workstack.pop();
+ bool curitemok = true;
+ while ( curitemok && count++ < maxnumberofpoints )
+ {
+ double t0 = curitem.first.first;
+ double t1 = curitem.second.first;
+ Coordinate p0 = curitem.first.second;
+ bool valid0 = p0.valid();
+ Coordinate p1 = curitem.second.second;
+ bool valid1 = p1.valid();
+
+ // we take the middle parameter of the two previous points...
+ double t2 = ( t0 + t1 ) / 2;
+ double h = fabs( t1 - t0 ) /2;
+
+ // if exactly one of the two endpoints is invalid, then
+ // we prefer to find an internal value of the parameter
+ // separating valid points from invalid points. We use
+ // a bisection strategy (this is not implemented yet!)
+// if ( ( valid0 && ! valid1 ) || ( valid1 && ! valid0 ) )
+// {
+// while ( h >= hmin )
+// {
+// .......................................
+// }
+// }
+
+ Rect *overlaypt = curitem.overlay;
+ Coordinate p2 = curve->getPoint( t2, mdoc );
+ bool allvalid = p2.valid() && valid0 && valid1;
+ bool dooverlay = ! overlaypt && h < hmaxoverlay && valid0 && valid1
+ && fabs( p0.x - p1.x ) <= overlayRectSize()
+ && fabs( p0.y - p1.y ) <= overlayRectSize();
+ bool addn = sr.contains( p2 ) || h >= hmax;
+ // estimated error between the curve and the segments
+ double errsq = 1e21;
+ if ( allvalid ) errsq = (0.5*p0 + 0.5*p1 - p2).squareLength();
+ errsq /= 4;
+ curitemok = false;
+// bool dodraw = allvalid && h < hmax && ( errsq < sigma || h < hmin );
+ bool dodraw = allvalid && h < hmax && errsq < sigma;
+ if ( tNeedOverlay && ( dooverlay || dodraw ) )
+ {
+ Rect newoverlay( p0, p1 );
+ overlaystack.push( newoverlay );
+ overlaypt = &overlaystack.top();
+ }
+ if ( overlaypt ) overlaypt->setContains( p2 );
+ if ( dodraw )
+ {
+ // draw the two segments
+ QPoint tp0 = toScreen(p0);
+ QPoint tp1 = toScreen(p1);
+ QPoint tp2 = toScreen(p2);
+ if ( curpolylinenextfree > 0 && curpolyline[curpolylinenextfree - 1] != tp1 )
+ {
+ // flush the current part of the curve
+ mP.drawPolyline( curpolyline, 0, curpolylinenextfree );
+ curpolylinenextfree = 0;
+ }
+ if ( curpolylinenextfree == 0 )
+ curpolyline[curpolylinenextfree++] = tp1;
+ curpolyline[curpolylinenextfree++] = tp2;
+ curpolyline[curpolylinenextfree++] = tp0;
+ }
+ else if ( h >= hmin ) // we do not continue to subdivide indefinitely!
+ {
+ // push into stack in order to process both subintervals
+ if ( addn || ( valid0 && sr.contains( p0 ) ) )
+ workstack.push( workitem( curitem.first, coordparampair( t2, p2 ),
+ overlaypt ) );
+ if ( addn || ( valid1 && sr.contains( p1 ) ) )
+ {
+ curitem = workitem( coordparampair( t2, p2 ), curitem.second ,
+ overlaypt );
+ curitemok = true;
+ }
+ }
+ }
+ }
+ // flush the rest of the curve
+ mP.drawPolyline( curpolyline, 0, curpolylinenextfree );
+ curpolylinenextfree = 0;
+
+ if ( ! workstack.empty () )
+ kdDebug() << "Stack not empty in KigPainter::drawCurve!\n" << endl;
+ assert ( tNeedOverlay || overlaystack.empty() );
+ if ( tNeedOverlay )
+ {
+ Rect border = window();
+ while ( ! overlaystack.empty() )
+ {
+ Rect overlay = overlaystack.top();
+ overlaystack.pop();
+ if (overlay.intersects( border ))
+ mOverlay.push_back( toScreenEnlarge( overlay ) );
+ }
+ }
+ mNeedOverlay = tNeedOverlay;
+}
+
+void KigPainter::drawTextFrame( const Rect& frame,
+ const QString& s, bool needframe )
+{
+ QPen oldpen = mP.pen();
+ QBrush oldbrush = mP.brush();
+ if ( needframe )
+ {
+ // inspired upon kgeo, thanks to Marc Bartsch, i've taken some of
+ // his code too..
+ setPen( QPen( Qt::black, 1 ) );
+ setBrush( QBrush( QColor( 255, 255, 222 ) ) );
+ drawRect( frame );
+ setPen( QPen( QColor( 197, 194, 197 ), 1, Qt::SolidLine ) );
+
+ QRect qr = toScreen( frame );
+
+ mP.drawLine( qr.topLeft(), qr.topRight() );
+ mP.drawLine( qr.topLeft(), qr.bottomLeft() );
+ };
+ setPen( oldpen );
+ setBrush( oldbrush );
+ drawText( frame, s, Qt::AlignVCenter | Qt::AlignLeft );
+}
+
+void KigPainter::drawArc( const Coordinate& center, const double radius,
+ const double dstartangle, const double dangle )
+{
+ // convert to 16th of degrees...
+ const int startangle = static_cast<int>( Goniometry::convert( 16 * dstartangle, Goniometry::Rad, Goniometry::Deg ) );
+ const int angle = static_cast<int>( Goniometry::convert( 16 * dangle, Goniometry::Rad, Goniometry::Deg ) );
+
+ if ( angle <= 16 )
+ {
+ Coordinate a = center + radius * Coordinate( cos( dstartangle ), sin( dstartangle ));
+ Coordinate b = center + radius * Coordinate( cos( dstartangle + dangle ), sin( dstartangle + dangle ));
+ drawSegment ( a , b );
+ }
+ else
+ {
+ Rect krect( 0, 0, 2*radius, 2*radius );
+ krect.setCenter( center );
+ QRect rect = toScreen( krect );
+
+ mP.drawArc( rect, startangle, angle );
+ setWholeWinOverlay();
+ }
+}
+
diff --git a/kig/misc/kigpainter.h b/kig/misc/kigpainter.h
new file mode 100644
index 00000000..e7f884f4
--- /dev/null
+++ b/kig/misc/kigpainter.h
@@ -0,0 +1,291 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002-2003 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+
+#ifndef KIGPAINTER_H
+#define KIGPAINTER_H
+
+#include "coordinate.h"
+#include "rect.h"
+#include "screeninfo.h"
+
+#include <qpainter.h>
+#include <qcolor.h>
+
+#include <vector>
+
+class KigWidget;
+class QPaintDevice;
+class CoordinateSystem;
+class ObjectHierarchy;
+class ConicPolarData;
+class CubicCartesianData;
+class LineData;
+class CurveImp;
+class KigDocument;
+class ObjectHolder;
+
+/**
+ * KigPainter is an extended QPainter.
+ *
+ * Currently the only difference is that it translates coordinates
+ * from and to the internal coordinates/ the widget coordinates...
+ *
+ * It calls KigWidget::appendOverlay() for all of the places it draws in...
+ */
+class KigPainter
+ : public Qt
+{
+protected:
+ // don't blaim me for this mutable hack. It's TT that hasn't got
+ // its consts correctly...
+ mutable QPainter mP;
+
+ QColor color;
+ PenStyle style;
+ int pointstyle;
+ int width;
+ BrushStyle brushStyle;
+ QColor brushColor;
+
+ const KigDocument& mdoc;
+ ScreenInfo msi;
+
+ bool mNeedOverlay;
+ int overlayenlarge;
+public:
+ /**
+ * construct a new KigPainter:
+ * the ScreenInfo is used to map the document coordinates to the
+ * widget coordinates. This is done transparently to the objects.
+ * needOverlay sets whether we try to remember the places we're
+ * drawing on using the various overlay methods. @see overlay()
+ */
+ KigPainter( const ScreenInfo& r, QPaintDevice* device, const KigDocument& doc,
+ bool needOverlay = true );
+ ~KigPainter();
+
+ /**
+ * what rect are we drawing on ?
+ */
+ Rect window();
+
+ QPoint toScreen( const Coordinate p ) const;
+ QRect toScreen( const Rect r ) const;
+ QRect toScreenEnlarge( const Rect r ) const;
+ Coordinate fromScreen( const QPoint& p ) const;
+ Rect fromScreen( const QRect& r ) const;
+
+ // colors and stuff...
+ void setStyle( const PenStyle c );
+ void setColor( const QColor& c );
+ /**
+ * setting this to -1 means to use the default width for the object
+ * being drawn.. a point -> 5, other objects -> 1
+ */
+ void setWidth( const int c );
+ void setPointStyle( const int p );
+ void setPen( const QPen& p );
+ void setBrushStyle( const BrushStyle c );
+ void setBrush( const QBrush& b );
+ void setBrushColor( const QColor& c );
+
+ QColor getColor() const;
+ bool getNightVision( ) const;
+
+ double pixelWidth();
+
+ /**
+ * this is called by some drawing functions that modify the 'entire'
+ * screen, i.e. they do so many changes that it's easier to just
+ * update the entire screen, or else i have been to lazy to
+ * implement an appropriate overlay function ;)
+ * it clears mOverlay, and sets it to the entire widget...
+ */
+ void setWholeWinOverlay();
+
+ /**
+ * draw an object ( by calling its draw function.. )
+ */
+ void drawObject( const ObjectHolder* o, bool sel );
+ void drawObjects( const std::vector<ObjectHolder*>& os, bool sel );
+ template<typename iter>
+ void drawObjects( iter begin, iter end, bool sel )
+ {
+ for ( ; begin != end; ++begin )
+ drawObject( *begin, sel );
+ }
+
+ /**
+ * draw a generic curve...
+ */
+ void drawCurve( const CurveImp* curve );
+
+ /**
+ * draws text in a standard manner, convenience function...
+ */
+ void drawTextStd( const QPoint& p, const QString& s );
+
+ /**
+ * draws a rect filled up with a pattern of cyan lines...
+ */
+ void drawFilledRect( const QRect& );
+
+ /**
+ * draw a rect..
+ */
+ void drawRect( const Rect& r );
+
+ /**
+ * overload, mainly for drawing the selection rectangle by
+ * KigWidget...
+ */
+ void drawRect( const QRect& r );
+
+ /**
+ * draw a circle...
+ */
+ void drawCircle( const Coordinate& center, const double radius );
+
+ /**
+ * draw a segment...
+ */
+ void drawSegment ( const Coordinate& from, const Coordinate& to );
+ void drawSegment( const LineData& d );
+
+ /**
+ * draw a ray...
+ */
+ void drawRay( const Coordinate& a, const Coordinate& b );
+ void drawRay( const LineData& d );
+
+ /**
+ * draw a line...
+ */
+ void drawLine ( const Coordinate& p1, const Coordinate& p2 );
+ void drawLine( const LineData& d );
+
+ /**
+ * draw a point... This means a single point, as in
+ * QPainter::drawPoint(), unlike drawFatPoint()...
+ */
+ void drawPoint( const Coordinate& p );
+
+ /**
+ * draw a thick point.. This is what the user sees when he draws a
+ * point. In fact it isn't a point, but a filled circle of a
+ * certain radius...
+ */
+ void drawFatPoint( const Coordinate& p );
+
+ /**
+ * draw a polygon defined by the points in pts...
+ */
+ void drawPolygon( const std::vector<QPoint>& pts, bool winding = false, int index = 0, int npoints = -1 );
+ void drawPolygon( const std::vector<Coordinate>& pts, bool winding = false, int index = 0, int npoints = -1 );
+
+ /**
+ * draw an area defined by the points in pts filled with the set
+ * color...
+ */
+ void drawArea( const std::vector<Coordinate>& pts, bool border = true );
+
+ /**
+ * draw the angle with center point, with size angle, starting
+ * at the angle startAngle.. Angles should be in radians.
+ */
+ void drawAngle( const Coordinate& point, const double startangle,
+ const double angle );
+
+ /**
+ * draw the arc ( a part of a circle ), of the circle with center
+ * center, radius radius, with size angle, starting at the angle
+ * startAngle.. Angles should be in radians..
+ */
+ void drawArc( const Coordinate& center, const double radius,
+ const double startangle, const double angle );
+
+ /**
+ * draw a vector ( with an arrow etc. )
+ */
+
+ void drawVector( const Coordinate& a, const Coordinate& b );
+
+ /**
+ * draw text...
+ * \see QPainter::drawText()
+ */
+ void drawText( const Rect r, const QString s, int textFlags = 0,
+ int len = -1);
+ void drawText( const Coordinate p, const QString s,
+ int textFlags = 0, int len = -1);
+
+ void drawSimpleText( const Coordinate& c, const QString s );
+ void drawTextFrame( const Rect& frame, const QString& s, bool needframe );
+
+ const Rect boundingRect( const Rect& r, const QString s,
+ int f = 0, int l = -1 ) const;
+
+ const Rect boundingRect( const Coordinate& c, const QString s,
+ int f = 0, int l = -1 ) const;
+
+ const Rect simpleBoundingRect( const Coordinate& c, const QString s );
+
+ void drawGrid( const CoordinateSystem& c, bool showGrid = true, bool showAxes = true );
+
+ const std::vector<QRect>& overlay() { return mOverlay; }
+
+protected:
+ /**
+ * adds a number of rects to mOverlay so that the rects entirely
+ * contain the circle...
+ * \see mOverlay
+ */
+ void circleOverlay( const Coordinate& centre, double radius );
+ // this works recursively...
+ void circleOverlayRecurse( const Coordinate& centre, double radius, const Rect& currentRect );
+
+ /**
+ * adds some rects to mOverlay, so that they cover the segment p1p2
+ * completely...
+ * \see Object::getOverlay()
+ */
+ void segmentOverlay( const Coordinate& p1, const Coordinate& p2 );
+
+ /**
+ * ...
+ */
+ void pointOverlay( const Coordinate& p1 );
+
+ /**
+ * ...
+ * \see drawText(), QPainter::boundingRect()
+ */
+ void textOverlay( const QRect& r, const QString s, int textFlags, int len );
+
+ /**
+ * the size we want the overlay rects to be...
+ */
+ double overlayRectSize();
+
+ std::vector<QRect> mOverlay;
+};
+
+#endif
diff --git a/kig/misc/kigtransform.cpp b/kig/misc/kigtransform.cpp
new file mode 100644
index 00000000..a297ed6e
--- /dev/null
+++ b/kig/misc/kigtransform.cpp
@@ -0,0 +1,810 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Maurizio Paolini <paolini@dmf.unicatt.it>
+ Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "kigtransform.h"
+
+#include "kignumerics.h"
+#include "common.h"
+
+#include <cmath>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+// Transformation getProjectiveTransformation ( int argsnum,
+// Object *transforms[], bool& valid )
+// {
+// valid = true;
+
+// assert ( argsnum > 0 );
+// int argn = 0;
+// Object* transform = transforms[argn++];
+// if (transform->toVector())
+// {
+// // translation
+// assert (argn == argsnum);
+// Vector* v = transform->toVector();
+// Coordinate dir = v->getDir();
+// return Transformation::translation( dir );
+// }
+
+// if (transform->toPoint())
+// {
+// // point reflection ( or is point symmetry the correct term ? )
+// assert (argn == argsnum);
+// Point* p = transform->toPoint();
+// return Transformation::pointReflection( p->getCoord() );
+// }
+
+// if (transform->toLine())
+// {
+// // line reflection ( or is it line symmetry ? )
+// Line* line = transform->toLine();
+// assert (argn == argsnum);
+// return Transformation::lineReflection( line->lineData() );
+// }
+
+// if (transform->toRay())
+// {
+// // domi: sorry, but what kind of transformation does this do ?
+// // i'm guessing it's some sort of rotation, but i'm not
+// // really sure..
+// Ray* line = transform->toRay();
+// Coordinate d = line->direction().normalize();
+// Coordinate t = line->p1();
+// double alpha = 0.1*M_PI/2; // a small angle for the DrawPrelim
+// if (argn < argsnum)
+// {
+// Angle* angle = transforms[argn++]->toAngle();
+// alpha = angle->size();
+// }
+// assert (argn == argsnum);
+// return Transformation::projectiveRotation( alpha, d, t );
+// }
+
+// if (transform->toAngle())
+// {
+// // rotation..
+// Coordinate center = Coordinate( 0., 0. );
+// if (argn < argsnum)
+// {
+// Object* arg = transforms[argn++];
+// assert (arg->toPoint());
+// center = arg->toPoint()->getCoord();
+// }
+// Angle* angle = transform->toAngle();
+// double alpha = angle->size();
+
+// assert (argn == argsnum);
+
+// return Transformation::rotation( alpha, center );
+// }
+
+// if (transform->toSegment()) // this is a scaling
+// {
+// Segment* segment = transform->toSegment();
+// Coordinate p = segment->p2() - segment->p1();
+// double s = p.length();
+// if (argn < argsnum)
+// {
+// Object* arg = transforms[argn++];
+// if (arg->toSegment()) // s is the length of the first segment
+// // divided by the length of the second..
+// {
+// Segment* segment = arg->toSegment();
+// Coordinate p = segment->p2() - segment->p1();
+// s /= p.length();
+// if (argn < argsnum) arg = transforms[argn++];
+// }
+// if (arg->toPoint()) // scaling w.r. to a point
+// {
+// Point* p = arg->toPoint();
+// assert (argn == argsnum);
+// return Transformation::scaling( s, p->getCoord() );
+// }
+// if (arg->toLine()) // scaling w.r. to a line
+// {
+// Line* line = arg->toLine();
+// assert( argn == argsnum );
+// return Transformation::scaling( s, line->lineData() );
+// }
+// }
+
+// return Transformation::scaling( s, Coordinate( 0., 0. ) );
+// }
+
+// valid = false;
+// return Transformation::identity();
+// }
+
+// tWantArgsResult WantTransformation ( Objects::const_iterator& i,
+// const Objects& os )
+// {
+// Object* o = *i++;
+// if (o->toVector()) return tComplete;
+// if (o->toPoint()) return tComplete;
+// if (o->toLine()) return tComplete;
+// if (o->toAngle())
+// {
+// if ( i == os.end() ) return tNotComplete;
+// o = *i++;
+// if (o->toPoint()) return tComplete;
+// if (o->toLine()) return tComplete;
+// return tNotGood;
+// }
+// if (o->toRay())
+// {
+// if ( i == os.end() ) return tNotComplete;
+// o = *i++;
+// if (o->toAngle()) return tComplete;
+// return tNotGood;
+// }
+// if (o->toSegment())
+// {
+// if ( i == os.end() ) return tNotComplete;
+// o = *i++;
+// if ( o->toSegment() )
+// {
+// if ( i == os.end() ) return tNotComplete;
+// o = *i++;
+// }
+// if (o->toPoint()) return tComplete;
+// if (o->toLine()) return tComplete;
+// return tNotGood;
+// }
+// return tNotGood;
+// }
+
+// QString getTransformMessage ( const Objects& os, const Object *o )
+// {
+// int size = os.size();
+// switch (size)
+// {
+// case 1:
+// if (o->toVector()) return i18n("translate by this vector");
+// if (o->toPoint()) return i18n("central symmetry by this point. You"
+// " can obtain different transformations by clicking on lines (mirror),"
+// " vectors (translation), angles (rotation), segments (scaling) and rays"
+// " (projective transformation)");
+// if (o->toLine()) return i18n("reflect in this line");
+// if (o->toAngle()) return i18n("rotate by this angle");
+// if (o->toSegment()) return i18n("scale using the length of this vector");
+// if (o->toRay()) return i18n("a projective transformation in the direction"
+// " indicated by this ray, it is a rotation in the projective plane"
+// " about a point at infinity");
+// return i18n("Use this transformation");
+
+// case 2: // we ask for the first parameter of the transformation
+// case 3:
+// if (os[1]->toAngle())
+// {
+// if (o->toPoint()) return i18n("about this point");
+// assert (false);
+// }
+// if (os[1]->toSegment())
+// {
+// if (o->toSegment())
+// return i18n("relative to the length of this other vector");
+// if (o->toPoint())
+// return i18n("about this point");
+// if (o->toLine())
+// return i18n("about this line");
+// }
+// if (os[1]->toRay())
+// {
+// if (o->toAngle()) return i18n("rotate by this angle in the projective"
+// " plane");
+// }
+// return i18n("Using this object");
+
+// default: assert(false);
+// }
+
+// return i18n("Use this transformation");
+// }
+
+
+/* domi: not necessary anymore, homotheticness is kept as a bool in
+ * the Transformation class..
+ * keeping it here, in case a need for it arises some time in the
+ * future...
+ * decide if the given transformation is homotetic
+ */
+// bool isHomoteticTransformation ( double transformation[3][3] )
+// {
+// if (transformation[0][1] != 0 || transformation[0][2] != 0) return (false);
+// // test the orthogonality of the matrix 2x2 of second and third rows
+// // and columns
+// if (fabs(fabs(transformation[1][1]) -
+// fabs(transformation[2][2])) > 1e-8) return (false);
+// if (fabs(fabs(transformation[1][2]) -
+// fabs(transformation[2][1])) > 1e-8) return (false);
+
+// return transformation[1][2] * transformation[2][1] *
+// transformation[1][1] * transformation[2][2] <= 0.;
+// }
+
+const Transformation Transformation::identity()
+{
+ Transformation ret;
+ for ( int i = 0; i < 3; ++i )
+ for ( int j = 0; j < 3; ++j )
+ ret.mdata[i][j] = ( i == j ? 1 : 0 );
+ ret.mIsHomothety = ret.mIsAffine = true;
+ return ret;
+}
+
+const Transformation Transformation::scalingOverPoint( double factor, const Coordinate& center )
+{
+ Transformation ret;
+ for ( int i = 0; i < 3; ++i )
+ for ( int j = 0; j < 3; ++j )
+ ret.mdata[i][j] = ( i == j ? factor : 0 );
+ ret.mdata[0][0] = 1;
+ ret.mdata[1][0] = center.x - factor * center.x;
+ ret.mdata[2][0] = center.y - factor * center.y;
+ ret.mIsHomothety = ret.mIsAffine = true;
+ return ret;
+}
+
+const Transformation Transformation::translation( const Coordinate& c )
+{
+ Transformation ret = identity();
+ ret.mdata[1][0] = c.x;
+ ret.mdata[2][0] = c.y;
+
+ // this is already set in the identity() constructor, but just for
+ // clarity..
+ ret.mIsHomothety = ret.mIsAffine = true;
+ return ret;
+}
+
+const Transformation Transformation::pointReflection( const Coordinate& c )
+{
+ Transformation ret = scalingOverPoint( -1, c );
+ ret.mIsHomothety = ret.mIsAffine = true;
+ return ret;
+}
+
+const Transformation operator*( const Transformation& a, const Transformation& b )
+{
+ // just multiply the two matrices..
+ Transformation ret;
+
+ for ( int i = 0; i < 3; ++i )
+ for ( int j = 0; j < 3; ++j )
+ {
+ ret.mdata[i][j] = 0;
+ for ( int k = 0; k < 3; ++k )
+ ret.mdata[i][j] += a.mdata[i][k] * b.mdata[k][j];
+ };
+
+ // combination of two homotheties is a homothety..
+
+ ret.mIsHomothety = a.mIsHomothety && b.mIsHomothety;
+
+ // combination of two affinities is affine..
+
+ ret.mIsAffine = a.mIsAffine && b.mIsAffine;
+
+ return ret;
+}
+
+const Transformation Transformation::lineReflection( const LineData& l )
+{
+ Transformation ret = scalingOverLine( -1, l );
+ // a reflection is a homothety...
+ ret.mIsHomothety = ret.mIsAffine = true;
+ return ret;
+}
+
+const Transformation Transformation::scalingOverLine( double factor, const LineData& l )
+{
+ Transformation ret = identity();
+
+ Coordinate a = l.a;
+ Coordinate d = l.dir();
+ double dirnormsq = d.squareLength();
+ ret.mdata[1][1] = (d.x*d.x + factor*d.y*d.y)/dirnormsq;
+ ret.mdata[2][2] = (d.y*d.y + factor*d.x*d.x)/dirnormsq;
+ ret.mdata[1][2] = ret.mdata[2][1] = (d.x*d.y - factor*d.x*d.y)/dirnormsq;
+
+ ret.mdata[1][0] = a.x - ret.mdata[1][1]*a.x - ret.mdata[1][2]*a.y;
+ ret.mdata[2][0] = a.y - ret.mdata[2][1]*a.x - ret.mdata[2][2]*a.y;
+
+ // domi: is 1e-8 a good value ?
+ ret.mIsHomothety = ( fabs( factor - 1 ) < 1e-8 || fabs ( factor + 1 ) < 1e-8 );
+ ret.mIsAffine = true;
+ return ret;
+}
+
+const Transformation Transformation::harmonicHomology(
+ const Coordinate& center, const LineData& axis )
+{
+ // this is a well known projective transformation. We find it by first
+ // computing the homogeneous equation of the axis ax + by + cz = 0
+ // then a straightforward computation shows that the 3x3 matrix describing
+ // the transformation is of the form:
+ //
+ // (r . C) Id - 2 (C tensor r)
+ //
+ // where r = [c, a, b], C = [1, Cx, Cy], Cx and Cy are the coordinates of
+ // the center, '.' denotes the scalar product, Id is the identity matrix,
+ // 'tensor' is the tensor product producing a 3x3 matrix.
+ //
+ // note: here we decide to use coordinate '0' in place of the third coordinate
+ // in homogeneous notation; e.g. C = [1, cx, cy]
+
+ Coordinate pointa = axis.a;
+ Coordinate pointb = axis.b;
+
+ double a = pointa.y - pointb.y;
+ double b = pointb.x - pointa.x;
+ double c = pointa.x*pointb.y - pointa.y*pointb.x;
+
+ double cx = center.x;
+ double cy = center.y;
+
+ double scalprod = a*cx + b*cy + c;
+ scalprod *= 0.5;
+ Transformation ret;
+
+ ret.mdata[0][0] = c - scalprod;
+ ret.mdata[0][1] = a;
+ ret.mdata[0][2] = b;
+
+ ret.mdata[1][0] = c*cx;
+ ret.mdata[1][1] = a*cx - scalprod;
+ ret.mdata[1][2] = b*cx;
+
+ ret.mdata[2][0] = c*cy;
+ ret.mdata[2][1] = a*cy;
+ ret.mdata[2][2] = b*cy - scalprod;
+
+ ret.mIsHomothety = ret.mIsAffine = false;
+ return ret;
+}
+
+const Transformation Transformation::affinityGI3P(
+ const std::vector<Coordinate>& FromPoints,
+ const std::vector<Coordinate>& ToPoints,
+ bool& valid )
+{
+ // construct the (generically) unique affinity that transforms 3 given
+ // point into 3 other given points; i.e. it depends on the coordinates of
+ // a total of 6 points. This actually amounts in solving a 6x6 linear
+ // system to find the entries of a 2x2 linear transformation matrix T
+ // and of a translation vector t.
+ // If Pi denotes one of the starting points and Qi the corresponding
+ // final position we actually have to solve: Qi = t + T Pi, for i=1,2,3
+ // (each one is a vector equation, so that it really gives 2 equations).
+ // In our context T and t are used to build a 3x3 projective transformation
+ // as follows:
+ //
+ // [ 1 0 0 ]
+ // [ t1 T11 T12 ]
+ // [ t2 T21 T22 ]
+ //
+ // In order to take advantage of the two functions "GaussianElimination"
+ // and "BackwardSubstitution", which are specifically aimed at solving
+ // homogeneous underdetermined linear systems, we just add a further
+ // unknown m and solve for t + T Pi - m Qi = 0. Since our functions
+ // returns a nonzero solution we shall have a nonzero 'm' in the end and
+ // can build the 3x3 matrix as follows:
+ //
+ // [ m 0 0 ]
+ // [ t1 T11 T12 ]
+ // [ t2 T21 T22 ]
+ //
+ // we order the unknowns as follows: m, t1, t2, T11, T12, T21, T22
+
+ double row0[7], row1[7], row2[7], row3[7], row4[7], row5[7];
+
+ double *matrix[6] = {row0, row1, row2, row3, row4, row5};
+
+ double solution[7];
+ int scambio[7];
+
+ assert (FromPoints.size() == 3);
+ assert (ToPoints.size() == 3);
+
+ // fill in the matrix elements
+ for ( int i = 0; i < 6; i++ )
+ {
+ for ( int j = 0; j < 7; j++ )
+ {
+ matrix[i][j] = 0.0;
+ }
+ }
+
+ for ( int i = 0; i < 3; i++ )
+ {
+ Coordinate p = FromPoints[i];
+ Coordinate q = ToPoints[i];
+ matrix[i][0] = -q.x;
+ matrix[i][1] = 1.0;
+ matrix[i][3] = p.x;
+ matrix[i][4] = p.y;
+ matrix[i+3][0] = -q.y;
+ matrix[i+3][2] = 1.0;
+ matrix[i+3][5] = p.x;
+ matrix[i+3][6] = p.y;
+ }
+
+ Transformation ret;
+ valid = true;
+ if ( ! GaussianElimination( matrix, 6, 7, scambio ) )
+ { valid = false; return ret; }
+
+ // fine della fase di eliminazione
+ BackwardSubstitution( matrix, 6, 7, scambio, solution );
+
+ // now we can build the 3x3 transformation matrix; remember that
+ // unknown 0 is the multiplicator 'm'
+
+ ret.mdata[0][0] = solution[0];
+ ret.mdata[0][1] = ret.mdata[0][2] = 0.0;
+ ret.mdata[1][0] = solution[1];
+ ret.mdata[2][0] = solution[2];
+ ret.mdata[1][1] = solution[3];
+ ret.mdata[1][2] = solution[4];
+ ret.mdata[2][1] = solution[5];
+ ret.mdata[2][2] = solution[6];
+
+ ret.mIsHomothety = false;
+ ret.mIsAffine = true;
+ return ret;
+}
+
+const Transformation Transformation::projectivityGI4P(
+ const std::vector<Coordinate>& FromPoints,
+ const std::vector<Coordinate>& ToPoints,
+ bool& valid )
+{
+ // construct the (generically) unique projectivity that transforms 4 given
+ // point into 4 other given points; i.e. it depends on the coordinates of
+ // a total of 8 points. This actually amounts in solving an underdetermined
+ // homogeneous linear system.
+
+ double
+ row0[13], row1[13], row2[13], row3[13], row4[13], row5[13], row6[13], row7[13],
+ row8[13], row9[13], row10[13], row11[13];
+
+ double *matrix[12] = {row0, row1, row2, row3, row4, row5, row6, row7,
+ row8, row9, row10, row11};
+
+ double solution[13];
+ int scambio[13];
+
+ assert (FromPoints.size() == 4);
+ assert (ToPoints.size() == 4);
+
+ // fill in the matrix elements
+ for ( int i = 0; i < 12; i++ )
+ {
+ for ( int j = 0; j < 13; j++ )
+ {
+ matrix[i][j] = 0.0;
+ }
+ }
+
+ for ( int i = 0; i < 4; i++ )
+ {
+ Coordinate p = FromPoints[i];
+ Coordinate q = ToPoints[i];
+ matrix[i][0] = matrix[4+i][3] = matrix[8+i][6] = 1.0;
+ matrix[i][1] = matrix[4+i][4] = matrix[8+i][7] = p.x;
+ matrix[i][2] = matrix[4+i][5] = matrix[8+i][8] = p.y;
+ matrix[i][9+i] = -1.0;
+ matrix[4+i][9+i] = -q.x;
+ matrix[8+i][9+i] = -q.y;
+ }
+
+ Transformation ret;
+ valid = true;
+ if ( ! GaussianElimination( matrix, 12, 13, scambio ) )
+ { valid = false; return ret; }
+
+ // fine della fase di eliminazione
+ BackwardSubstitution( matrix, 12, 13, scambio, solution );
+
+ // now we can build the 3x3 transformation matrix; remember that
+ // unknowns from 9 to 13 are just multiplicators that we don't need here
+
+ int k = 0;
+ for ( int i = 0; i < 3; i++ )
+ {
+ for ( int j = 0; j < 3; j++ )
+ {
+ ret.mdata[i][j] = solution[k++];
+ }
+ }
+
+ ret.mIsHomothety = ret.mIsAffine = false;
+ return ret;
+}
+
+const Transformation Transformation::castShadow(
+ const Coordinate& lightsrc, const LineData& l )
+{
+ // first deal with the line l, I need to find an appropriate reflection
+ // that transforms l onto the x-axis
+
+ Coordinate d = l.dir();
+ Coordinate a = l.a;
+ double k = d.length();
+ if ( d.x < 0 ) k *= -1; // for numerical stability
+ Coordinate w = d + Coordinate( k, 0 );
+ // w /= w.length();
+ // w defines a Householder transformation, but we don't need to normalize
+ // it here.
+ // warning: this w is the orthogonal of the w of the textbooks!
+ // this is fine for us since in this way it indicates the line direction
+ Coordinate ra = Coordinate ( a.x + w.y*a.y/(2*w.x), a.y/2 );
+ Transformation sym = lineReflection ( LineData( ra, ra + w ) );
+
+ // in the new coordinates the line is the x-axis
+ // I must transform the point
+
+ Coordinate modlightsrc = sym.apply ( lightsrc );
+ Transformation ret = identity();
+ // parameter t indicates the distance of the light source from
+ // the plane of the drawing. A negative value means that the light
+ // source is behind the plane.
+ double t = -1.0;
+ // double t = -modlightsrc.y; <-- this gives the old transformation!
+ double e = modlightsrc.y - t;
+ ret.mdata[0][0] = e;
+ ret.mdata[0][2] = -1;
+ ret.mdata[1][1] = e;
+ ret.mdata[1][2] = -modlightsrc.x;
+ ret.mdata[2][2] = -t;
+
+ ret.mIsHomothety = ret.mIsAffine = false;
+ return sym*ret*sym;
+// return translation( t )*ret*translation( -t );
+}
+
+const Transformation Transformation::projectiveRotation(
+ double alpha, const Coordinate& d, const Coordinate& t )
+{
+ Transformation ret;
+ double cosalpha = cos( alpha );
+ double sinalpha = sin( alpha );
+ ret.mdata[0][0] = cosalpha;
+ ret.mdata[1][1] = cosalpha*d.x*d.x + d.y*d.y;
+ ret.mdata[0][1] = -sinalpha*d.x;
+ ret.mdata[1][0] = sinalpha*d.x;
+ ret.mdata[0][2] = -sinalpha*d.y;
+ ret.mdata[2][0] = sinalpha*d.y;
+ ret.mdata[1][2] = cosalpha*d.x*d.y - d.x*d.y;
+ ret.mdata[2][1] = cosalpha*d.x*d.y - d.x*d.y;
+ ret.mdata[2][2] = cosalpha*d.y*d.y + d.x*d.x;
+
+ ret.mIsHomothety = ret.mIsAffine = false;
+ return translation( t )*ret*translation( -t );
+}
+
+const Coordinate Transformation::apply( const double x0,
+ const double x1,
+ const double x2) const
+{
+ double phom[3] = {x0, x1, x2};
+ double rhom[3] = {0., 0., 0.};
+
+
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ rhom[i] += mdata[i][j]*phom[j];
+ }
+ }
+
+ if (rhom[0] == 0.)
+ return Coordinate::invalidCoord();
+
+ return Coordinate (rhom[1]/rhom[0], rhom[2]/rhom[0]);
+}
+
+const Coordinate Transformation::apply( const Coordinate& p ) const
+{
+ return apply( 1., p.x, p.y );
+// double phom[3] = {1., p.x, p.y};
+// double rhom[3] = {0., 0., 0.};
+//
+// for (int i = 0; i < 3; i++)
+// {
+// for (int j = 0; j < 3; j++)
+// {
+// rhom[i] += mdata[i][j]*phom[j];
+// }
+// }
+//
+// if (rhom[0] == 0.)
+// return Coordinate::invalidCoord();
+//
+// return Coordinate (rhom[1]/rhom[0], rhom[2]/rhom[0]);
+}
+
+const Coordinate Transformation::apply0( const Coordinate& p ) const
+{
+ return apply( 0., p.x, p.y );
+}
+
+const Transformation Transformation::rotation( double alpha, const Coordinate& center )
+{
+ Transformation ret = identity();
+
+ double x = center.x;
+ double y = center.y;
+
+ double cosalpha = cos( alpha );
+ double sinalpha = sin( alpha );
+
+ ret.mdata[1][1] = ret.mdata[2][2] = cosalpha;
+ ret.mdata[1][2] = -sinalpha;
+ ret.mdata[2][1] = sinalpha;
+ ret.mdata[1][0] = x - ret.mdata[1][1]*x - ret.mdata[1][2]*y;
+ ret.mdata[2][0] = y - ret.mdata[2][1]*x - ret.mdata[2][2]*y;
+
+ // this is already set in the identity() constructor, but just for
+ // clarity..
+ ret.mIsHomothety = ret.mIsAffine = true;
+
+ return ret;
+}
+
+bool Transformation::isHomothetic() const
+{
+ return mIsHomothety;
+}
+
+bool Transformation::isAffine() const
+{
+ return mIsAffine;
+}
+
+/*
+ *mp:
+ * this function has the property that it changes sign if computed
+ * on two points that lie on either sides with respect to the critical
+ * line (this is the line that goes to the line at infinity).
+ * For affine transformations the result has always the same sign.
+ * NOTE: the result is *not* invariant under rescaling of all elements
+ * of the transformation matrix.
+ * The typical use is to determine whether a segment is transformed
+ * into a segment or a couple of half-lines.
+ */
+
+double Transformation::getProjectiveIndicator( const Coordinate& c ) const
+{
+ return mdata[0][0] + mdata[0][1]*c.x + mdata[0][2]*c.y;
+}
+
+// assuming that this is an affine transformation, return its
+// determinant. What is really important here is just the sign
+// of the determinant.
+double Transformation::getAffineDeterminant() const
+{
+ return mdata[1][1]*mdata[2][2] - mdata[1][2]*mdata[2][1];
+}
+
+// this assumes that the 2x2 affine part of the matrix is of the
+// form [ cos a, sin a; -sin a, cos a] or a multiple
+double Transformation::getRotationAngle() const
+{
+ return atan2( mdata[1][2], mdata[1][1] );
+}
+
+const Coordinate Transformation::apply2by2only( const Coordinate& p ) const
+{
+ double x = p.x;
+ double y = p.y;
+ double nx = mdata[1][1]*x + mdata[1][2]*y;
+ double ny = mdata[2][1]*x + mdata[2][2]*y;
+ return Coordinate( nx, ny );
+}
+
+double Transformation::data( int r, int c ) const
+{
+ return mdata[r][c];
+}
+
+const Transformation Transformation::inverse( bool& valid ) const
+{
+ Transformation ret;
+
+ valid = Invert3by3matrix( mdata, ret.mdata );
+
+ // the inverse of a homothety is a homothety, same for affinities..
+ ret.mIsHomothety = mIsHomothety;
+ ret.mIsAffine = mIsAffine;
+
+ return ret;
+}
+
+Transformation::Transformation()
+{
+ // this is the constructor used by the static Transformation
+ // creation functions, so mIsHomothety is in general false
+ mIsHomothety = mIsAffine = false;
+ for ( int i = 0; i < 3; ++i )
+ for ( int j = 0; j < 3; ++j )
+ mdata[i][j] = ( i == j ) ? 1 : 0;
+}
+
+Transformation::~Transformation()
+{
+}
+
+double Transformation::apply( double length ) const
+{
+ assert( isHomothetic() );
+ double det = mdata[1][1]*mdata[2][2] -
+ mdata[1][2]*mdata[2][1];
+ return sqrt( fabs( det ) ) * length;
+}
+
+Transformation::Transformation( double data[3][3], bool ishomothety )
+ : mIsHomothety( ishomothety )
+{
+ for ( int i = 0; i < 3; ++i )
+ for ( int j = 0; j < 3; ++j )
+ mdata[i][j] = data[i][j];
+
+ //mp: a test for affinity is used to initialize mIsAffine...
+ mIsAffine = false;
+ if ( fabs(mdata[0][1]) + fabs(mdata[0][2]) < 1e-8 * fabs(mdata[0][0]) )
+ mIsAffine = true;
+}
+
+bool operator==( const Transformation& lhs, const Transformation& rhs )
+{
+ for ( int i = 0; i < 3; ++i )
+ for ( int j = 0; j < 3; ++j )
+ if ( lhs.data( i, j ) != rhs.data( i, j ) )
+ return false;
+ return true;
+}
+
+const Transformation Transformation::similitude(
+ const Coordinate& center, double theta, double factor )
+{
+ //kdDebug() << k_funcinfo << "theta: " << theta << " factor: " << factor << endl;
+ Transformation ret;
+ ret.mIsHomothety = true;
+ double costheta = cos( theta );
+ double sintheta = sin( theta );
+ ret.mdata[0][0] = 1;
+ ret.mdata[0][1] = 0;
+ ret.mdata[0][2] = 0;
+ ret.mdata[1][0] = ( 1 - factor*costheta )*center.x + factor*sintheta*center.y;
+ ret.mdata[1][1] = factor*costheta;
+ ret.mdata[1][2] = -factor*sintheta;
+ ret.mdata[2][0] = -factor*sintheta*center.x + ( 1 - factor*costheta )*center.y;
+ ret.mdata[2][1] = factor*sintheta;
+ ret.mdata[2][2] = factor*costheta;
+ // fails for factor == infinity
+ //assert( ( ret.apply( center ) - center ).length() < 1e-5 );
+ ret.mIsHomothety = ret.mIsAffine = true;
+ return ret;
+}
diff --git a/kig/misc/kigtransform.h b/kig/misc/kigtransform.h
new file mode 100644
index 00000000..252a0f72
--- /dev/null
+++ b/kig/misc/kigtransform.h
@@ -0,0 +1,190 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Maurizio Paolini <paolini@dmf.unicatt.it>
+ Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#ifndef KIG_MISC_KIGTRANSFORM_H
+#define KIG_MISC_KIGTRANSFORM_H
+
+#include "coordinate.h"
+#include <vector>
+
+class LineData;
+
+/**
+ * Class representing a transformation. More specifically, this class
+ * represents a pretty generic 2-dimensional transformation. Various
+ * common transformations can be used. Construct a Transformation by
+ * using one of its static members, and use it either with its
+ * Transformation::apply method, or the ObjectImp::transform method.
+ */
+class Transformation
+{
+ double mdata[3][3];
+ bool mIsHomothety;
+ bool mIsAffine;
+ Transformation();
+public:
+ ~Transformation();
+ Transformation( double data[3][3], bool ishomothety );
+
+ /**
+ * Apply this Tranformation. Apply this transformation to the
+ * Coordinate c. Can return an invalid Coordinate.
+ * apply0 assumes that c indicates a point at infinity, having
+ * [0, c.x, c.y] as homogeneous coordinates
+ */
+ const Coordinate apply( const double x0, const double x1, const double x2 ) const;
+ const Coordinate apply( const Coordinate& c ) const;
+ const Coordinate apply0( const Coordinate& c ) const;
+
+ /**
+ * Returns whether this is a homothetic (affine) transformation.
+ */
+ bool isHomothetic() const;
+ bool isAffine() const;
+ double getProjectiveIndicator( const Coordinate& c ) const;
+ double getAffineDeterminant() const;
+ double getRotationAngle() const;
+ const Coordinate apply2by2only( const Coordinate& c ) const;
+ /**
+ * \ifnot creating-python-scripting-doc
+ * a homothetic transformation maintains the ratio's of lengths.
+ * This means that every length is multiplied by a fixed number when
+ * it is projected... This function does that calculation for
+ * you..
+ * \endif
+ */
+ double apply( double length ) const;
+ double data( int r, int c ) const;
+ /**
+ * The inverse Transformation. Returns the inverse Transformation
+ * of this Transformation.
+ */
+ const Transformation inverse( bool& valid ) const;
+
+ /**
+ * Identity. Returns the Identity Transformation, i.e. a
+ * Transformation that doesn't do anything.
+ */
+ static const Transformation identity();
+ /**
+ * Scaling over Point. Returns a Transformation that scales points
+ * by a certain factor with relation to a center point.
+ */
+ static const Transformation scalingOverPoint( double factor, const Coordinate& center = Coordinate() );
+ /**
+ * Scaling over Line. Returns a Transformation that scales points
+ * by a certain factor with relation to a line. Note: This is not a
+ * homothetic transformation.
+ */
+ static const Transformation scalingOverLine( double factor, const LineData& l );
+ /**
+ * Translation. Returns a Translation by a vector c.
+ */
+ static const Transformation translation( const Coordinate& c );
+ /**
+ * Rotation. Returns a Rotation by a certain angle, around a
+ * certain center.
+ */
+ static const Transformation rotation( double angle, const Coordinate& center = Coordinate() );
+ /**
+ * Point Reflection. Returns a reflection over a point
+ * \note This equals scaling( -1, c );
+ */
+ static const Transformation pointReflection( const Coordinate& c );
+ /**
+ * Line Reflection. Returns a reflection over a line
+ * \note This equals scaling( -1, l );
+ */
+ static const Transformation lineReflection( const LineData& l );
+ /**
+ * Harmonic Homology. Returns a Transformation that transforms points in
+ * such a way that it appears to cast a shadow, given a certain
+ * light source (center), and a line (axis) indicating a plane.
+ */
+ static const Transformation harmonicHomology( const Coordinate& center,
+ const LineData& axis );
+ /**
+ * Affinity given the image of 3 points. Returns the unique
+ * affinity that transforms 3 given points into 3 given points.
+ */
+ static const Transformation affinityGI3P(
+ const std::vector<Coordinate>& FromPoints,
+ const std::vector<Coordinate>& ToPoints,
+ bool& valid );
+ /**
+ * Projectivity given the image of 4 points. Returns the unique
+ * projectivity that transforms 4 given points into 4 given points.
+ */
+ static const Transformation projectivityGI4P(
+ const std::vector<Coordinate>& FromPoints,
+ const std::vector<Coordinate>& ToPoints,
+ bool& valid );
+ /**
+ * Cast Shadow. Returns a Transformation that transforms points in
+ * such a way that it appears to cast a shadow, given a certain
+ * light source, and a line indicating a plane.
+ */
+ static const Transformation castShadow( const Coordinate& ls,
+ const LineData& d );
+ /**
+ * Projective Rotation. This is really only a test example of a
+ * projective non-affine transformation...
+ */
+ static const Transformation projectiveRotation( double alpha,
+ const Coordinate& d,
+ const Coordinate& t );
+
+ /**
+ * Similitude. Sequence of a rotation and a scaling with relation
+ * to a certain center.
+ */
+ static const Transformation similitude(
+ const Coordinate& center, double theta, double factor );
+
+ /**
+ * Sequence. This creates a Transformation that executes first
+ * transformation b, and then a.
+ */
+ friend const Transformation operator*( const Transformation& a, const Transformation& b );
+
+ /**
+ * Equality. Tests two Transformation's for equality.
+ */
+ friend bool operator==( const Transformation& lhs, const Transformation& rhs );
+};
+
+const Transformation operator*( const Transformation&, const Transformation& );
+bool operator==( const Transformation& lhs, const Transformation& rhs );
+
+// enum tWantArgsResult { tComplete, tNotComplete, tNotGood };
+
+// Transformation getProjectiveTransformation(
+// int transformationsnum, Object *mtransformations[],
+// bool& valid );
+
+// tWantArgsResult WantTransformation ( Objects::const_iterator& i,
+// const Objects& os );
+
+// QString getTransformMessage ( const Objects& os, const Object *o );
+
+// bool isHomoteticTransformation ( double transformation[3][3] );
+
+#endif // KIG_MISC_KIGTRANSFORM_H
diff --git a/kig/misc/lists.cc b/kig/misc/lists.cc
new file mode 100644
index 00000000..e93700a1
--- /dev/null
+++ b/kig/misc/lists.cc
@@ -0,0 +1,389 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "lists.h"
+
+#include "object_constructor.h"
+#include "guiaction.h"
+#include "object_hierarchy.h"
+#include "../kig/kig_part.h"
+
+#include "config.h"
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qdom.h>
+#include <qregexp.h>
+#include <algorithm>
+using namespace std;
+
+template<typename T>
+void vect_remove( std::vector<T>& v, const T& t )
+{
+ typename std::vector<T>::iterator new_end = std::remove( v.begin(), v.end(), t );
+ v.erase( new_end, v.end() );
+}
+
+GUIActionList* GUIActionList::instance()
+{
+ static GUIActionList l;
+ return &l;
+}
+
+GUIActionList::~GUIActionList()
+{
+ for ( avectype::iterator i = mactions.begin(); i != mactions.end(); ++i )
+ delete *i;
+}
+
+GUIActionList::GUIActionList()
+{
+}
+
+void GUIActionList::regDoc( KigPart* d )
+{
+ mdocs.insert( d );
+}
+
+void GUIActionList::unregDoc( KigPart* d )
+{
+ mdocs.erase( d );
+}
+
+void GUIActionList::add( const std::vector<GUIAction*>& a )
+{
+ copy( a.begin(), a.end(), inserter( mactions, mactions.begin() ) );
+ for ( dvectype::iterator i = mdocs.begin(); i != mdocs.end(); ++i )
+ {
+ KigPart::GUIUpdateToken t = (*i)->startGUIActionUpdate();
+ for ( uint j = 0; j < a.size(); ++j )
+ (*i)->actionAdded( a[j], t );
+ (*i)->endGUIActionUpdate( t );
+ };
+}
+
+void GUIActionList::add( GUIAction* a )
+{
+ mactions.insert( a );
+ for ( dvectype::iterator i = mdocs.begin(); i != mdocs.end(); ++i )
+ {
+ KigPart::GUIUpdateToken t = (*i)->startGUIActionUpdate();
+ (*i)->actionAdded( a, t );
+ (*i)->endGUIActionUpdate( t );
+ };
+}
+
+void GUIActionList::remove( const std::vector<GUIAction*>& a )
+{
+ for ( uint i = 0; i < a.size(); ++i )
+ {
+ mactions.erase( a[i] );
+ };
+ for ( dvectype::iterator i = mdocs.begin(); i != mdocs.end(); ++i )
+ {
+ KigPart::GUIUpdateToken t = (*i)->startGUIActionUpdate();
+ for ( uint j = 0; j < a.size(); ++j )
+ (*i)->actionRemoved( a[j], t );
+ (*i)->endGUIActionUpdate( t );
+ };
+ delete_all( a.begin(), a.end() );
+}
+
+void GUIActionList::remove( GUIAction* a )
+{
+ mactions.erase( a );
+ for ( dvectype::iterator i = mdocs.begin(); i != mdocs.end(); ++i )
+ {
+ KigPart::GUIUpdateToken t = (*i)->startGUIActionUpdate();
+ (*i)->actionRemoved( a, t );
+ (*i)->endGUIActionUpdate( t );
+ };
+ delete a;
+}
+
+ObjectConstructorList::ObjectConstructorList()
+{
+}
+
+ObjectConstructorList::~ObjectConstructorList()
+{
+ for ( vectype::iterator i = mctors.begin(); i != mctors.end(); ++i )
+ delete *i;
+}
+
+ObjectConstructorList* ObjectConstructorList::instance()
+{
+ static ObjectConstructorList s;
+ return &s;
+}
+
+ObjectConstructorList::vectype ObjectConstructorList::ctorsThatWantArgs(
+ const std::vector<ObjectCalcer*>& os, const KigDocument& d,
+ const KigWidget& w, bool co ) const
+{
+ vectype ret;
+ for ( vectype::const_iterator i = mctors.begin(); i != mctors.end(); ++i )
+ {
+ int r = (*i)->wantArgs( os, d, w );
+ if ( r == ArgsParser::Complete || ( !co && r == ArgsParser::Valid ) )
+ ret.push_back( *i );
+ };
+ return ret;
+}
+
+void ObjectConstructorList::remove( ObjectConstructor* a )
+{
+ vect_remove( mctors, a );
+ delete a;
+}
+
+void ObjectConstructorList::add( ObjectConstructor* a )
+{
+ mctors.push_back( a );
+}
+
+Macro::Macro( GUIAction* a, MacroConstructor* c )
+ : action( a ), ctor( c )
+{
+}
+
+bool operator==( const Macro& l, const Macro& r )
+{
+ return ( l.action->descriptiveName() == r.action->descriptiveName() ) &&
+ ( l.action->description() == r.action->description() ) &&
+ ( l.action->iconFileName() == r.action->iconFileName() );
+}
+
+MacroList::MacroList()
+{
+}
+
+MacroList::~MacroList()
+{
+ std::vector<GUIAction*> actions;
+ std::vector<ObjectConstructor*> ctors;
+ for ( vectype::iterator i = mdata.begin(); i != mdata.end(); ++i )
+ {
+ Macro* m = *i;
+ GUIAction* a = m->action;
+ actions.push_back( a );
+ ObjectConstructor* c = m->ctor;
+ ctors.push_back( c );
+ delete m;
+ };
+ mdata.clear();
+ GUIActionList::instance()->remove( actions );
+ for ( uint i = 0; i < ctors.size(); ++i )
+ ObjectConstructorList::instance()->remove( ctors[i] );
+}
+
+MacroList* MacroList::instance()
+{
+ static MacroList t;
+ return &t;
+}
+
+void MacroList::add( const std::vector<Macro*>& ms )
+{
+ copy( ms.begin(), ms.end(), back_inserter( mdata ) );
+ std::vector<GUIAction*> acts;
+ for ( uint i = 0; i < ms.size(); ++i )
+ {
+ ObjectConstructorList::instance()->add( ms[i]->ctor );
+ acts.push_back( ms[i]->action );
+ };
+ GUIActionList::instance()->add( acts );
+}
+
+void MacroList::add( Macro* m )
+{
+ mdata.push_back( m );
+ ObjectConstructorList::instance()->add( m->ctor );
+ GUIActionList::instance()->add( m->action );
+}
+
+void MacroList::remove( Macro* m )
+{
+ GUIAction* a = m->action;
+ ObjectConstructor* c = m->ctor;
+ mdata.erase( std::remove( mdata.begin(), mdata.end(), m ),
+ mdata.end() );
+ delete m;
+ GUIActionList::instance()->remove( a );
+ ObjectConstructorList::instance()->remove( c );
+}
+
+const MacroList::vectype& MacroList::macros() const
+{
+ return mdata;
+}
+
+Macro::~Macro()
+{
+}
+
+bool MacroList::save( Macro* m, const QString& f )
+{
+ std::vector<Macro*> ms;
+ ms.push_back( m );
+ return save( ms, f );
+}
+
+bool MacroList::save( const std::vector<Macro*>& ms, const QString& f )
+{
+ QDomDocument doc( "KigMacroFile" );
+
+ QDomElement docelem = doc.createElement( "KigMacroFile" );
+ docelem.setAttribute( "Version", KIGVERSION );
+ docelem.setAttribute( "Number", ms.size() );
+
+ for ( uint i = 0; i < ms.size(); ++i )
+ {
+ MacroConstructor* ctor = ms[i]->ctor;
+
+ QDomElement macroelem = doc.createElement( "Macro" );
+
+ // name
+ QDomElement nameelem = doc.createElement( "Name" );
+ nameelem.appendChild( doc.createTextNode( ctor->descriptiveName() ) );
+ macroelem.appendChild( nameelem );
+
+ // desc
+ QDomElement descelem = doc.createElement( "Description" );
+ descelem.appendChild( doc.createTextNode( ctor->description() ) );
+ macroelem.appendChild( descelem );
+
+ // icon
+ QCString icon = ctor->iconFileName( true );
+ if ( !icon.isNull() )
+ {
+ QDomElement descelem = doc.createElement( "IconFileName" );
+ descelem.appendChild( doc.createTextNode( icon ) );
+ macroelem.appendChild( descelem );
+ }
+
+ // data
+ QDomElement hierelem = doc.createElement( "Construction" );
+ ctor->hierarchy().serialize( hierelem, doc );
+ macroelem.appendChild( hierelem );
+
+ docelem.appendChild( macroelem );
+ };
+
+ doc.appendChild( docelem );
+
+ QFile file( f );
+ if ( ! file.open( IO_WriteOnly ) )
+ return false;
+ QTextStream stream( &file );
+ stream << doc.toCString();
+ return true;
+}
+
+bool MacroList::load( const QString& f, std::vector<Macro*>& ret, const KigPart& kdoc )
+{
+ QFile file( f );
+ if ( ! file.open( IO_ReadOnly ) )
+ {
+ KMessageBox::sorry( 0, i18n( "Could not open macro file '%1'" ).arg( f ) );
+ return false;
+ }
+ QDomDocument doc( "KigMacroFile" );
+ if ( !doc.setContent( &file ) )
+ {
+ KMessageBox::sorry( 0, i18n( "Could not open macro file '%1'" ).arg( f ) );
+ return false;
+ }
+ file.close();
+ QDomElement main = doc.documentElement();
+
+ if ( main.tagName() == "KigMacroFile" )
+ return loadNew( main, ret, kdoc );
+ else
+ {
+ KMessageBox::detailedSorry(
+ 0, i18n( "Kig cannot open the macro file \"%1\"." ).arg( f ),
+ i18n( "This file was created by a very old Kig version (pre-0.4). "
+ "Support for this format has been removed from recent Kig versions. "
+ "You can try to import this macro using a previous Kig version "
+ "(0.4 to 0.6) and then export it again in the new format." ),
+ i18n( "Not Supported" ) );
+ return false;
+ }
+}
+
+bool MacroList::loadNew( const QDomElement& docelem, std::vector<Macro*>& ret, const KigPart& )
+{
+ bool sok = true;
+ // unused..
+// int number = docelem.attribute( "Number" ).toInt( &sok );
+ if ( ! sok ) return false;
+
+ QString version = docelem.attribute( "Version" );
+// QRegExp re( "(\\d+)\\.(\\d+)\\.(\\d+)" );
+// re.match( version );
+ // unused..
+// int major = re.cap( 1 ).toInt( &sok );
+// int minor = re.cap( 2 ).toInt( &sok );
+// int mminor = re.cap( 3 ).toInt( &sok );
+// if ( ! sok ) return false;
+
+ int unnamedindex = 1;
+ QString tmp;
+
+ for ( QDomElement macroelem = docelem.firstChild().toElement();
+ ! macroelem.isNull(); macroelem = macroelem.nextSibling().toElement() )
+ {
+ QString name, description;
+ ObjectHierarchy* hierarchy = 0;
+ QCString actionname, iconfile;
+ if ( macroelem.tagName() != "Macro" ) continue; // forward compat ?
+ for ( QDomElement dataelem = macroelem.firstChild().toElement();
+ ! dataelem.isNull(); dataelem = dataelem.nextSibling().toElement() )
+ {
+ if ( dataelem.tagName() == "Name" )
+ name = dataelem.text();
+ else if ( dataelem.tagName() == "Description" )
+ description = dataelem.text();
+ else if ( dataelem.tagName() == "Construction" )
+ hierarchy = ObjectHierarchy::buildSafeObjectHierarchy( dataelem, tmp );
+ else if ( dataelem.tagName() == "ActionName" )
+ actionname = dataelem.text().latin1();
+ else if ( dataelem.tagName() == "IconFileName" )
+ iconfile = dataelem.text().latin1();
+ else continue;
+ };
+ assert( hierarchy );
+ // if the macro has no name, we give it a bogus name...
+ if ( name.isEmpty() )
+ name = i18n( "Unnamed Macro #%1" ).arg( unnamedindex++ );
+ MacroConstructor* ctor =
+ new MacroConstructor( *hierarchy, i18n( name.latin1() ), i18n( description.latin1() ), iconfile );
+ delete hierarchy;
+ GUIAction* act = new ConstructibleAction( ctor, actionname );
+ Macro* macro = new Macro( act, ctor );
+ ret.push_back( macro );
+ };
+ return true;
+}
+
+const ObjectConstructorList::vectype& ObjectConstructorList::constructors() const
+{
+ return mctors;
+}
diff --git a/kig/misc/lists.h b/kig/misc/lists.h
new file mode 100644
index 00000000..a3f97f1d
--- /dev/null
+++ b/kig/misc/lists.h
@@ -0,0 +1,170 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MISC_LISTS_H
+#define KIG_MISC_LISTS_H
+
+#include <vector>
+#include <set>
+
+class GUIAction;
+class ObjectConstructor;
+class MacroConstructor;
+class KigDocument;
+class KigPart;
+class KigWidget;
+class QString;
+class QDomElement;
+class ObjectCalcer;
+
+/**
+ * List of GUIActions for the parts to show. Note that the list owns
+ * the actions it receives..
+ */
+class GUIActionList
+{
+public:
+ typedef std::set<GUIAction*> avectype;
+ typedef std::set<KigPart*> dvectype;
+private:
+ avectype mactions;
+ dvectype mdocs;
+ GUIActionList();
+ ~GUIActionList();
+public:
+ static GUIActionList* instance();
+ const avectype& actions() const { return mactions; }
+
+ /**
+ * register this document, so that it receives notifications for
+ * added and removed actions..
+ */
+ void regDoc( KigPart* d );
+ void unregDoc( KigPart* d );
+
+ void add( GUIAction* a );
+ void add( const std::vector<GUIAction*>& a );
+ void remove( GUIAction* a );
+ void remove( const std::vector<GUIAction*>& a );
+};
+
+/**
+ * The list of object constructors for use in various places, e.g. RMB
+ * menu's. Note that the list owns the ctors it gets..
+ */
+class ObjectConstructorList
+{
+public:
+ typedef std::vector<ObjectConstructor*> vectype;
+private:
+ vectype mctors;
+ ObjectConstructorList();
+ ~ObjectConstructorList();
+public:
+ static ObjectConstructorList* instance();
+ void add( ObjectConstructor* a );
+ void remove( ObjectConstructor* a );
+ vectype ctorsThatWantArgs( const std::vector<ObjectCalcer*>&, const KigDocument&,
+ const KigWidget&, bool completeOnly = false
+ ) const;
+ const vectype& constructors() const;
+};
+
+/**
+ * this is just a simple data struct. doesn't have any functionality
+ * of its own..
+ */
+class Macro
+{
+public:
+ GUIAction* action;
+ MacroConstructor* ctor;
+ Macro( GUIAction* a, MacroConstructor* c );
+ ~Macro();
+};
+
+/**
+ * a simply equality operator for Macro class.
+ */
+bool operator==( const Macro& l, const Macro& r );
+
+/**
+ * This class keeps a list of all macro's, and allows them to be
+ * easily accessed, added etc. Macro objects are owned by this
+ * list..
+ */
+class MacroList
+{
+public:
+ typedef std::vector<Macro*> vectype;
+private:
+ vectype mdata;
+ MacroList();
+ ~MacroList();
+public:
+ /**
+ * MacroList is a singleton
+ */
+ static MacroList* instance();
+
+ /**
+ * Add a Macro \p m . MacroList takes care of adding the action and
+ * ctor in the relevant places..
+ */
+ void add( Macro* m );
+ /**
+ * Add the Macro's \p ms. MacroList takes care of adding the action
+ * and ctor in the relevant places..
+ */
+ void add( const vectype& ms );
+
+ /**
+ * Remove macro \p m . Macrolist takes care of deleting everything, and
+ * unregistering the action and ctor from the relevant places..
+ */
+ void remove( Macro* m );
+
+ /**
+ * Save macro \p m to file \p f ..
+ */
+ bool save( Macro* m, const QString& f );
+ /**
+ * Save macros \p ms to file \p f ..
+ */
+ bool save( const vectype& ms, const QString& f );
+
+ /**
+ * load macro's from file \p f ..
+ * note that this just returns the loaded macro's, and doesn't add
+ * them to the various lists. Use add() if you want
+ * that behaviour..
+ * The fact that this functions requires a KigPart argument is
+ * semantically incorrect, but i haven't been able to work around
+ * it..
+ */
+ bool load( const QString& f, vectype& ret, const KigPart& );
+
+ /**
+ * get access to the list of macro's..
+ */
+ const vectype& macros() const;
+
+private:
+ bool loadNew( const QDomElement& docelem, std::vector<Macro*>& ret, const KigPart& );
+};
+
+#endif
diff --git a/kig/misc/object_constructor.cc b/kig/misc/object_constructor.cc
new file mode 100644
index 00000000..5634d0d2
--- /dev/null
+++ b/kig/misc/object_constructor.cc
@@ -0,0 +1,609 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "object_constructor.h"
+
+#include "argsparser.h"
+#include "kigpainter.h"
+#include "guiaction.h"
+
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+
+#include "../objects/object_holder.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_type.h"
+#include "../objects/other_type.h"
+#include "../objects/object_imp.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/line_imp.h"
+#include "../objects/circle_imp.h"
+#include "../objects/point_imp.h"
+
+#include "../modes/construct_mode.h"
+
+#include <qpen.h>
+
+#include <klocale.h>
+
+#include <algorithm>
+#include <functional>
+
+const QString StandardConstructorBase::descriptiveName() const
+{
+ return i18n( mdescname );
+}
+
+const QString StandardConstructorBase::description() const
+{
+ return i18n( mdesc );
+}
+
+const QCString StandardConstructorBase::iconFileName( const bool ) const
+{
+ return miconfile;
+}
+
+const bool StandardConstructorBase::isAlreadySelectedOK( const std::vector<ObjectCalcer*>&, const int& ) const
+{
+ return false;
+}
+
+StandardConstructorBase::StandardConstructorBase(
+ const char* descname, const char* desc,
+ const char* iconfile, const ArgsParser& parser )
+ : mdescname( descname ),
+ mdesc( desc ),
+ miconfile( iconfile ),
+ margsparser( parser )
+{
+}
+
+const int StandardConstructorBase::wantArgs( const std::vector<ObjectCalcer*>& os,
+ const KigDocument&,
+ const KigWidget& ) const
+{
+ return margsparser.check( os );
+}
+
+void StandardConstructorBase::handleArgs(
+ const std::vector<ObjectCalcer*>& os, KigPart& d,
+ KigWidget& v ) const
+{
+ std::vector<ObjectHolder*> bos = build( os, d.document(), v );
+ for ( std::vector<ObjectHolder*>::iterator i = bos.begin();
+ i != bos.end(); ++i )
+ {
+ (*i)->calc( d.document() );
+ }
+
+ d.addObjects( bos );
+}
+
+void StandardConstructorBase::handlePrelim(
+ KigPainter& p, const std::vector<ObjectCalcer*>& os,
+ const KigDocument& d, const KigWidget&
+ ) const
+{
+ assert ( margsparser.check( os ) != ArgsParser::Invalid );
+ std::vector<ObjectCalcer*> args = margsparser.parse( os );
+ p.setBrushStyle( Qt::NoBrush );
+ p.setBrushColor( Qt::red );
+ p.setPen( QPen ( Qt::red, 1) );
+ p.setWidth( -1 ); // -1 means the default width for the object being
+ // drawn..
+
+ ObjectDrawer drawer( Qt::red );
+ drawprelim( drawer, p, args, d );
+}
+
+SimpleObjectTypeConstructor::SimpleObjectTypeConstructor(
+ const ArgsParserObjectType* t, const char* descname,
+ const char* desc, const char* iconfile )
+ : StandardConstructorBase( descname, desc, iconfile,
+ t->argsParser() ),
+ mtype( t )
+{
+}
+
+SimpleObjectTypeConstructor::~SimpleObjectTypeConstructor()
+{
+}
+
+void SimpleObjectTypeConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const
+{
+ Args args;
+ using namespace std;
+ transform( parents.begin(), parents.end(),
+ back_inserter( args ), mem_fun( &ObjectCalcer::imp ) );
+ ObjectImp* data = mtype->calc( args, doc );
+ drawer.draw( *data, p, true );
+ delete data;
+}
+
+std::vector<ObjectHolder*> SimpleObjectTypeConstructor::build(
+ const std::vector<ObjectCalcer*>& os, KigDocument&, KigWidget& ) const
+{
+ ObjectTypeCalcer* calcer = new ObjectTypeCalcer( mtype, os );
+ ObjectHolder* h = new ObjectHolder( calcer );
+ std::vector<ObjectHolder*> ret;
+ ret.push_back( h );
+ return ret;
+}
+
+StandardConstructorBase::~StandardConstructorBase()
+{
+}
+
+MultiObjectTypeConstructor::MultiObjectTypeConstructor(
+ const ArgsParserObjectType* t, const char* descname,
+ const char* desc, const char* iconfile,
+ const std::vector<int>& params )
+ : StandardConstructorBase( descname, desc, iconfile, mparser ),
+ mtype( t ), mparams( params ),
+ mparser( t->argsParser().without( IntImp::stype() ) )
+{
+}
+
+MultiObjectTypeConstructor::MultiObjectTypeConstructor(
+ const ArgsParserObjectType* t, const char* descname,
+ const char* desc, const char* iconfile,
+ int a, int b, int c, int d )
+ : StandardConstructorBase( descname, desc, iconfile, mparser ),
+ mtype( t ), mparams(),
+ mparser( t->argsParser().without( IntImp::stype() ) )
+{
+ mparams.push_back( a );
+ mparams.push_back( b );
+ if ( c != -999 ) mparams.push_back( c );
+ if ( d != -999 ) mparams.push_back( d );
+}
+
+MultiObjectTypeConstructor::~MultiObjectTypeConstructor()
+{
+}
+
+void MultiObjectTypeConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const
+{
+ Args args;
+ using namespace std;
+ transform( parents.begin(), parents.end(),
+ back_inserter( args ), mem_fun( &ObjectCalcer::imp ) );
+
+ for ( vector<int>::const_iterator i = mparams.begin(); i != mparams.end(); ++i )
+ {
+ IntImp param( *i );
+ args.push_back( &param );
+ ObjectImp* data = mtype->calc( args, doc );
+ drawer.draw( *data, p, true );
+ delete data;
+ args.pop_back();
+ };
+}
+
+std::vector<ObjectHolder*> MultiObjectTypeConstructor::build(
+ const std::vector<ObjectCalcer*>& os, KigDocument&, KigWidget& ) const
+{
+ std::vector<ObjectHolder*> ret;
+ for ( std::vector<int>::const_iterator i = mparams.begin();
+ i != mparams.end(); ++i )
+ {
+ ObjectConstCalcer* d = new ObjectConstCalcer( new IntImp( *i ) );
+
+ std::vector<ObjectCalcer*> args( os );
+ args.push_back( d );
+
+ ret.push_back( new ObjectHolder( new ObjectTypeCalcer( mtype, args ) ) );
+ };
+ return ret;
+}
+
+MergeObjectConstructor::~MergeObjectConstructor()
+{
+ for ( vectype::iterator i = mctors.begin(); i != mctors.end(); ++i )
+ delete *i;
+}
+
+MergeObjectConstructor::MergeObjectConstructor(
+ const char* descname, const char* desc, const char* iconfilename )
+ : ObjectConstructor(), mdescname( descname ), mdesc( desc ),
+ miconfilename( iconfilename ), mctors()
+{
+}
+
+ObjectConstructor::~ObjectConstructor()
+{
+}
+
+void MergeObjectConstructor::merge( ObjectConstructor* e )
+{
+ mctors.push_back( e );
+}
+
+const QString MergeObjectConstructor::descriptiveName() const
+{
+ return i18n( mdescname );
+}
+
+const QString MergeObjectConstructor::description() const
+{
+ return i18n( mdesc );
+}
+
+const QCString MergeObjectConstructor::iconFileName( const bool ) const
+{
+ return miconfilename;
+}
+
+const bool MergeObjectConstructor::isAlreadySelectedOK( const std::vector<ObjectCalcer*>&, const int& ) const
+{
+ return false;
+}
+
+const int MergeObjectConstructor::wantArgs(
+ const std::vector<ObjectCalcer*>& os, const KigDocument& d, const KigWidget& v ) const
+{
+ for ( vectype::const_iterator i = mctors.begin(); i != mctors.end(); ++i )
+ {
+ int w = (*i)->wantArgs( os, d, v );
+ if ( w != ArgsParser::Invalid ) return w;
+ };
+ return ArgsParser::Invalid;
+}
+
+void MergeObjectConstructor::handleArgs(
+ const std::vector<ObjectCalcer*>& os, KigPart& d, KigWidget& v ) const
+{
+ for ( vectype::const_iterator i = mctors.begin(); i != mctors.end(); ++i )
+ {
+ int w = (*i)->wantArgs( os, d.document(), v );
+ if ( w == ArgsParser::Complete )
+ {
+ (*i)->handleArgs( os, d, v );
+ return;
+ };
+ };
+ assert( false );
+}
+
+void MergeObjectConstructor::handlePrelim(
+ KigPainter& p, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d, const KigWidget& v ) const
+{
+ for ( vectype::const_iterator i = mctors.begin(); i != mctors.end(); ++i )
+ {
+ int w = (*i)->wantArgs( sel, d, v );
+ if ( w != ArgsParser::Invalid )
+ {
+ (*i)->handlePrelim( p, sel, d, v );
+ return;
+ };
+ };
+}
+
+QString StandardConstructorBase::useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument&, const KigWidget& ) const
+{
+ using namespace std;
+ Args args;
+ transform( sel.begin(), sel.end(), back_inserter( args ), mem_fun( &ObjectCalcer::imp ) );
+
+ std::string ret = margsparser.usetext( o.imp(), args );
+ if ( ret.empty() ) return QString::null;
+ return i18n( ret.c_str() );
+}
+
+QString StandardConstructorBase::selectStatement(
+ const std::vector<ObjectCalcer*>& sel, const KigDocument&,
+ const KigWidget& ) const
+{
+ using namespace std;
+ Args args;
+ transform( sel.begin(), sel.end(), back_inserter( args ), mem_fun( &ObjectCalcer::imp ) );
+
+ std::string ret = margsparser.selectStatement( args );
+ if ( ret.empty() ) return QString::null;
+ return i18n( ret.c_str() );
+}
+
+QString MergeObjectConstructor::useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d, const KigWidget& v ) const
+{
+ for ( vectype::const_iterator i = mctors.begin(); i != mctors.end(); ++i )
+ {
+ std::vector<ObjectCalcer*> args( sel );
+ int w = (*i)->wantArgs( args, d, v );
+ if ( w != ArgsParser::Invalid ) return (*i)->useText( o, sel, d, v );
+ };
+ return QString::null;
+}
+
+QString MergeObjectConstructor::selectStatement(
+ const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& w ) const
+{
+ for ( vectype::const_iterator i = mctors.begin(); i != mctors.end(); ++i )
+ {
+ std::vector<ObjectCalcer*> args( sel );
+ int wa = (*i)->wantArgs( args, d, w );
+ if ( wa != ArgsParser::Invalid ) return (*i)->selectStatement( sel, d, w );
+ };
+ return QString::null;
+}
+
+MacroConstructor::MacroConstructor( const ObjectHierarchy& hier, const QString& name,
+ const QString& desc, const QCString& iconfile )
+ : ObjectConstructor(), mhier( hier ), mname( name ), mdesc( desc ),
+ mbuiltin( false ), miconfile( iconfile ),
+ mparser( mhier.argParser() )
+{
+}
+
+MacroConstructor::MacroConstructor(
+ const std::vector<ObjectCalcer*>& input, const std::vector<ObjectCalcer*>& output,
+ const QString& name, const QString& description,
+ const QCString& iconfile )
+ : ObjectConstructor(), mhier( input, output ),
+ mname( name ), mdesc( description ), mbuiltin( false ),
+ miconfile( iconfile ),
+ mparser( mhier.argParser() )
+{
+}
+
+MacroConstructor::~MacroConstructor()
+{
+}
+
+const QString MacroConstructor::descriptiveName() const
+{
+ return mname;
+}
+
+const QString MacroConstructor::description() const
+{
+ return mdesc;
+}
+
+const QCString MacroConstructor::iconFileName( const bool canBeNull ) const
+{
+ return ( miconfile.isNull() && !canBeNull ) ? QCString( "gear" ) : miconfile;
+}
+
+const bool MacroConstructor::isAlreadySelectedOK( const std::vector<ObjectCalcer*>&, const int& ) const
+{
+ return false;
+}
+
+const int MacroConstructor::wantArgs( const std::vector<ObjectCalcer*>& os, const KigDocument&,
+ const KigWidget& ) const
+{
+ return mparser.check( os );
+}
+
+void MacroConstructor::handleArgs( const std::vector<ObjectCalcer*>& os, KigPart& d,
+ KigWidget& ) const
+{
+ std::vector<ObjectCalcer*> args = mparser.parse( os );
+ std::vector<ObjectCalcer*> bos = mhier.buildObjects( args, d.document() );
+ std::vector<ObjectHolder*> hos;
+ for ( std::vector<ObjectCalcer*>::iterator i = bos.begin();
+ i != bos.end(); ++i )
+ {
+ hos.push_back( new ObjectHolder( *i ) );
+ hos.back()->calc( d.document() );
+ }
+
+ d.addObjects( hos );
+}
+
+QString MacroConstructor::selectStatement(
+ const std::vector<ObjectCalcer*>& sel, const KigDocument&,
+ const KigWidget& ) const
+{
+ using namespace std;
+ Args args;
+ transform( sel.begin(), sel.end(), back_inserter( args ),
+ mem_fun( &ObjectCalcer::imp ) );
+ std::string ret = mparser.selectStatement( args );
+ if ( ret.empty() ) return QString::null;
+ else return i18n( ret.c_str() );
+}
+
+QString MacroConstructor::useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument&, const KigWidget&
+ ) const
+{
+ using namespace std;
+ Args args;
+ transform( sel.begin(), sel.end(), back_inserter( args ),
+ mem_fun( &ObjectCalcer::imp ) );
+ std::string ret = mparser.usetext( o.imp(), args );
+ if ( ret.empty() ) return QString::null;
+ else return i18n( ret.c_str() );
+}
+
+void MacroConstructor::handlePrelim( KigPainter& p, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& doc, const KigWidget&
+ ) const
+{
+ if ( sel.size() != mhier.numberOfArgs() ) return;
+
+ using namespace std;
+ Args args;
+ transform( sel.begin(), sel.end(), back_inserter( args ),
+ mem_fun( &ObjectCalcer::imp ) );
+ args = mparser.parse( args );
+ std::vector<ObjectImp*> ret = mhier.calc( args, doc );
+ for ( uint i = 0; i < ret.size(); ++i )
+ {
+ ObjectDrawer d;
+ d.draw( *ret[i], p, true );
+ ret[i]->draw( p );
+ delete ret[i];
+ };
+}
+
+void SimpleObjectTypeConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+void MultiObjectTypeConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+void MergeObjectConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+void MacroConstructor::plug( KigPart* doc, KigGUIAction* kact )
+{
+ if ( mbuiltin ) return;
+ if ( mhier.numberOfResults() != 1 )
+ doc->aMNewOther.append( kact );
+ else
+ {
+ if ( mhier.idOfLastResult() == SegmentImp::stype() )
+ doc->aMNewSegment.append( kact );
+ else if ( mhier.idOfLastResult() == PointImp::stype() )
+ doc->aMNewPoint.append( kact );
+ else if ( mhier.idOfLastResult() == CircleImp::stype() )
+ doc->aMNewCircle.append( kact );
+ else if ( mhier.idOfLastResult()->inherits( AbstractLineImp::stype() ) )
+ // line or ray
+ doc->aMNewLine.append( kact );
+ else if ( mhier.idOfLastResult() == ConicImp::stype() )
+ doc->aMNewConic.append( kact );
+ else doc->aMNewOther.append( kact );
+ };
+ doc->aMNewAll.append( kact );
+}
+
+const ObjectHierarchy& MacroConstructor::hierarchy() const
+{
+ return mhier;
+}
+
+bool SimpleObjectTypeConstructor::isTransform() const
+{
+ return mtype->isTransform();
+}
+
+bool MultiObjectTypeConstructor::isTransform() const
+{
+ return mtype->isTransform();
+}
+
+bool MergeObjectConstructor::isTransform() const
+{
+ bool ret = false;
+ for ( vectype::const_iterator i = mctors.begin(); i != mctors.end(); ++i )
+ ret |= (*i)->isTransform();
+ return ret;
+}
+
+bool MacroConstructor::isTransform() const
+{
+ return false;
+}
+
+void MacroConstructor::setBuiltin( bool builtin )
+{
+ mbuiltin = builtin;
+}
+
+bool ObjectConstructor::isIntersection() const
+{
+ return false;
+}
+
+PropertyObjectConstructor::PropertyObjectConstructor(
+ const ObjectImpType* imprequirement, const char* usetext,
+ const char* selectstat, const char* descname, const char* desc,
+ const char* iconfile, const char* propertyinternalname )
+ : StandardConstructorBase( descname, desc, iconfile, mparser ),
+ mpropinternalname( propertyinternalname )
+{
+ ArgsParser::spec argsspec[1];
+ argsspec[0].type = imprequirement;
+ argsspec[0].usetext = usetext;
+ argsspec[0].selectstat = selectstat;
+ mparser.initialize( argsspec, 1 );
+}
+
+PropertyObjectConstructor::~PropertyObjectConstructor()
+{
+}
+
+void PropertyObjectConstructor::drawprelim(
+ const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& d ) const
+{
+ int index = parents[0]->imp()->propertiesInternalNames().findIndex( mpropinternalname );
+ assert ( index != -1 );
+ ObjectImp* imp = parents[0]->imp()->property( index, d );
+ drawer.draw( *imp, p, true );
+ delete imp;
+}
+
+std::vector<ObjectHolder*> PropertyObjectConstructor::build(
+ const std::vector<ObjectCalcer*>& parents, KigDocument&,
+ KigWidget& ) const
+{
+ int index = parents[0]->imp()->propertiesInternalNames().findIndex( mpropinternalname );
+ assert( index != -1 );
+ std::vector<ObjectHolder*> ret;
+ ret.push_back(
+ new ObjectHolder(
+ new ObjectPropertyCalcer( parents[0], index ) ) );
+ return ret;
+}
+
+void PropertyObjectConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+bool PropertyObjectConstructor::isTransform() const
+{
+ return false;
+}
+
+bool ObjectConstructor::isTest() const
+{
+ return false;
+}
+
+BaseConstructMode* ObjectConstructor::constructMode( KigPart& doc )
+{
+ return new ConstructMode( doc, this );
+}
+
+void MacroConstructor::setName( const QString& name )
+{
+ mname = name;
+}
+
+void MacroConstructor::setDescription( const QString& desc )
+{
+ mdesc = desc;
+}
+
+void MacroConstructor::setIcon( QCString& icon )
+{
+ miconfile = icon;
+}
diff --git a/kig/misc/object_constructor.h b/kig/misc/object_constructor.h
new file mode 100644
index 00000000..57261c69
--- /dev/null
+++ b/kig/misc/object_constructor.h
@@ -0,0 +1,396 @@
+// Copyright (C) 2002-2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MISC_OBJECT_CONSTRUCTOR_H
+#define KIG_MISC_OBJECT_CONSTRUCTOR_H
+
+#include "argsparser.h"
+#include "object_hierarchy.h"
+
+class KigPainter;
+class KigDocument;
+class KigGUIAction;
+class KigWidget;
+class ArgsParserObjectType;
+class ObjectType;
+class BaseConstructMode;
+
+class QString;
+class QCString;
+
+/**
+ * This class represents a way to construct a set of objects from a
+ * set of other objects. There are some important child classes, like
+ * MacroConstructor, StandardObjectConstructor etc. ( see below )
+ * Actually, it is more generic than that, it provides a way to do
+ * _something_ with a set of objects, but for now, i only use it to
+ * construct objects. Maybe some day, i'll find something more
+ * interesting to do with it, who knows... ;)
+ */
+class ObjectConstructor
+{
+public:
+ virtual ~ObjectConstructor();
+
+ virtual const QString descriptiveName() const = 0;
+ virtual const QString description() const = 0;
+ virtual const QCString iconFileName( const bool canBeNull = false ) const = 0;
+
+ /**
+ * the following function is called in case of duplication of arguments
+ * and returns true if this is acceptable; this will return false for
+ * typical objects
+ */
+ virtual const bool isAlreadySelectedOK( const std::vector<ObjectCalcer*>& os,
+ const int& ) const = 0;
+ /**
+ * can this constructor do something useful with \p os ? return
+ * ArgsParser::Complete, Valid or NotGood
+ */
+ virtual const int wantArgs( const std::vector<ObjectCalcer*>& os,
+ const KigDocument& d,
+ const KigWidget& v
+ ) const = 0;
+
+ /**
+ * do something fun with \p os .. This func is only called if wantArgs
+ * returned Complete.. handleArgs should <i>not</i> do any
+ * drawing.. after somebody calls this function, he should
+ * redrawScreen() himself..
+ */
+ virtual void handleArgs( const std::vector<ObjectCalcer*>& os,
+ KigPart& d,
+ KigWidget& v
+ ) const = 0;
+
+ /**
+ * return a string describing what you would use \p o for if it were
+ * selected... \p o should be part of \p sel .
+ */
+ virtual QString useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d, const KigWidget& v
+ ) const = 0;
+
+ /**
+ * return a string describing what argument you want next, if the
+ * given selection of objects were selected.
+ */
+ virtual QString selectStatement(
+ const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& w ) const = 0;
+
+ /**
+ * show a preliminary version of what you would do when \ref handleArgs
+ * would be called.. E.g. if this constructor normally constructs a
+ * locus through some 5 points, then it will try to draw a locus
+ * through whatever number of points it gets..
+ */
+ virtual void handlePrelim( KigPainter& p,
+ const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d,
+ const KigWidget& v
+ ) const = 0;
+
+ virtual void plug( KigPart* doc, KigGUIAction* kact ) = 0;
+
+ virtual bool isTransform() const = 0;
+ virtual bool isTest() const;
+ virtual bool isIntersection() const;
+
+ /**
+ * Which construct mode should be used for this ObjectConstructor.
+ * In fact, this is not a pretty design. The Kig
+ * GUIAction-ObjectConstructor stuff should be reworked into a
+ * general GUIAction, which just models something which can be
+ * executed given a certain number of arguments. The code for
+ * drawPrelim and such should all be in the ConstructMode, and the
+ * new GUIAction should just start the correct KigMode with the
+ * correct arguments.
+ *
+ * This function is only overridden in TestConstructor.
+ */
+ virtual BaseConstructMode* constructMode( KigPart& doc );
+};
+
+/**
+ * This class provides wraps ObjectConstructor in a more simple
+ * interface for the most common object types..
+ */
+class StandardConstructorBase
+ : public ObjectConstructor
+{
+ const char* mdescname;
+ const char* mdesc;
+ const char* miconfile;
+ const ArgsParser& margsparser;
+public:
+ StandardConstructorBase( const char* descname,
+ const char* desc,
+ const char* iconfile,
+ const ArgsParser& parser );
+
+ virtual ~StandardConstructorBase();
+
+ const QString descriptiveName() const;
+ const QString description() const;
+ const QCString iconFileName( const bool canBeNull = false ) const;
+
+ const bool isAlreadySelectedOK( const std::vector<ObjectCalcer*>& os,
+ const int& ) const;
+ virtual const int wantArgs(
+ const std::vector<ObjectCalcer*>& os, const KigDocument& d,
+ const KigWidget& v
+ ) const;
+
+ void handleArgs( const std::vector<ObjectCalcer*>& os,
+ KigPart& d,
+ KigWidget& v
+ ) const;
+
+ void handlePrelim( KigPainter& p, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d, const KigWidget& v
+ ) const;
+
+ virtual void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& ) const = 0;
+
+ QString useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d, const KigWidget& v ) const;
+
+ QString selectStatement(
+ const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& w ) const;
+
+ virtual std::vector<ObjectHolder*> build(
+ const std::vector<ObjectCalcer*>& os,
+ KigDocument& d, KigWidget& w
+ ) const = 0;
+};
+
+/**
+ * A standard implementation of StandardConstructorBase for simple
+ * types..
+ */
+class SimpleObjectTypeConstructor
+ : public StandardConstructorBase
+{
+ const ArgsParserObjectType* mtype;
+public:
+ SimpleObjectTypeConstructor(
+ const ArgsParserObjectType* t, const char* descname,
+ const char* desc, const char* iconfile );
+
+ ~SimpleObjectTypeConstructor();
+
+ void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& ) const;
+
+ std::vector<ObjectHolder*> build( const std::vector<ObjectCalcer*>& os,
+ KigDocument& d,
+ KigWidget& w ) const;
+
+ void plug( KigPart* doc, KigGUIAction* kact );
+
+ bool isTransform() const;
+};
+
+/**
+ * A standard implementation of StandardConstructorBase for property
+ * objects...
+ */
+class PropertyObjectConstructor
+ : public StandardConstructorBase
+{
+ ArgsParser mparser;
+ const char* mpropinternalname;
+public:
+ PropertyObjectConstructor(
+ const ObjectImpType* imprequirement, const char* usetext,
+ const char* selectstat, const char* descname, const char* desc,
+ const char* iconfile, const char* propertyinternalname );
+
+ ~PropertyObjectConstructor();
+
+ void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& ) const;
+
+ std::vector<ObjectHolder*> build( const std::vector<ObjectCalcer*>& os,
+ KigDocument& d, KigWidget& w ) const;
+
+ void plug( KigPart* doc, KigGUIAction* kact );
+
+ bool isTransform() const;
+};
+
+/**
+ * This class is the equivalent of \ref SimpleObjectTypeConstructor
+ * for object types that are constructed in groups of more than one.
+ * For example, the intersection of a circle and line in general
+ * produces two points, in general. Internally, we differentiate
+ * betweem them by passing them a parameter of ( in this case ) 1 or
+ * -1. There are still other object types that work the same, and
+ * they all require this sort of parameter.
+ * E.g. CubicLineIntersectionType takes a parameter between 1 and 3.
+ * This class knows about that, and constructs the objects along this
+ * scheme..
+ */
+class MultiObjectTypeConstructor
+ : public StandardConstructorBase
+{
+ const ArgsParserObjectType* mtype;
+ std::vector<int> mparams;
+ ArgsParser mparser;
+public:
+ MultiObjectTypeConstructor(
+ const ArgsParserObjectType* t, const char* descname,
+ const char* desc, const char* iconfile,
+ const std::vector<int>& params );
+ MultiObjectTypeConstructor(
+ const ArgsParserObjectType* t, const char* descname,
+ const char* desc, const char* iconfile,
+ int a, int b, int c = -999, int d = -999 );
+ ~MultiObjectTypeConstructor();
+
+ void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& ) const;
+
+ std::vector<ObjectHolder*> build(
+ const std::vector<ObjectCalcer*>& os,
+ KigDocument& d, KigWidget& w ) const;
+
+ void plug( KigPart* doc, KigGUIAction* kact );
+
+ bool isTransform() const;
+};
+
+/**
+ * This class is a collection of some other ObjectConstructors, that
+ * makes them appear to the user as a single ObjectConstructor. It is
+ * e.g. used for the "intersection" constructor.
+ */
+class MergeObjectConstructor
+ : public ObjectConstructor
+{
+ const char* mdescname;
+ const char* mdesc;
+ const char* miconfilename;
+ typedef std::vector<ObjectConstructor*> vectype;
+ vectype mctors;
+public:
+ MergeObjectConstructor( const char* descname, const char* desc,
+ const char* iconfilename );
+ ~MergeObjectConstructor();
+
+ void merge( ObjectConstructor* e );
+
+ const QString descriptiveName() const;
+ const QString description() const;
+ const QCString iconFileName( const bool canBeNull = false ) const;
+
+ const bool isAlreadySelectedOK( const std::vector<ObjectCalcer*>& os,
+ const int& ) const;
+ const int wantArgs( const std::vector<ObjectCalcer*>& os,
+ const KigDocument& d,
+ const KigWidget& v
+ ) const;
+
+ QString useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d, const KigWidget& v ) const;
+
+ QString selectStatement(
+ const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& w ) const;
+
+ void handleArgs( const std::vector<ObjectCalcer*>& os, KigPart& d, KigWidget& v ) const;
+
+ void handlePrelim( KigPainter& p, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d, const KigWidget& v ) const;
+
+ void plug( KigPart* doc, KigGUIAction* kact );
+
+ bool isTransform() const;
+};
+
+/**
+ * MacroConstructor is a class that represents Kig macro's: these are
+ * constructed by the user, and defined by a set of input and a set of
+ * output objects. The macro-constructor saves the way in which the
+ * output objects have been built from the input objects, and when
+ * given similar input objects, it will produce objects in the given
+ * way. The data is saved in a \ref ObjectHierarchy.
+ */
+class MacroConstructor
+ : public ObjectConstructor
+{
+ ObjectHierarchy mhier;
+ QString mname;
+ QString mdesc;
+ bool mbuiltin;
+ QCString miconfile;
+ ArgsParser mparser;
+public:
+ MacroConstructor( const std::vector<ObjectCalcer*>& input, const std::vector<ObjectCalcer*>& output,
+ const QString& name, const QString& description,
+ const QCString& iconfile = 0 );
+ MacroConstructor( const ObjectHierarchy& hier, const QString& name,
+ const QString& desc,
+ const QCString& iconfile = 0 );
+ ~MacroConstructor();
+
+ const ObjectHierarchy& hierarchy() const;
+
+ const QString descriptiveName() const;
+ const QString description() const;
+ const QCString iconFileName( const bool canBeNull = false ) const;
+
+ const bool isAlreadySelectedOK( const std::vector<ObjectCalcer*>& os,
+ const int& ) const;
+ const int wantArgs( const std::vector<ObjectCalcer*>& os, const KigDocument& d,
+ const KigWidget& v ) const;
+
+ void handleArgs( const std::vector<ObjectCalcer*>& os, KigPart& d,
+ KigWidget& v ) const;
+
+ QString useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d, const KigWidget& v
+ ) const;
+
+ QString selectStatement(
+ const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& w ) const;
+
+ void handlePrelim( KigPainter& p, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d, const KigWidget& v
+ ) const;
+
+ void plug( KigPart* doc, KigGUIAction* kact );
+
+ void setBuiltin( bool builtin );
+
+ /**
+ * is this the ctor for a transformation type. We want to know this
+ * cause transform types are shown separately in an object's RMB
+ * menu..
+ */
+ bool isTransform() const;
+
+ void setName( const QString& name );
+ void setDescription( const QString& desc );
+ void setIcon( QCString& icon );
+};
+
+#endif
diff --git a/kig/misc/object_hierarchy.cc b/kig/misc/object_hierarchy.cc
new file mode 100644
index 00000000..9102051a
--- /dev/null
+++ b/kig/misc/object_hierarchy.cc
@@ -0,0 +1,774 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "object_hierarchy.h"
+
+#include "../objects/object_holder.h"
+#include "../objects/other_type.h"
+#include "../objects/object_imp.h"
+#include "../objects/object_imp_factory.h"
+#include "../objects/object_type_factory.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/transform_types.h"
+#include "../objects/object_type.h"
+
+#include <kglobal.h>
+#include <qdom.h>
+
+class ObjectHierarchy::Node
+{
+public:
+ enum { ID_PushStack, ID_ApplyType, ID_FetchProp };
+ virtual int id() const = 0;
+
+ virtual ~Node();
+ virtual Node* copy() const = 0;
+
+ virtual void apply( std::vector<const ObjectImp*>& stack, int loc,
+ const KigDocument& ) const = 0;
+
+ virtual void apply( std::vector<ObjectCalcer*>& stack, int loc ) const = 0;
+
+ // this function is used to check whether the final objects depend
+ // on the given objects. The dependsstack contains a set of
+ // booleans telling which parts of the hierarchy certainly depend on
+ // the given objects. In this function, the node should check
+ // whether any of its parents have true set, and if so, set its own
+ // value to true.
+ virtual void checkDependsOnGiven( std::vector<bool>& dependsstack, int loc ) const = 0;
+ // this function is used to check whether the given objects are all
+ // used by one or more of the final objects. The usedstack contains
+ // a set of booleans telling which parts of the hierarchy are
+ // certainly ancestors of the final objects. In this function, the
+ // node should set all of its parents' booleans to true.
+ virtual void checkArgumentsUsed( std::vector<bool>& usedstack ) const = 0;
+};
+
+ObjectHierarchy::Node::~Node()
+{
+}
+
+class PushStackNode
+ : public ObjectHierarchy::Node
+{
+ ObjectImp* mimp;
+public:
+ PushStackNode( ObjectImp* imp ) : mimp( imp ) {}
+ ~PushStackNode();
+
+ const ObjectImp* imp() const { return mimp; }
+
+ int id() const;
+ Node* copy() const;
+ void apply( std::vector<const ObjectImp*>& stack,
+ int loc, const KigDocument& ) const;
+ void apply( std::vector<ObjectCalcer*>& stack, int loc ) const;
+
+ void checkDependsOnGiven( std::vector<bool>& dependsstack, int loc ) const;
+ void checkArgumentsUsed( std::vector<bool>& usedstack ) const;
+};
+
+void PushStackNode::checkArgumentsUsed( std::vector<bool>& ) const
+{
+}
+
+void PushStackNode::apply( std::vector<ObjectCalcer*>& stack, int loc ) const
+{
+ stack[loc] = new ObjectConstCalcer( mimp->copy() );
+}
+
+void PushStackNode::checkDependsOnGiven( std::vector<bool>&, int ) const {
+ // pushstacknode depends on nothing..
+ return;
+}
+
+int PushStackNode::id() const { return ID_PushStack; }
+
+PushStackNode::~PushStackNode()
+{
+ delete mimp;
+}
+
+ObjectHierarchy::Node* PushStackNode::copy() const
+{
+ return new PushStackNode( mimp->copy() );
+}
+
+void PushStackNode::apply( std::vector<const ObjectImp*>& stack,
+ int loc, const KigDocument& ) const
+{
+ stack[loc] = mimp->copy();
+}
+
+class ApplyTypeNode
+ : public ObjectHierarchy::Node
+{
+ const ObjectType* mtype;
+ std::vector<int> mparents;
+public:
+ ApplyTypeNode( const ObjectType* type, const std::vector<int>& parents )
+ : mtype( type ), mparents( parents ) {}
+ ~ApplyTypeNode();
+ Node* copy() const;
+
+ const ObjectType* type() const { return mtype; }
+ const std::vector<int>& parents() const { return mparents; }
+
+ int id() const;
+ void apply( std::vector<const ObjectImp*>& stack,
+ int loc, const KigDocument& ) const;
+ void apply( std::vector<ObjectCalcer*>& stack, int loc ) const;
+
+ void checkDependsOnGiven( std::vector<bool>& dependsstack, int loc ) const;
+ void checkArgumentsUsed( std::vector<bool>& usedstack ) const;
+};
+
+int ApplyTypeNode::id() const { return ID_ApplyType; }
+
+void ApplyTypeNode::checkArgumentsUsed( std::vector<bool>& usedstack ) const
+{
+ for ( uint i = 0; i < mparents.size(); ++i )
+ {
+ usedstack[mparents[i]] = true;
+ }
+}
+
+void ApplyTypeNode::checkDependsOnGiven( std::vector<bool>& dependsstack, int loc ) const
+{
+ bool result = false;
+ for ( uint i = 0; i < mparents.size(); ++i )
+ if ( dependsstack[mparents[i]] == true ) result = true;
+ dependsstack[loc] = result;
+}
+
+ApplyTypeNode::~ApplyTypeNode()
+{
+}
+
+ObjectHierarchy::Node* ApplyTypeNode::copy() const
+{
+ return new ApplyTypeNode( mtype, mparents );
+}
+
+void ApplyTypeNode::apply( std::vector<ObjectCalcer*>& stack, int loc ) const
+{
+ std::vector<ObjectCalcer*> parents;
+ for ( uint i = 0; i < mparents.size(); ++i )
+ parents.push_back( stack[ mparents[i] ] );
+ stack[loc] = new ObjectTypeCalcer( mtype, parents );
+}
+
+void ApplyTypeNode::apply( std::vector<const ObjectImp*>& stack,
+ int loc, const KigDocument& doc ) const
+{
+ Args args;
+ for ( uint i = 0; i < mparents.size(); ++i )
+ args.push_back( stack[mparents[i]] );
+ args = mtype->sortArgs( args );
+ stack[loc] = mtype->calc( args, doc );
+}
+
+class FetchPropertyNode
+ : public ObjectHierarchy::Node
+{
+ mutable int mpropid;
+ int mparent;
+ const QCString mname;
+public:
+ // propid is a cache of the location of name in the parent's
+ // propertiesInternalNames(), just as it is in PropertyObject. We
+ // don't want to ever save this value, since we cannot guarantee it
+ // remains consistent if we add properties some place..
+ FetchPropertyNode( const int parent, const QCString& name, const int propid = -1 )
+ : mpropid( propid ), mparent( parent ), mname( name ) {}
+ ~FetchPropertyNode();
+ Node* copy() const;
+
+ void checkDependsOnGiven( std::vector<bool>& dependsstack, int loc ) const;
+ void checkArgumentsUsed( std::vector<bool>& usedstack ) const;
+ int parent() const { return mparent; }
+ const QCString& propinternalname() const { return mname; }
+
+ int id() const;
+ void apply( std::vector<const ObjectImp*>& stack,
+ int loc, const KigDocument& ) const;
+ void apply( std::vector<ObjectCalcer*>& stack, int loc ) const;
+};
+
+FetchPropertyNode::~FetchPropertyNode()
+{
+}
+
+void FetchPropertyNode::checkArgumentsUsed( std::vector<bool>& usedstack ) const
+{
+ usedstack[mparent] = true;
+}
+
+void FetchPropertyNode::checkDependsOnGiven( std::vector<bool>& dependsstack, int loc ) const
+{
+ dependsstack[loc] = dependsstack[mparent];
+}
+
+ObjectHierarchy::Node* FetchPropertyNode::copy() const
+{
+ return new FetchPropertyNode( mparent, mname, mpropid );
+}
+
+int FetchPropertyNode::id() const
+{
+ return ID_FetchProp;
+}
+
+void FetchPropertyNode::apply( std::vector<const ObjectImp*>& stack,
+ int loc, const KigDocument& d ) const
+{
+ assert( stack[mparent] );
+ if ( mpropid == -1 ) mpropid = stack[mparent]->propertiesInternalNames().findIndex( mname );
+ if ( mpropid != -1 )
+ stack[loc] = stack[mparent]->property( mpropid, d );
+ else
+ stack[loc] = new InvalidImp();
+}
+
+void FetchPropertyNode::apply( std::vector<ObjectCalcer*>& stack, int loc ) const
+{
+ if ( mpropid == -1 )
+ mpropid = stack[mparent]->imp()->propertiesInternalNames().findIndex( mname );
+ assert( mpropid != -1 );
+ stack[loc] = new ObjectPropertyCalcer( stack[mparent], mpropid );
+}
+
+std::vector<ObjectImp*> ObjectHierarchy::calc( const Args& a, const KigDocument& doc ) const
+{
+ assert( a.size() == mnumberofargs );
+ for ( uint i = 0; i < a.size(); ++i )
+ assert( a[i]->inherits( margrequirements[i] ) );
+
+ std::vector<const ObjectImp*> stack;
+ stack.resize( mnodes.size() + mnumberofargs, 0 );
+ std::copy( a.begin(), a.end(), stack.begin() );
+ for( uint i = 0; i < mnodes.size(); ++i )
+ {
+ mnodes[i]->apply( stack, mnumberofargs + i, doc );
+ };
+ for ( uint i = mnumberofargs; i < stack.size() - mnumberofresults; ++i )
+ delete stack[i];
+ if ( stack.size() < mnumberofargs + mnumberofresults )
+ {
+ std::vector<ObjectImp*> ret;
+ ret.push_back( new InvalidImp );
+ return ret;
+ }
+ else
+ {
+ std::vector<ObjectImp*> ret;
+ for ( uint i = stack.size() - mnumberofresults; i < stack.size(); ++i )
+ ret.push_back( const_cast<ObjectImp*>( stack[i] ) );
+ return ret;
+ };
+}
+
+int ObjectHierarchy::visit( const ObjectCalcer* o, std::map<const ObjectCalcer*, int>& seenmap,
+ bool needed, bool neededatend )
+{
+ using namespace std;
+
+ std::map<const ObjectCalcer*, int>::iterator smi = seenmap.find( o );
+ if ( smi != seenmap.end() )
+ {
+ if ( neededatend )
+ {
+ // neededatend means that this object is one of the resultant
+ // objects. Therefore, its node has to appear at the end,
+ // because that's where we expect it.. We therefore copy it
+ // there using CopyObjectType..
+ int ret = mnumberofargs + mnodes.size();
+ std::vector<int> parents;
+ parents.push_back( smi->second );
+ mnodes.push_back( new ApplyTypeNode( CopyObjectType::instance(), parents ) );
+ return ret;
+ }
+ else return smi->second;
+ }
+
+ std::vector<ObjectCalcer*> p( o->parents() );
+ // we check if o descends from the given objects..
+ bool descendsfromgiven = false;
+ std::vector<int> parents;
+ parents.resize( p.size(), -1 );
+ for ( uint i = 0; i < p.size(); ++i )
+ {
+ int v = visit( p[i], seenmap, false );
+ parents[i] = v;
+ descendsfromgiven |= (v != -1);
+ };
+
+ if ( ! descendsfromgiven && ! ( needed && o->imp()->isCache() ) )
+ {
+ if ( needed )
+ {
+ assert( ! o->imp()->isCache() );
+ // o is an object that does not depend on the given objects, but
+ // is needed by other objects, so we just have to just save its
+ // current value here.
+ Node* node = new PushStackNode( o->imp()->copy() );
+ mnodes.push_back( node );
+ int ret = mnodes.size() + mnumberofargs - 1;
+ seenmap[o] = ret;
+ return ret;
+ }
+ else
+ return -1;
+ };
+
+ return storeObject( o, p, parents, seenmap );
+}
+
+ObjectHierarchy::~ObjectHierarchy()
+{
+ for ( uint i = 0; i < mnodes.size(); ++i ) delete mnodes[i];
+}
+
+ObjectHierarchy::ObjectHierarchy( const ObjectHierarchy& h )
+ : mnumberofargs( h.mnumberofargs ), mnumberofresults( h.mnumberofresults ),
+ margrequirements( h.margrequirements ), musetexts( h.musetexts ),
+ mselectstatements( h.mselectstatements )
+{
+ mnodes.reserve( h.mnodes.size() );
+ for ( uint i = 0; i < h.mnodes.size(); ++i )
+ mnodes.push_back( h.mnodes[i]->copy() );
+}
+
+ObjectHierarchy ObjectHierarchy::withFixedArgs( const Args& a ) const
+{
+ assert( a.size() <= mnumberofargs );
+ ObjectHierarchy ret( *this );
+
+ ret.mnumberofargs -= a.size();
+ ret.margrequirements.resize( ret.mnumberofargs );
+
+ std::vector<Node*> newnodes( mnodes.size() + a.size() );
+ std::vector<Node*>::iterator newnodesiter = newnodes.begin();
+ for ( uint i = 0; i < a.size(); ++i )
+ {
+ assert( ! a[i]->isCache() );
+ *newnodesiter++ = new PushStackNode( a[i]->copy() );
+ };
+ std::copy( ret.mnodes.begin(), ret.mnodes.end(), newnodesiter );
+ ret.mnodes = newnodes;
+
+ return ret;
+}
+
+void ObjectHierarchy::init( const std::vector<ObjectCalcer*>& from, const std::vector<ObjectCalcer*>& to )
+{
+ mnumberofargs = from.size();
+ mnumberofresults = to.size();
+ margrequirements.resize( from.size(), ObjectImp::stype() );
+ musetexts.resize( margrequirements.size(), "" );
+ std::map<const ObjectCalcer*, int> seenmap;
+ for ( uint i = 0; i < from.size(); ++i )
+ seenmap[from[i]] = i;
+ for ( std::vector<ObjectCalcer*>::const_iterator i = to.begin(); i != to.end(); ++i )
+ {
+ std::vector<ObjectCalcer*> parents = (*i)->parents();
+ for ( std::vector<ObjectCalcer*>::const_iterator j = parents.begin();
+ j != parents.end(); ++j )
+ visit( *j, seenmap, true );
+ }
+ for ( std::vector<ObjectCalcer*>::const_iterator i = to.begin(); i != to.end(); ++i )
+ visit( *i, seenmap, true, true );
+
+ mselectstatements.resize( margrequirements.size(), "" );
+}
+
+ObjectHierarchy::ObjectHierarchy( const std::vector<ObjectCalcer*>& from, const ObjectCalcer* to )
+{
+ std::vector<ObjectCalcer*> tov;
+ tov.push_back( const_cast<ObjectCalcer*>( to ) );
+ init( from, tov );
+}
+
+ObjectHierarchy::ObjectHierarchy( const std::vector<ObjectCalcer*>& from, const std::vector<ObjectCalcer*>& to )
+{
+ init( from, to );
+}
+
+void ObjectHierarchy::serialize( QDomElement& parent, QDomDocument& doc ) const
+{
+ int id = 1;
+ for ( uint i = 0; i < mnumberofargs; ++i )
+ {
+ QDomElement e = doc.createElement( "input" );
+ e.setAttribute( "id", id++ );
+ e.setAttribute( "requirement", margrequirements[i]->internalName() );
+ // we don't save these atm, since the user can't define them.
+ // we only load them from builtin macro's.
+// QDomElement ut = doc.createElement( "UseText" );
+// ut.appendChild( doc.createTextNode( QString::fromLatin1(musetexts[i].c_str() ) ) );
+// e.appendChild( ut );
+// QDomElement ss = doc.createElement( "SelectStatement" );
+// ss.appendChild( doc.createTextNode( QString::fromLatin1(mselectstatements[i].c_str() ) ) );
+// e.appendChild( ss );
+ parent.appendChild( e );
+ }
+
+ for ( uint i = 0; i < mnodes.size(); ++i )
+ {
+ bool result = mnodes.size() - ( id - mnumberofargs - 1 ) <= mnumberofresults;
+ QDomElement e = doc.createElement( result ? "result" : "intermediate" );
+ e.setAttribute( "id", id++ );
+
+ if ( mnodes[i]->id() == Node::ID_ApplyType )
+ {
+ const ApplyTypeNode* node = static_cast<const ApplyTypeNode*>( mnodes[i] );
+ e.setAttribute( "action", "calc" );
+ e.setAttribute( "type", QString::fromLatin1( node->type()->fullName() ) );
+ for ( uint i = 0; i < node->parents().size(); ++i )
+ {
+ int parent = node->parents()[i] + 1;
+ QDomElement arge = doc.createElement( "arg" );
+ arge.appendChild( doc.createTextNode( QString::number( parent ) ) );
+ e.appendChild( arge );
+ };
+ }
+ else if ( mnodes[i]->id() == Node::ID_FetchProp )
+ {
+ const FetchPropertyNode* node = static_cast<const FetchPropertyNode*>( mnodes[i] );
+ e.setAttribute( "action", "fetch-property" );
+ e.setAttribute( "property", node->propinternalname() );
+ QDomElement arge = doc.createElement( "arg" );
+ arge.appendChild( doc.createTextNode( QString::number( node->parent() + 1 ) ) );
+ e.appendChild( arge );
+ }
+ else
+ {
+ assert( mnodes[i]->id() == ObjectHierarchy::Node::ID_PushStack );
+ const PushStackNode* node = static_cast<const PushStackNode*>( mnodes[i] );
+ e.setAttribute( "action", "push" );
+ QString type = ObjectImpFactory::instance()->serialize( *node->imp(), e, doc );
+ e.setAttribute( "type", type );
+ };
+
+ parent.appendChild( e );
+ };
+}
+
+ObjectHierarchy::ObjectHierarchy()
+ : mnumberofargs( 0 ), mnumberofresults( 0 )
+{
+}
+
+ObjectHierarchy* ObjectHierarchy::buildSafeObjectHierarchy( const QDomElement& parent, QString& error )
+{
+#define KIG_GENERIC_PARSE_ERROR \
+ { \
+ error = i18n( "An error was encountered at line %1 in file %2." ) \
+ .arg( __LINE__ ).arg( __FILE__ ); \
+ return 0; \
+ }
+
+ ObjectHierarchy* obhi = new ObjectHierarchy();
+
+ bool ok = true;
+ QString tmp;
+ QDomElement e = parent.firstChild().toElement();
+ for (; !e.isNull(); e = e.nextSibling().toElement() )
+ {
+ if ( e.tagName() != "input" ) break;
+
+ tmp = e.attribute( "id" );
+ uint id = tmp.toInt( &ok );
+ if ( !ok ) KIG_GENERIC_PARSE_ERROR;
+
+ obhi->mnumberofargs = kMax( id, obhi->mnumberofargs );
+
+ tmp = e.attribute( "requirement" );
+ const ObjectImpType* req = ObjectImpType::typeFromInternalName( tmp.latin1() );
+ if ( req == 0 ) req = ObjectImp::stype(); // sucks, i know..
+ obhi->margrequirements.resize( obhi->mnumberofargs, ObjectImp::stype() );
+ obhi->musetexts.resize( obhi->mnumberofargs, "" );
+ obhi->mselectstatements.resize( obhi->mnumberofargs, "" );
+ obhi->margrequirements[id - 1] = req;
+ obhi->musetexts[id - 1] = req->selectStatement();
+ QDomElement esub = e.firstChild().toElement();
+ for ( ; !esub.isNull(); esub = esub.nextSibling().toElement() )
+ {
+ if ( esub.tagName() == "UseText" )
+ {
+ obhi->musetexts[id - 1] = esub.text().latin1();
+ }
+ else if ( esub.tagName() == "SelectStatement" )
+ {
+ obhi->mselectstatements[id - 1] = esub.text().latin1();
+ }
+ else
+ {
+ // broken file ? ignore...
+ }
+ }
+ }
+ for (; !e.isNull(); e = e.nextSibling().toElement() )
+ {
+ bool result = e.tagName() == "result";
+ if ( result ) ++obhi->mnumberofresults;
+
+ tmp = e.attribute( "id" );
+ int id = tmp.toInt( &ok );
+ if ( !ok ) KIG_GENERIC_PARSE_ERROR;
+
+ tmp = e.attribute( "action" );
+ Node* newnode = 0;
+ if ( tmp == "calc" )
+ {
+ // ApplyTypeNode
+ QCString typen = e.attribute( "type" ).latin1();
+ const ObjectType* type = ObjectTypeFactory::instance()->find( typen );
+ if ( ! type )
+ {
+ error = i18n( "This Kig file uses an object of type \"%1\", "
+ "which this Kig version does not support."
+ "Perhaps you have compiled Kig without support "
+ "for this object type,"
+ "or perhaps you are using an older Kig version." ).arg( typen );
+ return 0;
+ }
+
+ std::vector<int> parents;
+ for ( QDomNode p = e.firstChild(); !p.isNull(); p = p.nextSibling() )
+ {
+ QDomElement q = p.toElement();
+ if ( q.isNull() ) KIG_GENERIC_PARSE_ERROR; // see above
+ if ( q.tagName() != "arg" ) KIG_GENERIC_PARSE_ERROR;
+ int pid = q.text().toInt(&ok );
+ if ( !ok ) KIG_GENERIC_PARSE_ERROR;
+ parents.push_back( pid - 1 );
+ };
+ newnode = new ApplyTypeNode( type, parents );
+ }
+ else if ( tmp == "fetch-property" )
+ {
+ // FetchPropertyNode
+ QCString propname = e.attribute( "property" ).latin1();
+ QDomElement arge = e.firstChild().toElement();
+ int parent = arge.text().toInt( &ok );
+ if ( !ok ) KIG_GENERIC_PARSE_ERROR;
+ newnode = new FetchPropertyNode( parent - 1, propname );
+ }
+ else
+ {
+ // PushStackNode
+ if ( e.attribute( "action" ) != "push" ) KIG_GENERIC_PARSE_ERROR;
+ QString typen = e.attribute( "type" );
+ if ( typen.isNull() ) KIG_GENERIC_PARSE_ERROR;
+ ObjectImp* imp = ObjectImpFactory::instance()->deserialize( typen, e, error );
+ if ( ( ! imp ) && !error.isEmpty() ) return 0;
+ newnode = new PushStackNode( imp );
+ };
+ obhi->mnodes.resize( kMax( size_t(id - obhi->mnumberofargs), obhi->mnodes.size() ) );
+ obhi->mnodes[id - obhi->mnumberofargs - 1] = newnode;
+ };
+
+ // if we are here, all went fine
+ return obhi;
+}
+
+ArgsParser ObjectHierarchy::argParser() const
+{
+ std::vector<ArgsParser::spec> specs;
+ for ( uint i = 0; i < margrequirements.size(); ++i )
+ {
+ const ObjectImpType* req = margrequirements[i];
+ ArgsParser::spec spec;
+ spec.type = req;
+ spec.usetext = musetexts[i];
+ spec.selectstat = mselectstatements[i];
+ specs.push_back( spec );
+ };
+ return ArgsParser( specs );
+}
+
+std::vector<ObjectCalcer*> ObjectHierarchy::buildObjects( const std::vector<ObjectCalcer*>& os, const KigDocument& doc ) const
+{
+ assert( os.size() == mnumberofargs );
+ for ( uint i = 0; i < os.size(); ++i )
+ assert( os[i]->imp()->inherits( margrequirements[i] ) );
+
+ std::vector<ObjectCalcer*> stack;
+ stack.resize( mnodes.size() + mnumberofargs, 0 );
+ std::copy( os.begin(), os.end(), stack.begin() );
+
+ for( uint i = 0; i < mnodes.size(); ++i )
+ {
+ mnodes[i]->apply( stack, mnumberofargs + i );
+ stack[mnumberofargs + i]->calc( doc );
+ };
+
+ std::vector<ObjectCalcer*> ret( stack.end() - mnumberofresults, stack.end() );
+
+ return ret;
+}
+
+const ObjectImpType* ObjectHierarchy::idOfLastResult() const
+{
+ const Node* n = mnodes.back();
+ if ( n->id() == Node::ID_PushStack )
+ return static_cast<const PushStackNode*>( n )->imp()->type();
+ else if ( n->id() == Node::ID_FetchProp )
+ return ObjectImp::stype();
+ else
+ return static_cast<const ApplyTypeNode*>( n )->type()->resultId();
+}
+
+ObjectHierarchy ObjectHierarchy::transformFinalObject( const Transformation& t ) const
+{
+ assert( mnumberofresults == 1 );
+ ObjectHierarchy ret( *this );
+ ret.mnodes.push_back( new PushStackNode( new TransformationImp( t ) ) );
+
+ std::vector<int> parents;
+ parents.push_back( ret.mnodes.size() - 1);
+ parents.push_back( ret.mnodes.size() );
+ const ObjectType* type = ApplyTransformationObjectType::instance();
+ ret.mnodes.push_back( new ApplyTypeNode( type, parents ) );
+ return ret;
+}
+
+bool operator==( const ObjectHierarchy& lhs, const ObjectHierarchy& rhs )
+{
+ if ( ! ( lhs.mnumberofargs == rhs.mnumberofargs &&
+ lhs.mnumberofresults == rhs.mnumberofresults &&
+ lhs.margrequirements == rhs.margrequirements &&
+ lhs.mnodes.size() == rhs.mnodes.size() ) )
+ return false;
+
+ // this isn't entirely correct, but it will do, because we don't
+ // really want to know whether the hierarchies are different, but
+ // whether rhs has changed with regard to lhs..
+ for ( uint i = 0; i < lhs.mnodes.size(); ++i )
+ if ( lhs.mnodes[i] != lhs.mnodes[i] )
+ return false;
+
+ return true;
+}
+
+bool ObjectHierarchy::resultDoesNotDependOnGiven() const
+{
+ std::vector<bool> dependsstack( mnodes.size() + mnumberofargs, false );
+
+ for ( uint i = 0; i < mnumberofargs; ++i )
+ dependsstack[i] = true;
+ for ( uint i = 0; i < mnodes.size(); ++i )
+ mnodes[i]->checkDependsOnGiven( dependsstack, i + mnumberofargs );
+ for ( uint i = dependsstack.size() - mnumberofresults; i < dependsstack.size(); ++i )
+ if ( !dependsstack[i] )
+ return true;
+ return false;
+}
+
+// returns the "minimum" of a and b ( in the partially ordered set of
+// ObjectImpType's, using the inherits member function as comparison,
+// if you for some reason like this sort of non-sense ;) ). This
+// basically means: return the type that inherits the other type,
+// because if another type inherits the lowermost type, then it will
+// also inherit the other..
+const ObjectImpType* lowermost( const ObjectImpType* a, const ObjectImpType* b )
+{
+ if ( a->inherits( b ) ) return a;
+ assert( b->inherits( a ) );
+ return b;
+}
+
+// this function is part of the visit procedure really. It is
+// factored out, because it recurses for cache ObjectImp's. What this
+// does is, it makes sure that object o is calcable, by putting
+// appropriate Node's in mnodes.. po is o->parents() and pl contains
+// the location of objects that are already in mnodes and -1
+// otherwise.. -1 means we have to store their ObjectImp, unless
+// they're cache ObjectImp's etc.
+int ObjectHierarchy::storeObject( const ObjectCalcer* o, const std::vector<ObjectCalcer*>& po, std::vector<int>& pl,
+ std::map<const ObjectCalcer*, int>& seenmap )
+{
+ for ( uint i = 0; i < po.size(); ++i )
+ {
+ if ( pl[i] == -1 )
+ {
+ // we can't store cache ObjectImp's..
+ if ( po[i]->imp()->isCache() )
+ {
+ pl[i] = visit( po[i], seenmap, true, false );
+ }
+ else
+ {
+ Node* argnode = new PushStackNode( po[i]->imp()->copy() );
+ mnodes.push_back( argnode );
+ int argloc = mnumberofargs + mnodes.size() - 1;
+ seenmap[po[i]] = argloc;
+ pl[i] = argloc;
+ };
+ }
+ else if ( (uint) pl[i] < mnumberofargs )
+ {
+ ObjectCalcer* parent = o->parents()[i];
+ std::vector<ObjectCalcer*> opl = o->parents();
+
+ margrequirements[pl[i]] =
+ lowermost( margrequirements[pl[i]],
+ o->impRequirement( parent, opl ) );
+ musetexts[pl[i]] = margrequirements[pl[i]]->selectStatement();
+ };
+ };
+ if ( dynamic_cast<const ObjectTypeCalcer*>( o ) )
+ mnodes.push_back( new ApplyTypeNode( static_cast<const ObjectTypeCalcer*>( o )->type(), pl ) );
+ else if ( dynamic_cast<const ObjectPropertyCalcer*>( o ) )
+ {
+ assert( pl.size() == 1 );
+ int parent = pl.front();
+ ObjectCalcer* op = po.front();
+ assert( op );
+ uint propid = static_cast<const ObjectPropertyCalcer*>( o )->propId();
+ assert( propid < op->imp()->propertiesInternalNames().size() );
+ mnodes.push_back( new FetchPropertyNode( parent, op->imp()->propertiesInternalNames()[propid], propid ) );
+ }
+ else
+ assert( false );
+ seenmap[o] = mnumberofargs + mnodes.size() - 1;
+ return mnumberofargs + mnodes.size() - 1;
+}
+
+ObjectHierarchy::ObjectHierarchy( const ObjectCalcer* from, const ObjectCalcer* to )
+{
+ std::vector<ObjectCalcer*> fromv;
+ fromv.push_back( const_cast<ObjectCalcer*>( from ) );
+ std::vector<ObjectCalcer*> tov;
+ tov.push_back( const_cast<ObjectCalcer*>( to ) );
+ init( fromv, tov );
+}
+
+bool ObjectHierarchy::allGivenObjectsUsed() const
+{
+ std::vector<bool> usedstack( mnodes.size() + mnumberofargs, false );
+ for ( uint i = mnodes.size() - mnumberofresults; i < mnodes.size(); ++i )
+ usedstack[i + mnumberofargs] = true;
+ for ( int i = mnodes.size() - 1; i >= 0; --i )
+ if ( usedstack[i + mnumberofargs] )
+ mnodes[i]->checkArgumentsUsed( usedstack );
+ for ( uint i = 0; i < mnumberofargs; ++i )
+ if ( ! usedstack[i] ) return false;
+ return true;
+}
+
diff --git a/kig/misc/object_hierarchy.h b/kig/misc/object_hierarchy.h
new file mode 100644
index 00000000..3133dc7c
--- /dev/null
+++ b/kig/misc/object_hierarchy.h
@@ -0,0 +1,111 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MISC_OBJECT_HIERARCHY_H
+#define KIG_MISC_OBJECT_HIERARCHY_H
+
+#include "../objects/common.h"
+
+#include <map>
+#include <vector>
+#include <string>
+
+class ObjectImpType;
+class ArgsParser;
+
+class ObjectHierarchy
+{
+public:
+ class Node;
+private:
+ std::vector<Node*> mnodes;
+ uint mnumberofargs;
+ uint mnumberofresults;
+ std::vector<const ObjectImpType*> margrequirements;
+ std::vector<std::string> musetexts;
+ std::vector<std::string> mselectstatements;
+
+ // these two are really part of the constructor...
+ int visit( const ObjectCalcer* o, std::map<const ObjectCalcer*, int>&,
+ bool needed, bool neededatend = false);
+ int storeObject( const ObjectCalcer*, const std::vector<ObjectCalcer*>& po, std::vector<int>& pl,
+ std::map<const ObjectCalcer*, int>& seenmap );
+
+ friend bool operator==( const ObjectHierarchy& lhs, const ObjectHierarchy& rhs );
+
+ void init( const std::vector<ObjectCalcer*>& from, const std::vector<ObjectCalcer*>& to );
+
+ /**
+ * this constructor is private since it should be used only by the static
+ * constructor buildSafeObjectHierarchy
+ *
+ * \see ObjectHierarchy::buildSafeObjectHierarchy
+ */
+ ObjectHierarchy();
+
+public:
+ ObjectHierarchy( const ObjectCalcer* from, const ObjectCalcer* to );
+ ObjectHierarchy( const std::vector<ObjectCalcer*>& from, const ObjectCalcer* to );
+ ObjectHierarchy( const std::vector<ObjectCalcer*>& from, const std::vector<ObjectCalcer*>& to );
+ ObjectHierarchy( const ObjectHierarchy& h );
+ ~ObjectHierarchy();
+
+ /**
+ * this creates a new ObjectHierarchy, that takes a.size() less
+ * arguments, but uses copies of the ObjectImp's in \p a instead..
+ */
+ ObjectHierarchy withFixedArgs( const Args& a ) const;
+
+ std::vector<ObjectImp*> calc( const Args& a, const KigDocument& doc ) const;
+
+ /**
+ * saves the ObjectHierarchy data in children xml tags of \p parent ..
+ */
+ void serialize( QDomElement& parent, QDomDocument& doc ) const;
+ /**
+ * Deserialize the ObjectHierarchy data from the xml element \p parent ..
+ * Since this operation can fail for some reasons, we provide it as a
+ * static to return 0 in case of error.
+ */
+ static ObjectHierarchy* buildSafeObjectHierarchy( const QDomElement& parent, QString& error );
+// ObjectHierarchy( const QDomElement& parent );
+
+ /**
+ * build a set of objects that interdepend according to this
+ * ObjectHierarchy.. Only the result objects are returned. Helper
+ * objects that connect the given objects with the returned objects,
+ * can only be found by following the returned objects' parents()
+ * methods..
+ */
+ std::vector<ObjectCalcer*> buildObjects( const std::vector<ObjectCalcer*>& os, const KigDocument& ) const;
+
+ ArgsParser argParser() const;
+
+ uint numberOfArgs() const { return mnumberofargs; }
+ uint numberOfResults() const { return mnumberofresults; }
+
+ const ObjectImpType* idOfLastResult() const;
+
+ bool resultDoesNotDependOnGiven() const;
+ bool allGivenObjectsUsed() const;
+
+ ObjectHierarchy transformFinalObject( const Transformation& t ) const;
+};
+
+bool operator==( const ObjectHierarchy& lhs, const ObjectHierarchy& rhs );
+
+#endif
diff --git a/kig/misc/rect.cc b/kig/misc/rect.cc
new file mode 100644
index 00000000..dc28de82
--- /dev/null
+++ b/kig/misc/rect.cc
@@ -0,0 +1,308 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "rect.h"
+#include "common.h"
+
+bool operator==( const Rect& r, const Rect& s )
+{
+ return ( r.bottomLeft() == s.bottomLeft()
+ && r.width() == s.width()
+ && r.height() == s.height() );
+}
+
+kdbgstream& operator<<( kdbgstream& s, const Rect& t )
+{
+ s << "left: " << t.left()
+ << "bottom: " << t.bottom()
+ << "right: " << t.right()
+ << "top: " << t.top()
+ << endl;
+ return s;
+}
+
+Rect::Rect( const Coordinate bottomLeft, const Coordinate topRight )
+ : mBottomLeft(bottomLeft)
+{
+ mwidth = topRight.x - bottomLeft.x;
+ mheight = topRight.y - bottomLeft.y;
+ normalize();
+}
+
+Rect::Rect( const Coordinate p, const double width, const double height )
+ : mBottomLeft(p),
+ mwidth(width),
+ mheight(height)
+{
+ normalize();
+}
+
+Rect::Rect( double xa, double ya, double width, double height )
+ : mBottomLeft( xa, ya ),
+ mwidth( width ),
+ mheight( height )
+{
+ normalize();
+}
+
+Rect::Rect( const Rect& r )
+ : mBottomLeft (r.mBottomLeft),
+ mwidth(r.mwidth),
+ mheight(r.mheight)
+{
+ normalize();
+}
+
+Rect::Rect()
+ : mwidth(0),
+ mheight(0)
+{
+}
+
+void Rect::setBottomLeft( const Coordinate p )
+{
+ mBottomLeft = p;
+}
+
+void Rect::setBottomRight( const Coordinate p )
+{
+ mBottomLeft = p - Coordinate(mwidth,0);
+}
+
+void Rect::setTopRight( const Coordinate p )
+{
+ mBottomLeft = p - Coordinate(mwidth, mheight);
+}
+
+void Rect::setCenter( const Coordinate p )
+{
+ mBottomLeft = p - Coordinate(mwidth, mheight)/2;
+}
+
+void Rect::setLeft( const double p )
+{
+ double r = right();
+ mBottomLeft.x = p;
+ setRight( r );
+}
+
+void Rect::setRight( const double p )
+{
+ mwidth = p - left();
+}
+
+void Rect::setBottom( const double p )
+{
+ double t = top();
+ mBottomLeft.y = p;
+ setTop( t );
+}
+
+void Rect::setTop( const double p )
+{
+ mheight = p - bottom();
+}
+
+void Rect::setWidth( const double w )
+{
+ mwidth = w;
+}
+
+void Rect::setHeight( const double h )
+{
+ mheight = h;
+}
+
+void Rect::normalize()
+{
+ if ( mwidth < 0 )
+ {
+ mBottomLeft.x += mwidth;
+ mwidth = -mwidth;
+ };
+ if ( mheight < 0 )
+ {
+ mBottomLeft.y += mheight;
+ mheight = -mheight;
+ };
+}
+
+void Rect::moveBy( const Coordinate p )
+{
+ mBottomLeft += p;
+}
+
+void Rect::scale( const double r )
+{
+ mwidth *= r;
+ mheight *= r;
+}
+
+
+QRect Rect::toQRect() const
+{
+ return QRect(mBottomLeft.toQPoint(), topRight().toQPoint());
+}
+
+Coordinate Rect::bottomLeft() const
+{
+ return mBottomLeft;
+}
+
+Coordinate Rect::bottomRight() const
+{
+ return mBottomLeft + Coordinate(mwidth, 0);
+}
+
+Coordinate Rect::topLeft() const
+{
+ return mBottomLeft + Coordinate(0, mheight);
+}
+
+Coordinate Rect::topRight() const
+{
+ return mBottomLeft + Coordinate(mwidth, mheight);
+}
+
+Coordinate Rect::center() const
+{
+ return mBottomLeft + Coordinate(mwidth, mheight)/2;
+}
+
+double Rect::left() const
+{
+ return mBottomLeft.x;
+}
+double Rect::right() const
+{
+ return left() + mwidth;
+}
+double Rect::bottom() const
+{
+ return mBottomLeft.y;
+}
+
+double Rect::top() const
+{
+ return bottom() + mheight;
+}
+
+double Rect::width() const
+{
+ return mwidth;
+}
+
+double Rect::height() const
+{
+ return mheight;
+}
+
+bool Rect::contains( const Coordinate& p, double allowed_miss ) const
+{
+ return p.x - left() >= - allowed_miss &&
+ p.y - bottom() >= - allowed_miss &&
+ p.x - left() - width() <= allowed_miss &&
+ p.y - bottom() - height() <= allowed_miss;
+}
+
+bool Rect::contains( const Coordinate& p ) const
+{
+ return p.x >= left() &&
+ p.y >= bottom() &&
+ p.x - left() <= width() &&
+ p.y - bottom() <= height();
+}
+
+bool Rect::intersects( const Rect& p ) const
+{
+ // never thought it was this simple :)
+ if( p.left() < left() && p.right() < left()) return false;
+ if( p.left() > right() && p.right() > right()) return false;
+ if( p.bottom() < bottom() && p.top() < bottom()) return false;
+ if( p.bottom() > top() && p.top() > top()) return false;
+ return true;
+}
+
+void Rect::setContains( Coordinate p )
+{
+ normalize();
+ if( p.x < left() ) setLeft( p.x );
+ if( p.x > right() ) setRight(p.x);
+ if( p.y < bottom() ) setBottom( p.y );
+ if( p.y > top() ) setTop( p.y );
+}
+
+Rect Rect::normalized() const
+{
+ Rect t = *this;
+ (void) t.normalize();
+ return t;
+}
+
+Rect Rect::fromQRect( const QRect& r )
+{
+ return Rect( r.left(), r.top(), r.right(), r.bottom() );
+}
+
+void Rect::setTopLeft( const Coordinate p )
+{
+ Coordinate bl = Coordinate( p.x, p.y - mheight );
+ setBottomLeft( bl );
+}
+
+Rect operator|( const Rect& lhs, const Rect& rhs )
+{
+ Rect r( lhs );
+ r |= rhs;
+ return r;
+}
+
+void Rect::eat( const Rect& r )
+{
+ setLeft( kigMin( left(), r.left() ) );
+ setRight( kigMax( right(), r.right() ) );
+ setBottom( kigMin( bottom(), r.bottom() ) );
+ setTop( kigMax( top(), r.top() ) );
+}
+
+Rect Rect::matchShape( const Rect& rhs, bool shrink ) const
+{
+ Rect ret = *this;
+ Coordinate c = center();
+ double v = width()/height(); // current ratio
+ double w = rhs.width()/rhs.height(); // wanted ratio
+
+ // we don't show less than r, if the dimensions don't match, we
+ // extend r into some dimension...
+ if( ( v > w ) ^ shrink )
+ ret.setHeight( ret.width() / w );
+ else
+ ret.setWidth( ret.height() * w );
+
+ ret.setCenter(c);
+ return ret.normalized();
+}
+
+bool Rect::valid()
+{
+ return mBottomLeft.valid() && mwidth != double_inf && mheight != double_inf;
+}
+
+Rect Rect::invalidRect()
+{
+ return Rect( Coordinate::invalidCoord(), double_inf, double_inf );
+}
diff --git a/kig/misc/rect.h b/kig/misc/rect.h
new file mode 100644
index 00000000..a222d1ab
--- /dev/null
+++ b/kig/misc/rect.h
@@ -0,0 +1,140 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+
+#ifndef RECT_H
+#define RECT_H
+
+#include "coordinate.h"
+
+#include <qrect.h>
+#include <kdebug.h>
+
+/**
+ * like Coordinate is a QPoint replacement with doubles, this is a
+ * QRect replacement with doubles...
+ */
+class Rect
+{
+public:
+ /**
+ * constructors...
+ */
+ Rect( const Coordinate bottomLeft, const Coordinate topRight );
+ Rect( const Coordinate bottomLeft, const double width, const double height );
+ Rect( double xa, double ya, double width, double height );
+ Rect( const Rect& r );
+ Rect();
+ static Rect invalidRect();
+
+
+ bool valid();
+
+ void setBottomLeft( const Coordinate p );
+ void setTopLeft( const Coordinate p );
+ void setTopRight( const Coordinate p );
+ void setBottomRight( const Coordinate p );
+ void setCenter( const Coordinate p );
+ void setLeft( const double p);
+ void setRight( const double p);
+ void setTop( const double p );
+ void setBottom( const double p );
+ void setWidth( const double w );
+ void setHeight( const double h );
+ /**
+ * this makes sure width and height are > 0 ...
+ */
+ void normalize();
+ /**
+ * this makes sure p is in the rect, extending it if necessary...
+ */
+ void setContains( Coordinate p );
+ /**
+ * moves the rect while keeping the size constant...
+ */
+ void moveBy( const Coordinate p );
+ /**
+ * synonym for moveBy...
+ */
+ Rect& operator+=( const Coordinate p ) { moveBy(p); return *this; }
+ /**
+ * scale: only the size changes, topLeft is kept where it is...
+ */
+ void scale( const double r );
+ /**
+ * synonym for scale...
+ */
+ Rect& operator*=( const double r ) { scale(r); return *this; }
+ Rect& operator/=( const double r ) { scale(1/r); return *this; }
+
+ /**
+ * This expands the rect so that it contains r. It has friends
+ * '|=' and '|' below...
+ */
+ void eat( const Rect& r );
+
+ /**
+ * synonym for eat..
+ */
+ Rect& operator|=( const Rect& rhs ) { eat( rhs ); return *this; }
+
+ /**
+ * return a rect which is a copy of this rect, but has an aspect
+ * ratio equal to rhs's one.. if \p shrink is true, the rect will be
+ * shrunk, otherwise extended.. The center of the new rect is the
+ * same as this rect's center..
+ */
+ Rect matchShape( const Rect& rhs, bool shrink = false ) const;
+
+ QRect toQRect() const;
+ Coordinate bottomLeft() const;
+ Coordinate bottomRight() const;
+ Coordinate topLeft() const;
+ Coordinate topRight() const;
+ Coordinate center() const;
+ double left() const;
+ double right() const;
+ double bottom() const;
+ double top() const;
+ double width() const;
+ double height() const;
+ bool contains( const Coordinate& p ) const;
+ bool contains( const Coordinate& p, double allowed_miss ) const;
+ bool intersects( const Rect& p ) const;
+ Rect normalized() const;
+ friend kdbgstream& operator<<( kdbgstream& s, const Rect& t );
+
+ static Rect fromQRect( const QRect& );
+protected:
+ Coordinate mBottomLeft;
+ double mwidth;
+ double mheight;
+};
+
+bool operator==( const Rect& r, const Rect& s );
+kdbgstream& operator<<( kdbgstream& s, const Rect& t );
+/**
+ * this operator returns a Rect that contains both the given
+ * rects..
+ */
+Rect operator|( const Rect& lhs, const Rect& rhs );
+
+#endif
+
diff --git a/kig/misc/screeninfo.cc b/kig/misc/screeninfo.cc
new file mode 100644
index 00000000..c1418876
--- /dev/null
+++ b/kig/misc/screeninfo.cc
@@ -0,0 +1,92 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "screeninfo.h"
+
+#include <cmath>
+
+ScreenInfo::ScreenInfo( const Rect& docRect, const QRect& viewRect )
+ : mkrect( docRect.normalized() ), mqrect( viewRect.normalize() )
+{
+}
+
+Rect ScreenInfo::fromScreen( const QRect& r ) const
+{
+ return Rect(
+ fromScreen( r.topLeft() ),
+ fromScreen( r.bottomRight() )
+ ).normalized();
+}
+
+Coordinate ScreenInfo::fromScreen( const QPoint& p ) const
+{
+ // invert the y-axis: 0 is at the bottom !
+ Coordinate t( p.x(), mqrect.height() - p.y() );
+ t *= mkrect.width();
+ t /= mqrect.width();
+ return t + mkrect.bottomLeft();
+}
+
+QPoint ScreenInfo::toScreen( const Coordinate& p ) const
+{
+ Coordinate t = p - mkrect.bottomLeft();
+ t *= mqrect.width();
+ t /= mkrect.width();
+ // invert the y-axis: 0 is at the bottom !
+ return QPoint( (int) t.x, mqrect.height() - (int) t.y );
+}
+
+QRect ScreenInfo::toScreen( const Rect& r ) const
+{
+ return QRect(
+ toScreen( r.bottomLeft() ),
+ toScreen( r.topRight() )
+ ).normalize();
+}
+
+double ScreenInfo::pixelWidth() const
+{
+ Coordinate a = fromScreen( QPoint( 0, 0 ) );
+ Coordinate b = fromScreen( QPoint( 0, 1000 ) );
+ return std::fabs( b.y - a.y ) / 1000;
+}
+
+const Rect& ScreenInfo::shownRect() const
+{
+ return mkrect;
+}
+
+void ScreenInfo::setShownRect( const Rect& r )
+{
+ mkrect = r;
+}
+
+const QRect ScreenInfo::viewRect() const
+{
+ return mqrect;
+}
+
+void ScreenInfo::setViewRect( const QRect& r )
+{
+ mqrect = r;
+}
+
+double ScreenInfo::normalMiss( int width ) const
+{
+ int twidth = width == -1 ? 1 : width;
+ return (twidth+2)*pixelWidth();
+}
diff --git a/kig/misc/screeninfo.h b/kig/misc/screeninfo.h
new file mode 100644
index 00000000..b7f94c49
--- /dev/null
+++ b/kig/misc/screeninfo.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef SCREENINFO_H
+#define SCREENINFO_H
+
+#include <qrect.h>
+
+#include "rect.h"
+
+/**
+ * ScreenInfo is a simple utility class that maps a region of the
+ * document onto a region of the screen. It is used by both
+ * KigPainter and KigWidget, and the objects use it in their calc()
+ * method...
+ */
+class ScreenInfo
+{
+ Rect mkrect;
+ QRect mqrect;
+public:
+ ScreenInfo( const Rect& docRect, const QRect& viewRect );
+
+ Coordinate fromScreen( const QPoint& p ) const;
+ Rect fromScreen( const QRect& r ) const;
+
+ QPoint toScreen( const Coordinate& p ) const;
+ QRect toScreen( const Rect& r ) const;
+
+ double pixelWidth() const;
+
+ double normalMiss( int width ) const;
+
+ const Rect& shownRect() const;
+
+ void setShownRect( const Rect& r );
+
+ const QRect viewRect() const;
+
+ void setViewRect( const QRect& r );
+};
+
+#endif
diff --git a/kig/misc/special_constructors.cc b/kig/misc/special_constructors.cc
new file mode 100644
index 00000000..04c8a097
--- /dev/null
+++ b/kig/misc/special_constructors.cc
@@ -0,0 +1,1628 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "special_constructors.h"
+
+#include "calcpaths.h"
+#include "common.h"
+#include "conic-common.h"
+#include "guiaction.h"
+#include "kigpainter.h"
+
+#include "../kig/kig_part.h"
+#include "../modes/construct_mode.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/centerofcurvature_type.h"
+#include "../objects/circle_imp.h"
+#include "../objects/conic_imp.h"
+#include "../objects/conic_types.h"
+#include "../objects/cubic_imp.h"
+#include "../objects/intersection_types.h"
+#include "../objects/inversion_type.h"
+#include "../objects/line_imp.h"
+#include "../objects/line_type.h"
+#include "../objects/locus_imp.h"
+#include "../objects/object_calcer.h"
+#include "../objects/object_drawer.h"
+#include "../objects/object_factory.h"
+#include "../objects/object_holder.h"
+#include "../objects/object_imp.h"
+#include "../objects/object_type.h"
+#include "../objects/other_imp.h"
+#include "../objects/other_type.h"
+#include "../objects/point_imp.h"
+#include "../objects/point_type.h"
+#include "../objects/polygon_imp.h"
+#include "../objects/polygon_type.h"
+#include "../objects/tangent_type.h"
+#include "../objects/text_imp.h"
+#include "../objects/transform_types.h"
+
+#include <qpen.h>
+
+#include <klocale.h>
+
+#include <algorithm>
+#include <functional>
+
+class ConicConicIntersectionConstructor
+ : public StandardConstructorBase
+{
+protected:
+ ArgsParser mparser;
+public:
+ ConicConicIntersectionConstructor();
+ ~ConicConicIntersectionConstructor();
+
+ void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& ) const;
+ std::vector<ObjectHolder*> build( const std::vector<ObjectCalcer*>& os, KigDocument& d, KigWidget& w ) const;
+ void plug( KigPart* doc, KigGUIAction* kact );
+
+ bool isTransform() const;
+};
+
+class ConicLineIntersectionConstructor
+ : public MultiObjectTypeConstructor
+{
+public:
+ ConicLineIntersectionConstructor();
+ ~ConicLineIntersectionConstructor();
+};
+
+class ArcLineIntersectionConstructor
+ : public MultiObjectTypeConstructor
+{
+public:
+ ArcLineIntersectionConstructor();
+ ~ArcLineIntersectionConstructor();
+};
+
+ConicRadicalConstructor::ConicRadicalConstructor()
+ : StandardConstructorBase(
+ I18N_NOOP( "Radical Lines for Conics" ),
+ I18N_NOOP( "The lines constructed through the intersections "
+ "of two conics. This is also defined for "
+ "non-intersecting conics." ),
+ "conicsradicalline", mparser ),
+ mtype( ConicRadicalType::instance() ),
+ mparser( mtype->argsParser().without( IntImp::stype() ) )
+{
+}
+
+ConicRadicalConstructor::~ConicRadicalConstructor()
+{
+}
+
+void ConicRadicalConstructor::drawprelim(
+ const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents, const KigDocument& doc ) const
+{
+ if ( parents.size() == 2 && parents[0]->imp()->inherits( ConicImp::stype() ) &&
+ parents[1]->imp()->inherits( ConicImp::stype() ) )
+ {
+ Args args;
+ std::transform( parents.begin(), parents.end(),
+ std::back_inserter( args ), std::mem_fun( &ObjectCalcer::imp ) );
+ for ( int i = -1; i < 2; i += 2 )
+ {
+ IntImp root( i );
+ IntImp zeroindex( 1 );
+ args.push_back( &root );
+ args.push_back( &zeroindex );
+ ObjectImp* data = mtype->calc( args, doc );
+ drawer.draw( *data, p, true );
+ delete data; data = 0;
+ args.pop_back();
+ args.pop_back();
+ };
+ };
+}
+
+std::vector<ObjectHolder*> ConicRadicalConstructor::build( const std::vector<ObjectCalcer*>& os, KigDocument&, KigWidget& ) const
+{
+ using namespace std;
+ std::vector<ObjectHolder*> ret;
+ ObjectCalcer* zeroindexcalcer = new ObjectConstCalcer( new IntImp( 1 ) );
+ for ( int i = -1; i < 2; i += 2 )
+ {
+ std::vector<ObjectCalcer*> args;
+ std::copy( os.begin(), os.end(), back_inserter( args ) );
+ args.push_back( new ObjectConstCalcer( new IntImp( i ) ) );
+ // we use only one zeroindex dataobject, so that if you switch one
+ // radical line around, then the other switches along..
+ args.push_back( zeroindexcalcer );
+ ret.push_back(
+ new ObjectHolder( new ObjectTypeCalcer( mtype, args ) ) );
+ };
+ return ret;
+}
+
+static const struct ArgsParser::spec argsspecpp[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Moving Point" ),
+ I18N_NOOP( "Select the moving point, which will be moved around while drawing the locus..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Following Point" ),
+ I18N_NOOP( "Select the following point, whose locations the locus will be drawn through..." ), true }
+};
+
+LocusConstructor::LocusConstructor()
+ : StandardConstructorBase( I18N_NOOP( "Locus" ), I18N_NOOP( "A locus" ),
+ "locus", margsparser ),
+ margsparser( argsspecpp, 2 )
+{
+}
+
+LocusConstructor::~LocusConstructor()
+{
+}
+
+void LocusConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& ) const
+{
+ // this function is rather ugly, but it is necessary to do it this
+ // way in order to play nice with Kig's design..
+
+ if ( parents.size() != 2 ) return;
+ const ObjectTypeCalcer* constrained = dynamic_cast<ObjectTypeCalcer*>( parents.front() );
+ const ObjectCalcer* moving = parents.back();
+ if ( ! constrained || ! constrained->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
+ {
+ // moving is in fact the constrained point.. swap them..
+ moving = parents.front();
+ constrained = dynamic_cast<const ObjectTypeCalcer*>( parents.back() );
+ assert( constrained );
+ };
+ assert( constrained->type()->inherits( ObjectType::ID_ConstrainedPointType ) );
+
+ const ObjectImp* oimp = constrained->parents().back()->imp();
+ if( !oimp->inherits( CurveImp::stype() ) )
+ oimp = constrained->parents().front()->imp();
+ assert( oimp->inherits( CurveImp::stype() ) );
+ const CurveImp* cimp = static_cast<const CurveImp*>( oimp );
+
+ ObjectHierarchy hier( constrained, moving );
+
+ LocusImp limp( cimp->copy(), hier );
+ drawer.draw( limp, p, true );
+}
+
+const int LocusConstructor::wantArgs(
+ const std::vector<ObjectCalcer*>& os, const KigDocument&, const KigWidget&
+ ) const
+{
+ int ret = margsparser.check( os );
+ if ( ret == ArgsParser::Invalid ) return ret;
+ else if ( os.size() != 2 ) return ret;
+ if ( dynamic_cast<ObjectTypeCalcer*>( os.front() ) &&
+ static_cast<ObjectTypeCalcer*>( os.front() )->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
+ {
+ std::set<ObjectCalcer*> children = getAllChildren( os.front() );
+ return children.find( os.back() ) != children.end() ? ret : ArgsParser::Invalid;
+ }
+ if ( dynamic_cast<ObjectTypeCalcer*>( os.back() ) &&
+ static_cast<ObjectTypeCalcer*>( os.back() )->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
+ {
+ std::set<ObjectCalcer*> children = getAllChildren( os.back() );
+ return children.find( os.front() ) != children.end() ? ret : ArgsParser::Invalid;
+ }
+ return ArgsParser::Invalid;
+}
+
+std::vector<ObjectHolder*> LocusConstructor::build( const std::vector<ObjectCalcer*>& parents, KigDocument&, KigWidget& ) const
+{
+ std::vector<ObjectHolder*> ret;
+ assert( parents.size() == 2 );
+
+ ObjectTypeCalcer* constrained = dynamic_cast<ObjectTypeCalcer*>( parents.front() );
+ ObjectCalcer* moving = parents.back();
+ if ( ! constrained || ! constrained->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
+ {
+ // moving is in fact the constrained point.. swap them..
+ moving = parents.front();
+ constrained = dynamic_cast<ObjectTypeCalcer*>( parents.back() );
+ assert( constrained );
+ };
+ assert( constrained->type()->inherits( ObjectType::ID_ConstrainedPointType ) );
+
+ ret.push_back( ObjectFactory::instance()->locus( constrained, moving ) );
+ return ret;
+}
+
+QString LocusConstructor::useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& os,
+ const KigDocument&, const KigWidget& ) const
+{
+ if ( dynamic_cast<const ObjectTypeCalcer*>( &o ) &&
+ static_cast<const ObjectTypeCalcer&>( o ).type()->inherits( ObjectType::ID_ConstrainedPointType ) &&
+ ( os.empty() || !dynamic_cast<ObjectTypeCalcer*>( os[0] ) ||
+ !static_cast<const ObjectTypeCalcer*>( os[0] )->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
+ ) return i18n( "Moving Point" );
+ else return i18n( "Dependent Point" );
+}
+
+void ConicRadicalConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+void LocusConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+bool ConicRadicalConstructor::isTransform() const
+{
+ return mtype->isTransform();
+}
+
+bool LocusConstructor::isTransform() const
+{
+ return false;
+}
+
+/*
+ * generic polygon constructor
+ */
+
+PolygonBNPTypeConstructor::PolygonBNPTypeConstructor()
+ : mtype( PolygonBNPType::instance() )
+{
+}
+
+PolygonBNPTypeConstructor::~PolygonBNPTypeConstructor()
+{
+}
+
+const QString PolygonBNPTypeConstructor::descriptiveName() const
+{
+ return i18n("Polygon by Its Vertices");
+}
+
+const QString PolygonBNPTypeConstructor::description() const
+{
+ return i18n("Construct a polygon by giving its vertices");
+}
+
+const QCString PolygonBNPTypeConstructor::iconFileName( const bool ) const
+{
+ return "kig_polygon";
+}
+
+const bool PolygonBNPTypeConstructor::isAlreadySelectedOK(
+ const std::vector<ObjectCalcer*>& os, const int& pos ) const
+{
+ if ( pos == 0 && os.size() >= 3 ) return true;
+ return false;
+}
+
+const int PolygonBNPTypeConstructor::wantArgs( const std::vector<ObjectCalcer*>& os,
+ const KigDocument&,
+ const KigWidget& ) const
+{
+ int count=os.size() - 1;
+
+ for ( int i = 0; i <= count; i++ )
+ {
+ if ( ! ( os[i]->imp()->inherits( PointImp::stype() ) ) ) return ArgsParser::Invalid;
+ }
+ if ( count < 3 ) return ArgsParser::Valid;
+ if ( os[0] == os[count] ) return ArgsParser::Complete;
+ return ArgsParser::Valid;
+}
+
+void PolygonBNPTypeConstructor::handleArgs(
+ const std::vector<ObjectCalcer*>& os, KigPart& d,
+ KigWidget& v ) const
+{
+ std::vector<ObjectHolder*> bos = build( os, d.document(), v );
+ for ( std::vector<ObjectHolder*>::iterator i = bos.begin();
+ i != bos.end(); ++i )
+ {
+ (*i)->calc( d.document() );
+ }
+
+ d.addObjects( bos );
+}
+
+void PolygonBNPTypeConstructor::handlePrelim(
+ KigPainter& p, const std::vector<ObjectCalcer*>& os,
+ const KigDocument& d, const KigWidget&
+ ) const
+{
+ uint count = os.size();
+ if ( count < 2 ) return;
+
+ for ( uint i = 0; i < count; i++ )
+ {
+ assert ( os[i]->imp()->inherits( PointImp::stype() ) );
+ }
+
+ std::vector<ObjectCalcer*> args = os;
+ p.setBrushStyle( Qt::NoBrush );
+ p.setBrushColor( Qt::red );
+ p.setPen( QPen ( Qt::red, 1) );
+ p.setWidth( -1 ); // -1 means the default width for the object being
+ // drawn..
+
+ ObjectDrawer drawer( Qt::red );
+ drawprelim( drawer, p, args, d );
+}
+
+QString PolygonBNPTypeConstructor::useText( const ObjectCalcer&, const std::vector<ObjectCalcer*>& os,
+ const KigDocument&, const KigWidget& ) const
+{
+ if ( os.size() > 3 )
+ return i18n("... with this vertex (click on the first vertex to terminate construction)");
+ else return i18n("Construct a polygon with this vertex");
+}
+
+QString PolygonBNPTypeConstructor::selectStatement(
+ const std::vector<ObjectCalcer*>&, const KigDocument&,
+ const KigWidget& ) const
+{
+ return i18n("Select a point to be a vertex of the new polygon...");
+}
+
+void PolygonBNPTypeConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& ) const
+{
+ if ( parents.size() < 2 ) return;
+
+ std::vector<Coordinate> points;
+
+ for ( uint i = 0; i < parents.size(); ++i )
+ {
+ const Coordinate vertex =
+ static_cast<const PointImp*>( parents[i]->imp() )->coordinate();
+ points.push_back( vertex );
+ }
+
+ if ( parents.size() == 2 )
+ {
+ SegmentImp segment = SegmentImp( points[0], points[1] );
+ drawer.draw( segment, p, true );
+ } else {
+ PolygonImp polygon = PolygonImp( points );
+ drawer.draw( polygon, p, true );
+ }
+}
+
+std::vector<ObjectHolder*> PolygonBNPTypeConstructor::build( const std::vector<ObjectCalcer*>& parents, KigDocument&, KigWidget& ) const
+{
+ uint count = parents.size() - 1;
+ assert ( count >= 3 );
+ std::vector<ObjectCalcer*> args;
+ for ( uint i = 0; i < count; ++i ) args.push_back( parents[i] );
+ ObjectTypeCalcer* calcer = new ObjectTypeCalcer( mtype, args );
+ ObjectHolder* h = new ObjectHolder( calcer );
+ std::vector<ObjectHolder*> ret;
+ ret.push_back( h );
+ return ret;
+}
+
+void PolygonBNPTypeConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+bool PolygonBNPTypeConstructor::isTransform() const
+{
+ return false;
+}
+
+/*
+ * construction of polygon vertices
+ */
+
+static const struct ArgsParser::spec argsspecpv[] =
+{
+ { PolygonImp::stype(), I18N_NOOP( "Polygon" ),
+ I18N_NOOP( "Construct the vertices of this polygon..." ), true }
+};
+
+PolygonVertexTypeConstructor::PolygonVertexTypeConstructor()
+ : StandardConstructorBase( I18N_NOOP( "Vertices of a Polygon" ),
+ I18N_NOOP( "The vertices of a polygon." ),
+ "polygonvertices", margsparser ),
+ mtype( PolygonVertexType::instance() ),
+ margsparser( argsspecpv, 1 )
+{
+}
+
+PolygonVertexTypeConstructor::~PolygonVertexTypeConstructor()
+{
+}
+
+void PolygonVertexTypeConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& ) const
+{
+ if ( parents.size() != 1 ) return;
+
+ const PolygonImp* polygon = dynamic_cast<const PolygonImp*>( parents.front()->imp() );
+ const std::vector<Coordinate> points = polygon->points();
+
+ int sides = points.size();
+ for ( int i = 0; i < sides; ++i )
+ {
+ PointImp point = PointImp( points[i] );
+ drawer.draw( point, p, true );
+ }
+}
+
+std::vector<ObjectHolder*> PolygonVertexTypeConstructor::build( const std::vector<ObjectCalcer*>& parents, KigDocument&, KigWidget& ) const
+{
+ std::vector<ObjectHolder*> ret;
+ assert( parents.size() == 1 );
+ const PolygonImp* polygon = dynamic_cast<const PolygonImp*>( parents.front()->imp() );
+ const std::vector<Coordinate> points = polygon->points();
+
+ int sides = points.size();
+
+ for ( int i = 0; i < sides; ++i )
+ {
+ ObjectConstCalcer* d = new ObjectConstCalcer( new IntImp( i ) );
+ std::vector<ObjectCalcer*> args( parents );
+ args.push_back( d );
+ ret.push_back( new ObjectHolder( new ObjectTypeCalcer( mtype, args ) ) );
+ }
+ return ret;
+}
+
+void PolygonVertexTypeConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+bool PolygonVertexTypeConstructor::isTransform() const
+{
+ return false;
+}
+
+/*
+ * construction of polygon sides
+ */
+
+static const struct ArgsParser::spec argsspecps[] =
+{
+ { PolygonImp::stype(), I18N_NOOP( "Polygon" ),
+ I18N_NOOP( "Construct the sides of this polygon..." ), false }
+};
+
+PolygonSideTypeConstructor::PolygonSideTypeConstructor()
+ : StandardConstructorBase( I18N_NOOP( "Sides of a Polygon" ),
+ I18N_NOOP( "The sides of a polygon." ),
+ "polygonsides", margsparser ),
+ mtype( PolygonSideType::instance() ),
+ margsparser( argsspecps, 1 )
+{
+}
+
+PolygonSideTypeConstructor::~PolygonSideTypeConstructor()
+{
+}
+
+void PolygonSideTypeConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& ) const
+{
+ if ( parents.size() != 1 ) return;
+
+ const PolygonImp* polygon = dynamic_cast<const PolygonImp*>( parents.front()->imp() );
+ const std::vector<Coordinate> points = polygon->points();
+
+ uint sides = points.size();
+ for ( uint i = 0; i < sides; ++i )
+ {
+ uint nexti = ( i + 1 < sides )?(i + 1):0;
+ SegmentImp segment = SegmentImp( points[i], points[nexti] );
+ drawer.draw( segment, p, true );
+ }
+}
+
+std::vector<ObjectHolder*> PolygonSideTypeConstructor::build( const std::vector<ObjectCalcer*>& parents, KigDocument&, KigWidget& ) const
+{
+ std::vector<ObjectHolder*> ret;
+ assert( parents.size() == 1 );
+ const PolygonImp* polygon = dynamic_cast<const PolygonImp*>( parents.front()->imp() );
+ const std::vector<Coordinate> points = polygon->points();
+
+ uint sides = points.size();
+
+ for ( uint i = 0; i < sides; ++i )
+ {
+ ObjectConstCalcer* d = new ObjectConstCalcer( new IntImp( i ) );
+ std::vector<ObjectCalcer*> args( parents );
+ args.push_back( d );
+ ret.push_back( new ObjectHolder( new ObjectTypeCalcer( mtype, args ) ) );
+ }
+ return ret;
+}
+
+void PolygonSideTypeConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+bool PolygonSideTypeConstructor::isTransform() const
+{
+ return false;
+}
+
+/*
+ * polygon by center and vertex
+ */
+
+PolygonBCVConstructor::PolygonBCVConstructor()
+ : mtype( PolygonBCVType::instance() )
+{
+}
+
+PolygonBCVConstructor::~PolygonBCVConstructor()
+{
+}
+
+const QString PolygonBCVConstructor::descriptiveName() const
+{
+ return i18n("Regular Polygon with Given Center");
+}
+
+const QString PolygonBCVConstructor::description() const
+{
+ return i18n("Construct a regular polygon with a given center and vertex");
+}
+
+const QCString PolygonBCVConstructor::iconFileName( const bool ) const
+{
+ return "hexagonbcv";
+}
+
+const bool PolygonBCVConstructor::isAlreadySelectedOK(
+ const std::vector<ObjectCalcer*>&, const int& ) const
+{
+ return false;
+}
+
+const int PolygonBCVConstructor::wantArgs( const std::vector<ObjectCalcer*>& os,
+ const KigDocument&,
+ const KigWidget& ) const
+{
+ if ( os.size() > 3 ) return ArgsParser::Invalid;
+
+ uint imax = ( os.size() <= 2) ? os.size() : 2;
+ for ( uint i = 0; i < imax; ++i )
+ if ( ! ( os[i]->imp()->inherits( PointImp::stype() ) ) ) return ArgsParser::Invalid;
+
+ if ( os.size() < 3 ) return ArgsParser::Valid;
+
+ if ( ! ( os[2]->imp()->inherits( BogusPointImp::stype() ) ) )
+ return ArgsParser::Invalid;
+
+ return ArgsParser::Complete;
+}
+
+void PolygonBCVConstructor::handleArgs(
+ const std::vector<ObjectCalcer*>& os, KigPart& d,
+ KigWidget& v ) const
+{
+ std::vector<ObjectHolder*> bos = build( os, d.document(), v );
+ for ( std::vector<ObjectHolder*>::iterator i = bos.begin();
+ i != bos.end(); ++i )
+ {
+ (*i)->calc( d.document() );
+ }
+
+ d.addObjects( bos );
+}
+
+void PolygonBCVConstructor::handlePrelim(
+ KigPainter& p, const std::vector<ObjectCalcer*>& os,
+ const KigDocument& d, const KigWidget&
+ ) const
+{
+ if ( os.size() < 2 ) return;
+
+ for ( uint i = 0; i < 2; i++ )
+ {
+ assert ( os[i]->imp()->inherits( PointImp::stype() ) );
+ }
+
+ Coordinate c = static_cast<const PointImp*>( os[0]->imp() )->coordinate();
+ Coordinate v = static_cast<const PointImp*>( os[1]->imp() )->coordinate();
+
+ int nsides = 6;
+ bool moreinfo = false;
+ int winding = 0; // 0 means allow winding > 1
+ if ( os.size() == 3 )
+ {
+ assert ( os[2]->imp()->inherits( BogusPointImp::stype() ) );
+ Coordinate cntrl = static_cast<const PointImp*>( os[2]->imp() )->coordinate();
+ nsides = computeNsides( c, v, cntrl, winding );
+ moreinfo = true;
+ }
+
+ std::vector<ObjectCalcer*> args;
+ args.push_back( os[0] );
+ args.push_back( os[1] );
+ ObjectConstCalcer* ns = new ObjectConstCalcer( new IntImp( nsides ) );
+ args.push_back( ns );
+ if ( winding > 1 )
+ {
+ ns = new ObjectConstCalcer( new IntImp( winding ) );
+ args.push_back( ns );
+ }
+
+ p.setBrushStyle( Qt::NoBrush );
+ p.setBrushColor( Qt::red );
+ p.setPen( QPen ( Qt::red, 1) );
+ p.setWidth( -1 ); // -1 means the default width for the object being
+ // drawn..
+
+ ObjectDrawer drawer( Qt::red );
+ drawprelim( drawer, p, args, d );
+ if ( moreinfo )
+ {
+ p.setPointStyle( 1 );
+ p.setWidth( 6 );
+ double ro = 1.0/(2.5);
+ Coordinate where = getRotatedCoord( c, (1-ro)*c+ro*v, 4*M_PI/5.0 );
+ PointImp ptn = PointImp( where );
+ TextImp text = TextImp( "(5,2)", where, false );
+ ptn.draw( p );
+ text.draw( p );
+ for ( int i = 3; i < 9; ++i )
+ {
+ where = getRotatedCoord( c, v, 2.0*M_PI/i );
+ ptn = PointImp( where );
+ ptn.draw( p );
+ if ( i > 5 ) continue;
+ text = TextImp( QString( "(%1)" ).arg(i), where, false );
+ text.draw( p );
+ }
+ p.setStyle( Qt::DotLine );
+ p.setWidth( 1 );
+ double radius = ( v - c ).length();
+ CircleImp circle = CircleImp( c, radius );
+ circle.draw( p );
+ for ( int i = 2; i < 5; i++ )
+ {
+ ro = 1.0/(i+0.5);
+ CircleImp circle = CircleImp( c, ro*radius );
+ circle.draw( p );
+ }
+ }
+ delete_all( args.begin() + 2, args.end() );
+}
+
+std::vector<ObjectHolder*> PolygonBCVConstructor::build( const std::vector<ObjectCalcer*>& parents, KigDocument&, KigWidget& ) const
+{
+ assert ( parents.size() == 3 );
+ std::vector<ObjectCalcer*> args;
+
+ Coordinate c = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+ Coordinate v = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
+ Coordinate cntrl = static_cast<const PointImp*>( parents[2]->imp() )->coordinate();
+
+ args.push_back( parents[0] );
+ args.push_back( parents[1] );
+ int winding = 0;
+ int nsides = computeNsides( c, v, cntrl, winding );
+ ObjectConstCalcer* d = new ObjectConstCalcer( new IntImp( nsides ) );
+ args.push_back( d );
+ if ( winding > 1 )
+ {
+ d = new ObjectConstCalcer( new IntImp( winding ) );
+ args.push_back( d );
+ }
+
+ ObjectTypeCalcer* calcer = new ObjectTypeCalcer( mtype, args );
+ ObjectHolder* h = new ObjectHolder( calcer );
+ std::vector<ObjectHolder*> ret;
+ ret.push_back( h );
+ return ret;
+}
+
+QString PolygonBCVConstructor::useText( const ObjectCalcer&, const std::vector<ObjectCalcer*>& os,
+ const KigDocument&, const KigWidget& ) const
+{
+ switch ( os.size() )
+ {
+ case 1:
+ return i18n( "Construct a regular polygon with this center" );
+ break;
+
+ case 2:
+ return i18n( "Construct a regular polygon with this vertex" );
+ break;
+
+ case 3:
+ Coordinate c = static_cast<const PointImp*>( os[0]->imp() )->coordinate();
+ Coordinate v = static_cast<const PointImp*>( os[1]->imp() )->coordinate();
+ Coordinate cntrl = static_cast<const PointImp*>( os[2]->imp() )->coordinate();
+ int winding = 0;
+ int nsides = computeNsides( c, v, cntrl, winding );
+
+ if ( winding > 1 )
+ {
+ QString result = QString(
+ i18n( "Adjust the number of sides (%1/%2)" )
+ ).arg( nsides ).arg( winding );
+ return result;
+ } else
+ {
+ QString result = QString(
+ i18n( "Adjust the number of sides (%1)" )
+ ).arg( nsides );
+ return result;
+ }
+ break;
+ }
+
+ return "";
+}
+
+QString PolygonBCVConstructor::selectStatement(
+ const std::vector<ObjectCalcer*>& os, const KigDocument&,
+ const KigWidget& ) const
+{
+ switch ( os.size() )
+ {
+ case 1:
+ return i18n( "Select the center of the new polygon..." );
+ break;
+
+ case 2:
+ return i18n( "Select a vertex for the new polygon..." );
+ break;
+
+ case 3:
+ return i18n( "Move the cursor to get the desired number of sides..." );
+ break;
+ }
+
+ return "";
+}
+
+void PolygonBCVConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const
+{
+ if ( parents.size() < 3 || parents.size() > 4 ) return;
+
+ assert ( parents[0]->imp()->inherits( PointImp::stype() ) &&
+ parents[1]->imp()->inherits( PointImp::stype() ) &&
+ parents[2]->imp()->inherits( IntImp::stype() ) );
+
+ if ( parents.size() == 4 )
+ assert ( parents[3]->imp()->inherits( IntImp::stype() ) );
+
+ Args args;
+ std::transform( parents.begin(), parents.end(),
+ std::back_inserter( args ), std::mem_fun( &ObjectCalcer::imp ) );
+
+ ObjectImp* data = mtype->calc( args, doc );
+ drawer.draw( *data, p, true );
+ delete data;
+ data = 0;
+}
+
+void PolygonBCVConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+bool PolygonBCVConstructor::isTransform() const
+{
+ return false;
+}
+
+Coordinate PolygonBCVConstructor::getRotatedCoord( const Coordinate& c,
+ const Coordinate& v, double alpha ) const
+{
+ double cosalpha = cos(alpha);
+ double sinalpha = sin(alpha);
+ double dx = v.x - c.x;
+ double dy = v.y - c.y;
+ return c + Coordinate( cosalpha*dx - sinalpha*dy, sinalpha*dx + cosalpha*dy );
+}
+
+int PolygonBCVConstructor::computeNsides ( const Coordinate& c,
+ const Coordinate& v, const Coordinate& cntrl, int& winding ) const
+{
+ Coordinate lvect = v - c;
+ Coordinate rvect = cntrl - c;
+
+ double angle = atan2( rvect.y, rvect.x ) - atan2( lvect.y, lvect.x );
+ angle = fabs( angle/(2*M_PI) );
+ while ( angle > 1 ) angle -= 1;
+ if ( angle > 0.5 ) angle = 1 - angle;
+
+ double realsides = 1.0/angle; // this is bigger that 2
+ if ( angle == 0. ) realsides = 3;
+ if ( winding <= 0 ) // free to compute winding
+ {
+ winding = 1;
+ double ratio = lvect.length()/rvect.length();
+ winding = int ( ratio );
+ if ( winding < 1 ) winding = 1;
+ if ( winding > 50 ) winding = 50;
+ }
+ int nsides = int( winding*realsides + 0.5 ); // nsides/winding should be reduced!
+ if ( nsides > 100 ) nsides = 100; // well, 100 seems large enough!
+ if ( nsides < 3 ) nsides = 3;
+ while ( !relativePrimes ( nsides, winding ) ) ++nsides;
+ return nsides;
+}
+
+/*
+ * ConicConic intersection...
+ */
+
+static const ArgsParser::spec argsspectc[] = {
+ { ConicImp::stype(), "SHOULD NOT BE SEEN", "SHOULD NOT BE SEEN", true },
+ { ConicImp::stype(), "SHOULD NOT BE SEEN", "SHOULD NOT BE SEEN", true }
+};
+
+ConicConicIntersectionConstructor::ConicConicIntersectionConstructor()
+ : StandardConstructorBase( "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "curvelineintersection", mparser ),
+ mparser( argsspectc, 2 )
+{
+}
+
+ConicConicIntersectionConstructor::~ConicConicIntersectionConstructor()
+{
+}
+
+void ConicConicIntersectionConstructor::drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& ) const
+{
+ if ( parents.size() != 2 ) return;
+ assert ( parents[0]->imp()->inherits( ConicImp::stype() ) &&
+ parents[1]->imp()->inherits( ConicImp::stype() ) );
+ const ConicCartesianData conica =
+ static_cast<const ConicImp*>( parents[0]->imp() )->cartesianData();
+ const ConicCartesianData conicb =
+ static_cast<const ConicImp*>( parents[1]->imp() )->cartesianData();
+ bool ok = true;
+ for ( int wr = -1; wr < 2; wr += 2 )
+ {
+ LineData radical = calcConicRadical( conica, conicb, wr, 1, ok );
+ if ( ok )
+ {
+ for ( int wi = -1; wi < 2; wi += 2 )
+ {
+ Coordinate c = calcConicLineIntersect( conica, radical, 0.0, wi );
+ if ( c.valid() ) {
+ PointImp pi( c );
+ drawer.draw( pi, p, true );
+ }
+ };
+ };
+ };
+}
+
+std::vector<ObjectHolder*> ConicConicIntersectionConstructor::build(
+ const std::vector<ObjectCalcer*>& os, KigDocument& doc, KigWidget& ) const
+{
+ assert( os.size() == 2 );
+ std::vector<ObjectHolder*> ret;
+ ObjectCalcer* conica = os[0];
+ ObjectConstCalcer* zeroindexdo = new ObjectConstCalcer( new IntImp( 1 ) );
+
+ for ( int wr = -1; wr < 2; wr += 2 )
+ {
+ std::vector<ObjectCalcer*> args = os;
+ args.push_back( new ObjectConstCalcer( new IntImp( wr ) ) );
+ args.push_back( zeroindexdo );
+ ObjectTypeCalcer* radical =
+ new ObjectTypeCalcer( ConicRadicalType::instance(), args );
+ radical->calc( doc );
+ for ( int wi = -1; wi < 2; wi += 2 )
+ {
+ args.clear();
+ args.push_back( conica );
+ args.push_back( radical );
+ args.push_back( new ObjectConstCalcer( new IntImp( wi ) ) );
+ ret.push_back(
+ new ObjectHolder(
+ new ObjectTypeCalcer(
+ ConicLineIntersectionType::instance(), args ) ) );
+ };
+ };
+ return ret;
+}
+
+void ConicConicIntersectionConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+bool ConicConicIntersectionConstructor::isTransform() const
+{
+ return false;
+}
+
+ConicLineIntersectionConstructor::ConicLineIntersectionConstructor()
+ : MultiObjectTypeConstructor(
+ ConicLineIntersectionType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "curvelineintersection", -1, 1 )
+{
+}
+
+ConicLineIntersectionConstructor::~ConicLineIntersectionConstructor()
+{
+}
+
+ArcLineIntersectionConstructor::ArcLineIntersectionConstructor()
+ : MultiObjectTypeConstructor(
+ ArcLineIntersectionType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "curvelineintersection", -1, 1 )
+{
+}
+
+ArcLineIntersectionConstructor::~ArcLineIntersectionConstructor()
+{
+}
+
+QString ConicRadicalConstructor::useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>&,
+ const KigDocument&, const KigWidget& ) const
+{
+ if ( o.imp()->inherits( CircleImp::stype() ) )
+ return i18n( "Construct the Radical Lines of This Circle" );
+ else
+ return i18n( "Construct the Radical Lines of This Conic" );
+}
+
+/*
+ * generic affinity and generic projectivity. A unique affinity can be
+ * obtained by specifying the image of three points (four for projectivity)
+ * in the end we need, besides the object to be transformed, a total of
+ * six point or (alternatively) two triangles; our affinity will map the
+ * first triangle onto the second with corresponding ordering of their
+ * vertices. Since we allow for two different ways of specifying the six
+ * points we shall use a Generic constructor, like that for intersections.
+ */
+
+GenericAffinityConstructor::GenericAffinityConstructor()
+ : MergeObjectConstructor(
+ I18N_NOOP( "Generic Affinity" ),
+ I18N_NOOP( "The unique affinity that maps three points (or a triangle) onto three other points (or a triangle)" ),
+ "genericaffinity" )
+{
+ SimpleObjectTypeConstructor* b2tr =
+ new SimpleObjectTypeConstructor(
+ AffinityB2TrType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "genericaffinity" );
+
+ SimpleObjectTypeConstructor* gi3p =
+ new SimpleObjectTypeConstructor(
+ AffinityGI3PType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "genericaffinity" );
+
+ merge( b2tr );
+ merge( gi3p );
+}
+
+GenericAffinityConstructor::~GenericAffinityConstructor() {}
+
+GenericProjectivityConstructor::GenericProjectivityConstructor()
+ : MergeObjectConstructor(
+ I18N_NOOP( "Generic Projective Transformation" ),
+ I18N_NOOP( "The unique projective transformation that maps four points (or a quadrilateral) onto four other points (or a quadrilateral)" ),
+ "genericprojectivity" )
+{
+ SimpleObjectTypeConstructor* b2qu =
+ new SimpleObjectTypeConstructor(
+ ProjectivityB2QuType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "genericprojectivity" );
+
+ SimpleObjectTypeConstructor* gi4p =
+ new SimpleObjectTypeConstructor(
+ ProjectivityGI4PType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "genericprojectivity" );
+
+ merge( b2qu );
+ merge( gi4p );
+}
+
+GenericProjectivityConstructor::~GenericProjectivityConstructor() {}
+
+/*
+ * inversion of points, lines with respect to a circle
+ */
+
+InversionConstructor::InversionConstructor()
+ : MergeObjectConstructor(
+ I18N_NOOP( "Inversion of Point, Line or Circle" ),
+ I18N_NOOP( "The inversion of a point, line or circle with respect to a circle" ),
+ "inversion" )
+{
+ SimpleObjectTypeConstructor* pointobj =
+ new SimpleObjectTypeConstructor(
+ InvertPointType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "inversion" );
+
+ SimpleObjectTypeConstructor* lineobj =
+ new SimpleObjectTypeConstructor(
+ InvertLineType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "inversion" );
+
+ SimpleObjectTypeConstructor* segmentobj =
+ new SimpleObjectTypeConstructor(
+ InvertSegmentType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "inversion" );
+
+ SimpleObjectTypeConstructor* circleobj =
+ new SimpleObjectTypeConstructor(
+ InvertCircleType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "inversion" );
+
+ SimpleObjectTypeConstructor* arcobj =
+ new SimpleObjectTypeConstructor(
+ InvertArcType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "inversion" );
+
+ merge( arcobj );
+ merge( circleobj );
+ merge( pointobj );
+ merge( segmentobj );
+ merge( lineobj );
+}
+
+InversionConstructor::~InversionConstructor() {}
+
+/*
+ * Transport of Measure
+ */
+
+MeasureTransportConstructor::MeasureTransportConstructor()
+ : mtype( MeasureTransportType::instance() )
+{
+}
+
+MeasureTransportConstructor::~MeasureTransportConstructor()
+{
+}
+
+const QString MeasureTransportConstructor::descriptiveName() const
+{
+ return i18n("Measure Transport");
+}
+
+const QString MeasureTransportConstructor::description() const
+{
+ return i18n("Transport the measure of a segment or arc over a line or circle.");
+}
+
+const QCString MeasureTransportConstructor::iconFileName( const bool ) const
+{
+ return "measuretransport";
+}
+
+const bool MeasureTransportConstructor::isAlreadySelectedOK(
+ const std::vector<ObjectCalcer*>&, const int& ) const
+{
+ return false;
+}
+
+/*
+ * we want the arguments in the exact order, this makes
+ * the code simpler, but I guess it is also less confusing
+ * to the user
+ */
+
+const int MeasureTransportConstructor::wantArgs(
+ const std::vector<ObjectCalcer*>& os,
+ const KigDocument&,
+ const KigWidget& ) const
+{
+ if ( os.size() == 0 ) return ArgsParser::Valid;
+
+ if ( ! os[0]->imp()->inherits( SegmentImp::stype() ) &&
+ ! os[0]->imp()->inherits( ArcImp::stype() ) )
+ return ArgsParser::Invalid;
+
+ if ( os.size() == 1 ) return ArgsParser::Valid;
+
+ if ( ! os[1]->imp()->inherits( LineImp::stype() ) &&
+ ! os[1]->imp()->inherits( CircleImp::stype() ) )
+ return ArgsParser::Invalid;
+
+ if ( os.size() == 2 ) return ArgsParser::Valid;
+
+ if ( ! os[2]->imp()->inherits( PointImp::stype() ) )
+ return ArgsParser::Invalid;
+
+ // we here use the "isPointOnCurve", which relies on
+ // "by construction" incidence, instead of a numerical
+ // check
+ if ( ! isPointOnCurve( os[2], os[1] ) )
+ return ArgsParser::Invalid;
+
+ if ( os.size() == 3 ) return ArgsParser::Complete;
+
+ return ArgsParser::Invalid;
+}
+
+void MeasureTransportConstructor::handleArgs(
+ const std::vector<ObjectCalcer*>& os, KigPart& d,
+ KigWidget& v ) const
+{
+ std::vector<ObjectHolder*> bos = build( os, d.document(), v );
+ for ( std::vector<ObjectHolder*>::iterator i = bos.begin();
+ i != bos.end(); ++i )
+ {
+ (*i)->calc( d.document() );
+ }
+
+ d.addObjects( bos );
+}
+
+void MeasureTransportConstructor::handlePrelim(
+ KigPainter& p, const std::vector<ObjectCalcer*>& os,
+ const KigDocument& d, const KigWidget&
+ ) const
+{
+ p.setBrushStyle( Qt::NoBrush );
+ p.setBrushColor( Qt::red );
+ p.setPen( QPen ( Qt::red, 1) );
+ p.setWidth( -1 ); // -1 means the default width for the object being
+ // drawn..
+
+ ObjectDrawer drawer( Qt::red );
+ drawprelim( drawer, p, os, d );
+}
+
+void MeasureTransportConstructor::drawprelim( const ObjectDrawer& drawer,
+ KigPainter& p,
+ const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const
+{
+ Args args;
+ using namespace std;
+ transform( parents.begin(), parents.end(),
+ back_inserter( args ), mem_fun( &ObjectCalcer::imp ) );
+ ObjectImp* data = mtype->calc( args, doc );
+ drawer.draw( *data, p, true );
+ delete data;
+}
+
+QString MeasureTransportConstructor::useText( const ObjectCalcer& o,
+ const std::vector<ObjectCalcer*>& os,
+ const KigDocument&, const KigWidget& ) const
+{
+ if ( o.imp()->inherits( SegmentImp::stype() ) )
+ return i18n("Segment to transport");
+ if ( o.imp()->inherits( ArcImp::stype() ) )
+ return i18n("Arc to transport");
+ if ( o.imp()->inherits( LineImp::stype() ) )
+ return i18n("Transport a measure on this line");
+ if ( o.imp()->inherits( CircleImp::stype() ) )
+ return i18n("Transport a measure on this circle");
+ if ( o.imp()->inherits( PointImp::stype() ) )
+ {
+ if ( os[1]->imp()->inherits( CircleImp::stype() ) )
+ return i18n("Start transport from this point of the circle");
+ if ( os[1]->imp()->inherits( LineImp::stype() ) )
+ return i18n("Start transport from this point of the line");
+ else
+ return i18n("Start transport from this point of the curve");
+ // well, this isn't impemented yet, should never get here
+ }
+ return "";
+}
+
+QString MeasureTransportConstructor::selectStatement(
+ const std::vector<ObjectCalcer*>&, const KigDocument&,
+ const KigWidget& ) const
+{
+//TODO
+ return i18n("Select a point to be a vertex of the new polygon...");
+}
+
+std::vector<ObjectHolder*> MeasureTransportConstructor::build(
+ const std::vector<ObjectCalcer*>& parents,
+ KigDocument&, KigWidget& ) const
+{
+ assert ( parents.size() == 3 );
+// std::vector<ObjectCalcer*> args;
+// for ( uint i = 0; i < count; ++i ) args.push_back( parents[i] );
+ ObjectTypeCalcer* calcer = new ObjectTypeCalcer( mtype, parents );
+ ObjectHolder* h = new ObjectHolder( calcer );
+ std::vector<ObjectHolder*> ret;
+ ret.push_back( h );
+ return ret;
+}
+
+void MeasureTransportConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+bool MeasureTransportConstructor::isTransform() const
+{
+ return false;
+}
+
+/*
+ * Generic intersection
+ */
+
+GenericIntersectionConstructor::GenericIntersectionConstructor()
+ : MergeObjectConstructor(
+ I18N_NOOP( "Intersect" ),
+ I18N_NOOP( "The intersection of two objects" ),
+ "curvelineintersection" )
+{
+ // intersection type..
+ // There is one "toplevel" object_constructor, that is composed
+ // of multiple subconstructors.. First we build the
+ // subconstructors:
+ SimpleObjectTypeConstructor* lineline =
+ new SimpleObjectTypeConstructor(
+ LineLineIntersectionType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "curvelineintersection" );
+
+ ObjectConstructor* lineconic =
+ new ConicLineIntersectionConstructor();
+
+ ObjectConstructor* arcline =
+ new ArcLineIntersectionConstructor();
+
+ MultiObjectTypeConstructor* linecubic =
+ new MultiObjectTypeConstructor(
+ LineCubicIntersectionType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "curvelineintersection", 1, 2, 3 );
+
+ ObjectConstructor* conicconic =
+ new ConicConicIntersectionConstructor();
+
+ MultiObjectTypeConstructor* circlecircle =
+ new MultiObjectTypeConstructor(
+ CircleCircleIntersectionType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "circlecircleintersection", -1, 1 );
+
+ SimpleObjectTypeConstructor* polygonline =
+ new SimpleObjectTypeConstructor(
+ PolygonLineIntersectionType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "curvelineintersection" );
+
+ merge( lineline );
+ merge( circlecircle );
+ merge( lineconic );
+ merge( linecubic );
+ merge( conicconic );
+ merge( arcline );
+ merge( polygonline );
+}
+
+GenericIntersectionConstructor::~GenericIntersectionConstructor()
+{
+}
+
+bool GenericIntersectionConstructor::isIntersection() const
+{
+ return true;
+}
+
+QString GenericIntersectionConstructor::useText(
+ const ObjectCalcer& o, const std::vector<ObjectCalcer*>& os,
+ const KigDocument&, const KigWidget& ) const
+{
+ QString preamble;
+ switch (os.size())
+ {
+ case 1:
+ if ( o.imp()->inherits( CircleImp::stype() ) )
+ return i18n( "Intersect this Circle" );
+ else if ( o.imp()->inherits( ConicImp::stype() ) )
+ return i18n( "Intersect this Conic" );
+ else if ( o.imp()->inherits( AbstractLineImp::stype() ) )
+ return i18n( "Intersect this Line" );
+ else if ( o.imp()->inherits( CubicImp::stype() ) )
+ return i18n( "Intersect this Cubic Curve" );
+ else if ( o.imp()->inherits( ArcImp::stype() ) )
+ return i18n( "Intersect this Arc" );
+ else if ( o.imp()->inherits( PolygonImp::stype() ) )
+ return i18n( "Intersect this Polygon" );
+ else assert( false );
+ break;
+ case 2:
+ if ( o.imp()->inherits( CircleImp::stype() ) )
+ return i18n( "with this Circle" );
+ else if ( o.imp()->inherits( ConicImp::stype() ) )
+ return i18n( "with this Conic" );
+ else if ( o.imp()->inherits( AbstractLineImp::stype() ) )
+ return i18n( "with this Line" );
+ else if ( o.imp()->inherits( CubicImp::stype() ) )
+ return i18n( "with this Cubic Curve" );
+ else if ( o.imp()->inherits( ArcImp::stype() ) )
+ return i18n( "with this Arc" );
+ else if ( o.imp()->inherits( PolygonImp::stype() ) )
+ return i18n( "with this Polygon" );
+ else assert( false );
+ break;
+ }
+
+ return QString::null;
+}
+
+static const ArgsParser::spec argsspecMidPointOfTwoPoints[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Construct Midpoint of This Point and Another One" ),
+ I18N_NOOP( "Select the first of the points of which you want to construct the midpoint..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct the midpoint of this point and another one" ),
+ I18N_NOOP( "Select the other of the points of which to construct the midpoint..." ), false }
+};
+
+MidPointOfTwoPointsConstructor::MidPointOfTwoPointsConstructor()
+ : StandardConstructorBase( "Mid Point",
+ "Construct the midpoint of two points",
+ "bisection", mparser ),
+ mparser( argsspecMidPointOfTwoPoints, 2 )
+{
+}
+
+MidPointOfTwoPointsConstructor::~MidPointOfTwoPointsConstructor()
+{
+}
+
+void MidPointOfTwoPointsConstructor::drawprelim(
+ const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& ) const
+{
+ if ( parents.size() != 2 ) return;
+ assert( parents[0]->imp()->inherits( PointImp::stype() ) );
+ assert( parents[1]->imp()->inherits( PointImp::stype() ) );
+ const Coordinate m =
+ ( static_cast<const PointImp*>( parents[0]->imp() )->coordinate() +
+ static_cast<const PointImp*>( parents[1]->imp() )->coordinate() ) / 2;
+ drawer.draw( PointImp( m ), p, true );
+}
+
+std::vector<ObjectHolder*> MidPointOfTwoPointsConstructor::build(
+ const std::vector<ObjectCalcer*>& os, KigDocument& d, KigWidget& ) const
+{
+ ObjectTypeCalcer* seg = new ObjectTypeCalcer( SegmentABType::instance(), os );
+ seg->calc( d );
+ int index = seg->imp()->propertiesInternalNames().findIndex( "mid-point" );
+ assert( index != -1 );
+ ObjectPropertyCalcer* prop = new ObjectPropertyCalcer( seg, index );
+ prop->calc( d );
+ std::vector<ObjectHolder*> ret;
+ ret.push_back( new ObjectHolder( prop ) );
+ return ret;
+}
+
+void MidPointOfTwoPointsConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+bool MidPointOfTwoPointsConstructor::isTransform() const
+{
+ return false;
+}
+
+TestConstructor::TestConstructor( const ArgsParserObjectType* type, const char* descname,
+ const char* desc, const char* iconfile )
+ : StandardConstructorBase( descname, desc, iconfile, type->argsParser() ),
+ mtype( type )
+{
+}
+
+TestConstructor::~TestConstructor()
+{
+}
+
+void TestConstructor::drawprelim( const ObjectDrawer&, KigPainter&, const std::vector<ObjectCalcer*>&,
+ const KigDocument& ) const
+{
+ // not used, only here because of the wrong
+ // ObjectConstructor-GUIAction design. See the TODO
+}
+
+std::vector<ObjectHolder*> TestConstructor::build( const std::vector<ObjectCalcer*>&, KigDocument&,
+ KigWidget& ) const
+{
+ // not used, only here because of the wrong
+ // ObjectConstructor-GUIAction design. See the TODO
+ std::vector<ObjectHolder*> ret;
+ return ret;
+}
+
+void TestConstructor::plug( KigPart*, KigGUIAction* )
+{
+}
+
+bool TestConstructor::isTransform() const
+{
+ return false;
+}
+
+bool TestConstructor::isTest() const
+{
+ return true;
+}
+
+BaseConstructMode* TestConstructor::constructMode( KigPart& doc )
+{
+ return new TestConstructMode( doc, mtype );
+}
+
+const int TestConstructor::wantArgs( const std::vector<ObjectCalcer*>& os,
+ const KigDocument& d, const KigWidget& v ) const
+{
+ int ret = StandardConstructorBase::wantArgs( os, d, v );
+ if ( ret == ArgsParser::Complete ) ret = ArgsParser::Valid;
+ return ret;
+}
+
+QString GenericIntersectionConstructor::selectStatement(
+ const std::vector<ObjectCalcer*>& sel, const KigDocument&,
+ const KigWidget& ) const
+{
+ if ( sel.size() == 0 )
+ return i18n( "Select the first object to intersect..." );
+ else
+ return i18n( "Select the second object to intersect..." );
+}
+
+TangentConstructor::TangentConstructor()
+ : MergeObjectConstructor(
+ I18N_NOOP( "Tangent" ),
+ I18N_NOOP( "The line tangent to a curve" ),
+ "tangent" )
+{
+ SimpleObjectTypeConstructor* conic =
+ new SimpleObjectTypeConstructor(
+ TangentConicType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "tangentconic" );
+
+ SimpleObjectTypeConstructor* arc =
+ new SimpleObjectTypeConstructor(
+ TangentArcType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "tangentarc" );
+
+ SimpleObjectTypeConstructor* cubic =
+ new SimpleObjectTypeConstructor(
+ TangentCubicType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "tangentcubic" );
+
+ SimpleObjectTypeConstructor* curve =
+ new SimpleObjectTypeConstructor(
+ TangentCurveType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "tangentcurve" );
+
+ merge( conic );
+ merge( arc );
+ merge( cubic );
+ merge( curve );
+}
+
+TangentConstructor::~TangentConstructor()
+{
+}
+
+QString TangentConstructor::useText(
+ const ObjectCalcer& o, const std::vector<ObjectCalcer*>&,
+ const KigDocument&, const KigWidget& ) const
+{
+ if ( o.imp()->inherits( CircleImp::stype() ) )
+ return i18n( "Tangent to This Circle" );
+ else if ( o.imp()->inherits( ConicImp::stype() ) )
+ return i18n( "Tangent to This Conic" );
+ else if ( o.imp()->inherits( ArcImp::stype() ) )
+ return i18n( "Tangent to This Arc" );
+ else if ( o.imp()->inherits( CubicImp::stype() ) )
+ return i18n( "Tangent to This Cubic Curve" );
+ else if ( o.imp()->inherits( CurveImp::stype() ) )
+ return i18n( "Tangent to This Curve" );
+ else if ( o.imp()->inherits( PointImp::stype() ) )
+ return i18n( "Tangent at This Point" );
+// else assert( false );
+ return QString::null;
+}
+
+//QString TangentConstructor::selectStatement(
+// const std::vector<ObjectCalcer*>& sel, const KigDocument&,
+// const KigWidget& ) const
+//{
+// if ( sel.size() == 0 )
+// return i18n( "Select the object..." );
+// else
+// return i18n( "Select the point for the tangent to go through..." );
+//}
+
+/*
+ * center of curvature of a curve
+ */
+
+CocConstructor::CocConstructor()
+ : MergeObjectConstructor(
+ I18N_NOOP( "Center Of Curvature" ),
+ I18N_NOOP( "The center of the osculating circle to a curve" ),
+ "centerofcurvature" )
+{
+ SimpleObjectTypeConstructor* conic =
+ new SimpleObjectTypeConstructor(
+ CocConicType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "cocconic" );
+
+ SimpleObjectTypeConstructor* cubic =
+ new SimpleObjectTypeConstructor(
+ CocCubicType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "coccubic" );
+
+ SimpleObjectTypeConstructor* curve =
+ new SimpleObjectTypeConstructor(
+ CocCurveType::instance(),
+ "SHOULDNOTBESEEN", "SHOULDNOTBESEEN",
+ "coccurve" );
+
+ merge( conic );
+ merge( cubic );
+ merge( curve );
+}
+
+CocConstructor::~CocConstructor()
+{
+}
+
+QString CocConstructor::useText(
+ const ObjectCalcer& o, const std::vector<ObjectCalcer*>&,
+ const KigDocument&, const KigWidget& ) const
+{
+ if ( o.imp()->inherits( ConicImp::stype() ) )
+ return i18n( "Center of Curvature of This Conic" );
+ else if ( o.imp()->inherits( CubicImp::stype() ) )
+ return i18n( "Center of Curvature of This Cubic Curve" );
+ else if ( o.imp()->inherits( CurveImp::stype() ) )
+ return i18n( "Center of Curvature of This Curve" );
+ else if ( o.imp()->inherits( PointImp::stype() ) )
+ return i18n( "Center of Curvature at This Point" );
+ return QString::null;
+}
+
+bool relativePrimes( int n, int p )
+{
+ if ( p > n ) return relativePrimes( p, n );
+ assert ( p >= 0 );
+ if ( p == 0 ) return false;
+ if ( p == 1 ) return true;
+ int d = int( n/p );
+ return relativePrimes( p, n-d*p );
+}
+
+//QString CocConstructor::selectStatement(
+// const std::vector<ObjectCalcer*>& sel, const KigDocument&,
+// const KigWidget& ) const
+//{
+// if ( sel.size() == 0 )
+// return i18n( "Select the object..." );
+// else
+// return i18n( "Select the point where to compute the center of curvature..." );
+//}
diff --git a/kig/misc/special_constructors.h b/kig/misc/special_constructors.h
new file mode 100644
index 00000000..99760be3
--- /dev/null
+++ b/kig/misc/special_constructors.h
@@ -0,0 +1,320 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MISC_SPECIAL_CONSTRUCTORS_H
+#define KIG_MISC_SPECIAL_CONSTRUCTORS_H
+
+#include "object_constructor.h"
+
+class PolygonVertexTypeConstructor
+ : public StandardConstructorBase
+{
+ const ArgsParserObjectType* mtype;
+ ArgsParser margsparser;
+public:
+ PolygonVertexTypeConstructor();
+ ~PolygonVertexTypeConstructor();
+
+ void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents, const KigDocument& ) const;
+ std::vector<ObjectHolder*> build( const std::vector<ObjectCalcer*>& os, KigDocument& d, KigWidget& w ) const;
+ void plug( KigPart* doc, KigGUIAction* kact );
+ bool isTransform() const;
+};
+
+class PolygonSideTypeConstructor
+ : public StandardConstructorBase
+{
+ const ArgsParserObjectType* mtype;
+ ArgsParser margsparser;
+public:
+ PolygonSideTypeConstructor();
+ ~PolygonSideTypeConstructor();
+
+ void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents, const KigDocument& ) const;
+ std::vector<ObjectHolder*> build( const std::vector<ObjectCalcer*>& os, KigDocument& d, KigWidget& w ) const;
+ void plug( KigPart* doc, KigGUIAction* kact );
+ bool isTransform() const;
+};
+
+class PolygonBNPTypeConstructor
+ : public ObjectConstructor
+{
+ const ObjectType* mtype;
+public:
+ PolygonBNPTypeConstructor();
+ ~PolygonBNPTypeConstructor();
+
+ const QString descriptiveName() const;
+ const QString description() const;
+ const QCString iconFileName( const bool canBeNull = false ) const;
+ const bool isAlreadySelectedOK( const std::vector<ObjectCalcer*>& os,
+ const int& ) const;
+ const int wantArgs( const std::vector<ObjectCalcer*>& os,
+ const KigDocument& d,
+ const KigWidget& v
+ ) const;
+ void handleArgs( const std::vector<ObjectCalcer*>& os,
+ KigPart& d,
+ KigWidget& v
+ ) const;
+ QString useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d, const KigWidget& v
+ ) const;
+ QString selectStatement(
+ const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& w ) const;
+ void handlePrelim( KigPainter& p,
+ const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d,
+ const KigWidget& v
+ ) const;
+
+ void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents, const KigDocument& ) const;
+ std::vector<ObjectHolder*> build( const std::vector<ObjectCalcer*>& os, KigDocument& d, KigWidget& w ) const;
+ void plug( KigPart* doc, KigGUIAction* kact );
+ bool isTransform() const;
+};
+
+class PolygonBCVConstructor
+ : public ObjectConstructor
+{
+ const ObjectType* mtype;
+public:
+ PolygonBCVConstructor();
+ ~PolygonBCVConstructor();
+
+ const QString descriptiveName() const;
+ const QString description() const;
+ const QCString iconFileName( const bool canBeNull = false ) const;
+ const bool isAlreadySelectedOK( const std::vector<ObjectCalcer*>& os,
+ const int& ) const;
+ const int wantArgs( const std::vector<ObjectCalcer*>& os,
+ const KigDocument& d,
+ const KigWidget& v
+ ) const;
+ void handleArgs( const std::vector<ObjectCalcer*>& os,
+ KigPart& d,
+ KigWidget& v
+ ) const;
+ QString useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d, const KigWidget& v
+ ) const;
+ QString selectStatement(
+ const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& w ) const;
+ void handlePrelim( KigPainter& p,
+ const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d,
+ const KigWidget& v
+ ) const;
+ void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents, const KigDocument& ) const;
+ std::vector<ObjectHolder*> build( const std::vector<ObjectCalcer*>& os, KigDocument& d, KigWidget& w ) const;
+ void plug( KigPart* doc, KigGUIAction* kact );
+ bool isTransform() const;
+ int computeNsides( const Coordinate& c, const Coordinate& v, const Coordinate& cntrl, int& winding ) const;
+ Coordinate getRotatedCoord( const Coordinate& c1,
+ const Coordinate& c2, double alpha ) const;
+};
+
+class MeasureTransportConstructor
+ : public ObjectConstructor
+{
+ const ObjectType* mtype;
+public:
+ MeasureTransportConstructor();
+ ~MeasureTransportConstructor();
+
+ const QString descriptiveName() const;
+ const QString description() const;
+ const QCString iconFileName( const bool canBeNull = false ) const;
+ const bool isAlreadySelectedOK( const std::vector<ObjectCalcer*>& os,
+ const int& ) const;
+ const int wantArgs( const std::vector<ObjectCalcer*>& os,
+ const KigDocument& d,
+ const KigWidget& v
+ ) const;
+ void handleArgs( const std::vector<ObjectCalcer*>& os,
+ KigPart& d,
+ KigWidget& v
+ ) const;
+ QString useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d, const KigWidget& v
+ ) const;
+ QString selectStatement(
+ const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& w ) const;
+ void handlePrelim( KigPainter& p,
+ const std::vector<ObjectCalcer*>& sel,
+ const KigDocument& d,
+ const KigWidget& v
+ ) const;
+
+ void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents, const KigDocument& ) const;
+ std::vector<ObjectHolder*> build( const std::vector<ObjectCalcer*>& os, KigDocument& d, KigWidget& w ) const;
+ void plug( KigPart* doc, KigGUIAction* kact );
+ bool isTransform() const;
+};
+
+class ConicRadicalConstructor
+ : public StandardConstructorBase
+{
+ const ArgsParserObjectType* mtype;
+ const ArgsParser mparser;
+public:
+ ConicRadicalConstructor();
+ ~ConicRadicalConstructor();
+ QString useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& v ) const;
+ void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents, const KigDocument& ) const;
+ std::vector<ObjectHolder*> build( const std::vector<ObjectCalcer*>& os, KigDocument& d, KigWidget& w ) const;
+ void plug( KigPart* doc, KigGUIAction* kact );
+
+ bool isTransform() const;
+};
+
+class LocusConstructor
+ : public StandardConstructorBase
+{
+ ArgsParser margsparser;
+public:
+ LocusConstructor();
+ ~LocusConstructor();
+ /**
+ * we override the wantArgs() function, since we need to see
+ * something about the objects that an ArgsParser can't know about,
+ * namely, whether the first point is a constrained point...
+ */
+ const int wantArgs(
+ const std::vector<ObjectCalcer*>& os, const KigDocument& d,
+ const KigWidget& v
+ ) const;
+ QString useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& v ) const;
+
+ void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents, const KigDocument& ) const;
+ std::vector<ObjectHolder*> build( const std::vector<ObjectCalcer*>& os, KigDocument& d, KigWidget& w ) const;
+ void plug( KigPart* doc, KigGUIAction* kact );
+
+ bool isTransform() const;
+};
+
+class GenericAffinityConstructor
+ : public MergeObjectConstructor
+{
+public:
+ GenericAffinityConstructor();
+ ~GenericAffinityConstructor();
+};
+
+class GenericProjectivityConstructor
+ : public MergeObjectConstructor
+{
+public:
+ GenericProjectivityConstructor();
+ ~GenericProjectivityConstructor();
+};
+
+class InversionConstructor
+ : public MergeObjectConstructor
+{
+public:
+ InversionConstructor();
+ ~InversionConstructor();
+};
+
+class GenericIntersectionConstructor
+ : public MergeObjectConstructor
+{
+public:
+ GenericIntersectionConstructor();
+ ~GenericIntersectionConstructor();
+
+ bool isIntersection() const;
+
+ QString useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& v ) const;
+ QString selectStatement(
+ const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& w ) const;
+};
+
+class MidPointOfTwoPointsConstructor
+ : public StandardConstructorBase
+{
+ ArgsParser mparser;
+public:
+ MidPointOfTwoPointsConstructor();
+ ~MidPointOfTwoPointsConstructor();
+ void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& ) const;
+ std::vector<ObjectHolder*> build( const std::vector<ObjectCalcer*>& os, KigDocument& d,
+ KigWidget& w ) const;
+ void plug( KigPart* doc, KigGUIAction* kact );
+ bool isTransform() const;
+};
+
+class TestConstructor
+ : public StandardConstructorBase
+{
+ const ArgsParserObjectType* mtype;
+public:
+ TestConstructor( const ArgsParserObjectType* type, const char* descname,
+ const char* desc, const char* iconfile );
+ ~TestConstructor();
+ void drawprelim( const ObjectDrawer& drawer, KigPainter& p, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& ) const;
+ std::vector<ObjectHolder*> build( const std::vector<ObjectCalcer*>& os, KigDocument& d,
+ KigWidget& w ) const;
+ const int wantArgs( const std::vector<ObjectCalcer*>& os,
+ const KigDocument& d, const KigWidget& v ) const;
+ void plug( KigPart* doc, KigGUIAction* kact );
+ bool isTransform() const;
+ bool isTest() const;
+
+ BaseConstructMode* constructMode( KigPart& doc );
+};
+
+class TangentConstructor
+ : public MergeObjectConstructor
+{
+public:
+ TangentConstructor();
+ ~TangentConstructor();
+
+ QString useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& v ) const;
+// QString selectStatement(
+// const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+// const KigWidget& w ) const;
+};
+
+class CocConstructor
+ : public MergeObjectConstructor
+{
+public:
+ CocConstructor();
+ ~CocConstructor();
+
+ QString useText( const ObjectCalcer& o, const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+ const KigWidget& v ) const;
+// QString selectStatement(
+// const std::vector<ObjectCalcer*>& sel, const KigDocument& d,
+// const KigWidget& w ) const;
+};
+
+bool relativePrimes( int n, int p );
+#endif
diff --git a/kig/modes/Makefile.am b/kig/modes/Makefile.am
new file mode 100644
index 00000000..5f7518e5
--- /dev/null
+++ b/kig/modes/Makefile.am
@@ -0,0 +1,39 @@
+INCLUDES=$(all_includes)
+
+noinst_LTLIBRARIES=libmodes.la
+libmodes_la_SOURCES= \
+ base_mode.cc \
+ construct_mode.cc \
+ dragrectmode.cc \
+ edittype.cc \
+ edittypebase.ui \
+ label.cc \
+ linkslabel.cpp \
+ macro.cc \
+ macrowizard.cc \
+ macrowizardbase.ui \
+ mode.cc \
+ moving.cc \
+ normal.cc \
+ popup.cc \
+ textlabelwizard.cc \
+ textlabelwizardbase.ui \
+ typesdialog.cpp \
+ typesdialogbase.ui
+noinst_HEADERS=\
+ base_mode.h \
+ construct_mode.h \
+ dragrectmode.h \
+ edittype.h \
+ label.h \
+ linkslabel.h \
+ macro.h \
+ macrowizard.h \
+ mode.h \
+ moving.h \
+ normal.h \
+ popup.h \
+ textlabelwizard.h \
+ typesdialog.h
+
+METASOURCES=AUTO
diff --git a/kig/modes/base_mode.cc b/kig/modes/base_mode.cc
new file mode 100644
index 00000000..9e92274a
--- /dev/null
+++ b/kig/modes/base_mode.cc
@@ -0,0 +1,160 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "base_mode.h"
+
+#include "popup.h"
+
+#include "../kig/kig_view.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_document.h"
+
+#include <qevent.h>
+#include <kcursor.h>
+
+BaseMode::BaseMode( KigPart& d )
+ : KigMode( d )
+{
+}
+
+BaseMode::~BaseMode()
+{
+}
+
+void BaseMode::leftClicked( QMouseEvent* e, KigWidget* v )
+{
+ // touch screens don't send a mouseMoved event before a click event,
+ // apparently, so we simulate it.
+ mouseMoved( e, v );
+
+ // get rid of text still showing...
+ v->updateCurPix();
+ v->updateWidget();
+
+ mplc = e->pos();
+ moco = mdoc.document().whatAmIOn( v->fromScreen( mplc ), *v );
+
+ if( moco.empty() )
+ {
+ // clicked on an empty spot --> we show the rectangle for
+ // selecting stuff...
+ dragRect( mplc, *v );
+ }
+ else
+ {
+ // the user clicked on some object.. --> this could either mean
+ // that he/she wants to select the object or that he wants to
+ // start moving it. We assume nothing here, we wait till he
+ // either moves some 4 pixels, or till he releases his mouse
+ // button in leftReleased() or mouseMoved()...
+ };
+}
+
+void BaseMode::leftMouseMoved( QMouseEvent* e, KigWidget* w )
+{
+ if( !moco.empty() && ( mplc - e->pos() ).manhattanLength() > 3 )
+ dragObject( moco, mplc, *w,
+ ( e->state() & (ShiftButton | ControlButton ) ) != 0
+ );
+}
+
+void BaseMode::leftReleased( QMouseEvent* e, KigWidget* v )
+{
+ if( (mplc - e->pos()).manhattanLength() > 4 ) return;
+
+ ObjectHolder* o = 0;
+ bool keyCtrl = ( e->state() & ControlButton ) != 0;
+ bool keyShift = ( e->state() & ShiftButton ) != 0;
+ if ( ! moco.empty() )
+ {
+ if ( keyShift )
+ {
+ int id = ObjectChooserPopup::getObjectFromList( e->pos(), v, moco );
+ if ( id >= 0 )
+ o = moco[id];
+ }
+ else
+ o = moco.front();
+ }
+ leftClickedObject( o, e->pos(), *v, keyCtrl );
+}
+
+void BaseMode::midClicked( QMouseEvent* e, KigWidget* v )
+{
+ // get rid of text still showing...
+ v->updateCurPix();
+ v->updateWidget();
+
+ mplc = e->pos();
+ moco = mdoc.document().whatAmIOn( v->fromScreen( e->pos() ), *v );
+}
+
+void BaseMode::midReleased( QMouseEvent* e, KigWidget* v )
+{
+ if( (e->pos() - mplc).manhattanLength() > 4 ) return;
+
+ midClicked( mplc, *v );
+}
+
+void BaseMode::rightClicked( QMouseEvent* e, KigWidget* w )
+{
+ // get rid of text still showing...
+ w->updateCurPix();
+ w->updateWidget();
+ // set a normal cursor...
+ w->setCursor( KCursor::arrowCursor() );
+
+ mplc = e->pos();
+ moco = mdoc.document().whatAmIOn( w->fromScreen( mplc ), *w );
+
+ rightClicked( moco, mplc, *w );
+}
+
+void BaseMode::mouseMoved( QMouseEvent* e, KigWidget* w )
+{
+ std::vector<ObjectHolder*> os = mdoc.document().whatAmIOn( w->fromScreen( e->pos() ), *w );
+ mouseMoved( os, e->pos(), *w, e->state() & Qt::ShiftButton );
+}
+
+void BaseMode::dragRect( const QPoint&, KigWidget& )
+{
+}
+
+void BaseMode::leftClickedObject( ObjectHolder*, const QPoint&,
+ KigWidget&, bool )
+{
+}
+
+void BaseMode::dragObject( const std::vector<ObjectHolder*>&, const QPoint&,
+ KigWidget&, bool )
+{
+}
+
+void BaseMode::enableActions()
+{
+ KigMode::enableActions();
+}
+
+std::vector<ObjectHolder*> BaseMode::oco()
+{
+ return moco;
+}
+
+QPoint BaseMode::pointLocation()
+{
+ return mplc;
+}
diff --git a/kig/modes/base_mode.h b/kig/modes/base_mode.h
new file mode 100644
index 00000000..2f89996f
--- /dev/null
+++ b/kig/modes/base_mode.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MODE_BASE_MODE_H
+#define KIG_MODE_BASE_MODE_H
+
+#include "mode.h"
+
+#include <qpoint.h>
+#include <vector>
+
+class KigWidget;
+class KigDocument;
+class ObjectHolder;
+
+class BaseMode
+ : public KigMode
+{
+ QPoint mplc;
+ std::vector<ObjectHolder*> moco;
+
+ void leftClicked( QMouseEvent* e, KigWidget* v );
+ void leftMouseMoved( QMouseEvent*, KigWidget* );
+ void leftReleased( QMouseEvent* e, KigWidget* v );
+ void midClicked( QMouseEvent* e, KigWidget* v );
+ void midReleased( QMouseEvent* e, KigWidget* v );
+ void rightClicked( QMouseEvent*, KigWidget* );
+ void mouseMoved( QMouseEvent* e, KigWidget* v );
+
+protected:
+ void enableActions();
+
+ std::vector<ObjectHolder*> oco();
+ QPoint pointLocation();
+protected:
+
+ virtual void dragRect( const QPoint& p, KigWidget& w );
+ virtual void dragObject( const std::vector<ObjectHolder*>& os, const QPoint& pointClickedOn, KigWidget& w, bool ctrlOrShiftDown );
+ virtual void leftClickedObject( ObjectHolder* o, const QPoint& p,
+ KigWidget& w, bool ctrlOrShiftDown ) = 0;
+ virtual void midClicked( const QPoint& p, KigWidget& w ) = 0;
+ virtual void rightClicked( const std::vector<ObjectHolder*>& oco, const QPoint& p, KigWidget& w ) = 0;
+ virtual void mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w, bool shiftpressed ) = 0;
+
+protected:
+ BaseMode( KigPart& );
+ ~BaseMode();
+};
+
+#endif
diff --git a/kig/modes/construct_mode.cc b/kig/modes/construct_mode.cc
new file mode 100644
index 00000000..9618aded
--- /dev/null
+++ b/kig/modes/construct_mode.cc
@@ -0,0 +1,572 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "construct_mode.h"
+
+#include "../objects/object_factory.h"
+#include "../objects/object_drawer.h"
+#include "../objects/text_type.h"
+#include "../objects/text_imp.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/point_imp.h"
+#include "../misc/argsparser.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../misc/object_constructor.h"
+#include "../misc/coordinate_system.h"
+#include "../misc/kigpainter.h"
+#include "../misc/calcpaths.h"
+
+#include "popup.h"
+
+#include <kcursor.h>
+#include <kaction.h>
+
+#include <algorithm>
+#include <functional>
+
+static void redefinePoint( ObjectTypeCalcer* mpt, const Coordinate& c, KigDocument& doc, const KigWidget& w )
+{
+ ObjectFactory::instance()->redefinePoint( mpt, c, doc, w );
+ mpt->calc( doc );
+}
+
+BaseConstructMode::BaseConstructMode( KigPart& d )
+ : BaseMode( d )
+{
+ mpt = ObjectFactory::instance()->fixedPointCalcer( Coordinate( 0, 0 ) );
+ mpt->calc( d.document() );
+ mcursor = ObjectFactory::instance()->cursorPointCalcer( Coordinate( 0, 0 ) );
+ mcursor->calc( d.document() );
+// mcursorholder = new ObjectHolder( mcursor );
+}
+
+BaseConstructMode::~BaseConstructMode()
+{
+ delete mcursor;
+// delete mcursorholder;
+}
+
+void BaseConstructMode::leftReleased( QMouseEvent* e, KigWidget* v )
+{
+ if( (pointLocation() - e->pos()).manhattanLength() > 4 ) return;
+
+ ObjectHolder* o = 0;
+ bool keyCtrlOrShift = ( e->state() & ( ControlButton | ShiftButton) ) != 0;
+ std::vector<ObjectHolder*> moco = oco();
+ if ( ! moco.empty() )
+ {
+ std::vector<ObjectHolder*> goodargs;
+ if ( !moco.empty() )
+ {
+ std::vector<ObjectHolder*>::const_iterator it;
+ std::vector<ObjectCalcer*> testargs = getCalcers( mparents );
+ for ( std::vector<ObjectHolder*>::const_iterator i = moco.begin(); i != moco.end(); ++i )
+ {
+ it = std::find( mparents.begin(), mparents.end(), *i );
+ bool newdup =
+ ( it == mparents.end() ) ||
+ isAlreadySelectedOK( testargs, it - mparents.begin() );
+ if ( newdup )
+ {
+ testargs.push_back( ( *i )->calcer() );
+ if ( wantArgs( testargs, mdoc.document(), *v ) )
+ goodargs.push_back( *i );
+ testargs.pop_back();
+ }
+ }
+ int id = ObjectChooserPopup::getObjectFromList( e->pos(), v, goodargs );
+ if ( id >= 0 )
+ o = goodargs[id];
+ }
+ }
+ leftClickedObject( o, e->pos(), *v, keyCtrlOrShift );
+ KigMode::leftReleased( e, v );
+}
+
+void BaseConstructMode::leftClickedObject(
+ ObjectHolder* o, const QPoint& p, KigWidget& w, bool )
+{
+ std::vector<ObjectHolder*>::iterator it = std::find( mparents.begin(), mparents.end(), o );
+ std::vector<ObjectCalcer*> nargs = getCalcers( mparents );
+//
+// mp: duplicationchecked controls whether the arguments list is
+// free of duplications or if a duplication is safe (asking this to
+// the Constructor class through the "isAlreadySelectedOK" method).
+//
+ bool duplicationchecked =
+ ( it == mparents.end() ) ||
+ isAlreadySelectedOK( nargs, it - mparents.begin() );
+ if ( o && duplicationchecked )
+ {
+ nargs.push_back( o->calcer() );
+ if ( wantArgs( nargs, mdoc.document(), w ) )
+ {
+ selectObject( o, w );
+ return;
+ }
+ }
+
+ nargs = getCalcers( mparents );
+ nargs.push_back( mpt.get() );
+ if ( wantArgs( nargs, mdoc.document(), w ) )
+ {
+ // add mpt to the document..
+ ObjectHolder* n = new ObjectHolder( mpt.get() );
+ mdoc.addObject( n );
+ selectObject( n, w );
+ // get a new mpt for our further use..
+ mpt = ObjectFactory::instance()->sensiblePointCalcer( w.fromScreen( p ), mdoc.document(), w );
+ mpt->calc( mdoc.document() );
+ return;
+ }
+
+ nargs = getCalcers( mparents );
+ nargs.push_back( mcursor );
+
+ if ( wantArgs( nargs, mdoc.document(), w ) )
+ {
+ // DON'T add mpt to the document..
+ // the objectholder has been constructed once and for all
+ // when entering construction mode, and delete in the
+ // destructor.
+ ObjectHolder* n = new ObjectHolder( mcursor );
+ selectObject( n, w );
+ mcursor = ObjectFactory::instance()->cursorPointCalcer( w.fromScreen( p ) );
+// mcursor = ObjectFactory::instance()->sensiblePointCalcer( w.fromScreen( p ), mdoc.document(), w );
+ mcursor->calc( mdoc.document() );
+ delete n;
+ }
+}
+
+void BaseConstructMode::midClicked( const QPoint& p, KigWidget& w )
+{
+ std::vector<ObjectCalcer*> args = getCalcers( mparents );
+ args.push_back( mpt.get() );
+ if ( wantArgs( args, mdoc.document(), w ) )
+ {
+ ObjectHolder* n = new ObjectHolder( mpt.get() );
+ mdoc.addObject( n );
+
+ selectObject( n, w );
+
+ mpt = ObjectFactory::instance()->sensiblePointCalcer( w.fromScreen( p ), mdoc.document(), w );
+ mpt->calc( mdoc.document() );
+ }
+}
+
+void BaseConstructMode::rightClicked( const std::vector<ObjectHolder*>&, const QPoint&, KigWidget& )
+{
+ // TODO ?
+}
+
+void BaseConstructMode::mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p,
+ KigWidget& w, bool shiftpressed )
+{
+ mdoc.emitStatusBarText( selectStatement( getCalcers( mparents ), w ) );
+
+ w.updateCurPix();
+ KigPainter pter( w.screenInfo(), &w.curPix, mdoc.document() );
+
+ Coordinate ncoord = w.fromScreen( p );
+ if ( shiftpressed )
+ ncoord = mdoc.document().coordinateSystem().snapToGrid( ncoord, w );
+
+ redefinePoint( mpt.get(), ncoord, mdoc.document(), w );
+ mcursor->move( ncoord, mdoc.document() );
+ mcursor->calc( mdoc.document() );
+
+ std::vector<ObjectCalcer*> args = getCalcers( mparents );
+ bool duplicationchecked = false;
+ std::vector<ObjectHolder*> goodargs;
+ if ( ! os.empty() )
+ {
+ std::vector<ObjectHolder*>::const_iterator it;
+ std::vector<ObjectCalcer*> testargs = getCalcers( mparents );
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i )
+ {
+ it = std::find( mparents.begin(), mparents.end(), *i );
+ bool newdup =
+ ( it == mparents.end() ) ||
+ isAlreadySelectedOK( args, it - mparents.begin() );
+ if ( newdup )
+ {
+ testargs.push_back( ( *i )->calcer() );
+ if ( wantArgs( testargs, mdoc.document(), w ) )
+ goodargs.push_back( *i );
+ testargs.pop_back();
+ }
+ duplicationchecked |= newdup;
+ }
+ }
+ bool calcnow = ( goodargs.size() == 1 ) || ( ( goodargs.size() > 0 ) && ( goodargs.front()->imp()->inherits( PointImp::stype() ) ) );
+ if ( calcnow )
+ {
+ args.push_back( goodargs.front()->calcer() );
+ }
+
+ if ( !os.empty() && duplicationchecked && calcnow )
+ {
+ handlePrelim( args, p, pter, w );
+
+ w.setCursor( KCursor::handCursor() );
+ }
+ else
+ {
+ std::vector<ObjectCalcer*> args = getCalcers( mparents );
+ args.push_back( mpt.get() );
+ std::vector<ObjectCalcer*> argscursor = getCalcers( mparents );
+ argscursor.push_back( mcursor );
+ bool text = true;
+ if ( wantArgs( args, mdoc.document(), w ) )
+ {
+ ObjectDrawer d;
+ d.draw( *mpt->imp(), pter, true );
+
+ handlePrelim( args, p, pter, w );
+
+ w.setCursor( KCursor::handCursor() );
+ }
+ else if ( wantArgs( argscursor, mdoc.document(), w ) )
+ {
+ ObjectDrawer d;
+// d.draw( *mcursor->imp(), pter, true );
+
+ handlePrelim( argscursor, p, pter, w );
+
+ w.setCursor( KCursor::crossCursor() );
+ }
+ else
+ {
+ w.setCursor( KCursor::arrowCursor() );
+ text = false;
+ }
+ if ( !text && ( goodargs.size() > 1 ) )
+ {
+ QString strwhich = i18n( "Which object?" );
+ mdoc.emitStatusBarText( strwhich );
+
+ QPoint textloc = p;
+ textloc.setX( textloc.x() + 15 );
+ pter.drawTextStd( textloc, strwhich );
+
+ w.setCursor( KCursor::handCursor() );
+ }
+ }
+ w.updateWidget( pter.overlay() );
+}
+
+void BaseConstructMode::selectObject( ObjectHolder* o, KigWidget& w )
+{
+ mparents.push_back( o );
+ std::vector<ObjectCalcer*> args = getCalcers( mparents );
+
+ if ( wantArgs( args, mdoc.document(), w ) == ArgsParser::Complete )
+ {
+ handleArgs( args, w );
+ };
+
+ w.redrawScreen( mparents );
+}
+
+PointConstructMode::PointConstructMode( KigPart& d )
+ : BaseMode( d )
+{
+ // we add the data objects to the document cause
+ // ObjectFactory::redefinePoint does that too, and this way, we can
+ // depend on them already being known by the doc when we add the
+ // mpt..
+ mpt = ObjectFactory::instance()->fixedPointCalcer( Coordinate() );
+ mpt->calc( d.document() );
+
+ mdoc.emitStatusBarText( i18n( "Click the location where you want to place the new point, or the curve that you want to attach it to..." ) );
+}
+
+PointConstructMode::~PointConstructMode()
+{
+}
+
+void PointConstructMode::leftClickedObject(
+ ObjectHolder*, const QPoint&, KigWidget& w, bool )
+{
+ mdoc.addObject( new ObjectHolder( mpt.get() ) );
+ w.redrawScreen( std::vector<ObjectHolder*>() );
+
+ mdoc.emitStatusBarText( QString::null );
+ mdoc.doneMode( this );
+}
+
+void PointConstructMode::midClicked( const QPoint& p, KigWidget& w )
+{
+ leftClickedObject( 0, p, w, true );
+}
+
+void PointConstructMode::rightClicked( const std::vector<ObjectHolder*>&, const QPoint&,
+ KigWidget& )
+{
+ // TODO ?
+}
+
+void PointConstructMode::mouseMoved(
+ const std::vector<ObjectHolder*>&,
+ const QPoint& p,
+ KigWidget& w,
+ bool shiftpressed )
+{
+ w.updateCurPix();
+ KigPainter pter( w.screenInfo(), &w.curPix, mdoc.document() );
+
+ Coordinate ncoord = w.fromScreen( p );
+ if ( shiftpressed )
+ ncoord = mdoc.document().coordinateSystem().snapToGrid( ncoord, w );
+
+ redefinePoint( mpt.get(), ncoord, mdoc.document(), w );
+
+ ObjectDrawer d;
+ d.draw( *mpt->imp(), pter, true );
+ w.setCursor( KCursor::blankCursor() );
+
+ w.updateWidget( pter.overlay() );
+}
+
+void BaseConstructMode::enableActions()
+{
+ BaseMode::enableActions();
+
+ mdoc.aCancelConstruction->setEnabled( true );
+}
+
+void BaseConstructMode::cancelConstruction()
+{
+ finish();
+}
+
+void PointConstructMode::enableActions()
+{
+ BaseMode::enableActions();
+
+ mdoc.aCancelConstruction->setEnabled( true );
+}
+
+void PointConstructMode::cancelConstruction()
+{
+ mdoc.doneMode( this );
+}
+
+void BaseConstructMode::selectObjects( const std::vector<ObjectHolder*>& os, KigWidget& w )
+{
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i )
+ {
+ std::vector<ObjectCalcer*> args = getCalcers( mparents );
+ assert( wantArgs( args, mdoc.document(), w ) != ArgsParser::Complete );
+ selectObject( *i, w );
+ };
+}
+
+void ConstructMode::handlePrelim( const std::vector<ObjectCalcer*>& args, const QPoint& p, KigPainter& pter, KigWidget& w )
+{
+ // set the text next to the arrow cursor like in modes/normal.cc
+ QPoint textloc = p;
+ textloc.setX( textloc.x() + 15 );
+
+ mctor->handlePrelim( pter, args, mdoc.document(), w );
+
+ QString o = mctor->useText( *args.back(), args, mdoc.document(), w );
+ pter.drawTextStd( textloc, o );
+}
+
+int ConstructMode::isAlreadySelectedOK( const std::vector<ObjectCalcer*>& os,
+ const int& pos )
+{
+ return mctor->isAlreadySelectedOK( os, pos );
+}
+
+int ConstructMode::wantArgs( const std::vector<ObjectCalcer*>& os, KigDocument& d, KigWidget& w )
+{
+ return mctor->wantArgs( os, d, w );
+}
+
+void BaseConstructMode::finish()
+{
+ mdoc.doneMode( this );
+}
+
+ConstructMode::ConstructMode( KigPart& d, const ObjectConstructor* ctor )
+ : BaseConstructMode( d ), mctor( ctor )
+{
+}
+
+ConstructMode::~ConstructMode()
+{
+}
+
+// does a test result have a frame by default ?
+static const bool test_has_frame_dflt = true;
+
+void TestConstructMode::handlePrelim( const std::vector<ObjectCalcer*>& os, const QPoint& p, KigPainter& pter, KigWidget& w )
+{
+ Args args;
+ std::transform( os.begin(), os.end(), std::back_inserter( args ),
+ std::mem_fun( &ObjectCalcer::imp ) );
+
+ // usetext
+ QString usetext = i18n( mtype->argsParser().usetext( args.back(), args ).c_str() );
+ QPoint textloc = p;
+ textloc.setX( textloc.x() + 15 );
+ pter.drawTextStd( textloc, usetext );
+
+ // test result
+ ObjectImp* data = mtype->calc( args, mdoc.document() );
+ if ( ! data->valid() ) return;
+ assert( data->inherits( TestResultImp::stype() ) );
+ QString outputtext = static_cast<TestResultImp*>( data )->data();
+ TextImp ti( outputtext, w.fromScreen( p + QPoint( - 40, 30 ) ), test_has_frame_dflt );
+ ti.draw( pter );
+
+ delete data;
+}
+
+TestConstructMode::TestConstructMode( KigPart& d, const ArgsParserObjectType* type )
+ : BaseConstructMode( d ), mtype( type )
+{
+}
+
+TestConstructMode::~TestConstructMode()
+{
+}
+
+void ConstructMode::handleArgs( const std::vector<ObjectCalcer*>& args, KigWidget& w )
+{
+ mctor->handleArgs( args, mdoc, w );
+ finish();
+}
+
+int TestConstructMode::isAlreadySelectedOK( const std::vector<ObjectCalcer*>&,
+ const int& )
+{
+ return false;
+}
+
+int TestConstructMode::wantArgs( const std::vector<ObjectCalcer*>& os, KigDocument&, KigWidget& )
+{
+ return mtype->argsParser().check( os );
+}
+
+void TestConstructMode::handleArgs( const std::vector<ObjectCalcer*>& args, KigWidget& )
+{
+ mresult = new ObjectTypeCalcer( mtype, args );
+ mresult->calc( mdoc.document() );
+ mdoc.emitStatusBarText( i18n( "Now select the location for the result label." ) );
+}
+
+void TestConstructMode::leftClickedObject( ObjectHolder* o, const QPoint& p,
+ KigWidget& w, bool ctrlOrShiftDown )
+{
+ if ( mresult ) {
+ QPoint qloc = p + QPoint( -40, 0 );
+ Coordinate loc = w.fromScreen( qloc );
+
+ std::vector<ObjectCalcer*> parents;
+ parents.push_back( new ObjectConstCalcer( new IntImp( test_has_frame_dflt ) ) );
+ parents.push_back( new ObjectConstCalcer( new PointImp( loc ) ) );
+ parents.push_back( new ObjectConstCalcer( new StringImp( QString::fromLatin1( "%1" ) ) ) );
+ assert( mresult->imp()->inherits( TestResultImp::stype() ) );
+ parents.push_back(
+ new ObjectPropertyCalcer(
+ mresult.get(), mresult->imp()->propertiesInternalNames().findIndex( "test-result" ) ) );
+ parents.back()->calc( mdoc.document() );
+
+ ObjectCalcer* ret = new ObjectTypeCalcer( TextType::instance(), parents );
+ ret->calc( mdoc.document() );
+ mdoc.addObject( new ObjectHolder( ret ) );
+
+ w.unsetCursor();
+ mdoc.emitStatusBarText( QString::null );
+
+ finish();
+ }
+ else
+ BaseConstructMode::leftClickedObject( o, p, w, ctrlOrShiftDown );
+}
+
+void TestConstructMode::midClicked( const QPoint& p, KigWidget& w )
+{
+ if ( mresult ) {
+ // nothing to be done here, really
+ }
+ else
+ BaseConstructMode::midClicked( p, w );
+}
+
+void TestConstructMode::rightClicked( const std::vector<ObjectHolder*>& oco, const QPoint& p, KigWidget& w )
+{
+ if ( mresult ) {
+ // nothing to be done here, really
+ }
+ else
+ BaseConstructMode::rightClicked( oco, p, w );
+}
+
+void TestConstructMode::mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w, bool shiftPressed )
+{
+ if ( mresult ) {
+ w.setCursor( KCursor::blankCursor() );
+
+ w.updateCurPix();
+ KigPainter pter( w.screenInfo(), &w.curPix, mdoc.document() );
+
+ QPoint qloc = p + QPoint( -40, 0 );
+ Coordinate loc = w.fromScreen( qloc );
+ assert( dynamic_cast<const TestResultImp*>( mresult->imp() ) );
+ TextImp ti( static_cast<const TestResultImp*>( mresult->imp() )->data(), loc, test_has_frame_dflt );
+ ObjectDrawer d;
+ d.draw( ti, pter, false );
+
+
+ w.updateWidget( pter.overlay() );
+ }
+ else
+ BaseConstructMode::mouseMoved( os, p, w, shiftPressed );
+}
+
+QString ConstructMode::selectStatement( const std::vector<ObjectCalcer*>& args, const KigWidget& w )
+{
+ return mctor->selectStatement( args, mdoc.document(), w );
+}
+
+QString TestConstructMode::selectStatement( const std::vector<ObjectCalcer*>& sel, const KigWidget& )
+{
+ using namespace std;
+ Args args;
+ transform( sel.begin(), sel.end(), back_inserter( args ), mem_fun( &ObjectCalcer::imp ) );
+
+ std::string ret = mtype->argsParser().selectStatement( args );
+ if ( ret.empty() ) return QString::null;
+ return i18n( ret.c_str() );
+}
+
+void PointConstructMode::redrawScreen( KigWidget* w )
+{
+ w->redrawScreen( std::vector<ObjectHolder*>() );
+}
+
+void BaseConstructMode::redrawScreen( KigWidget* w )
+{
+ w->redrawScreen( std::vector<ObjectHolder*>() );
+}
diff --git a/kig/modes/construct_mode.h b/kig/modes/construct_mode.h
new file mode 100644
index 00000000..fa1be86e
--- /dev/null
+++ b/kig/modes/construct_mode.h
@@ -0,0 +1,154 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MODES_CONSTRUCT_MODE_H
+#define KIG_MODES_CONSTRUCT_MODE_H
+
+#include "base_mode.h"
+
+#include "../objects/object_calcer.h"
+
+class ArgsParserObjectType;
+class ObjectConstructor;
+class ObjectCalcer;
+
+class PointConstructMode
+ : public BaseMode
+{
+ /**
+ * this is the point that we move around, for the user to add
+ * somewhere..
+ */
+ ObjectTypeCalcer::shared_ptr mpt;
+public:
+ PointConstructMode( KigPart& d );
+ ~PointConstructMode();
+protected:
+ void leftClickedObject( ObjectHolder* o, const QPoint& p,
+ KigWidget& w, bool ctrlOrShiftDown );
+ void midClicked( const QPoint& p, KigWidget& w );
+ void rightClicked( const std::vector<ObjectHolder*>& oco, const QPoint& p, KigWidget& w );
+ void mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w, bool shiftpressed );
+
+ void enableActions();
+ void cancelConstruction();
+
+ void redrawScreen( KigWidget* );
+};
+
+class BaseConstructMode
+ : public BaseMode
+{
+ /**
+ * this is the point that we move around, in case the user wants to
+ * add a point somewhere..
+ */
+ ObjectTypeCalcer::shared_ptr mpt;
+ /**
+ * mp: this point always follows the cursor
+ *
+ * IMPORTANT: this Calcer must NEVER be added to the document, since
+ * its is used in constructors that need more input from the user
+ * to decide parameters of the constructed object that will be fixed
+ * afterwards (like the number of sides of a regular polygon)
+ */
+ ObjectTypeCalcer* mcursor;
+ // we also allocate here the corresponding objectholder, since the
+ // only sensible place where to deallocate it is in the destructor
+ // of this class
+// ObjectHolder* mcursorholder;
+ std::vector<ObjectHolder*> mparents;
+
+ void leftReleased( QMouseEvent* e, KigWidget* v );
+
+public:
+ void selectObject( ObjectHolder* o, KigWidget& w );
+ void selectObjects( const std::vector<ObjectHolder*>& os, KigWidget& w );
+ virtual ~BaseConstructMode();
+protected:
+ BaseConstructMode( KigPart& d );
+protected:
+ void leftClickedObject( ObjectHolder* o, const QPoint& p,
+ KigWidget& w, bool ctrlOrShiftDown );
+ void midClicked( const QPoint& p, KigWidget& w );
+ void rightClicked( const std::vector<ObjectHolder*>& oco, const QPoint& p, KigWidget& w );
+ void mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w, bool shiftpressed );
+
+ void enableActions();
+ void cancelConstruction();
+ void finish();
+
+protected:
+ virtual void handlePrelim( const std::vector<ObjectCalcer*>& os, const QPoint& p, KigPainter&, KigWidget& w ) = 0;
+ virtual QString selectStatement( const std::vector<ObjectCalcer*>& args, const KigWidget& w ) = 0;
+ virtual int isAlreadySelectedOK( const std::vector<ObjectCalcer*>&, const int& ) = 0;
+ virtual int wantArgs( const std::vector<ObjectCalcer*>&, KigDocument& d, KigWidget& w ) = 0;
+ virtual void handleArgs( const std::vector<ObjectCalcer*>& args, KigWidget& w ) = 0;
+
+ void redrawScreen( KigWidget* );
+};
+
+class ConstructMode
+ : public BaseConstructMode
+{
+ const ObjectConstructor* mctor;
+public:
+ ConstructMode( KigPart& d, const ObjectConstructor* ctor );
+ ~ConstructMode();
+
+ void handlePrelim( const std::vector<ObjectCalcer*>& os, const QPoint& p, KigPainter&, KigWidget& w );
+ QString selectStatement( const std::vector<ObjectCalcer*>& args, const KigWidget& w );
+ int isAlreadySelectedOK( const std::vector<ObjectCalcer*>&, const int& );
+ int wantArgs( const std::vector<ObjectCalcer*>&, KigDocument& d, KigWidget& w );
+ void handleArgs( const std::vector<ObjectCalcer*>& args, KigWidget& w );
+};
+
+/**
+ * This class constructs a test object. It has special needs over
+ * ConstructMode because first the arguments need to be chosen, and
+ * then the location for the resulting TextImp needs to be chosen. It
+ * also needs special code for the drawPrelim and wantArgs code.
+ *
+ * Therefore, we inherit from BaseConstructMode, and override the
+ * event callbacks, so that this mode behaves like a
+ * BaseConstructMode, until handleArgs is called. After that, mresult
+ * is no longer 0, and then the mode behaves in its own way, allowing
+ * the user to choose a location for the new label object.
+ */
+class TestConstructMode
+ : public BaseConstructMode
+{
+ const ArgsParserObjectType* mtype;
+ ObjectCalcer::shared_ptr mresult;
+public:
+ TestConstructMode( KigPart& d, const ArgsParserObjectType* type );
+ ~TestConstructMode();
+
+ void handlePrelim( const std::vector<ObjectCalcer*>& os, const QPoint& p, KigPainter&, KigWidget& w );
+ QString selectStatement( const std::vector<ObjectCalcer*>& args, const KigWidget& w );
+ int isAlreadySelectedOK( const std::vector<ObjectCalcer*>&, const int& );
+ int wantArgs( const std::vector<ObjectCalcer*>&, KigDocument& d, KigWidget& w );
+ void handleArgs( const std::vector<ObjectCalcer*>& args, KigWidget& w );
+
+ void leftClickedObject( ObjectHolder* o, const QPoint& p,
+ KigWidget& w, bool ctrlOrShiftDown );
+ void midClicked( const QPoint& p, KigWidget& w );
+ void rightClicked( const std::vector<ObjectHolder*>& oco, const QPoint& p, KigWidget& w );
+ void mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w, bool shiftpressed );
+};
+
+#endif
diff --git a/kig/modes/dragrectmode.cc b/kig/modes/dragrectmode.cc
new file mode 100644
index 00000000..a3c8c033
--- /dev/null
+++ b/kig/modes/dragrectmode.cc
@@ -0,0 +1,180 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "dragrectmode.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../misc/kigpainter.h"
+
+#include <qevent.h>
+#include <qglobal.h>
+#include <kaction.h>
+
+DragRectMode::DragRectMode( const QPoint& start, KigPart& d, KigWidget& w )
+ : KigMode( d ), mstart( start ), mnc( true ), mstartselected( true ),
+ mcancelled( false )
+{
+ moved( start, w );
+}
+
+DragRectMode::DragRectMode( KigPart& d, KigWidget& w )
+ : KigMode( d ), mnc( true ), mstartselected( false ),
+ mcancelled( false )
+{
+ w.updateCurPix();
+ w.updateWidget();
+}
+
+void DragRectMode::moved( const QPoint& p, KigWidget& w )
+{
+ // update the rect...
+ w.updateCurPix();
+ std::vector<QRect> overlay;
+ if ( mstartselected )
+ {
+ KigPainter pt( w.screenInfo(), &w.curPix, mdoc.document() );
+ pt.drawFilledRect( QRect( p, mstart ) );
+ overlay = pt.overlay();
+ };
+ w.updateWidget( overlay );
+}
+
+void DragRectMode::released( const QPoint& p, KigWidget& w, bool nc )
+{
+ if ( mstartselected )
+ {
+ mrect = w.fromScreen( QRect( mstart, p ) );
+ mret = mdoc.document().whatIsInHere( mrect, w );
+ mnc = nc;
+
+ mdoc.doneMode( this );
+ };
+}
+
+void DragRectMode::enableActions()
+{
+ KigMode::enableActions();
+
+ mdoc.aCancelConstruction->setEnabled( true );
+}
+
+std::vector<ObjectHolder*> DragRectMode::ret() const
+{
+ return mret;
+}
+
+bool DragRectMode::needClear() const
+{
+ return mnc;
+}
+
+void DragRectMode::moved( QMouseEvent* e, KigWidget& w )
+{
+ moved( e->pos(), w );
+}
+
+void DragRectMode::released( QMouseEvent* e, KigWidget& w )
+{
+ released( e->pos(), w, ! ( e->state() & ( ControlButton | ShiftButton ) ) );
+}
+
+DragRectMode::~DragRectMode()
+{
+}
+
+void DragRectMode::mouseMoved( QMouseEvent* e, KigWidget* w )
+{
+ moved( e, *w );
+}
+
+void DragRectMode::leftMouseMoved( QMouseEvent* e, KigWidget* w )
+{
+ moved( e, *w );
+}
+
+void DragRectMode::midMouseMoved( QMouseEvent* e, KigWidget* w )
+{
+ moved( e, *w );
+}
+
+void DragRectMode::rightMouseMoved( QMouseEvent* e, KigWidget* w )
+{
+ moved( e, *w );
+}
+
+void DragRectMode::leftReleased( QMouseEvent* e, KigWidget* w )
+{
+ released( e, *w );
+}
+
+void DragRectMode::midReleased( QMouseEvent* e, KigWidget* w )
+{
+ released( e, *w );
+}
+
+void DragRectMode::rightReleased( QMouseEvent* e, KigWidget* w )
+{
+ released( e, *w );
+}
+
+Rect DragRectMode::rect() const
+{
+ return mrect;
+}
+
+void DragRectMode::clicked( const QMouseEvent* e, KigWidget& w )
+{
+ clicked( e->pos(), w );
+}
+
+void DragRectMode::leftClicked( QMouseEvent* e, KigWidget* w )
+{
+ clicked( e, *w );
+}
+
+void DragRectMode::midClicked( QMouseEvent* e, KigWidget* w )
+{
+ clicked( e, *w );
+}
+
+void DragRectMode::rightClicked( QMouseEvent* e, KigWidget* w )
+{
+ clicked( e, *w );
+}
+
+void DragRectMode::clicked( const QPoint& p, KigWidget& )
+{
+ if ( !mstartselected )
+ {
+ mstartselected = true;
+ mstart = p;
+ };
+}
+
+bool DragRectMode::cancelled() const
+{
+ return mcancelled;
+}
+
+void DragRectMode::cancelConstruction()
+{
+ mcancelled = true;
+ mdoc.doneMode( this );
+}
+
diff --git a/kig/modes/dragrectmode.h b/kig/modes/dragrectmode.h
new file mode 100644
index 00000000..29f92139
--- /dev/null
+++ b/kig/modes/dragrectmode.h
@@ -0,0 +1,104 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+
+#ifndef KIG_MODES_DRAGRECTMODE_H
+#define KIG_MODES_DRAGRECTMODE_H
+
+#include "mode.h"
+
+#include "../misc/rect.h"
+
+#include <qpoint.h>
+#include <vector>
+
+class ObjectHolder;
+
+/**
+ * DragRectMode is a mode that provides a rect for selecting the
+ * objects inside it. Here's an example of how to use it
+ * \code
+ * DragRectMode d( e->pos(), document, widget );
+ * mDoc.runMode( &d );
+ * Objects sel = d.ret();
+ * \endcode
+ */
+class DragRectMode
+ : public KigMode
+{
+ QPoint mstart;
+ std::vector<ObjectHolder*> mret;
+ Rect mrect;
+ bool mnc;
+ bool mstartselected;
+ bool mcancelled;
+private:
+ void clicked( const QPoint& p, KigWidget& w );
+ void clicked( const QMouseEvent* e, KigWidget& w );
+ void released( const QPoint& p, KigWidget& w, bool nc );
+ void released( QMouseEvent* e, KigWidget& w );
+ void moved( const QPoint& p, KigWidget& w );
+ void moved( QMouseEvent*, KigWidget& w );
+
+ void leftClicked( QMouseEvent*, KigWidget* );
+ void leftMouseMoved( QMouseEvent*, KigWidget* );
+ void leftReleased( QMouseEvent*, KigWidget* );
+ void midClicked( QMouseEvent*, KigWidget* );
+ void midMouseMoved( QMouseEvent*, KigWidget* );
+ void midReleased( QMouseEvent*, KigWidget* );
+ void rightClicked( QMouseEvent*, KigWidget* );
+ void rightMouseMoved( QMouseEvent*, KigWidget* );
+ void rightReleased( QMouseEvent*, KigWidget* );
+ void mouseMoved( QMouseEvent*, KigWidget* );
+
+ void cancelConstruction();
+
+ void enableActions();
+
+public:
+ DragRectMode( const QPoint& start, KigPart& d, KigWidget& w );
+ DragRectMode( KigPart& d, KigWidget& w );
+ ~DragRectMode();
+
+ /**
+ * this returns the selected objects..
+ */
+ std::vector<ObjectHolder*> ret() const;
+
+ /**
+ * this returns the selected rect..
+ */
+ Rect rect() const;
+
+ /**
+ * this returns false if the control or shift button were pressed
+ * when the mouse button was released, and true otherwise. This is
+ * because the user expects us to not clear the selection before
+ * adding the newly selected objects if (s)he pressed control or
+ * shift..
+ */
+ bool needClear() const;
+
+ /**
+ * whether the user cancelled the rect mode.. If this returns true,
+ * all the other return data above will be in undefined state, so
+ * first check this function's result..
+ */
+ bool cancelled() const;
+};
+
+#endif
diff --git a/kig/modes/edittype.cc b/kig/modes/edittype.cc
new file mode 100644
index 00000000..8c6b538f
--- /dev/null
+++ b/kig/modes/edittype.cc
@@ -0,0 +1,107 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+ Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+
+#include "edittype.h"
+#include "edittype.moc"
+
+#include <kapplication.h>
+#include <kicondialog.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+EditType::EditType( QWidget* parent, QString name, QString desc, QString icon )
+ : EditTypeBase( parent, "edittype", true ), mname( name ), mdesc( desc ), micon( icon )
+{
+ // improving GUI look'n'feel...
+ buttonHelp->setGuiItem( KStdGuiItem::help() );
+ buttonOk->setGuiItem( KStdGuiItem::ok() );
+ buttonCancel->setGuiItem( KStdGuiItem::cancel() );
+
+ editName->setText( mname );
+ editDescription->setText( mdesc );
+ typeIcon->setIcon( !micon.isEmpty() ? micon : "gear" );
+}
+
+EditType::~EditType()
+{
+}
+
+void EditType::helpSlot()
+{
+ kapp->invokeHelp( QString::fromLatin1( "working-with-types" ),
+ QString::fromLatin1( "kig" ) );
+}
+
+void EditType::okSlot()
+{
+ QString tmp = editName->text();
+ if ( tmp.isEmpty() )
+ {
+ KMessageBox::information( this, i18n( "The name of the macro can not be empty." ) );
+ return;
+ }
+
+ bool namechanged = false;
+ bool descchanged = false;
+ bool iconchanged = false;
+ if ( tmp != mname )
+ {
+ mname = tmp;
+ namechanged = true;
+ }
+ tmp = editDescription->text();
+ if ( tmp != mdesc )
+ {
+ mdesc = tmp;
+ descchanged = true;
+ }
+ tmp = typeIcon->icon();
+ if ( tmp != micon )
+ {
+ micon = tmp;
+ iconchanged = true;
+ }
+ done( namechanged || descchanged || iconchanged );
+}
+
+void EditType::cancelSlot()
+{
+ done( 0 );
+}
+
+const QString EditType::name() const
+{
+ return mname;
+}
+
+const QString EditType::description() const
+{
+ return mdesc;
+}
+
+const QString EditType::icon() const
+{
+ return micon;
+}
diff --git a/kig/modes/edittype.h b/kig/modes/edittype.h
new file mode 100644
index 00000000..c6530df5
--- /dev/null
+++ b/kig/modes/edittype.h
@@ -0,0 +1,48 @@
+// This file is part of Kig, a KDE program for Interactive Geometry...
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MODES_EDITTYPE_H
+#define KIG_MODES_EDITTYPE_H
+
+#include "edittypebase.h"
+
+/**
+ * Simply dialog that allow the user the editing of a macro type...
+ */
+class EditType : public EditTypeBase
+{
+ Q_OBJECT
+
+ QString mname;
+ QString mdesc;
+ QString micon;
+public:
+ EditType( QWidget* parent, QString name = QString::null, QString desc = QString::null, QString icon = QString::null );
+ ~EditType();
+ const QString name() const;
+ const QString description() const;
+ const QString icon() const;
+
+public slots:
+ void helpSlot();
+ void okSlot();
+ void cancelSlot();
+};
+
+#endif
diff --git a/kig/modes/edittypebase.ui b/kig/modes/edittypebase.ui
new file mode 100644
index 00000000..0dc8129d
--- /dev/null
+++ b/kig/modes/edittypebase.ui
@@ -0,0 +1,287 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>EditTypeBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>EditTypeBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>481</width>
+ <height>142</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="caption">
+ <string>Edit Type</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>label15</cstring>
+ </property>
+ <property name="text">
+ <string>Here you can modify the name, the description and the icon of this macro type.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>label16</cstring>
+ </property>
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>editName</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Here you can edit the name of the current macro type.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>label17</cstring>
+ </property>
+ <property name="text">
+ <string>Description:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>editDescription</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Here you can edit the description of the current macro type. This field is optional, so you can also leave this empty: if you do so, then your macro type will have no description.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout23</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIconButton">
+ <property name="name">
+ <cstring>typeIcon</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Use this button to change the icon of the current macro type.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout24</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Help</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>buttonHelp</sender>
+ <signal>clicked()</signal>
+ <receiver>EditTypeBase</receiver>
+ <slot>helpSlot()</slot>
+ </connection>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>EditTypeBase</receiver>
+ <slot>okSlot()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>EditTypeBase</receiver>
+ <slot>cancelSlot()</slot>
+ </connection>
+</connections>
+<slots>
+ <slot>helpSlot()</slot>
+ <slot>okSlot()</slot>
+ <slot>cancelSlot()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kicondialog.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kig/modes/label.cc b/kig/modes/label.cc
new file mode 100644
index 00000000..cd726918
--- /dev/null
+++ b/kig/modes/label.cc
@@ -0,0 +1,589 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "label.h"
+#include "normal.h"
+
+#include "textlabelwizard.h"
+#include "linkslabel.h"
+
+#include "../kig/kig_commands.h"
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../misc/common.h"
+#include "../misc/kigpainter.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/curve_imp.h"
+#include "../objects/object_factory.h"
+#include "../objects/point_imp.h"
+#include "../objects/text_imp.h"
+#include "../objects/text_type.h"
+
+#include <kcursor.h>
+#include <kmessagebox.h>
+#include <kaction.h>
+#include <klocale.h>
+#include <qtextedit.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <qregexp.h>
+#include <qpopupmenu.h>
+#include <qcheckbox.h>
+
+#include <algorithm>
+#include <functional>
+
+class TextLabelModeBase::Private
+{
+public:
+ // point last clicked..
+ QPoint plc;
+ // the currently selected coordinate
+ Coordinate mcoord;
+ // the possible parent object that defines the location of the label..
+ ObjectCalcer* locationparent;
+
+ // the text is only kept in the text input widget, not here
+ // QString mtext;
+
+ // the property objects we'll be using as args, we keep a reference
+ // to them in the args object, and keep a pointer to them ( or 0 )
+ // in the correct order in args ( separately, because we can't use
+ // the order of the parents of a ReferenceObject, and certainly
+ // can't give 0 as a parent..
+ argvect args;
+
+ // if we're ReallySelectingArgs, then this var points to the arg
+ // we're currently selecting...
+ int mwaaws;
+
+ // last percent count...
+ uint lpc;
+
+ TextLabelWizard* wiz;
+
+ // What Are We Doing
+ wawdtype mwawd;
+};
+
+TextLabelModeBase::~TextLabelModeBase()
+{
+ delete d->wiz;
+ delete d;
+}
+
+TextLabelModeBase::TextLabelModeBase( KigPart& doc )
+ : KigMode( doc ), d( new Private )
+{
+ d->locationparent = 0;
+ d->lpc = 0;
+ d->mwawd = SelectingLocation;
+ d->wiz = new TextLabelWizard( doc.widget(), this );
+}
+
+void TextLabelModeBase::leftClicked( QMouseEvent* e, KigWidget* )
+{
+ d->plc = e->pos();
+ switch( d->mwawd )
+ {
+ case RequestingText:
+ case SelectingArgs:
+ d->wiz->raise();
+ d->wiz->setActiveWindow();
+ break;
+ default:
+ break;
+ };
+}
+
+void TextLabelModeBase::leftReleased( QMouseEvent* e, KigWidget* v )
+{
+ switch( d->mwawd )
+ {
+ case SelectingLocation:
+ {
+ if ( ( d->plc - e->pos() ).manhattanLength() > 4 ) return;
+ setCoordinate( v->fromScreen( d->plc ) );
+ break;
+ }
+ case RequestingText:
+ case SelectingArgs:
+ d->wiz->raise();
+ d->wiz->setActiveWindow();
+ break;
+ case ReallySelectingArgs:
+ {
+ if ( ( d->plc - e->pos() ).manhattanLength() > 4 ) break;
+ std::vector<ObjectHolder*> os = mdoc.document().whatAmIOn( v->fromScreen( d->plc ), *v );
+ if ( os.empty() ) break;
+ ObjectHolder* o = os[0];
+ QPopupMenu* p = new QPopupMenu( v, "text_label_select_arg_popup" );
+ p->insertItem( i18n( "Name" ), 0 );
+ QCStringList l = o->imp()->properties();
+ assert( l.size() == o->imp()->numberOfProperties() );
+ for ( int i = 0; static_cast<uint>( i ) < l.size(); ++i )
+ {
+ QString s = i18n( l[i] );
+ const char* iconfile = o->imp()->iconForProperty( i );
+ int t;
+ if ( iconfile && *iconfile )
+ {
+ QPixmap pix = mdoc.instance()->iconLoader()->loadIcon( iconfile, KIcon::User );
+ t = p->insertItem( QIconSet( pix ), s, i + 1 );
+ }
+ else
+ {
+ t = p->insertItem( s, i + 1 );
+ };
+ assert( t == i + 1 );
+ };
+ int result = p->exec( v->mapToGlobal( d->plc ) );
+ ObjectCalcer::shared_ptr argcalcer;
+ if ( result == -1 ) break;
+ else if ( result == 0 )
+ {
+ argcalcer = o->nameCalcer();
+ if ( !argcalcer )
+ {
+ ObjectConstCalcer* c = new ObjectConstCalcer( new StringImp( i18n( "<unnamed object>" ) ) );
+ o->setNameCalcer( c );
+ argcalcer = c;
+ }
+ }
+ else
+ {
+ assert( static_cast<uint>( result ) < l.size() + 1 );
+ argcalcer = new ObjectPropertyCalcer( o->calcer(), result - 1 );
+ }
+ d->args[d->mwaaws] = argcalcer.get();
+ argcalcer->calc( mdoc.document() );
+
+ updateLinksLabel();
+ updateWiz();
+ break;
+ }
+ default:
+ assert( false );
+ break;
+ };
+}
+
+void TextLabelModeBase::killMode()
+{
+ mdoc.doneMode( this );
+}
+
+void TextLabelModeBase::cancelConstruction()
+{
+ killMode();
+}
+
+void TextLabelModeBase::enableActions()
+{
+ KigMode::enableActions();
+
+ mdoc.aCancelConstruction->setEnabled( true );
+}
+
+void TextLabelModeBase::mouseMoved( QMouseEvent* e, KigWidget* w )
+{
+ if ( d->mwawd == ReallySelectingArgs )
+ {
+ std::vector<ObjectHolder*> os = mdoc.document().whatAmIOn( w->fromScreen( e->pos() ), *w );
+ if ( !os.empty() ) w->setCursor( KCursor::handCursor() );
+ else w->setCursor( KCursor::arrowCursor() );
+ }
+ else if ( d->mwawd == SelectingLocation )
+ {
+ std::vector<ObjectHolder*> os = mdoc.document().whatAmIOn( w->fromScreen( e->pos() ), *w );
+ bool attachable = false;
+ d->locationparent = 0;
+ for ( std::vector<ObjectHolder*>::iterator i = os.begin(); i != os.end(); ++i )
+ {
+ if( (*i)->imp()->attachPoint().valid() ||
+ (*i)->imp()->inherits( PointImp::stype() ) ||
+ (*i)->imp()->inherits( CurveImp::stype() ) )
+ {
+ attachable = true;
+ d->locationparent = (*i)->calcer();
+ break;
+ };
+ };
+ w->updateCurPix();
+ if ( attachable )
+ {
+ w->setCursor( KCursor::handCursor() );
+ QString s = d->locationparent->imp()->type()->attachToThisStatement();
+ mdoc.emitStatusBarText( s );
+
+ KigPainter p( w->screenInfo(), &w->curPix, mdoc.document() );
+
+ // set the text next to the arrow cursor
+ QPoint point = e->pos();
+ point.setX(point.x()+15);
+
+ p.drawTextStd( point, s );
+ w->updateWidget( p.overlay() );
+ }
+ else
+ {
+ w->setCursor( KCursor::crossCursor() );
+ mdoc.emitStatusBarText( 0 );
+ w->updateWidget();
+ };
+ }
+}
+
+void TextLabelModeBase::enterTextPageEntered()
+{
+}
+
+void TextLabelModeBase::selectArgumentsPageEntered()
+{
+ updateLinksLabel();
+}
+
+void TextLabelModeBase::cancelPressed()
+{
+ cancelConstruction();
+}
+
+static uint percentCount( const QString& s )
+{
+// QRegExp re( QString::fromUtf8( "%[0-9]" ) );
+ QRegExp re( QString::fromUtf8( "%[\\d]+" ) );
+ int offset = 0;
+ uint percentcount = 0;
+ while ( ( offset = re.search( s, offset ) ) != -1 )
+ {
+ ++percentcount;
+ offset += re.matchedLength();
+ };
+ return percentcount;
+}
+
+void TextLabelModeBase::finishPressed()
+{
+ bool needframe = d->wiz->needFrameCheckBox->isChecked();
+ QString s = d->wiz->labelTextInput->text();
+
+ assert( percentCount( s ) == d->args.size() );
+ if ( d->wiz->currentPage() == d->wiz->enter_text_page )
+ assert( d->args.size() == 0 );
+
+ bool finished = true;
+ for ( argvect::iterator i = d->args.begin(); i != d->args.end(); ++i )
+ finished &= ( *i != 0 );
+
+ if ( ! finished )
+ KMessageBox::sorry( mdoc.widget(),
+ i18n( "There are '%n' parts in the text that you have not selected a "
+ "value for. Please remove them or select enough arguments." ) );
+ else
+ {
+ finish( d->mcoord, s, d->args, needframe, d->locationparent );
+ killMode();
+ };
+}
+
+void TextLabelModeBase::updateWiz()
+{
+ QString s = d->wiz->labelTextInput->text();
+ uint percentcount = percentCount( s );
+ if ( d->lpc > percentcount )
+ {
+ d->args = argvect( d->args.begin(), d->args.begin() + percentcount );
+ }
+ else if ( d->lpc < percentcount )
+ {
+ d->args.resize( percentcount, 0 );
+ };
+
+ if ( percentcount == 0 && ! s.isEmpty() )
+ {
+ d->wiz->setNextEnabled( d->wiz->enter_text_page, false );
+ d->wiz->setFinishEnabled( d->wiz->enter_text_page, true );
+ d->wiz->setAppropriate( d->wiz->select_arguments_page, false );
+ }
+ else
+ {
+ d->wiz->setAppropriate( d->wiz->select_arguments_page, !s.isEmpty() );
+ d->wiz->setNextEnabled( d->wiz->enter_text_page, ! s.isEmpty() );
+ d->wiz->setFinishEnabled( d->wiz->enter_text_page, false );
+ bool finished = true;
+ for ( argvect::iterator i = d->args.begin(); i != d->args.end(); ++i )
+ finished &= ( *i != 0 );
+ assert( percentCount( s ) == d->args.size() );
+
+ d->wiz->setFinishEnabled( d->wiz->select_arguments_page, finished );
+ };
+
+ d->lpc = percentcount;
+}
+
+void TextLabelModeBase::labelTextChanged()
+{
+ updateWiz();
+}
+
+void TextLabelModeBase::updateLinksLabel()
+{
+ LinksLabel::LinksLabelEditBuf buf = d->wiz->myCustomWidget1->startEdit();
+ QString s = d->wiz->labelTextInput->text();
+// QRegExp re( "%[0-9]" );
+ QRegExp re( "%[\\d]+" );
+ int prevpos = 0;
+ int pos = 0;
+ uint count = 0;
+ // we split up the string into text and "links"
+ while ( ( pos = re.search( s, pos ) ) != -1 )
+ {
+ // prevpos is the first character after the last match, pos is the
+ // first char of the current match..
+ if ( prevpos != pos )
+ {
+ // there is a text part between the previous and the current
+ // "link"...
+ assert( prevpos < pos );
+ // fetch the text part...
+ QString subs = s.mid( prevpos, pos - prevpos );
+ // and add it...
+ d->wiz->myCustomWidget1->addText( subs, buf );
+ };
+ // we always need a link part...
+ QString linktext( "%1" );
+ assert( count < d->args.size() );
+ if ( d->args[count] )
+ {
+ // if the user has already selected a property, then we show its
+ // value...
+ d->args[count]->imp()->fillInNextEscape( linktext, mdoc.document() );
+ }
+ else
+ // otherwise, we show a stub...
+ linktext = i18n( "argument %1" ).arg( count + 1 );
+
+ d->wiz->myCustomWidget1->addLink( linktext, buf );
+ // set pos and prevpos to the next char after the last match, so
+ // we don't enter infinite loops...
+// pos += 2;
+ pos += re.matchedLength();
+ prevpos = pos;
+ ++count;
+ };
+
+ if ( static_cast<uint>( prevpos ) != s.length() )
+ d->wiz->myCustomWidget1->addText( s.mid( prevpos ), buf );
+
+ d->wiz->myCustomWidget1->applyEdit( buf );
+ d->wiz->relayoutArgsPage();
+
+ d->wiz->resize( d->wiz->size() );
+}
+
+void TextLabelModeBase::linkClicked( int i )
+{
+ mdoc.widget()->setActiveWindow();
+ mdoc.widget()->raise();
+
+ assert( d->args.size() >= static_cast<uint>( i + 1 ) );
+
+ d->mwawd = ReallySelectingArgs;
+ d->mwaaws = i;
+
+ mdoc.emitStatusBarText( i18n( "Selecting argument %1" ).arg( i + 1 ) );
+}
+
+void TextLabelModeBase::redrawScreen( KigWidget* w )
+{
+ w->redrawScreen( std::vector<ObjectHolder*>() );
+ w->updateScrollBars();
+}
+
+void TextLabelModeBase::setCoordinate( const Coordinate& coord )
+{
+ d->mcoord = coord;
+ if ( d->mwawd == SelectingLocation )
+ {
+ d->mwawd = RequestingText;
+ updateWiz();
+ d->wiz->show();
+ // shouldn't be necessary, but seems to be anyway.. :(
+ updateWiz();
+ };
+}
+
+void TextLabelModeBase::setText( const QString& s )
+{
+ d->wiz->labelTextInput->setText( s );
+}
+
+void TextLabelModeBase::setPropertyObjects( const argvect& props )
+{
+ d->args = props;
+ for ( argvect::iterator i = d->args.begin(); i != d->args.end(); ++i )
+ (*i)->calc( mdoc.document() );
+}
+
+TextLabelConstructionMode::TextLabelConstructionMode( KigPart& d )
+ : TextLabelModeBase( d )
+{
+}
+
+TextLabelConstructionMode::~TextLabelConstructionMode()
+{
+}
+
+void TextLabelConstructionMode::finish(
+ const Coordinate& coord, const QString& s,
+ const argvect& props, bool needframe,
+ ObjectCalcer* locationparent )
+{
+ std::vector<ObjectCalcer*> args;
+ for ( argvect::const_iterator i = props.begin();
+ i != props.end(); ++i )
+ args.push_back( i->get() );
+
+ ObjectHolder* label = 0;
+ if ( locationparent )
+ label = ObjectFactory::instance()->attachedLabel( s, locationparent, coord, needframe, args, mdoc.document() );
+ else
+ label = ObjectFactory::instance()->label( s, coord, needframe, args, mdoc.document() );
+ mdoc.addObject( label );
+}
+
+TextLabelRedefineMode::TextLabelRedefineMode( KigPart& d, ObjectTypeCalcer* label )
+ : TextLabelModeBase( d ), mlabel( label )
+{
+ assert( label->imp()->inherits( TextImp::stype() ) );
+ std::vector<ObjectCalcer*> parents = label->parents();
+ assert( parents.size() >= 3 );
+ std::vector<ObjectCalcer*> firstthree( parents.begin(), parents.begin() + 3 );
+ std::vector<ObjectCalcer*> rest( parents.begin() + 3, parents.end() );
+ firstthree = TextType::instance()->argParser().parse( firstthree );
+
+ assert( firstthree[0]->imp()->inherits( IntImp::stype() ) );
+ assert( firstthree[1]->imp()->inherits( PointImp::stype() ) );
+ assert( firstthree[2]->imp()->inherits( StringImp::stype() ) );
+
+ bool frame = static_cast<const IntImp*>( firstthree[0]->imp() )->data() != 0;
+ Coordinate coord = static_cast<const PointImp*>( firstthree[1]->imp() )->coordinate();
+ QString text = static_cast<const StringImp*>( firstthree[2]->imp() )->data();
+
+ // don't set it, let the user redefine it..
+// setCoordinate( coord );
+ setText( text );
+ setFrame( frame );
+
+ argvect v;
+ for ( uint i = 0; i < rest.size(); ++i )
+ {
+ v.push_back( rest[i] );
+ };
+ assert( v.size() == rest.size() );
+
+ setPropertyObjects( v );
+}
+
+TextLabelRedefineMode::~TextLabelRedefineMode()
+{
+}
+
+void TextLabelRedefineMode::finish(
+ const Coordinate& coord, const QString& s,
+ const argvect& props, bool needframe,
+ ObjectCalcer* locationparent )
+{
+ std::vector<ObjectCalcer*> parents = mlabel->parents();
+ assert( parents.size() >= 3 );
+ std::vector<ObjectCalcer*> firstthree( parents.begin(), parents.begin() + 3 );
+ std::vector<ObjectCalcer*> rest( parents.begin() + 3, parents.end() );
+ firstthree = TextType::instance()->argParser().parse( firstthree );
+
+ KigCommand* kc = new KigCommand( mdoc, i18n( "Change Label" ) );
+ MonitorDataObjects mon( firstthree );
+
+ assert( firstthree[0]->imp()->inherits( IntImp::stype() ) );
+ assert( firstthree[1]->imp()->inherits( PointImp::stype() ) );
+ assert( firstthree[2]->imp()->inherits( StringImp::stype() ) );
+
+ assert( dynamic_cast<ObjectConstCalcer*>( firstthree[0] ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( firstthree[2] ) );
+ static_cast<ObjectConstCalcer*>( firstthree[0] )->setImp( new IntImp( needframe ? 1 : 0 ) );
+
+ // we don't do this, because
+ // 1 this isn't necessarily a DataObject, we also support it to be a
+ // user-known point, or an internal constrained point..
+ // 2 we don't know that we don't want it to become a user-known
+ // point or an internal constrained point, instead of a
+ // DataObject..
+ // static_cast<DataObject*>( firstthree[1] )->setImp( new PointImp(
+ // coord ) );
+
+ static_cast<ObjectConstCalcer*>( firstthree[2] )->setImp( new StringImp( s ) );
+ mon.finish( kc );
+
+ std::vector<ObjectCalcer*> oldparents = mlabel->parents();
+ std::vector<ObjectCalcer*> p;
+ for ( argvect::const_iterator i = props.begin();
+ i != props.end(); ++i )
+ p.push_back( i->get() );
+ for ( std::vector<ObjectCalcer*>::iterator i = p.begin();
+ i != p.end(); ++i )
+ ( *i )->calc( mdoc.document() );
+
+ std::vector<ObjectCalcer*> np = firstthree;
+ /*
+ * take advantage of the method "getAttachPoint" that should
+ * do all the work; it is also used when creating a new label
+ */
+ np[1] = ObjectFactory::instance()->getAttachPoint( locationparent, coord, mdoc.document() );
+
+/* this is the old code, just in case... */
+// if ( locationparent && locationparent->imp()->inherits( CurveImp::stype() ) )
+// {
+// double param = static_cast<const CurveImp*>( locationparent->imp() )->getParam( coord, mdoc.document() );
+// np[1] = ObjectFactory::instance()->constrainedPointCalcer( locationparent, param );
+// np[1]->calc( mdoc.document() );
+// }
+// else if ( locationparent )
+// {
+// assert( locationparent->imp()->inherits( PointImp::stype() ) );
+// np[1] = locationparent;
+// }
+// else
+// np[1] = new ObjectConstCalcer( new PointImp( coord ) );
+
+ copy( p.begin(), p.end(), back_inserter( np ) );
+
+ kc->addTask(
+ new ChangeParentsAndTypeTask(
+ mlabel, np, TextType::instance() ) );
+
+ mdoc.history()->addCommand( kc );
+}
+
+void TextLabelModeBase::setFrame( bool f )
+{
+ d->wiz->needFrameCheckBox->setChecked( f );
+}
+
+void TextLabelModeBase::setLocationParent( ObjectCalcer* o )
+{
+ d->locationparent = o;
+}
diff --git a/kig/modes/label.h b/kig/modes/label.h
new file mode 100644
index 00000000..4a3d09f7
--- /dev/null
+++ b/kig/modes/label.h
@@ -0,0 +1,129 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MODE_LABEL_H
+#define KIG_MODE_LABEL_H
+
+#include "mode.h"
+
+#include "../objects/object_calcer.h"
+
+#include <vector>
+
+class TextLabelWizard;
+class NormalMode;
+class Coordinate;
+class QString;
+class ObjectPropertyCalcer;
+class ObjectTypeCalcer;
+class ObjectCalcer;
+
+/**
+ * this is the base class for TextLabelConstructionMode and
+ * TextLabelRedefineMode.. most of the work is done in this class,
+ * with some specific things delegated to the children.. Template
+ * method pattern, right ? :)
+ */
+class TextLabelModeBase
+ : public KigMode
+{
+ class Private;
+ Private* d;
+
+public:
+ // below is the interface towards TextLabelWizard...
+ void cancelPressed();
+ void finishPressed();
+ void enterTextPageEntered();
+ void selectArgumentsPageEntered();
+ void labelTextChanged();
+ void linkClicked( int );
+ void redrawScreen( KigWidget* w );
+
+protected:
+ typedef std::vector<ObjectCalcer::shared_ptr> argvect;
+ // the protected interface for subclasses
+ TextLabelModeBase( KigPart& d );
+ ~TextLabelModeBase();
+
+ void setCoordinate( const Coordinate& coord );
+ void setText( const QString& s );
+ void setLocationParent( ObjectCalcer* o );
+ /**
+ * objects you pass here, should be newly created property objects,
+ * that have no children..
+ */
+ void setPropertyObjects( const argvect& props );
+ void setFrame( bool f );
+
+ virtual void finish( const Coordinate& c, const QString& s,
+ const argvect& props, bool needframe,
+ ObjectCalcer* locationparent ) = 0;
+
+private:
+ // the KigMode interface..
+ void leftClicked( QMouseEvent*, KigWidget* );
+ void leftReleased( QMouseEvent*, KigWidget* );
+
+ void mouseMoved( QMouseEvent*, KigWidget* );
+
+ void enableActions();
+
+ void cancelConstruction();
+
+ void killMode();
+
+private:
+ /**
+ * \internal
+ * What Are We Doing...
+ * the diff between SelectingArgs and ReallySelectingArgs is that
+ * the latter means the user is selecting an arg in the kig window,
+ * whereas the first only means that he's looking at the second
+ * page of the wizard...
+ */
+ typedef enum { SelectingLocation, RequestingText, SelectingArgs, ReallySelectingArgs } wawdtype;
+
+ void updateWiz();
+ void updateLinksLabel();
+};
+
+class TextLabelConstructionMode
+ : public TextLabelModeBase
+{
+public:
+ TextLabelConstructionMode( KigPart& d );
+ ~TextLabelConstructionMode();
+
+ void finish( const Coordinate& coord, const QString& s,
+ const argvect& props, bool needframe,
+ ObjectCalcer* locationparent );
+};
+
+class TextLabelRedefineMode
+ : public TextLabelModeBase
+{
+ ObjectTypeCalcer* mlabel;
+ void finish( const Coordinate& coord, const QString& s,
+ const argvect& props, bool needframe,
+ ObjectCalcer* locationparent );
+public:
+ TextLabelRedefineMode( KigPart& d, ObjectTypeCalcer* label );
+ ~TextLabelRedefineMode();
+};
+
+#endif
diff --git a/kig/modes/linkslabel.cpp b/kig/modes/linkslabel.cpp
new file mode 100644
index 00000000..572c0bf8
--- /dev/null
+++ b/kig/modes/linkslabel.cpp
@@ -0,0 +1,134 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 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
+// Lesser General Public License for more details.
+
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301 USA
+
+
+#include "linkslabel.h"
+#include "linkslabel.moc"
+
+#include <qlabel.h>
+#include <kurllabel.h>
+#include <qlayout.h>
+
+#include <vector>
+#include <algorithm>
+#include <functional>
+
+#include <assert.h>
+using namespace std;
+
+class LinksLabel::Private
+{
+public:
+ QHBoxLayout* layout;
+ std::vector<QLabel*> labels;
+ std::vector<KURLLabel*> urllabels;
+};
+
+LinksLabel::LinksLabel( QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ p = new Private;
+ p->layout = new QHBoxLayout( this );
+
+ QLabel* l = new QLabel( QString::fromUtf8( "Dit is een " ), this );
+ p->labels.push_back( l );
+ p->layout->addWidget( l );
+
+ KURLLabel* u = new KURLLabel( QString::fromUtf8( "http://www.kde.org/" ),
+ QString::fromUtf8( "url"), this );
+ p->urllabels.push_back( u );
+ p->layout->addWidget( u );
+
+ l = new QLabel( QString::fromUtf8( " !" ), this );
+ p->labels.push_back( l );
+ p->layout->addWidget(l );
+
+ p->layout->activate();
+}
+
+LinksLabel::~LinksLabel()
+{
+ delete p;
+}
+
+void LinksLabel::urlClicked()
+{
+ const QObject* o = sender();
+ std::vector<KURLLabel*>::iterator i = std::find( p->urllabels.begin(), p->urllabels.end(), static_cast<const KURLLabel*>( o ) );
+ assert( i != p->urllabels.end() );
+ emit linkClicked( i - p->urllabels.begin() );
+}
+
+LinksLabel::LinksLabelEditBuf LinksLabel::startEdit()
+{
+ return LinksLabelEditBuf();
+}
+
+void LinksLabel::addText( const QString& s, LinksLabelEditBuf& buf )
+{
+ buf.data.push_back( std::pair<bool, QString>( false, s ) );
+}
+
+void LinksLabel::addLink( const QString& s, LinksLabelEditBuf& buf )
+{
+ buf.data.push_back( std::pair<bool, QString>( true, s ) );
+}
+
+namespace {
+ void deleteObj( QObject* o ) { delete o; }
+}
+
+void LinksLabel::applyEdit( LinksLabelEditBuf& buf )
+{
+ std::for_each( p->urllabels.begin(), p->urllabels.end(), deleteObj );
+ std::for_each( p->labels.begin(), p->labels.end(), deleteObj );
+ p->urllabels.clear();
+ p->labels.clear();
+
+ delete p->layout;
+ p->layout = new QHBoxLayout( this );
+
+ for ( LinksLabelEditBuf::vec::iterator i = buf.data.begin(); i != buf.data.end(); ++i )
+ {
+ if ( i->first )
+ {
+ // we need a KURLLabel...
+ // the url is an unused stub...
+ KURLLabel* l = new KURLLabel( QString::fromUtf8( "http://edu.kde.org/kig" ),
+ i->second, this );
+ p->urllabels.push_back( l );
+ p->layout->addWidget( l );
+ connect( l, SIGNAL( leftClickedURL() ), SLOT( urlClicked() ) );
+ }
+ else
+ {
+ // we need a normal label...
+ QLabel* l = new QLabel( i->second, this );
+ p->labels.push_back( l );
+ p->layout->addWidget( l );
+ };
+ };
+
+ QSpacerItem* spacer = new QSpacerItem( 40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum );
+
+ p->layout->addItem( spacer );
+
+ p->layout->activate();
+
+ std::for_each( p->urllabels.begin(), p->urllabels.end(), mem_fun( &QWidget::show ) );
+ std::for_each( p->labels.begin(), p->labels.end(), mem_fun( &QWidget::show ) );
+}
diff --git a/kig/modes/linkslabel.h b/kig/modes/linkslabel.h
new file mode 100644
index 00000000..ba64dbc2
--- /dev/null
+++ b/kig/modes/linkslabel.h
@@ -0,0 +1,85 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 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
+// Lesser General Public License for more details.
+
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301 USA
+
+#ifndef KIG_lINKS_LABEL_H
+#define KIG_lINKS_LABEL_H
+
+#include <qwidget.h>
+
+#include <vector>
+#include <utility>
+
+/**
+ * this widget shows a line of text, with some links underlined, and
+ * emits a signal if one of the links is clicked...
+ */
+class LinksLabel : public QWidget
+{
+ Q_OBJECT
+
+public:
+ LinksLabel( QWidget* parent = 0, const char* name = 0 );
+ ~LinksLabel();
+
+ class LinksLabelEditBuf
+ {
+ public:
+ friend class LinksLabel;
+ ~LinksLabelEditBuf() {}
+ private:
+ // declare these private so only LinksLabel can use them...
+ LinksLabelEditBuf() {}
+ typedef std::vector<std::pair<bool,QString> > vec;
+ vec data;
+ };
+
+ /**
+ * start editing, start recording changes in a LinksLabelEditBuf,
+ * but don't apply them until after endEdit();
+ */
+ LinksLabelEditBuf startEdit();
+ /**
+ * add a piece of normal text..
+ */
+ void addText( const QString& s, LinksLabelEditBuf& buf );
+ /**
+ * add a link...
+ */
+ void addLink( const QString& s, LinksLabelEditBuf& buf );
+ /**
+ * apply the changes... This clears the current contents and adds
+ * the new data...
+ */
+ void applyEdit( LinksLabelEditBuf& buf );
+
+signals:
+ /**
+ * the user clicked on a link. The index is the order in which it
+ * was added. E.g. this signal is emitted with arg 0 if the link
+ * you first added is clicked, argument 2 for the third link etc.
+ */
+ void linkClicked( int i );
+
+private slots:
+ void urlClicked();
+
+private:
+ class Private;
+ Private* p;
+};
+
+#endif // KDE_URLS_LABEL_H
diff --git a/kig/modes/macro.cc b/kig/modes/macro.cc
new file mode 100644
index 00000000..879466dc
--- /dev/null
+++ b/kig/modes/macro.cc
@@ -0,0 +1,245 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "macro.h"
+
+#include "macrowizard.h"
+#include "dragrectmode.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../misc/kigpainter.h"
+#include "../misc/object_constructor.h"
+#include "../misc/lists.h"
+#include "../misc/guiaction.h"
+#include "../objects/object_imp.h"
+
+#include <klineedit.h>
+#include <kmessagebox.h>
+#include <kcursor.h>
+#include <klocale.h>
+
+#include <functional>
+#include <algorithm>
+
+using namespace std;
+
+DefineMacroMode::DefineMacroMode( KigPart& d )
+ : BaseMode( d )
+{
+ mwizard = new MacroWizard( d.widget(), this );
+ mwizard->show();
+ updateNexts();
+}
+
+DefineMacroMode::~DefineMacroMode()
+{
+ delete mwizard;
+}
+
+void DefineMacroMode::abandonMacro()
+{
+ mdoc.doneMode( this );
+}
+
+void DefineMacroMode::updateNexts()
+{
+ mwizard->setNextEnabled( mwizard->mpgiven,
+ !mgiven.empty() );
+ mwizard->setNextEnabled( mwizard->mpfinal,
+ !mfinal.empty() );
+ mwizard->setFinishEnabled(
+ mwizard->mpname,
+ !mwizard->KLineEdit2->text().isEmpty()
+ );
+}
+
+void DefineMacroMode::enableActions()
+{
+ KigMode::enableActions();
+ // we don't enable any actions...
+}
+
+void DefineMacroMode::givenPageEntered()
+{
+ std::vector<ObjectHolder*> given( mgiven.begin(), mgiven.end() );
+ static_cast<KigView*>( mdoc.widget() )->realWidget()->redrawScreen( given );
+ updateNexts();
+}
+
+void DefineMacroMode::finalPageEntered()
+{
+ std::vector<ObjectHolder*> final( mfinal.begin(), mfinal.end() );
+ static_cast<KigView*>( mdoc.widget() )->realWidget()->redrawScreen( final );
+
+ updateNexts();
+}
+
+void DefineMacroMode::namePageEntered()
+{
+ ObjectCalcer* (ObjectHolder::*memfun)() = &ObjectHolder::calcer;
+ std::vector<ObjectCalcer*> given;
+ std::transform( mgiven.begin(), mgiven.end(),
+ std::back_inserter( given ),
+ std::mem_fun( memfun ) );
+ std::vector<ObjectCalcer*> final;
+ std::transform( mfinal.begin(), mfinal.end(),
+ std::back_inserter( final ),
+ std::mem_fun( memfun ) );
+ ObjectHierarchy hier( given, final );
+ if ( hier.resultDoesNotDependOnGiven() )
+ {
+ KMessageBox::sorry( mwizard,
+ i18n( "One of the result objects you selected "
+ "cannot be calculated from the given objects. "
+ "Kig cannot calculate this macro because of this. "
+ "Please press Back, and construct the objects "
+ "in the correct order..." ) );
+ mwizard->back();
+ }
+ else if( !hier.allGivenObjectsUsed() )
+ {
+ KMessageBox::sorry( mwizard,
+ i18n( "One of the given objects is not used in the "
+ "calculation of the resultant objects. This "
+ "probably means you are expecting Kig to do "
+ "something impossible. Please check the "
+ "macro and try again." ) );
+ mwizard->back();
+ }
+
+ static_cast<KigView*>( mdoc.widget() )->realWidget()->redrawScreen( std::vector<ObjectHolder*>() );
+
+ updateNexts();
+}
+
+void DefineMacroMode::finishPressed()
+{
+ ObjectCalcer* (ObjectHolder::*memfun)() = &ObjectHolder::calcer;
+ std::vector<ObjectCalcer*> given;
+ std::transform( mgiven.begin(), mgiven.end(),
+ std::back_inserter( given ),
+ std::mem_fun( memfun ) );
+ std::vector<ObjectCalcer*> final;
+ std::transform( mfinal.begin(), mfinal.end(),
+ std::back_inserter( final ),
+ std::mem_fun( memfun ) );
+ ObjectHierarchy hier( given, final );
+ MacroConstructor* ctor =
+ new MacroConstructor( hier,
+ mwizard->KLineEdit2->text(),
+ mwizard->KLineEdit1->text() );
+ ConstructibleAction* act = new ConstructibleAction( ctor, 0 );
+ MacroList::instance()->add( new Macro( act, ctor ) );
+
+ abandonMacro();
+}
+
+void DefineMacroMode::cancelPressed()
+{
+ abandonMacro();
+}
+
+void DefineMacroMode::macroNameChanged()
+{
+ mwizard->setFinishEnabled(
+ mwizard->mpname,
+ !mwizard->KLineEdit2->text().isEmpty()
+ );
+}
+
+void DefineMacroMode::dragRect( const QPoint& p, KigWidget& w )
+{
+ if ( mwizard->currentPage() == mwizard->mpname ) return;
+ std::vector<ObjectHolder*>* objs = mwizard->currentPage() == mwizard->mpgiven ? &mgiven : &mfinal;
+ DragRectMode dm( p, mdoc, w );
+ mdoc.runMode( &dm );
+ KigPainter pter( w.screenInfo(), &w.stillPix, mdoc.document() );
+ if ( ! dm.cancelled() )
+ {
+ std::vector<ObjectHolder*> ret = dm.ret();
+ if ( dm.needClear() )
+ {
+ pter.drawObjects( objs->begin(), objs->end(), false );
+ objs->clear();
+ }
+
+ std::copy( ret.begin(), ret.end(), std::back_inserter( *objs ) );
+ pter.drawObjects( objs->begin(), objs->end(), true );
+ };
+ w.updateCurPix( pter.overlay() );
+ w.updateWidget();
+
+ updateNexts();
+}
+
+void DefineMacroMode::leftClickedObject( ObjectHolder* o, const QPoint&,
+ KigWidget& w, bool )
+{
+ if ( mwizard->currentPage() == mwizard->mpname ) return;
+ std::vector<ObjectHolder*>* objs = mwizard->currentPage() == mwizard->mpgiven ? &mgiven : &mfinal;
+ std::vector<ObjectHolder*>::iterator iter = std::find( objs->begin(), objs->end(), o );
+ bool isselected = ( iter != objs->end() );
+ if ( isselected ) objs->erase( iter );
+ else objs->push_back( o );
+
+ KigPainter p( w.screenInfo(), &w.stillPix, mdoc.document() );
+ p.drawObject( o, !isselected );
+ w.updateCurPix( p.overlay() );
+ w.updateWidget();
+
+ updateNexts();
+}
+
+void DefineMacroMode::mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& pt, KigWidget& w, bool )
+{
+ w.updateCurPix();
+
+ if ( os.empty() )
+ {
+ w.setCursor( KCursor::arrowCursor() );
+ mdoc.emitStatusBarText( 0 );
+ w.updateWidget();
+ }
+ else
+ {
+ // the cursor is over an object, show object type next to cursor
+ // and set statusbar text
+
+ w.setCursor( KCursor::handCursor() );
+ QString selectstat = os.front()->selectStatement();
+
+ // statusbar text
+ mdoc.emitStatusBarText( selectstat );
+ KigPainter p( w.screenInfo(), &w.curPix, mdoc.document() );
+
+ // set the text next to the arrow cursor
+ QPoint point = pt;
+ point.setX(point.x()+15);
+
+ p.drawTextStd( point, selectstat );
+ w.updateWidget( p.overlay() );
+ }
+}
+
+void DefineMacroMode::rightClicked( const std::vector<ObjectHolder*>&, const QPoint&, KigWidget& )
+{
+}
+
+void DefineMacroMode::midClicked( const QPoint&, KigWidget& )
+{
+}
+
diff --git a/kig/modes/macro.h b/kig/modes/macro.h
new file mode 100644
index 00000000..4bf8c43e
--- /dev/null
+++ b/kig/modes/macro.h
@@ -0,0 +1,68 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MODES_MACRO_H
+#define KIG_MODES_MACRO_H
+
+#include "base_mode.h"
+
+#include <qobject.h>
+
+class MacroWizard;
+
+class DefineMacroMode
+ : public BaseMode
+{
+public:
+ DefineMacroMode( KigPart& );
+ ~DefineMacroMode();
+
+ void dragRect( const QPoint& p, KigWidget& w );
+ void leftClickedObject( ObjectHolder* o, const QPoint& p,
+ KigWidget& w, bool ctrlOrShiftDown );
+ void rightClicked( const std::vector<ObjectHolder*>& oco, const QPoint& p, KigWidget& w );
+ void midClicked( const QPoint& p, KigWidget& w );
+ void mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w, bool shiftpressed );
+
+ // called by MacroWizard class
+ void givenPageEntered();
+ void finalPageEntered();
+ void namePageEntered();
+ void finishPressed();
+ void cancelPressed();
+ void macroNameChanged();
+
+protected:
+ void enableActions();
+ /**
+ * update the enabled state of the next buttons on the wizard...
+ */
+ void updateNexts();
+ /**
+ * quit this mode...
+ */
+ void abandonMacro();
+
+ QPoint plc;
+ MacroWizard* mwizard;
+
+ // we can't use a set for this because the order is important
+ std::vector<ObjectHolder*> mgiven;
+ std::vector<ObjectHolder*> mfinal;
+};
+
+#endif
diff --git a/kig/modes/macrowizard.cc b/kig/modes/macrowizard.cc
new file mode 100644
index 00000000..e6315caf
--- /dev/null
+++ b/kig/modes/macrowizard.cc
@@ -0,0 +1,90 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "macrowizard.h"
+#include "macrowizard.moc"
+
+#include "macro.h"
+
+#include <kdebug.h>
+#include <klineedit.h>
+#include <kapplication.h>
+
+MacroWizard::MacroWizard( QWidget* parent, DefineMacroMode* m )
+ : MacroWizardBase( parent, "Define Macro Wizard", false ), mmode( m )
+{
+ connect( KLineEdit2, SIGNAL( textChanged( const QString& ) ),
+ this, SLOT( nameTextChanged( const QString& ) ) );
+ connect( this, SIGNAL( helpClicked() ), this,
+ SLOT( slotHelpClicked() ) );
+}
+
+MacroWizard::~MacroWizard()
+{
+}
+
+void MacroWizard::back()
+{
+ if ( currentPage() == mpfinal )
+ {
+ // currentPage() is not yet updated when we get here, so this
+ // means that the page about to be shown is actually mpgiven...
+ mmode->givenPageEntered();
+ }
+ else if ( currentPage() == mpname )
+ {
+ mmode->finalPageEntered();
+ }
+ MacroWizardBase::back();
+}
+
+void MacroWizard::next()
+{
+ if ( currentPage() == mpgiven )
+ {
+ // currentPage() is not yet updated when we get here, so this
+ // means that the page about to be shown is actually mpfinal...
+ mmode->finalPageEntered();
+ }
+ else if ( currentPage() == mpfinal )
+ {
+ mmode->namePageEntered();
+ }
+ MacroWizardBase::next();
+}
+
+void MacroWizard::reject()
+{
+ MacroWizardBase::reject();
+ mmode->cancelPressed();
+}
+
+void MacroWizard::nameTextChanged( const QString& )
+{
+ mmode->macroNameChanged();
+}
+
+void MacroWizard::accept()
+{
+ mmode->finishPressed();
+}
+
+void MacroWizard::slotHelpClicked()
+{
+ kapp->invokeHelp( QString::fromLatin1( "defining-macros"),
+ QString::fromLatin1( "kig" ) );
+}
diff --git a/kig/modes/macrowizard.h b/kig/modes/macrowizard.h
new file mode 100644
index 00000000..dfce8b06
--- /dev/null
+++ b/kig/modes/macrowizard.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef MACROWIZARD_H
+#define MACROWIZARD_H
+
+#include "macrowizardbase.h"
+
+class DefineMacroMode;
+
+class MacroWizard : public MacroWizardBase
+{
+ Q_OBJECT
+public:
+ MacroWizard( QWidget* parent, DefineMacroMode* m );
+ ~MacroWizard();
+
+ void back();
+ void next();
+ void reject();
+ void accept();
+private slots:
+ void nameTextChanged( const QString& );
+ void slotHelpClicked();
+private:
+ DefineMacroMode* mmode;
+};
+
+#endif // MACROWIZARD_H
diff --git a/kig/modes/macrowizardbase.ui b/kig/modes/macrowizardbase.ui
new file mode 100644
index 00000000..d3929ad8
--- /dev/null
+++ b/kig/modes/macrowizardbase.ui
@@ -0,0 +1,188 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>MacroWizardBase</class>
+<widget class="QWizard">
+ <property name="name">
+ <cstring>MacroWizardBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>4</x>
+ <y>0</y>
+ <width>344</width>
+ <height>172</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="caption">
+ <string>Define New Macro</string>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>mpgiven</cstring>
+ </property>
+ <attribute name="title">
+ <string>Given Objects</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Select the "given" objects for your new macro and press "Next".</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>mpfinal</cstring>
+ </property>
+ <attribute name="title">
+ <string>Final Object</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Select the final object(s) for your new macro.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>mpname</cstring>
+ </property>
+ <attribute name="title">
+ <string>Name</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Enter a name and description for your new type.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>KLineEdit2</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>KLineEdit2</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Description:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>KLineEdit1</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>KLineEdit1</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/kig/modes/mode.cc b/kig/modes/mode.cc
new file mode 100644
index 00000000..9d95b64d
--- /dev/null
+++ b/kig/modes/mode.cc
@@ -0,0 +1,133 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "mode.h"
+
+#include "../kig/kig_part.h"
+
+#include <kaction.h>
+
+void KigMode::enableActions()
+{
+ mdoc.enableConstructActions( false );
+ mdoc.aSelectAll->setEnabled( false );
+ mdoc.aDeselectAll->setEnabled( false );
+ mdoc.aInvertSelection->setEnabled( false );
+ mdoc.aCancelConstruction->setEnabled( false );
+ mdoc.aConfigureTypes->setEnabled( false );
+ mdoc.aDeleteObjects->setEnabled( false );
+ mdoc.aShowHidden->setEnabled( false );
+ mdoc.aNewMacro->setEnabled( false );
+ mdoc.action( "edit_undo" )->setEnabled( false );
+ mdoc.action( "edit_redo" )->setEnabled( false );
+}
+
+KigMode::~KigMode()
+{
+}
+
+KigMode::KigMode( KigPart& d )
+ : mdoc( d )
+{
+}
+
+void KigMode::leftClicked( QMouseEvent*, KigWidget* )
+{
+}
+
+void KigMode::leftMouseMoved( QMouseEvent*, KigWidget* )
+{
+}
+
+void KigMode::leftReleased( QMouseEvent*, KigWidget* )
+{
+ /* insist disabling the undo button to avoid crashes */
+ mdoc.action( "edit_undo" )->setEnabled( false );
+ mdoc.action( "edit_redo" )->setEnabled( false );
+}
+
+void KigMode::midClicked( QMouseEvent*, KigWidget* )
+{
+}
+
+void KigMode::midMouseMoved( QMouseEvent*, KigWidget* )
+{
+}
+
+void KigMode::midReleased( QMouseEvent*, KigWidget* )
+{
+}
+
+void KigMode::rightClicked( QMouseEvent*, KigWidget* )
+{
+}
+
+void KigMode::rightMouseMoved( QMouseEvent*, KigWidget* )
+{
+}
+
+void KigMode::rightReleased( QMouseEvent*, KigWidget* )
+{
+}
+
+void KigMode::mouseMoved( QMouseEvent*, KigWidget* )
+{
+}
+
+void KigMode::cancelConstruction()
+{
+}
+
+void KigMode::deleteObjects()
+{
+}
+
+void KigMode::showHidden()
+{
+}
+
+void KigMode::newMacro()
+{
+}
+
+void KigMode::editTypes()
+{
+}
+
+void KigMode::redrawScreen( KigWidget* )
+{
+}
+
+StdConstructionMode* KigMode::toStdConstructionMode()
+{
+ return 0;
+}
+
+void KigMode::selectAll()
+{
+}
+
+void KigMode::deselectAll()
+{
+}
+
+void KigMode::invertSelection()
+{
+}
diff --git a/kig/modes/mode.h b/kig/modes/mode.h
new file mode 100644
index 00000000..6f476072
--- /dev/null
+++ b/kig/modes/mode.h
@@ -0,0 +1,91 @@
+/*
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+*/
+
+#ifndef KIG_PART_MODE_H
+#define KIG_PART_MODE_H
+
+#include <qnamespace.h>
+
+class KigDocument;
+class KigPart;
+class KigWidget;
+class QMouseEvent;
+class StdConstructionMode;
+
+/**
+ * this is an ABC of a class containing the current "Mode" of the Kig
+ * document... It tells us how to respond to a certain event.
+ */
+class KigMode
+ : public Qt
+{
+public:
+ virtual ~KigMode();
+
+ virtual StdConstructionMode* toStdConstructionMode();
+
+ virtual void leftClicked( QMouseEvent*, KigWidget* );
+ /**
+ * this means: mouse moved with left mouse button down (in case that
+ * wasn't clear...)
+ */
+ virtual void leftMouseMoved( QMouseEvent*, KigWidget* );
+ virtual void leftReleased( QMouseEvent*, KigWidget* );
+ virtual void midClicked( QMouseEvent*, KigWidget* );
+ virtual void midMouseMoved( QMouseEvent*, KigWidget* );
+ virtual void midReleased( QMouseEvent*, KigWidget* );
+ virtual void rightClicked( QMouseEvent*, KigWidget* );
+ virtual void rightMouseMoved( QMouseEvent*, KigWidget* );
+ virtual void rightReleased( QMouseEvent*, KigWidget* );
+ /**
+ * mouse moved without any buttons down...
+ */
+ virtual void mouseMoved( QMouseEvent*, KigWidget* );
+
+ /**
+ * actions: we enable the actions we want when our mode is made
+ * active. These actions are members of KigDocument, and call slots
+ * on KigDocument. These slots all call the correspondent mode()
+ * member. Modes reimplement the ones they need, and turn on the
+ * actions they support in enableActions().
+ */
+ virtual void enableActions();
+
+ virtual void cancelConstruction();
+ virtual void deleteObjects();
+ virtual void showHidden();
+ virtual void newMacro();
+ virtual void editTypes();
+ virtual void selectAll();
+ virtual void deselectAll();
+ virtual void invertSelection();
+
+ /**
+ * Redraw the document on KigWidget \p w . It's up to the mode to
+ * refresh the screen...
+ */
+ virtual void redrawScreen( KigWidget* w );
+protected:
+ KigPart& mdoc;
+
+ KigMode( KigPart& d );
+};
+
+#endif
diff --git a/kig/modes/moving.cc b/kig/modes/moving.cc
new file mode 100644
index 00000000..e628a7ce
--- /dev/null
+++ b/kig/modes/moving.cc
@@ -0,0 +1,245 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "moving.h"
+
+#include "normal.h"
+
+#include "../objects/object_imp.h"
+#include "../objects/object_factory.h"
+#include "../kig/kig_document.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../kig/kig_commands.h"
+#include "../misc/kigpainter.h"
+#include "../misc/calcpaths.h"
+#include "../misc/coordinate_system.h"
+
+#include <qevent.h>
+
+#include <functional>
+#include <algorithm>
+#include <map>
+
+void MovingModeBase::initScreen( const std::vector<ObjectCalcer*>& in )
+{
+ mcalcable = in;
+ std::set<ObjectCalcer*> calcableset( mcalcable.begin(), mcalcable.end() );
+
+ // don't try to move objects that have been deleted from the
+ // document or internal objects that the user is not aware of..
+ std::vector<ObjectHolder*> docobjs = mdoc.document().objects();
+ for ( std::vector<ObjectHolder*>::iterator i = docobjs.begin();
+ i != docobjs.end(); ++i )
+ if ( calcableset.find( ( *i )->calcer() ) != calcableset.end() )
+ mdrawable.push_back( *i );
+
+ std::set<ObjectHolder*> docobjsset( docobjs.begin(), docobjs.end() );
+ std::set<ObjectHolder*> drawableset( mdrawable.begin(), mdrawable.end() );
+ std::set<ObjectHolder*> notmovingobjs;
+ std::set_difference( docobjsset.begin(), docobjsset.end(), drawableset.begin(), drawableset.end(),
+ std::inserter( notmovingobjs, notmovingobjs.begin() ) );
+
+ mview.clearStillPix();
+ KigPainter p( mview.screenInfo(), &mview.stillPix, mdoc.document() );
+ p.drawGrid( mdoc.document().coordinateSystem(), mdoc.document().grid(),
+ mdoc.document().axes() );
+ p.drawObjects( notmovingobjs.begin(), notmovingobjs.end(), false );
+ mview.updateCurPix();
+
+ KigPainter p2( mview.screenInfo(), &mview.curPix, mdoc.document() );
+ p2.drawObjects( drawableset.begin(), drawableset.end(), true );
+}
+
+void MovingModeBase::leftReleased( QMouseEvent*, KigWidget* v )
+{
+ // clean up after ourselves:
+ for ( std::vector<ObjectCalcer*>::iterator i = mcalcable.begin();
+ i != mcalcable.end(); ++i )
+ ( *i )->calc( mdoc.document() );
+ stopMove();
+ mdoc.setModified( true );
+
+ // refresh the screen:
+ v->redrawScreen( std::vector<ObjectHolder*>() );
+ v->updateScrollBars();
+
+ mdoc.doneMode( this );
+}
+
+void MovingModeBase::mouseMoved( QMouseEvent* e, KigWidget* v )
+{
+ v->updateCurPix();
+ Coordinate c = v->fromScreen( e->pos() );
+
+ bool snaptogrid = e->state() & Qt::ShiftButton;
+ moveTo( c, snaptogrid );
+ for ( std::vector<ObjectCalcer*>::iterator i = mcalcable.begin();
+ i != mcalcable.end(); ++i )
+ ( *i )->calc( mdoc.document() );
+ KigPainter p( v->screenInfo(), &v->curPix, mdoc.document() );
+ // TODO: only draw the explicitly moving objects as selected, the
+ // other ones as deselected.. Needs some support from the
+ // subclasses..
+ p.drawObjects( mdrawable, true );
+ v->updateWidget( p.overlay() );
+ v->updateScrollBars();
+}
+
+class MovingMode::Private
+{
+public:
+ // explicitly moving objects: these are the objects that the user
+ // requested to move...
+ std::vector<ObjectCalcer*> emo;
+ // point where we started moving..
+ Coordinate pwwsm;
+ MonitorDataObjects* mon;
+ // we keep a map from the emo objects to their reference location.
+ // This is the location that they claim to be at before moving
+ // starts, and we use it as a reference point to determine where
+ // they should move next..
+ std::map<const ObjectCalcer*, Coordinate> refmap;
+};
+
+MovingMode::MovingMode( const std::vector<ObjectHolder*>& os, const Coordinate& c,
+ KigWidget& v, KigPart& doc )
+ : MovingModeBase( doc, v ), d( new Private )
+{
+ d->pwwsm = c;
+ std::vector<ObjectCalcer*> emo;
+ std::set<ObjectCalcer*> objs;
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i )
+ if ( (*i)->canMove() )
+ {
+ emo.push_back( ( *i )->calcer() );
+ d->refmap[( *i )->calcer()] = (*i)->moveReferencePoint();
+ objs.insert( ( *i )->calcer() );
+ std::vector<ObjectCalcer*> parents = ( *i )->calcer()->movableParents();
+ objs.insert( parents.begin(), parents.end() );
+ };
+
+ emo = calcPath( emo );
+ for ( std::vector<ObjectCalcer*>::const_iterator i = emo.begin(); i != emo.end(); ++i )
+ if ( !isChild( *i, d->emo ) )
+ d->emo.push_back( *i );
+
+ d->mon = new MonitorDataObjects( std::vector<ObjectCalcer*>( objs.begin(),objs.end() ) );
+
+ std::set<ObjectCalcer*> tmp = objs;
+ for ( std::set<ObjectCalcer*>::const_iterator i = tmp.begin(); i != tmp.end(); ++i )
+ {
+ std::set<ObjectCalcer*> children = getAllChildren(*i);
+ objs.insert( children.begin(), children.end() );
+ }
+
+ initScreen( calcPath( std::vector<ObjectCalcer*>( objs.begin(), objs.end() ) ) );
+}
+
+void MovingMode::stopMove()
+{
+ QString text = d->emo.size() == 1 ?
+ d->emo[0]->imp()->type()->moveAStatement() :
+ i18n( "Move %1 Objects" ).arg( d->emo.size() );
+ KigCommand* mc = new KigCommand( mdoc, text );
+ d->mon->finish( mc );
+ mdoc.history()->addCommand( mc );
+}
+
+void MovingMode::moveTo( const Coordinate& o, bool snaptogrid )
+{
+ for( std::vector<ObjectCalcer*>::iterator i = d->emo.begin(); i != d->emo.end(); ++i )
+ {
+ assert( d->refmap.find( *i ) != d->refmap.end() );
+ Coordinate nc = d->refmap[*i] + ( o - d->pwwsm );
+ if ( snaptogrid ) nc = mdoc.document().coordinateSystem().snapToGrid( nc, mview );
+ (*i)->move( nc, mdoc.document() );
+ };
+}
+
+PointRedefineMode::PointRedefineMode( ObjectHolder* p, KigPart& d, KigWidget& v )
+ : MovingModeBase( d, v ), mp( p ), mmon( 0 )
+{
+ assert( dynamic_cast<ObjectTypeCalcer*>( p->calcer() ) );
+ moldtype = static_cast<ObjectTypeCalcer*>( p->calcer() )->type();
+ std::vector<ObjectCalcer*> oldparents = p->calcer()->parents();
+ std::copy( oldparents.begin(), oldparents.end(), std::back_inserter( moldparents ) );
+
+ std::vector<ObjectCalcer*> parents = getAllParents( mp->calcer() );
+ mmon = new MonitorDataObjects( parents );
+ std::vector<ObjectCalcer*> moving = parents;
+ std::set<ObjectCalcer*> children = getAllChildren( mp->calcer() );
+ std::copy( children.begin(), children.end(), std::back_inserter( moving ) );
+ initScreen( moving );
+}
+
+void PointRedefineMode::moveTo( const Coordinate& o, bool snaptogrid )
+{
+ Coordinate realo =
+ snaptogrid ? mdoc.document().coordinateSystem().snapToGrid( o, mview ) : o;
+ ObjectFactory::instance()->redefinePoint(
+ static_cast<ObjectTypeCalcer*>( mp->calcer() ), realo, mdoc.document(), mview );
+}
+
+PointRedefineMode::~PointRedefineMode()
+{
+}
+
+MovingModeBase::MovingModeBase( KigPart& doc, KigWidget& v )
+ : KigMode( doc ), mview( v )
+{
+}
+
+MovingModeBase::~MovingModeBase()
+{
+}
+
+void MovingModeBase::leftMouseMoved( QMouseEvent* e, KigWidget* v )
+{
+ mouseMoved( e, v );
+}
+
+MovingMode::~MovingMode()
+{
+ delete d->mon;
+ delete d;
+}
+
+void PointRedefineMode::stopMove()
+{
+ assert( dynamic_cast<ObjectTypeCalcer*>( mp->calcer() ) );
+ ObjectTypeCalcer* mpcalc = static_cast<ObjectTypeCalcer*>( mp->calcer() );
+
+ std::vector<ObjectCalcer*> newparents = mpcalc->parents();
+ std::vector<ObjectCalcer::shared_ptr> newparentsref(
+ newparents.begin(), newparents.end() );
+ const ObjectType* newtype = mpcalc->type();
+
+ std::vector<ObjectCalcer*> oldparents;
+ for( std::vector<ObjectCalcer::shared_ptr>::iterator i = moldparents.begin();
+ i != moldparents.end(); ++i )
+ oldparents.push_back( i->get() );
+ mpcalc->setType( moldtype );
+ mpcalc->setParents( oldparents );
+ mp->calc( mdoc.document() );
+
+ KigCommand* command = new KigCommand( mdoc, i18n( "Redefine Point" ) );
+ command->addTask(
+ new ChangeParentsAndTypeTask( mpcalc, newparents, newtype ) );
+ mmon->finish( command );
+ mdoc.history()->addCommand( command );
+}
diff --git a/kig/modes/moving.h b/kig/modes/moving.h
new file mode 100644
index 00000000..32828db3
--- /dev/null
+++ b/kig/modes/moving.h
@@ -0,0 +1,101 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef MOVING_H
+#define MOVING_H
+
+#include "mode.h"
+
+#include "../misc/coordinate.h"
+#include "../objects/object_calcer.h"
+
+class ObjectType;
+class Coordinate;
+class NormalPoint;
+class KigWidget;
+class KigDocument;
+class MonitorDataObjects;
+
+/**
+ * "Template method" pattern ( see the Design patterns book ):
+ * This is a base class for two modes: normal MovingMode: used for
+ * moving a set of objects around, using Object::startMove,
+ * Object::moveTo and Object::stopMove, and another mode
+ * PointRedefineMode, used for redefining a NormalPoint...
+ */
+class MovingModeBase
+ : public KigMode
+{
+protected:
+ KigWidget& mview;
+private:
+ // all moving objects: these objects are all of the objects that
+ // need to be redrawn every time the cursor moves, and after calc is
+ // called.
+ std::vector<ObjectCalcer*> mcalcable;
+ std::vector<ObjectHolder*> mdrawable;
+protected:
+ MovingModeBase( KigPart& doc, KigWidget& v );
+ ~MovingModeBase();
+
+ /**
+ * Subclasses should call this in their constructor, when they know
+ * which objects will be moving around... They are expected to be in
+ * the right order for being calc()'ed...
+ */
+ void initScreen( const std::vector<ObjectCalcer*>& amo );
+
+ // in these functions, subclasses should do the equivalent of
+ // Object::stopMove() and moveTo()... Note that no calc()'ing or
+ // drawing is to be done..
+ virtual void stopMove() = 0;
+ virtual void moveTo( const Coordinate& o, bool snaptogrid ) = 0;
+
+public:
+ void leftReleased( QMouseEvent*, KigWidget* );
+ void leftMouseMoved( QMouseEvent*, KigWidget* );
+ void mouseMoved( QMouseEvent*, KigWidget* );
+};
+
+class MovingMode
+ : public MovingModeBase
+{
+ class Private;
+ Private* d;
+ void stopMove();
+ void moveTo( const Coordinate& o, bool snaptogrid );
+public:
+ MovingMode( const std::vector<ObjectHolder*>& objects, const Coordinate& c,
+ KigWidget&, KigPart& );
+ ~MovingMode();
+};
+
+class PointRedefineMode
+ : public MovingModeBase
+{
+ ObjectHolder* mp;
+ std::vector<ObjectCalcer::shared_ptr> moldparents;
+ const ObjectType* moldtype;
+ MonitorDataObjects* mmon;
+ void stopMove();
+ void moveTo( const Coordinate& o, bool snaptogrid );
+public:
+ PointRedefineMode( ObjectHolder* p, KigPart& d, KigWidget& v );
+ ~PointRedefineMode();
+};
+
+#endif
diff --git a/kig/modes/normal.cc b/kig/modes/normal.cc
new file mode 100644
index 00000000..ecf5f5c1
--- /dev/null
+++ b/kig/modes/normal.cc
@@ -0,0 +1,306 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "normal.h"
+
+#include "../kig/kig_view.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_document.h"
+#include "../kig/kig_commands.h"
+#include "../objects/object_factory.h"
+#include "../objects/object_imp.h"
+#include "../objects/object_drawer.h"
+#include "../misc/kigpainter.h"
+#include "popup.h"
+#include "moving.h"
+#include "macro.h"
+#include "dragrectmode.h"
+#include "typesdialog.h"
+
+#include <kcursor.h>
+#include <kaction.h>
+#include <kcommand.h>
+#include <klocale.h>
+
+#include <algorithm>
+#include <functional>
+
+using namespace std;
+
+void NormalMode::enableActions()
+{
+ KigMode::enableActions();
+ mdoc.enableConstructActions( true );
+ mdoc.aSelectAll->setEnabled( true );
+ mdoc.aDeselectAll->setEnabled( true );
+ mdoc.aInvertSelection->setEnabled( true );
+ mdoc.aDeleteObjects->setEnabled( true );
+ mdoc.aShowHidden->setEnabled( true );
+ mdoc.aNewMacro->setEnabled( true );
+ mdoc.aConfigureTypes->setEnabled( true );
+ mdoc.history()->updateActions();
+}
+
+void NormalMode::deleteObjects()
+{
+ std::vector<ObjectHolder*> sel( sos.begin(), sos.end() );
+ mdoc.delObjects( sel );
+ sos.clear();
+}
+
+void NormalMode::selectObject( ObjectHolder* o )
+{
+ sos.insert( o );
+}
+
+void NormalMode::selectObjects( const std::vector<ObjectHolder*>& os )
+{
+ // hehe, don't you love this c++ stuff ;)
+ std::for_each( os.begin(), os.end(),
+ std::bind1st(
+ std::mem_fun( &NormalMode::selectObject ), this ) );
+}
+
+void NormalMode::unselectObject( ObjectHolder* o )
+{
+ sos.erase( o );
+}
+
+void NormalMode::clearSelection()
+{
+ sos.clear();
+}
+
+// KigDocumentPopup* NormalMode::popup( KigDocument* )
+// {
+// return 0;
+// }
+
+void NormalMode::showHidden()
+{
+ mdoc.showObjects( mdoc.document().objects() );
+}
+
+void NormalMode::newMacro()
+{
+ DefineMacroMode m( mdoc );
+ mdoc.runMode( &m );
+}
+
+void NormalMode::redrawScreen( KigWidget* w )
+{
+ // unselect removed objects..
+ std::vector<ObjectHolder*> nsos;
+ const std::set<ObjectHolder*> docobjs = mdoc.document().objectsSet();
+ std::set_intersection( docobjs.begin(), docobjs.end(), sos.begin(), sos.end(),
+ std::back_inserter( nsos ) );
+ sos = std::set<ObjectHolder*>( nsos.begin(), nsos.end() );
+ w->redrawScreen( nsos, true );
+ w->updateScrollBars();
+}
+
+void NormalMode::editTypes()
+{
+ TypesDialog d( mdoc.widget(), mdoc );
+ d.exec();
+}
+
+NormalMode::NormalMode( KigPart& d )
+ : BaseMode( d )
+{
+}
+
+NormalMode::~NormalMode()
+{
+}
+
+void NormalMode::dragRect( const QPoint& p, KigWidget& w )
+{
+ DragRectMode d( p, mdoc, w );
+ mdoc.runMode( &d );
+
+ KigPainter pter( w.screenInfo(), &w.stillPix, mdoc.document() );
+
+ if ( ! d.cancelled() )
+ {
+ std::vector<ObjectHolder*> sel = d.ret();
+
+ if ( d.needClear() )
+ {
+ pter.drawObjects( sos.begin(), sos.end(), false );
+ clearSelection();
+ };
+
+ selectObjects( sel );
+ pter.drawObjects( sel, true );
+ };
+
+ w.updateCurPix( pter.overlay() );
+ w.updateWidget();
+}
+
+void NormalMode::dragObject( const std::vector<ObjectHolder*>& oco, const QPoint& pco,
+ KigWidget& w, bool ctrlOrShiftDown )
+{
+ // first determine what to move...
+ if( sos.find( oco.front() ) == sos.end() )
+ {
+ // the user clicked on something that is currently not
+ // selected... --> we select it, taking the Ctrl- and
+ // Shift-buttons into account...
+ if ( !ctrlOrShiftDown ) clearSelection();
+ selectObject(oco.front());
+ }
+
+ std::vector<ObjectHolder*> sosv( sos.begin(), sos.end() );
+ MovingMode m( sosv, w.fromScreen( pco ), w, mdoc );
+ mdoc.runMode( &m );
+}
+
+void NormalMode::leftClickedObject( ObjectHolder* o, const QPoint&,
+ KigWidget& w, bool ctrlOrShiftDown )
+{
+ KigPainter pter( w.screenInfo(), &w.stillPix, mdoc.document() );
+
+ if ( ! o )
+ {
+ pter.drawObjects( sos.begin(), sos.end(), false );
+ clearSelection();
+ }
+ else if( sos.find( o ) == sos.end() )
+ {
+ // clicked on an object that wasn't selected....
+ if (!ctrlOrShiftDown)
+ {
+ pter.drawObjects( sos.begin(), sos.end(), false );
+ clearSelection();
+ };
+ pter.drawObject( o, true );
+ selectObject( o );
+ }
+ else
+ {
+ // clicked on an object that was selected....
+ pter.drawObject( o, false );
+ unselectObject( o );
+ };
+ w.updateCurPix( pter.overlay() );
+ w.updateWidget();
+}
+
+void NormalMode::midClicked( const QPoint& p, KigWidget& w )
+{
+ ObjectHolder* pto = ObjectFactory::instance()->sensiblePoint( w.fromScreen( p ), mdoc.document(), w );
+ pto->calc( mdoc.document() );
+ mdoc.addObject( pto );
+
+ // refresh the screen...
+ // not necessary, done by addObjects, which calls NormalMode::redrawScreen..
+// w.redrawScreen();
+// w.updateScrollBars();
+}
+
+void NormalMode::rightClicked( const std::vector<ObjectHolder*>& os,
+ const QPoint& plc,
+ KigWidget& w )
+{
+ // saving the current cursor position
+ QPoint pt = QCursor::pos();
+ if( !os.empty() )
+ {
+ ObjectHolder* o = 0;
+ int id = ObjectChooserPopup::getObjectFromList( pt, &w, os );
+ if ( id >= 0 )
+ o = os[id];
+ else
+ return;
+ if( sos.find( o ) == sos.end() )
+ {
+ clearSelection();
+ selectObject( o );
+ };
+ // show a popup menu...
+ std::vector<ObjectHolder*> sosv( sos.begin(), sos.end() );
+ NormalModePopupObjects p( mdoc, w, *this, sosv, plc );
+ p.exec( pt );
+ }
+ else
+ {
+ NormalModePopupObjects p( mdoc, w, *this, std::vector<ObjectHolder*>(), plc );
+ p.exec( pt );
+ };
+}
+
+void NormalMode::mouseMoved( const std::vector<ObjectHolder*>& os,
+ const QPoint& plc,
+ KigWidget& w,
+ bool )
+{
+ w.updateCurPix();
+ if( os.empty() )
+ {
+ w.setCursor( KCursor::arrowCursor() );
+ mdoc.emitStatusBarText( 0 );
+ w.updateWidget();
+ }
+ else
+ {
+ // the cursor is over an object, show object type next to cursor
+ // and set statusbar text
+
+ w.setCursor( KCursor::handCursor() );
+
+ int id = ObjectChooserPopup::getObjectFromList( plc, &w, os, false );
+ QString stat = id == 0 ? os.front()->selectStatement() : i18n( "Which object?" );
+
+ // statusbar text
+ mdoc.emitStatusBarText( stat );
+ KigPainter p( w.screenInfo(), &w.curPix, mdoc.document() );
+
+ // set the text next to the arrow cursor
+ QPoint point = plc;
+ point.setX(point.x()+15);
+
+ p.drawTextStd( point, stat );
+ w.updateWidget( p.overlay() );
+ };
+}
+
+void NormalMode::selectAll()
+{
+ const std::vector<ObjectHolder*> os = mdoc.document().objects();
+ selectObjects( os );
+ mdoc.redrawScreen();
+}
+
+void NormalMode::deselectAll()
+{
+ clearSelection();
+ mdoc.redrawScreen();
+}
+
+void NormalMode::invertSelection()
+{
+ std::vector<ObjectHolder*> os = mdoc.document().objects();
+ std::set<ObjectHolder*> oldsel = sos;
+ clearSelection();
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ if ( oldsel.find( *i ) == oldsel.end() )
+ sos.insert( *i );
+ mdoc.redrawScreen();
+}
diff --git a/kig/modes/normal.h b/kig/modes/normal.h
new file mode 100644
index 00000000..dd51c854
--- /dev/null
+++ b/kig/modes/normal.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MODES_NORMAL_H
+#define KIG_MODES_NORMAL_H
+
+#include "base_mode.h"
+
+#include <qpoint.h>
+#include <set>
+
+class NormalMode
+ : public BaseMode
+{
+public:
+ NormalMode( KigPart& );
+ ~NormalMode();
+protected:
+ void dragRect( const QPoint& p, KigWidget& w );
+ void dragObject( const std::vector<ObjectHolder*>& os, const QPoint& pointClickedOn,
+ KigWidget& w, bool ctrlOrShiftDown );
+ void leftClickedObject( ObjectHolder* o, const QPoint& p,
+ KigWidget& w, bool ctrlOrShiftDown );
+ void midClicked( const QPoint& p, KigWidget& w );
+ void rightClicked( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w );
+ void mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p, KigWidget& w,
+ bool shiftpressed );
+ void selectAll();
+ void deselectAll();
+ void invertSelection();
+
+protected:
+ /**
+ * Objcects were added..
+ */
+ void redrawScreen( KigWidget* );
+
+ void enableActions();
+
+ void deleteObjects();
+ void showHidden();
+ void newMacro();
+ void editTypes();
+
+public:
+ void selectObject( ObjectHolder* o );
+ void selectObjects( const std::vector<ObjectHolder*>& os );
+ void unselectObject( ObjectHolder* o );
+ void clearSelection();
+
+// KigObjectsPopup* popup( const Objects& os );
+// KigDocumentPopup* popup( KigDocument* );
+protected:
+ /**
+ * selected objects...
+ */
+ std::set<ObjectHolder*> sos;
+};
+
+#endif
diff --git a/kig/modes/popup.cc b/kig/modes/popup.cc
new file mode 100644
index 00000000..b71d9896
--- /dev/null
+++ b/kig/modes/popup.cc
@@ -0,0 +1,1200 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "popup.h"
+#include "popup.moc"
+
+#include "../kig/kig_part.h"
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+#include "../kig/kig_commands.h"
+#include "../objects/object_imp.h"
+#include "../objects/object_drawer.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/point_imp.h"
+#include "../objects/line_imp.h"
+#include "../objects/other_type.h"
+#include "../objects/object_factory.h"
+#include "../objects/polygon_imp.h"
+#include "../objects/text_imp.h"
+#include "../misc/lists.h"
+#include "../misc/argsparser.h"
+#include "../misc/kigpainter.h"
+#include "../misc/coordinate_system.h"
+#include "../misc/object_constructor.h"
+#include "construct_mode.h"
+#include "normal.h"
+#include "moving.h"
+
+#include <algorithm>
+#include <functional>
+
+#include <qcursor.h>
+#include <qdialog.h>
+#include <qpen.h>
+#include <qregexp.h>
+#include <qvalidator.h>
+
+#include <kaction.h>
+#include <kcolordialog.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#if KDE_IS_VERSION( 3, 1, 90 )
+#include <kinputdialog.h>
+#else
+#include <klineeditdlg.h>
+#endif
+
+#include <config.h>
+
+using namespace std;
+
+class NormalModePopupObjects;
+
+/**
+ * This class is an abstract class. Its role is to fill up the
+ * NormalModePopupObjects with useful actions..
+ */
+class PopupActionProvider
+{
+public:
+ virtual ~PopupActionProvider();
+ /**
+ * add all your entries to menu menu in popup popup. Set nextfree
+ * to the next free index..
+ */
+ virtual void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree ) = 0;
+ /**
+ * try to execute the id'th action you added to menu menu in popup
+ * popup ( first is 0 ). Return true if this action does indeed
+ * belong to you ( is not greater than the number of actions you
+ * added ). Else return false, and subtract the number of actions
+ * you added from id. This requires you to keep a record of how
+ * much actions you added ( unless it's a fixed number, of course
+ * ).
+ */
+ virtual bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os,
+ NormalModePopupObjects& popup,
+ KigPart& doc, KigWidget& w, NormalMode& m ) = 0;
+};
+
+class BuiltinObjectActionsProvider
+ : public PopupActionProvider
+{
+public:
+ void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree );
+ bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os,
+ NormalModePopupObjects& popup,
+ KigPart& doc, KigWidget& w, NormalMode& m );
+};
+
+class NameObjectActionsProvider
+ : public PopupActionProvider
+{
+public:
+ void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree );
+ bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os,
+ NormalModePopupObjects& popup,
+ KigPart& doc, KigWidget& w, NormalMode& m );
+};
+
+class BuiltinDocumentActionsProvider
+ : public PopupActionProvider
+{
+ int mnumberofcoordsystems;
+ bool misfullscreen;
+public:
+ void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree );
+ bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os,
+ NormalModePopupObjects& popup,
+ KigPart& doc, KigWidget& w, NormalMode& m );
+};
+
+class ObjectConstructorActionsProvider
+ : public PopupActionProvider
+{
+ std::vector<ObjectConstructor*> mctors[NormalModePopupObjects::NumberOfMenus];
+public:
+ void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree );
+ bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os,
+ NormalModePopupObjects& popup,
+ KigPart& doc, KigWidget& w, NormalMode& m );
+};
+
+class PropertiesActionsProvider
+ : public PopupActionProvider
+{
+ // we don't really need NumberOfMenus vectors, but this is the
+ // easiest way to do it, and I'm too lazy to do it properly ;)
+ std::vector<int> mprops[NormalModePopupObjects::NumberOfMenus];
+public:
+ void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree );
+ bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os,
+ NormalModePopupObjects& popup,
+ KigPart& doc, KigWidget& w, NormalMode& m );
+};
+
+class ObjectTypeActionsProvider
+ : public PopupActionProvider
+{
+ int mnoa;
+public:
+ void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree );
+ bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os,
+ NormalModePopupObjects& popup,
+ KigPart& doc, KigWidget& w, NormalMode& m );
+};
+
+#ifdef KIG_ENABLE_PYTHON_SCRIPTING
+#include "../scripting/script-common.h"
+#include "../scripting/script_mode.h"
+#include "../scripting/python_type.h"
+
+class ScriptActionsProvider
+ : public PopupActionProvider
+{
+ int mns;
+public:
+ void fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree );
+ bool executeAction( int menu, int& id, const std::vector<ObjectHolder*>& os,
+ NormalModePopupObjects& popup,
+ KigPart& doc, KigWidget& w, NormalMode& m );
+};
+#endif
+
+NormalModePopupObjects::NormalModePopupObjects( KigPart& part,
+ KigWidget& view,
+ NormalMode& mode,
+ const std::vector<ObjectHolder*>& objs,
+ const QPoint& plc )
+ : KPopupMenu( &view ), mplc( plc ), mpart( part ), mview( view ), mobjs( objs ),
+ mmode( mode ), monlylabels( false )
+{
+ bool empty = objs.empty();
+ bool single = objs.size() == 1;
+ connect( this, SIGNAL( activated( int ) ), this, SLOT( toplevelMenuSlot( int ) ) );
+
+ QString title;
+ if ( empty )
+ title = i18n( "Kig Document" );
+ else if ( single )
+ {
+ if ( !objs[0]->name().isNull() )
+ title = QString::fromLatin1( "%1 %2" ).arg( objs[0]->imp()->type()->translatedName() ).arg( objs[0]->name() );
+ else
+ title = objs[0]->imp()->type()->translatedName();
+ }
+ else
+ title = i18n( "%1 Objects" ).arg( objs.size() );
+ insertTitle( title, 1 );
+
+ if ( !empty )
+ {
+ monlylabels = true;
+ uint i = 0;
+ while ( i < objs.size() && monlylabels )
+ {
+ monlylabels &= objs[i]->imp()->inherits( TextImp::stype() );
+ ++i;
+ }
+ }
+
+ if ( empty )
+ {
+ // provides some diverse stuff like "unhide all", set coordinate
+ // system etc.
+ mproviders.push_back( new BuiltinDocumentActionsProvider() );
+ };
+ // construct an object using these objects and start constructing an
+ // object using these objects
+ mproviders.push_back( new ObjectConstructorActionsProvider() );
+ if ( single )
+ mproviders.push_back( new NameObjectActionsProvider() );
+ if ( ! empty )
+ {
+ // stuff like hide, show, delete, set size, set color..
+ mproviders.push_back( new BuiltinObjectActionsProvider() );
+ // show property as text label -> show menu
+ // and construct property's as objects -> construct menu
+ mproviders.push_back( new PropertiesActionsProvider() );
+ // stuff like "redefine point" for a fixed or constrained point..
+ mproviders.push_back( new ObjectTypeActionsProvider() );
+ }
+#ifdef KIG_ENABLE_PYTHON_SCRIPTING
+ // script action..
+ mproviders.push_back( new ScriptActionsProvider() );
+#endif
+
+ for ( uint i = 0; i < NumberOfMenus; ++i )
+ mmenus[i] = new QPopupMenu( this );
+
+ connect( mmenus[TransformMenu], SIGNAL( activated( int ) ),
+ this, SLOT( transformMenuSlot( int ) ) );
+ connect( mmenus[TestMenu], SIGNAL( activated( int ) ),
+ this, SLOT( testMenuSlot( int ) ) );
+ connect( mmenus[ConstructMenu], SIGNAL( activated( int ) ),
+ this, SLOT( constructMenuSlot( int ) ) );
+ connect( mmenus[StartMenu], SIGNAL( activated( int ) ),
+ this, SLOT( startMenuSlot( int ) ) );
+ connect( mmenus[ShowMenu], SIGNAL( activated( int ) ),
+ this, SLOT( showMenuSlot( int ) ) );
+ connect( mmenus[SetColorMenu], SIGNAL( activated( int ) ),
+ this, SLOT( setColorMenuSlot( int ) ) );
+ connect( mmenus[SetSizeMenu], SIGNAL( activated( int ) ),
+ this, SLOT( setSizeMenuSlot( int ) ) );
+ connect( mmenus[SetStyleMenu], SIGNAL( activated( int ) ),
+ this, SLOT( setStyleMenuSlot( int ) ) );
+ connect( mmenus[SetCoordinateSystemMenu], SIGNAL( activated( int ) ),
+ this, SLOT( setCoordinateSystemMenuSlot( int ) ) );
+
+ for ( int i = 0; i <= NumberOfMenus; ++i )
+ {
+ int nextfree = 10;
+ for ( uint j = 0; j < mproviders.size(); ++j )
+ mproviders[j]->fillUpMenu( *this, i, nextfree );
+ };
+ static const QString menunames[NumberOfMenus] =
+ {
+ i18n( "&Transform" ),
+ i18n( "T&est" ),
+ i18n( "Const&ruct" ),
+ i18n( "&Start" ),
+ i18n( "Add Te&xt Label" ),
+ i18n( "Set Co&lor" ),
+ i18n( "Set &Pen Width" ),
+ i18n( "Set St&yle" ),
+ QString::null,
+ i18n( "Set Coordinate S&ystem" )
+ };
+ static const QString menuicons[NumberOfMenus] =
+ {
+ "centralsymmetry",
+ "test",
+ QString::null,
+ "launch",
+ "kig_text",
+ "color_fill",
+// "colorize",
+ "sizer",
+ "paintbrush",
+ QString::null,
+ QString::null
+ };
+ int index = 1;
+ for ( int i = 0; i < NumberOfMenus; ++i )
+ {
+ if ( mmenus[i]->count() == 0 ) continue;
+ if ( menuicons[i].isNull() )
+ insertItem( menunames[i], mmenus[i], i, index++ );
+ else
+ {
+ KIconLoader* l = part.instance()->iconLoader();
+ QPixmap icon = l->loadIcon( menuicons[i], KIcon::Small, 22, KIcon::DefaultState, 0L, true );
+ insertItem( QIconSet( icon ), menunames[i], mmenus[i], i, index++ );
+ }
+ };
+}
+
+void NormalModePopupObjects::testMenuSlot( int i )
+{
+ activateAction( TestMenu, i );
+}
+
+void NormalModePopupObjects::transformMenuSlot( int i )
+{
+ activateAction( TransformMenu, i );
+}
+
+void NormalModePopupObjects::constructMenuSlot( int i )
+{
+ activateAction( ConstructMenu, i );
+}
+
+void NormalModePopupObjects::startMenuSlot( int i )
+{
+ activateAction( StartMenu, i );
+}
+
+void NormalModePopupObjects::showMenuSlot( int i )
+{
+ activateAction( ShowMenu, i );
+}
+
+void NormalModePopupObjects::toplevelMenuSlot( int i )
+{
+ activateAction( ToplevelMenu, i );
+}
+
+void NormalModePopupObjects::activateAction( int menu, int action )
+{
+ bool done = false;
+ // we need action - 10 cause we called fillUpMenu with nextfree set
+ // to 10 initially..
+ action -= 10;
+ for ( uint i = 0; ! done && i < mproviders.size(); ++i )
+ done = mproviders[i]->executeAction( menu, action, mobjs, *this, mpart, mview, mmode );
+}
+
+NormalModePopupObjects::~NormalModePopupObjects()
+{
+ delete_all ( mproviders.begin(), mproviders.end() );
+}
+
+static const QColor* colors[] =
+{
+ &Qt::blue,
+ &Qt::black,
+ &Qt::gray,
+ &Qt::red,
+ &Qt::green,
+ &Qt::cyan,
+ &Qt::yellow,
+ &Qt::darkRed
+};
+static const int numberofcolors = sizeof( colors ) / sizeof( QColor* );
+
+void BuiltinObjectActionsProvider::fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree )
+{
+ if ( menu == NormalModePopupObjects::ToplevelMenu )
+ {
+ KIconLoader* l = popup.part().instance()->iconLoader();
+ std::vector<ObjectHolder*> os = popup.objects();
+
+ /*
+ * mp: we want the "show" action to be visible only
+ * if we selected only one object (to be conservative)
+ * and if that object is currently hidden.
+ * conversely for one hidden object we don't want
+ * the "hide" action to be inserted.
+ * in any case we have a fixed 'id' associated
+ * with the two actions.
+ */
+
+ if ( os.size() > 1 || os.front()->shown() )
+ {
+ popup.addAction( menu, i18n( "&Hide" ), nextfree );
+ }
+ if ( os.size() == 1 && !os.front()->shown() )
+ {
+ popup.addAction( menu, i18n( "&Show" ), nextfree+1 );
+ }
+ nextfree += 2;
+ QPixmap p = l->loadIcon( "move", KIcon::Toolbar );
+ popup.addAction( menu, p, i18n( "&Move" ), nextfree++ );
+ p = l->loadIcon( "editdelete", KIcon::Toolbar );
+ popup.addAction( menu, p, i18n( "&Delete" ), nextfree++ );
+ }
+ else if ( menu == NormalModePopupObjects::SetColorMenu )
+ {
+ QPixmap p( 50, 20 );
+ for( const QColor** c = colors; c < colors + numberofcolors; ++c )
+ {
+ p.fill( **c );
+ popup.addAction( menu, p, nextfree++ );
+ }
+ popup.addAction( menu, i18n( "&Custom Color" ), nextfree++ );
+ }
+ else if ( menu == NormalModePopupObjects::SetSizeMenu && !popup.onlyLabels() )
+ {
+ bool point = true;
+ bool samecolor = true;
+ std::vector<ObjectHolder*> os = popup.objects();
+ QColor color = os.front()->drawer()->color();
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i )
+ {
+ if ( ! (*i)->imp()->inherits( PointImp::stype() ) )
+ point = false;
+ if ( (*i)->drawer()->color() != color ) samecolor = false;
+ };
+ if ( ! samecolor ) color = Qt::blue;
+ QPixmap p( point ? 20 : 50, 20 );
+ for ( int i = 1; i < 8; ++i )
+ {
+ p.fill( popup.eraseColor() );
+ QPainter ptr( &p );
+ ptr.setPen( QPen( color, 1 ) );
+ ptr.setBrush( QBrush( color, Qt::SolidPattern ) );
+ if ( point )
+ {
+ int size = 2*i;
+ QRect r( ( 20 - size ) / 2, ( 20 - size ) / 2, size, size );
+ ptr.drawEllipse( r );
+ }
+ else
+ {
+ ptr.setPen( QPen( color, -1 + 2*i ) );
+ ptr.drawLine( QPoint( 0, 10 ), QPoint( 50, 10 ) );
+ };
+ ptr.end();
+ popup.addAction( menu, p, nextfree++ );
+ };
+ }
+ else if ( menu == NormalModePopupObjects::SetStyleMenu && !popup.onlyLabels() )
+ {
+ bool samecolor = true;
+ int npoints = 0;
+ int nothers = 0;
+ std::vector<ObjectHolder*> os = popup.objects();
+ QColor color = os.front()->drawer()->color();
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i )
+ {
+ if ( (*i)->imp()->inherits( PointImp::stype() ) )
+ npoints++;
+ else
+ nothers++;
+ if ( (*i)->drawer()->color() != color ) samecolor = false;
+ };
+ bool point = ( npoints > nothers );
+ if ( ! samecolor ) color = Qt::blue;
+ if ( point )
+ for ( int i = 0; i < 5; ++i )
+ {
+ QPixmap p( 20, 20 );
+ p.fill( popup.eraseColor() );
+ ScreenInfo si( Rect( -1, -1, 2, 2 ), p.rect() );
+ KigPainter ptr( si, &p, popup.part().document(), false );
+ PointImp pt( Coordinate( 0, 0 ) );
+ ObjectDrawer d( color, -1, true, Qt::SolidLine, i );
+ d.draw( pt, ptr, false );
+ popup.addAction( menu, p, nextfree++ );
+ }
+ else
+ {
+ Qt::PenStyle penstyles[] = {Qt::SolidLine, Qt::DashLine, Qt::DashDotLine, Qt::DashDotDotLine, Qt::DotLine};
+ for ( int i = 0; i < (int) ( sizeof( penstyles ) / sizeof( Qt::PenStyle ) ); ++i )
+ {
+ QPixmap p( 50, 20 );
+ p.fill( popup.eraseColor() );
+ ScreenInfo si( Rect( -2.5, -1, 5, 2 ), p.rect() );
+ KigPainter ptr( si, &p, popup.part().document(), false );
+ LineImp line( Coordinate( -1, 0 ), Coordinate( 1, 0 ) );
+ Qt::PenStyle ps = penstyles[i];
+ ObjectDrawer d( color, -1, true, ps, 1 );
+ d.draw( line, ptr, false );
+ popup.addAction( menu, p, nextfree++ );
+ };
+ }
+ }
+}
+
+void NameObjectActionsProvider::fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree )
+{
+ if ( menu == NormalModePopupObjects::ToplevelMenu )
+ {
+ popup.addAction( menu, i18n( "Set &Name..." ), nextfree++ );
+ }
+ else if ( menu == NormalModePopupObjects::ShowMenu )
+ {
+ popup.addAction( menu, i18n( "&Name" ), nextfree++ );
+ }
+}
+
+static void addNameLabel( ObjectCalcer* object, ObjectCalcer* namecalcer, const Coordinate& loc, KigPart& doc )
+{
+ std::vector<ObjectCalcer*> args;
+ args.push_back( namecalcer );
+ const bool namelabelneedsframe = false;
+ ObjectCalcer* attachto = 0;
+ if ( object->imp()->inherits( PointImp::stype() ) ||
+ object->imp()->attachPoint().valid() ||
+ object->imp()->inherits( CurveImp::stype() ) )
+ attachto = object;
+ ObjectHolder* label = ObjectFactory::instance()->attachedLabel(
+ QString::fromLatin1( "%1" ), attachto, loc, namelabelneedsframe, args, doc.document() );
+ doc.addObject( label );
+}
+
+bool NameObjectActionsProvider::executeAction(
+ int menu, int& id, const std::vector<ObjectHolder*>& os, NormalModePopupObjects& popup,
+ KigPart& doc, KigWidget& w, NormalMode& )
+{
+ if ( menu == NormalModePopupObjects::ToplevelMenu )
+ {
+ if ( id >= 1 )
+ {
+ id -= 1;
+ return false;
+ }
+ assert( os.size() == 1 );
+ QString name = os[0]->name();
+ bool ok;
+ QRegExp re( ".*" );
+ QRegExpValidator* rev = new QRegExpValidator( re, &doc );
+ QString caption = i18n( "Set Object Name" );
+ QString label = i18n( "Set Name of this Object:" );
+#if KDE_IS_VERSION( 3, 1, 90 )
+ name = KInputDialog::getText( caption, label, name, &ok, &w, 0, rev );
+#else
+ name = KLineEditDlg::getText( caption, label, name, &ok, &w, rev );
+#endif
+ if ( ok )
+ {
+ bool justadded = false;
+ ObjectCalcer* namecalcer = os[0]->nameCalcer();
+ if ( !namecalcer )
+ {
+ justadded = true;
+ ObjectConstCalcer* c = new ObjectConstCalcer( new StringImp( i18n( "<unnamed object>" ) ) );
+ os[0]->setNameCalcer( c );
+ namecalcer = c;
+ }
+ assert( dynamic_cast<ObjectConstCalcer*>( namecalcer ) );
+ ObjectConstCalcer* cnamecalcer = static_cast<ObjectConstCalcer*>( os[0]->nameCalcer() );
+ MonitorDataObjects mon( cnamecalcer );
+ cnamecalcer->setImp( new StringImp( name ) );
+ KigCommand* kc = new KigCommand( doc, i18n( "Set Object Name" ) );
+ mon.finish( kc );
+ doc.history()->addCommand( kc );
+
+ // if we just added the name, we add a label to show it to the user.
+ if ( justadded )
+ addNameLabel( os[0]->calcer(), namecalcer,
+// w.fromScreen( w.mapFromGlobal( popup.mapToGlobal( QPoint( 5, 0 ) ) ) ),
+ w.fromScreen( popup.plc() ),
+ doc );
+ }
+ return true;
+ }
+ else if ( menu == NormalModePopupObjects::ShowMenu )
+ {
+ if ( id >= 1 )
+ {
+ id -= 1;
+ return false;
+ }
+ assert( os.size() == 1 );
+ ObjectCalcer* namecalcer = os[0]->nameCalcer();
+ if ( !namecalcer )
+ {
+ ObjectConstCalcer* c = new ObjectConstCalcer( new StringImp( i18n( "<unnamed object>" ) ) );
+ os[0]->setNameCalcer( c );
+ namecalcer = c;
+ }
+ addNameLabel( os[0]->calcer(), namecalcer,
+// w.fromScreen( w.mapFromGlobal( popup.mapToGlobal( QPoint( 5, 0 ) ) ) ), doc );
+ w.fromScreen( popup.plc() ), doc );
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool BuiltinObjectActionsProvider::executeAction(
+ int menu, int& id, const std::vector<ObjectHolder*>& os, NormalModePopupObjects& popup,
+ KigPart& doc, KigWidget& w, NormalMode& mode )
+{
+ if ( menu == NormalModePopupObjects::ToplevelMenu )
+ {
+ if ( id > 3 )
+ {
+ id -= 4;
+ return false;
+ };
+ switch( id )
+ {
+ case 0:
+ // hide the objects..
+ doc.hideObjects( os );
+ break;
+ case 1:
+ // show the objects..
+ doc.showObjects( os );
+ break;
+ case 2:
+ {
+ // move
+ QCursor::setPos( popup.mapToGlobal( QPoint( 0, 0 ) ) );
+ QPoint p = w.mapFromGlobal( QCursor::pos() );
+ Coordinate c = w.fromScreen( p );
+ MovingMode m( os, c, w, doc );
+ doc.runMode( &m );
+ // in this case, we return, cause we don't want objects to be
+ // unselected... ( or maybe we do ? )
+ return true;
+ }
+ case 3:
+ // delete
+ doc.delObjects( os );
+ break;
+ default: assert( false );
+ };
+ mode.clearSelection();
+ return true;
+ }
+ else if ( menu == NormalModePopupObjects::SetColorMenu )
+ {
+ if ( id >= numberofcolors + 1 )
+ {
+ id -= numberofcolors + 1;
+ return false;
+ };
+ QColor color;
+ if ( id < numberofcolors )
+ color = *colors[id];
+ else
+ {
+ if ( os.size() == 1 )
+ color = os.front()->drawer()->color();
+ int result = KColorDialog::getColor( color, &w );
+ if ( result != KColorDialog::Accepted ) return true;
+ }
+ KigCommand* kc = new KigCommand( doc, i18n( "Change Object Color" ) );
+ assert( color.isValid() );
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i )
+ kc->addTask( new ChangeObjectDrawerTask( *i, ( *i )->drawer()->getCopyColor( color ) ) );
+ doc.history()->addCommand( kc );
+ mode.clearSelection();
+ return true;
+ }
+ else if ( menu == NormalModePopupObjects::SetSizeMenu )
+ {
+ if ( id >= 7 )
+ {
+ id -= 7;
+ return false;
+ };
+
+ KigCommand* kc = new KigCommand( doc, i18n( "Change Object Width" ) );
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i )
+ kc->addTask( new ChangeObjectDrawerTask( *i, ( *i )->drawer()->getCopyWidth( 1 + 2 * id ) ) );
+ doc.history()->addCommand( kc );
+ mode.clearSelection();
+ return true;
+ }
+ else if ( menu == NormalModePopupObjects::SetStyleMenu )
+ {
+ int npoints = 0;
+ int nothers = 0;
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i )
+ {
+ if ( (*i)->imp()->inherits( PointImp::stype() ) )
+ npoints++;
+ else
+ nothers++;
+ };
+ bool point = ( npoints > nothers );
+ int max = point ? 5 : 5;
+ if ( id >= max )
+ {
+ id -= max;
+ return false;
+ };
+
+ if ( point )
+ {
+ KigCommand* kc = new KigCommand( doc, i18n( "Change Point Style" ) );
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i )
+ if ( (*i)->imp()->inherits( PointImp::stype() ) )
+ kc->addTask( new ChangeObjectDrawerTask( *i, ( *i )->drawer()->getCopyPointStyle( id ) ) );
+ doc.history()->addCommand( kc );
+ mode.clearSelection();
+ return true;
+ }
+ else
+ {
+ Qt::PenStyle penstyles[] = {Qt::SolidLine, Qt::DashLine, Qt::DashDotLine, Qt::DashDotDotLine, Qt::DotLine};
+ assert( id < (int)( sizeof( penstyles ) / sizeof( Qt::PenStyle ) ) );
+ Qt::PenStyle p = penstyles[id];
+ KigCommand* kc = new KigCommand( doc, i18n( "Change Object Style" ) );
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin(); i != os.end(); ++i )
+ if ( ! (*i)->imp()->inherits( PointImp::stype() ) )
+ kc->addTask( new ChangeObjectDrawerTask( *i, ( *i )->drawer()->getCopyStyle( p ) ) );
+ doc.history()->addCommand( kc );
+ mode.clearSelection();
+ }
+ return true;
+ }
+ else return false;
+}
+
+void ObjectConstructorActionsProvider::fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree )
+{
+ const KigDocument& d = popup.part().document();
+ const KigWidget& v = popup.widget();
+ typedef ObjectConstructorList::vectype vectype;
+ vectype vec = ObjectConstructorList::instance()->constructors();
+
+ for ( vectype::iterator i = vec.begin(); i != vec.end(); ++i )
+ {
+ bool add = false;
+ if ( popup.objects().empty() )
+ {
+ add = menu == NormalModePopupObjects::StartMenu && ! (*i)->isTransform() && ! (*i)->isTest();
+ }
+ else
+ {
+ int ret = (*i)->wantArgs( getCalcers( popup.objects() ), d, v );
+ if ( ret == ArgsParser::Invalid ) continue;
+ if ( (*i)->isTransform() && popup.objects().size() == 1 ) add = menu == NormalModePopupObjects::TransformMenu;
+ else if ( (*i)->isTest() ) add = menu == NormalModePopupObjects::TestMenu;
+ else if ( ( *i )->isIntersection() ) add = menu == NormalModePopupObjects::ToplevelMenu;
+ else if ( ret == ArgsParser::Complete ) add = menu == NormalModePopupObjects::ConstructMenu;
+ else add = menu == NormalModePopupObjects::StartMenu;
+ };
+ if ( add )
+ {
+ QCString iconfile = (*i)->iconFileName();
+ if ( !iconfile.isEmpty() && !iconfile.isNull() )
+ {
+ QPixmap icon = popup.part().instance()->iconLoader()->loadIcon( iconfile, KIcon::Toolbar, 22, KIcon::DefaultState, 0L, true );
+ popup.addAction( menu, icon, (*i)->descriptiveName(), nextfree++ );
+ }
+ else
+ popup.addAction( menu, (*i)->descriptiveName(), nextfree++ );
+ mctors[menu].push_back( *i );
+ }
+ };
+}
+
+bool ObjectConstructorActionsProvider::executeAction(
+ int menu, int& id, const std::vector<ObjectHolder*>& os,
+ NormalModePopupObjects&,
+ KigPart& doc, KigWidget& w, NormalMode& m )
+{
+ if ( (uint) id >= mctors[menu].size() )
+ {
+ id -= mctors[menu].size();
+ return false;
+ }
+
+ ObjectConstructor* ctor = mctors[menu][id];
+ std::vector<ObjectCalcer*> osc = getCalcers( os );
+ if ( ! os.empty() && ctor->wantArgs( osc, doc.document(), w ) == ArgsParser::Complete )
+ {
+ ctor->handleArgs( osc, doc, w );
+ m.clearSelection();
+ }
+ else
+ {
+ BaseConstructMode* mode = ctor->constructMode( doc );
+ mode->selectObjects( os, w );
+ doc.runMode( mode );
+ delete mode;
+ };
+ return true;
+}
+
+void NormalModePopupObjects::addAction( int menu, const QPixmap& pix, int id )
+{
+ QPopupMenu* m = 0;
+ if ( menu == ToplevelMenu ) m = this;
+ else m = mmenus[menu];
+ int ret = m->insertItem( pix, id );
+ assert( ret == id );
+ // pretend to use this var..
+ (void) ret;
+}
+
+void NormalModePopupObjects::setColorMenuSlot( int i )
+{
+ activateAction( SetColorMenu, i );
+}
+
+void NormalModePopupObjects::setSizeMenuSlot( int i )
+{
+ activateAction( SetSizeMenu, i );
+}
+
+void NormalModePopupObjects::setStyleMenuSlot( int i )
+{
+ activateAction( SetStyleMenu, i );
+}
+
+void NormalModePopupObjects::setCoordinateSystemMenuSlot( int i )
+{
+ activateAction( SetCoordinateSystemMenu, i );
+}
+
+void NormalModePopupObjects::addAction( int menu, const QPixmap& icon, const QString& name, int id )
+{
+ QPopupMenu* m = 0;
+ if ( menu == ToplevelMenu ) m = this;
+ else m = mmenus[menu];
+ int ret = m->insertItem( QIconSet( icon ), name, id );
+ assert( ret == id );
+ // pretend to use this var..
+ (void)ret;
+}
+
+void NormalModePopupObjects::addAction( int menu, const QString& name, int id )
+{
+ QPopupMenu* m = 0;
+ if ( menu == ToplevelMenu ) m = this;
+ else m = mmenus[menu];
+ int ret = m->insertItem( name, id );
+ assert( ret == id );
+ // pretend to use this var..
+ (void)ret;
+}
+
+PopupActionProvider::~PopupActionProvider()
+{
+}
+
+void PropertiesActionsProvider::fillUpMenu( NormalModePopupObjects& popup,
+ int menu, int& nextfree )
+{
+ if ( popup.objects().size() != 1 ) return;
+ ObjectHolder* o = popup.objects()[0];
+ uint np = o->imp()->numberOfProperties();
+ if ( menu != NormalModePopupObjects::ConstructMenu &&
+ menu != NormalModePopupObjects::ShowMenu ) return;
+ for ( uint i = 0; i < np; ++i )
+ {
+ ObjectImp* prop = o->imp()->property( i, popup.part().document() );
+ const char* iconfile = o->imp()->iconForProperty( i );
+ bool add = true;
+ if ( menu == NormalModePopupObjects::ConstructMenu )
+ {
+ // we don't want imp's like DoubleImp, since we can't show them
+ // anyway..
+ add &= ! prop->inherits( BogusImp::stype() );
+ // we don't want to construct PointImp's coordinate property,
+ // since it would construct a point at the same place as its
+ // parent..
+ add &= ! ( o->imp()->inherits( PointImp::stype() ) &&
+ prop->inherits( PointImp::stype() ) );
+ }
+ else if ( menu == NormalModePopupObjects::ShowMenu )
+ add &= prop->canFillInNextEscape();
+ if ( add )
+ {
+ if ( iconfile && *iconfile )
+ {
+ QPixmap pix = popup.part().instance()->iconLoader()->loadIcon( iconfile, KIcon::Toolbar, 22, KIcon::DefaultState, 0L, true );
+ popup.addAction( menu, pix, i18n( o->imp()->properties()[i] ), nextfree++ );
+ }
+ else
+ {
+ popup.addAction( menu, i18n( o->imp()->properties()[i] ), nextfree++ );
+ };
+ mprops[menu-1].push_back( i );
+ };
+ delete prop;
+ };
+}
+
+bool PropertiesActionsProvider::executeAction(
+ int menu, int& id, const std::vector<ObjectHolder*>& os,
+ NormalModePopupObjects& popup,
+ KigPart& doc, KigWidget& w, NormalMode& )
+{
+ if ( menu != NormalModePopupObjects::ConstructMenu &&
+ menu != NormalModePopupObjects::ShowMenu )
+ return false;
+ if ( (uint) id >= mprops[menu - 1].size() )
+ {
+ id -= mprops[menu - 1].size();
+ return false;
+ }
+ int propid = mprops[menu-1][id];
+ assert( os.size() == 1 );
+ ObjectHolder* parent = os[0];
+ if ( menu == NormalModePopupObjects::ShowMenu )
+ {
+ std::vector<ObjectCalcer*> args;
+ args.push_back( new ObjectPropertyCalcer( parent->calcer(), propid ) );
+ args.back()->calc( doc.document() );
+// TODO: recover the cursor position somehow... the following does not work
+// in general...
+// Coordinate c = w.fromScreen( w.mapFromGlobal( popup.mapToGlobal( QPoint( 5, 0 ) ) ) );
+// mp: it seems that we have no idea where to position the label,
+// btw what's the meaning of (5,0)? let the
+// attach method decide what to do... (passing an invalidCoord)
+// /////// Coordinate c = Coordinate::invalidCoord();
+ Coordinate c = w.fromScreen( popup.plc() );
+ ObjectHolder* label = ObjectFactory::instance()->attachedLabel(
+ QString::fromLatin1( "%1" ), parent->calcer(), c,
+ false, args, doc.document() );
+ doc.addObject( label );
+ }
+ else
+ {
+ ObjectHolder* h = new ObjectHolder(
+ new ObjectPropertyCalcer( parent->calcer(), propid ) );
+ h->calc( doc.document() );
+ doc.addObject( h );
+ };
+ return true;
+}
+
+void ObjectTypeActionsProvider::fillUpMenu(
+ NormalModePopupObjects& popup, int menu, int& nextfree )
+{
+ if ( popup.objects().size() != 1 ) return;
+ if ( menu != NormalModePopupObjects::ToplevelMenu ) return;
+ ObjectHolder* to = popup.objects()[0];
+ ObjectTypeCalcer* c = dynamic_cast<ObjectTypeCalcer*>( to->calcer() );
+ if ( ! c ) return;
+ const ObjectType* t = c->type();
+
+ QStringList l = t->specialActions();
+ mnoa = l.count();
+ for ( int i = 0; i < mnoa; ++i )
+ popup.addAction( menu, l[i], nextfree++ );
+}
+
+bool ObjectTypeActionsProvider::executeAction(
+ int menu, int& id, const std::vector<ObjectHolder*>& os,
+ NormalModePopupObjects&,
+ KigPart& doc, KigWidget& w, NormalMode& m )
+{
+ if ( menu != NormalModePopupObjects::ToplevelMenu ) return false;
+ if ( id >= mnoa )
+ {
+ id -= mnoa;
+ return false;
+ }
+ assert( os.size() == 1 );
+ ObjectTypeCalcer* oc = dynamic_cast<ObjectTypeCalcer*>( os[0]->calcer() );
+ assert( oc );
+
+ oc->type()->executeAction( id, *os[0], *oc, doc, w, m );
+ return true;
+}
+
+void BuiltinDocumentActionsProvider::fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree )
+{
+ if ( menu == NormalModePopupObjects::ToplevelMenu )
+ {
+ popup.addAction( menu, i18n( "U&nhide All" ), nextfree++ );
+ popup.part().action( "view_zoom_in" )->plug( &popup );
+ popup.part().action( "view_zoom_out" )->plug( &popup );
+ popup.part().action( "fullscreen" )->plug( &popup );
+ nextfree += 3;
+ }
+ else if ( menu == NormalModePopupObjects::SetCoordinateSystemMenu )
+ {
+ int idoffset = nextfree;
+ QStringList l = CoordinateSystemFactory::names();
+ mnumberofcoordsystems = l.count();
+ for ( uint i = 0; i < l.count(); ++i )
+ popup.addAction( menu, l[i], nextfree++ );
+ int current = popup.part().document().coordinateSystem().id();
+ popup.setChecked( menu, idoffset + current, true );
+ }
+}
+
+bool BuiltinDocumentActionsProvider::executeAction(
+ int menu, int& id, const std::vector<ObjectHolder*>&,
+ NormalModePopupObjects&,
+ KigPart& doc, KigWidget&, NormalMode& m )
+{
+ if ( menu == NormalModePopupObjects::ToplevelMenu )
+ {
+ kdDebug() << "id: " << id << endl;
+ if ( id == 0 )
+ {
+ doc.showHidden();
+ m.clearSelection();
+ return true;
+ }
+ id -= 1;
+ return false;
+ }
+ else if ( menu == NormalModePopupObjects::SetCoordinateSystemMenu )
+ {
+ if ( id >= mnumberofcoordsystems )
+ {
+ id -= mnumberofcoordsystems;
+ return false;
+ };
+ CoordinateSystem* sys = CoordinateSystemFactory::build( id );
+ assert( sys );
+ doc.history()->addCommand( KigCommand::changeCoordSystemCommand( doc, sys ) );
+ m.clearSelection();
+ return true;
+ }
+ else return false;
+}
+
+void NormalModePopupObjects::setChecked( int menu, int n, bool checked )
+{
+ mmenus[menu]->setItemChecked( n, checked );
+}
+
+#ifdef KIG_ENABLE_PYTHON_SCRIPTING
+/**
+ * this is a local function that looks for a python script associated
+ * to a clicked object
+ */
+static ObjectTypeCalcer* getPythonExecuteTypeFromCalcer( ObjectCalcer* o )
+{
+ ObjectTypeCalcer* oc = dynamic_cast<ObjectTypeCalcer *>( o );
+ if ( !oc ) return 0;
+ const PythonExecuteType* pythonexec = dynamic_cast<const PythonExecuteType*>( oc->type() );
+ if ( pythonexec ) return oc;
+
+ return 0;
+}
+
+void ScriptActionsProvider::fillUpMenu( NormalModePopupObjects& popup, int menu, int& nextfree )
+{
+ if ( menu == NormalModePopupObjects::StartMenu )
+ {
+ KIconLoader* l = popup.part().instance()->iconLoader();
+ QPixmap p = l->loadIcon( ScriptType::icon( ScriptType::Python ), KIcon::Toolbar, 22, KIcon::DefaultState, 0L, true );
+ popup.addAction( menu, p, i18n( "Python Script" ), nextfree++ );
+ mns++;
+ }
+ else if ( menu == NormalModePopupObjects::ToplevelMenu )
+ {
+ if ( !popup.objects().empty() &&
+ getPythonExecuteTypeFromCalcer( popup.objects().front()->calcer() ) )
+ {
+ popup.addAction( menu, i18n( "Edit Script..." ), nextfree );
+ }
+ nextfree++;
+ }
+}
+
+bool ScriptActionsProvider::executeAction(
+ int menu, int& id, const std::vector<ObjectHolder*>& os,
+ NormalModePopupObjects&, KigPart& doc, KigWidget& w, NormalMode& mode )
+{
+ if ( menu == NormalModePopupObjects::StartMenu )
+ {
+ if ( id == 0 )
+ {
+ ScriptCreationMode m( doc );
+ m.setScriptType( ScriptType::Python );
+ if ( os.size() > 0 )
+ {
+ mode.clearSelection();
+ m.addArgs( os, w );
+ m.goToCodePage();
+ }
+ doc.runMode( &m );
+ return true;
+ }
+ else
+ {
+ id -= mns;
+ }
+ }
+ else if ( menu == NormalModePopupObjects::ToplevelMenu )
+ {
+ if ( id == 0 )
+ {
+ ObjectTypeCalcer* oc = getPythonExecuteTypeFromCalcer( os.front()->calcer() );
+ if ( oc )
+ {
+ ScriptEditMode m( oc, doc );
+ m.setScriptType( ScriptType::Python );
+ doc.runMode( &m );
+ }
+ return true;
+ }
+ else
+ {
+ id -= 1;
+ }
+ }
+
+ return false;
+}
+#endif
+
+int ObjectChooserPopup::getObjectFromList( const QPoint& p, KigWidget* w,
+ const std::vector<ObjectHolder*>& objs,
+ bool givepopup )
+{
+ int size = objs.size();
+
+ // no objects
+ if ( size == 0 )
+ return -1;
+
+ int id = -1;
+
+ int numpoints = 0;
+ int numpolygons = 0;
+ int numothers = 0;
+
+ for ( std::vector<ObjectHolder*>::const_iterator i = objs.begin();
+ i != objs.end(); ++i )
+ {
+ if ( (*i)->imp()->inherits( PointImp::stype() ) ) numpoints++;
+ else if ( (*i)->imp()->inherits( PolygonImp::stype() ) ) numpolygons++;
+ else numothers++;
+ }
+
+ // simply cases:
+ // - only 1 point ( and eventually other objects )
+ // - no points and an object which is not a polygon
+ // - only one object
+ // FIXME: we assume that our objects are sorted ( points, others, polygons )!
+ if ( ( numpoints == 1 ) ||
+ ( ( numpoints == 0 ) && ( numothers == 1 ) ) ||
+ ( size == 1 ) )
+ id = 0;
+ else
+ {
+ if ( givepopup )
+ {
+ ObjectChooserPopup* ppp = new ObjectChooserPopup( p, *w, objs );
+ ppp->exec( QCursor::pos() );
+
+ id = ppp->mselected;
+
+ delete ppp;
+ ppp = 0;
+ }
+ else
+ {
+ // we don't want to show a popup to the user, so let's give a
+ // value > 0 to indicate that it's not the first
+ id = 1;
+ }
+ }
+// kdDebug() << "numpoints: " << numpoints << endl
+// << "numothers: " << numothers << endl
+// << "numpolygons: " << numpolygons << endl
+// << "id: " << id << endl;
+
+ return id;
+}
+
+ObjectChooserPopup::ObjectChooserPopup( const QPoint& p, KigWidget& view,
+ const std::vector<ObjectHolder*>& objs )
+ : KPopupMenu(), mplc( p ), mview( view ), mobjs( objs ), mselected( -1 )
+{
+ for ( uint i = 0; i < mobjs.size(); i++ )
+ {
+ insertItem( !mobjs[i]->name().isEmpty()
+ ? QString::fromLatin1( "%1 %2" ).arg( mobjs[i]->imp()->type()->translatedName() ).arg( mobjs[i]->name() )
+ : mobjs[i]->imp()->type()->translatedName(),
+ i );
+ }
+
+ connect( this, SIGNAL( activated( int ) ), this, SLOT( actionActivatedSlot( int ) ) );
+}
+
+ObjectChooserPopup::~ObjectChooserPopup()
+{
+}
+
+void ObjectChooserPopup::actionActivatedSlot( int which )
+{
+ mselected = which;
+}
diff --git a/kig/modes/popup.h b/kig/modes/popup.h
new file mode 100644
index 00000000..405bcee6
--- /dev/null
+++ b/kig/modes/popup.h
@@ -0,0 +1,153 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#ifndef KIG_MODES_POPUP_H
+#define KIG_MODES_POPUP_H
+
+#include <kpopupmenu.h>
+
+#include <vector>
+
+class KigDocument;
+class KigPart;
+class KigWidget;
+class NormalMode;
+class PopupActionProvider;
+class ObjectHolder;
+
+/**
+ * This is the popup menu that appears when you click on selected
+ * objects in NormalMode.. It's quite complex, since it has to fetch
+ * a lot of information from various places, and dispatch it again
+ * when the user selects something.
+ * Update: I'm also using it for when you clicked on an empty space in
+ * the document, because the difference between the two cases is not
+ * that important, and this class is generic enough to handle both
+ * cases.. When this is the case, mobjs is empty, some
+ * PopupActionProviders are disabled, and some others enabled..
+ */
+class NormalModePopupObjects
+ : public KPopupMenu
+{
+ Q_OBJECT
+
+public:
+ NormalModePopupObjects( KigPart& part, KigWidget& view,
+ NormalMode& mode,
+ const std::vector<ObjectHolder*>& objs, const QPoint& p );
+ ~NormalModePopupObjects();
+
+ // the different "menu's", the toplevel is considered as just
+ // another menu..
+ enum { TransformMenu = 0, TestMenu, ConstructMenu, StartMenu, ShowMenu,
+ SetColorMenu, SetSizeMenu, SetStyleMenu, ToplevelMenu,
+ SetCoordinateSystemMenu, NumberOfMenus };
+
+ // used by the PopupActionProvider's to add actions to us..
+ void addAction( int menu, const QString& name, int id );
+ void addAction( int menu, const QPixmap& icon, const QString& name, int id );
+ void addAction( int menu, const QPixmap& pix, int id );
+
+ /**
+ * set the checked state of the \p n 'th item in \p menu to \p checked ..
+ */
+ void setChecked( int menu, int n, bool checked );
+
+ std::vector<ObjectHolder*> objects() const { return mobjs; }
+ KigPart& part() { return mpart; }
+ KigWidget& widget() { return mview; }
+ QPoint plc() { return mplc; }
+
+ bool onlyLabels() const { return monlylabels; }
+
+protected:
+ void activateAction( int menu, int action );
+
+private slots:
+ void transformMenuSlot( int );
+ void testMenuSlot( int );
+ void constructMenuSlot( int );
+ void startMenuSlot( int );
+ void showMenuSlot( int );
+ void setColorMenuSlot( int );
+ void setSizeMenuSlot( int );
+ void setStyleMenuSlot( int );
+ void toplevelMenuSlot( int );
+ void setCoordinateSystemMenuSlot( int );
+
+protected:
+ QPoint mplc;
+ KigPart& mpart;
+ KigWidget& mview;
+ std::vector<ObjectHolder*> mobjs;
+ NormalMode& mmode;
+
+ std::vector<PopupActionProvider*> mproviders;
+
+ QPopupMenu* mmenus[NumberOfMenus];
+
+private:
+ bool monlylabels;
+};
+
+/**
+ * This class is useful to choose one object from a list of some, by
+ * querying the user via popup menu.
+ *
+ * You can't use this class directly, but these's a convenience method.
+ */
+class ObjectChooserPopup
+ : public KPopupMenu
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Get the index of the choosen object from a list of objects.
+ *
+ * \param p is the point whene executre the popup
+ * \param w is the pointer to a KigWidget
+ * \param objs is the vector with the objects to chose from
+ * \param givepopup true means that we have to show a popup to the user
+ *
+ * \return the index of the chosen element ( starting from 0 ), or -1
+ * if none was selected.
+ */
+ static int getObjectFromList( const QPoint& p, KigWidget* w,
+ const std::vector<ObjectHolder*>& objs,
+ bool givepopup = true );
+
+protected:
+ ObjectChooserPopup( const QPoint& p, KigWidget& view,
+ const std::vector<ObjectHolder*>& objs );
+ ~ObjectChooserPopup();
+
+protected slots:
+ void actionActivatedSlot( int );
+
+protected:
+ QPoint mplc;
+ KigWidget& mview;
+ std::vector<ObjectHolder*> mobjs;
+
+ int mselected;
+};
+
+#endif
diff --git a/kig/modes/textlabelwizard.cc b/kig/modes/textlabelwizard.cc
new file mode 100644
index 00000000..803ca819
--- /dev/null
+++ b/kig/modes/textlabelwizard.cc
@@ -0,0 +1,95 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "textlabelwizard.h"
+#include "textlabelwizard.moc"
+
+#include "label.h"
+#include "linkslabel.h"
+
+#include <qtextedit.h>
+#include <kapplication.h>
+
+#include <qlayout.h>
+
+TextLabelWizard::TextLabelWizard( QWidget* parent, TextLabelModeBase* mode )
+ : TextLabelWizardBase( parent, "TextLabelWizard", false ), mmode( mode )
+{
+ connect( labelTextInput, SIGNAL( textChanged() ),
+ SLOT( textChanged() ) );
+ connect( myCustomWidget1, SIGNAL( linkClicked( int ) ),
+ SLOT( linkClicked( int ) ) );
+ connect( this, SIGNAL( helpClicked() ),
+ this, SLOT( slotHelpClicked() ) );
+ labelTextInput->setFocus();
+}
+
+TextLabelWizard::~TextLabelWizard()
+{
+}
+
+void TextLabelWizard::back()
+{
+ if ( currentPage() == select_arguments_page )
+ {
+ mmode->enterTextPageEntered();
+ }
+ TextLabelWizardBase::back();
+}
+
+void TextLabelWizard::next()
+{
+ if ( currentPage() == enter_text_page )
+ {
+ mmode->selectArgumentsPageEntered();
+ }
+ TextLabelWizardBase::next();
+}
+
+void TextLabelWizard::reject()
+{
+ TextLabelWizardBase::reject();
+ mmode->cancelPressed();
+}
+
+void TextLabelWizard::accept()
+{
+ mmode->finishPressed();
+}
+
+void TextLabelWizard::textChanged()
+{
+ mmode->labelTextChanged();
+}
+
+void TextLabelWizard::linkClicked( int which )
+{
+ mmode->linkClicked( which );
+}
+
+void TextLabelWizard::relayoutArgsPage()
+{
+ select_arguments_pageLayout->activate();
+ repaint();
+}
+
+void TextLabelWizard::slotHelpClicked()
+{
+ kapp->invokeHelp( QString::fromLatin1( "text-labels" ),
+ QString::fromLatin1( "kig" ) );
+}
+
diff --git a/kig/modes/textlabelwizard.h b/kig/modes/textlabelwizard.h
new file mode 100644
index 00000000..787e0803
--- /dev/null
+++ b/kig/modes/textlabelwizard.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MODES_TEXTLABELWIZARD_H
+#define KIG_MODES_TEXTLABELWIZARD_H
+
+#include "textlabelwizardbase.h"
+
+class TextLabelModeBase;
+
+class TextLabelWizard : public TextLabelWizardBase
+{
+ Q_OBJECT
+public:
+ TextLabelWizard( QWidget* parent, TextLabelModeBase* mode );
+ ~TextLabelWizard();
+
+ void back();
+ void next();
+ void reject();
+ void accept();
+
+ void relayoutArgsPage();
+private slots:
+ void textChanged();
+ void linkClicked( int which );
+ void slotHelpClicked();
+private:
+ TextLabelModeBase* mmode;
+};
+
+#endif // TEXTLABELWIZARD_H
diff --git a/kig/modes/textlabelwizardbase.ui b/kig/modes/textlabelwizardbase.ui
new file mode 100644
index 00000000..4e195b0d
--- /dev/null
+++ b/kig/modes/textlabelwizardbase.ui
@@ -0,0 +1,113 @@
+<!DOCTYPE UI><UI version="3.1.2" stdsetdef="1">
+<class>TextLabelWizardBase</class>
+<widget class="QWizard">
+ <property name="name">
+ <cstring>TextLabelWizardBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>488</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Construct Label</string>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>enter_text_page</cstring>
+ </property>
+ <attribute name="title">
+ <string>Enter Label Text</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>enterTextLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Enter the text for your label here and press "Next".
+If you want to show variable parts, then put %1, %2, ... at the appropriate places (e.g. "This segment is %1 units long.").</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QTextEdit">
+ <property name="name">
+ <cstring>labelTextInput</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>needFrameCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Show text in a frame</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>select_arguments_page</cstring>
+ </property>
+ <attribute name="title">
+ <string>Select Arguments</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>selectArgsLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Now select the argument(s) you need. For every argument, click on it, select an object and a property in the Kig window, and click finish when you are done...</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="LinksLabel">
+ <property name="name">
+ <cstring>myCustomWidget1</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>LinksLabel</class>
+ <header location="local">linkslabel.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="XPM.GZ" length="4462">789c9d97c76e24490e86effd1442f3d65870d2451a0ce6206f5adeb4cc620f8c34f2553225b5a4c1befb46927fe6a1d4c0ccac4287fa8a0c26834193f5dbb785b3fd9d856fbf7d799ec9ecba5ea8afe469e15bf3727ffffeeffffcf1e797af49b2d0ffc7d142f2f55f5fbe1ecc16ea85dde9a4ed81290045faa77ca49cf4ab67ba1e3953969173651ab9d4fdf1c8a27c3872ad7c3c72d3b32c2a67c3f3444636fbef23eb7e590267e68fcc4656395d8dacf6d938ef97eaef289781cddebdb2846fccff44b989ba58e3411f3dc75158e6df1d3889539517ca49bf54fe43398d1dec4f46567f685fd9c539f43fc025f80c1c3ce8d93f28e77185f8bf0c6cfae4c0b5f9c3c6e5c0542a4b5876fe13708df39d2bd7716372aa8c93c4e4723bb2f977aadc26ceec4bdb7310e6b0bfab9c2445ecd49f1370694cebca65d260ffa6711a41aef14d24e94cee6be3348e0ae5e9c8765f07ca3e8db17f0f9c825794eb3489351fe9bb7217e4969f29388bd51ee9fda5715a19730696b852fea95c6471647ca95cf64bcf43e0cef4657b647bfe6acf213d6bb32f9a9f5992b5a64f9a8f990b6cf9ecc15d6cf9acf6b2da55a8a75cb973dee4b2d1b38b5c05de02434e87e01aacfb351df5bebddea74b5c67f9c795711ea15e357e2ecde358fb87efc0a867df8cac728a074e62e527706afb59f3cf6583be5c28bb3c35f693812d1fbdc6dbe57966fec932d899ffa4f7e38adca17e34beaeca4b9c271a18f1d5fc739257b0d70d9c68be7bed7fcee7827ab91cd8e4740cf6b19d4ffb87ab07b9bf516e72d4a3ac821b9cef6e60d84f47367ded2fae1d9f7704f6163f79000ffde27660f387ed3c5dbf54dfeebb0bf6acbe6b706bfa5ef32f8f8b18f5bf0f463f20edb77956a4e68fbc80b3c4facd163847be6bfde72ec86dbeac82715fbc0286be683cf3bc081d44f7df80d344fb0b6b7de64581fb916765297263d6fccd9b7ee97e566e8b06cfdb1f59cf2bda2f8bbc2c11df0c5c41aefdb328ca22b1feb0012eedbce24736f91b18fb796d64eb87cb60817dcdafb07d906bfd14d22f659d8785ef97b2f6d7b2df6ef1d6fb2babaac6f92e8c25b27ecc1f239b7f3a5fca5a8678ea7c2d9bc0e6ef1238b3fca2c7814d5f4cbf9334b5f833384bed3c7a5f5514f4adbe2ec07962e7590457f06f6f649b977afe2a16f42f5e070bfc591e18f7a5f1a812a9e0df39d827da4fbd8c6ccfd7785569bf945f953371a9d5a3de67950bfa2d75c63eb2fb15bdcfaaf011e6c7263846bf8f4636f91618f3c7d3c0f047fb69550efab2074e12bd6fd27957553ec33c5b043bcc7f9d0795f818fdb501a3df8ae673e507ff69021eea37063bc45ffb73550736ff36c0a84f3e0317a86f8b5f139e6ffe1f821de6d9127898ff3be00a7c3ab2cd03e3d697560ff40016e47b3bb2e96bbd559d8f32bbff4b7065f193042c98873acf240af6adbf3c83c5f2954bb0c7bcd77c107d81d2fdebc63e33ff640aaecc9e1c8151df5c803dfaadc64b52dfa03ed64636ffb4ff4b2867f453ede7227586fcd3f9264ded91fffafe236d5da37fe83c91ceb7b9e5b7f6731ff92ed7f747d6fbf7e185cf58347e3e6932e47b3430fa893edf87d795c2fc3f003b67f5f902cec17abfde0dfa3c053b3c5ffb832fc2eb8fddcf233887fc195c801f46b6f3cdc02558fba72f7d2d1a7f7e321ee58fe0cad86bbff24dd3e2fe74fef836b0c6eb60d62fa6bf5e07b3419f853dd7dc70fb8bd5f1255fd90ed30f9f3c5ff30ddff21ddff384a7fcc08ffcc4cf61cdf8855ff9e79c7e1db4dff89d3f7891977899577895d7789d377893b7f83b6fcfe937bc13b477798ff7f9800ff928ac633ee11f7cca6761d7f99c7e1b3cb908da11c7413be1943376e153cc39175c72f549ff9e17c31744429e6a6aa8a58e2ee98aaee9866e7f617fc24b7417a4f734a1293dd0233dd133cd8285177aa5f9f3b63ca5377aa78f607b919668995682e62aadd17ab0b1419b9ff41f682b48bed336edd02eed05ed7d5ea3033a0cdf1ed1f127fd273ae123fa41a774a6b685cee982228a837e42e927fd47caf8985c38651eb40b2ac38e4a5842658a97fab33fd248cb87d2c9a55cc9b5dcc82d1fc99ddccb44a6f230af2f8ff224cf417f262ff22a3fe54ddee543166549966545567f617f4dd66523dc6b2c9bb225df655b7682f692ecca9eeccfe97772c09b722847722c27c1f3eb70f66bf9116c9fca999ccbc59cfe25bf4a143a5ef8992561324a78bd92522acf9ebc78efe7cf7b153276db37bef59dbff457fedadff85b7f27abfede4ffcd4cf9ff76faeff4fffefeff8c7f5fedfdfbffc0fa355c495</data>
+ </image>
+</images>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>linkslabel.h</includehint>
+</includehints>
+</UI>
diff --git a/kig/modes/typesdialog.cpp b/kig/modes/typesdialog.cpp
new file mode 100644
index 00000000..67621c20
--- /dev/null
+++ b/kig/modes/typesdialog.cpp
@@ -0,0 +1,282 @@
+/**
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+**/
+
+#include "typesdialog.h"
+#include "typesdialog.moc"
+
+#include "edittype.h"
+#include "../kig/kig_part.h"
+#include "../misc/guiaction.h"
+#include "../misc/object_constructor.h"
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include <qfile.h>
+#include <qpixmap.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+
+#include <algorithm>
+#include <vector>
+
+class MacroListElement
+ : public QListViewItem
+{
+ Macro* macro;
+public:
+ MacroListElement( KListView* lv, Macro* m );
+ Macro* getMacro() const { return macro; }
+};
+
+MacroListElement::MacroListElement( KListView* lv, Macro* m )
+ : QListViewItem( lv, QString::null, m->action->descriptiveName(), m->action->description() ),
+ macro( m )
+{
+}
+
+TypesDialog::TypesDialog( QWidget* parent, KigPart& part )
+ : TypesDialogBase( parent, "types_dialog", true ), mpart( part )
+{
+ // improving GUI look'n'feel...
+ buttonHelp->setGuiItem( KStdGuiItem::help() );
+ buttonOk->setGuiItem( KStdGuiItem::ok() );
+ buttonCancel->setGuiItem( KStdGuiItem::cancel() );
+ il = part.instance()->iconLoader();
+ buttonEdit->setIconSet( QIconSet( il->loadIcon( "edit", KIcon::Small ) ) );
+ buttonRemove->setIconSet( QIconSet( il->loadIcon( "editdelete", KIcon::Small ) ) );
+ buttonExport->setIconSet( QIconSet( il->loadIcon( "fileexport", KIcon::Small ) ) );
+ buttonImport->setIconSet( QIconSet( il->loadIcon( "fileimport", KIcon::Small ) ) );
+
+ typeList->setColumnWidth( 0, 22 );
+ typeList->setColumnWidth( 1, 140 );
+ typeList->setColumnWidth( 2, 240 );
+
+ // loading macros...
+ loadAllMacros();
+
+ popup = new QPopupMenu( this );
+ popup->insertItem( SmallIcon( "edit" ), i18n( "&Edit..." ), this, SLOT( editType() ) );
+ popup->insertItem( SmallIcon( "editdelete" ), i18n( "&Delete" ), this, SLOT( deleteType() ) );
+ popup->insertSeparator();
+ popup->insertItem( SmallIcon( "fileexport" ), i18n( "E&xport..." ), this, SLOT( exportType() ) );
+
+ // saving types
+ part.saveTypes();
+}
+
+QListViewItem* TypesDialog::newListItem( Macro* m )
+{
+ MacroListElement* e = new MacroListElement( typeList, m );
+ QCString ifn = m->action->iconFileName();
+ if ( !ifn.isNull() )
+ {
+ QPixmap p = il->loadIcon( ifn, KIcon::Small );
+ e->setPixmap( 0, p );
+ }
+ return e;
+}
+
+TypesDialog::~TypesDialog()
+{
+}
+
+void TypesDialog::helpSlot()
+{
+ kapp->invokeHelp( QString::fromLatin1( "working-with-types" ),
+ QString::fromLatin1( "kig" ) );
+}
+
+void TypesDialog::okSlot()
+{
+ mpart.saveTypes();
+ mpart.deleteTypes();
+ mpart.loadTypes();
+ accept();
+}
+
+void TypesDialog::deleteType()
+{
+ std::vector<QListViewItem*> items;
+ std::vector<Macro*> selectedTypes;
+ QListViewItemIterator it( typeList );
+ while ( it.current() ) {
+ if ( ( it.current() )->isSelected() )
+ {
+ items.push_back( it.current() );
+ selectedTypes.push_back( static_cast<MacroListElement*>( it.current() )->getMacro() );
+ }
+ ++it;
+ }
+ if (selectedTypes.empty()) return;
+ QStringList types;
+ for ( std::vector<Macro*>::iterator j = selectedTypes.begin();
+ j != selectedTypes.end(); ++j )
+ types << ( *j )->action->descriptiveName();
+ if ( KMessageBox::warningContinueCancelList( this,
+ i18n( "Are you sure you want to delete this type?",
+ "Are you sure you want to delete these %n types?", selectedTypes.size() ),
+ types, i18n("Are You Sure?"), KStdGuiItem::cont(),
+ "deleteTypeWarning") == KMessageBox::Cancel )
+ return;
+ for ( std::vector<QListViewItem*>::iterator i = items.begin(); i != items.end(); ++i)
+ {
+ int appel = typeList->itemIndex(*i);
+ assert (appel != -1);
+ delete *i;
+ };
+ for ( std::vector<Macro*>::iterator j = selectedTypes.begin();
+ j != selectedTypes.end(); ++j)
+ MacroList::instance()->remove( *j );
+}
+
+void TypesDialog::exportType()
+{
+ std::vector<Macro*> types;
+ QListViewItemIterator it( typeList );
+ while ( it.current() ) {
+ if ( ( it.current() )->isSelected() )
+ {
+ types.push_back( static_cast<MacroListElement*>( it.current() )->getMacro() );
+ }
+ ++it;
+ }
+ if (types.empty()) return;
+ QString file_name = KFileDialog::getSaveFileName(":macro", i18n("*.kigt|Kig Types Files\n*|All Files"), this, i18n( "Export Types" ) );
+ if ( file_name.isNull() )
+ return;
+ QFile fi( file_name );
+ if ( fi.exists() )
+ if ( KMessageBox::warningContinueCancel( this, i18n( "The file \"%1\" already exists. "
+ "Do you wish to overwrite it?" ).arg( fi.name() ),
+ i18n( "Overwrite File?" ), i18n("Overwrite") ) == KMessageBox::Cancel )
+ return;
+ MacroList::instance()->save( types, file_name );
+}
+
+void TypesDialog::importTypes()
+{
+ QStringList file_names =
+ KFileDialog::getOpenFileNames(":importTypes", i18n("*.kigt|Kig Types Files\n*|All Files"), this, i18n( "Import Types" ));
+
+ std::vector<Macro*> macros;
+
+ for ( QStringList::Iterator i = file_names.begin();
+ i != file_names.end(); ++i)
+ {
+ std::vector<Macro*> nmacros;
+ bool ok = MacroList::instance()->load( *i, nmacros, mpart );
+ if ( ! ok )
+ continue;
+ std::copy( nmacros.begin(), nmacros.end(), std::back_inserter( macros ) );
+ };
+ MacroList::instance()->add( macros );
+
+ for ( uint i = 0; i < macros.size(); ++i )
+ typeList->insertItem( newListItem( macros[i] ) );
+}
+
+QString TypesDialog::fetchIconFromListItem( QListViewItem* i )
+{
+ QListViewItemIterator it( typeList );
+ Macro* ai = static_cast<MacroListElement*>( i )->getMacro();
+ while ( it.current() ) {
+ if ( ( it.current() )->isSelected() )
+ {
+ Macro* ait = static_cast<MacroListElement*>( it.current() )->getMacro();
+ if ( ai == ait )
+ {
+ return ai->ctor->iconFileName( true );
+ }
+ }
+ ++it;
+ }
+ return "gear";
+}
+
+void TypesDialog::editType()
+{
+ std::vector<QListViewItem*> items;
+ QListViewItemIterator it( typeList );
+ while ( it.current() ) {
+ if ( ( it.current() )->isSelected() )
+ items.push_back( it.current() );
+ ++it;
+ }
+ if ( items.size() == 0 )
+ return;
+ if ( items.size() > 1 )
+ {
+ KMessageBox::sorry( this,
+ i18n( "There is more than one type selected. You can "
+ "only edit one type at a time. Please select "
+ "only the type you want to edit and try again." ),
+ i18n( "More Than One Type Selected" ) );
+ return;
+ }
+ QListViewItem* i = items[0];
+ EditType* d = new EditType( this, i->text( 1 ), i->text( 2 ), fetchIconFromListItem( i ) );
+ if ( d->exec() )
+ {
+ QString newname = d->name();
+ QString newdesc = d->description();
+ QString newicon = d->icon();
+
+ Macro* oldmacro = static_cast<MacroListElement*>( i )->getMacro();
+// mpart.unplugActionLists();
+ oldmacro->ctor->setName( newname );
+ oldmacro->ctor->setDescription( newdesc );
+ QCString ncicon( newicon.utf8() );
+ oldmacro->ctor->setIcon( ncicon );
+// mpart.plugActionLists();
+
+ typeList->clear();
+
+ loadAllMacros();
+ }
+ delete d;
+}
+
+void TypesDialog::contextMenuRequested( QListViewItem*, const QPoint& p, int )
+{
+ popup->exec( p );
+}
+
+void TypesDialog::loadAllMacros()
+{
+ const vec& macros = MacroList::instance()->macros();
+ for ( vec::const_reverse_iterator i = macros.rbegin(); i != macros.rend(); ++i )
+ {
+ typeList->insertItem( newListItem( *i ) );
+ }
+}
+
+void TypesDialog::cancelSlot()
+{
+ mpart.deleteTypes();
+ mpart.loadTypes();
+ reject();
+}
diff --git a/kig/modes/typesdialog.h b/kig/modes/typesdialog.h
new file mode 100644
index 00000000..6f0e4702
--- /dev/null
+++ b/kig/modes/typesdialog.h
@@ -0,0 +1,70 @@
+/*
+ This file is part of Kig, a KDE program for Interactive Geometry...
+ Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+*/
+
+#ifndef KIG_MODES_TYPESDIALOG_H
+#define KIG_MODES_TYPESDIALOG_H
+
+#include "typesdialogbase.h"
+
+#include "../misc/lists.h"
+
+#include <qpopupmenu.h>
+
+#include <klistview.h>
+#include <kiconloader.h>
+
+class KigPart;
+class KigDocument;
+
+/**
+ * Manage the macro types...
+ */
+class TypesDialog : public TypesDialogBase
+{
+ Q_OBJECT
+
+ // necessary because some MacroList functions need it..
+ KigPart& mpart;
+ const KIconLoader* il;
+ QPopupMenu* popup;
+public:
+ TypesDialog( QWidget* parent, KigPart& );
+ ~TypesDialog();
+
+public slots:
+ void helpSlot();
+ void okSlot();
+ void cancelSlot();
+
+protected slots:
+ void deleteType();
+ void exportType();
+ void importTypes();
+ void editType();
+ void contextMenuRequested( QListViewItem* i, const QPoint& p, int c );
+
+private:
+ QListViewItem* newListItem( Macro* m );
+ QString fetchIconFromListItem( QListViewItem* i );
+ void loadAllMacros();
+ typedef MacroList::vectype vec;
+};
+
+#endif
diff --git a/kig/modes/typesdialogbase.ui b/kig/modes/typesdialogbase.ui
new file mode 100644
index 00000000..7cc7effb
--- /dev/null
+++ b/kig/modes/typesdialogbase.ui
@@ -0,0 +1,337 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>TypesDialogBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>TypesDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>456</width>
+ <height>249</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Manage Types</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Here you can manage types; you can remove them, and load and save them from and to files...</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Icon</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Description</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>typeList</cstring>
+ </property>
+ <property name="selectionMode" stdset="0">
+ <enum>Extended</enum>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Select types here...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This is a list of the current macro types... You can select, edit, delete, export and import them...</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonEdit</cstring>
+ </property>
+ <property name="text">
+ <string>Edit...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Edit the selected type.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonRemove</cstring>
+ </property>
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Delete all the selected types in the list.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonExport</cstring>
+ </property>
+ <property name="text">
+ <string>Export...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Export all the selected types to a file.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonImport</cstring>
+ </property>
+ <property name="text">
+ <string>Import...</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Import macros that are contained in one or more files.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Help</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>buttonExport</sender>
+ <signal>clicked()</signal>
+ <receiver>TypesDialogBase</receiver>
+ <slot>exportType()</slot>
+ </connection>
+ <connection>
+ <sender>buttonHelp</sender>
+ <signal>clicked()</signal>
+ <receiver>TypesDialogBase</receiver>
+ <slot>helpSlot()</slot>
+ </connection>
+ <connection>
+ <sender>buttonImport</sender>
+ <signal>clicked()</signal>
+ <receiver>TypesDialogBase</receiver>
+ <slot>importTypes()</slot>
+ </connection>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>TypesDialogBase</receiver>
+ <slot>okSlot()</slot>
+ </connection>
+ <connection>
+ <sender>buttonRemove</sender>
+ <signal>clicked()</signal>
+ <receiver>TypesDialogBase</receiver>
+ <slot>deleteType()</slot>
+ </connection>
+ <connection>
+ <sender>buttonEdit</sender>
+ <signal>clicked()</signal>
+ <receiver>TypesDialogBase</receiver>
+ <slot>editType()</slot>
+ </connection>
+ <connection>
+ <sender>typeList</sender>
+ <signal>contextMenuRequested(QListViewItem*,const QPoint&amp;,int)</signal>
+ <receiver>TypesDialogBase</receiver>
+ <slot>contextMenuRequested(QListViewItem*,const QPoint&amp;,int)</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>TypesDialogBase</receiver>
+ <slot>cancelSlot()</slot>
+ </connection>
+</connections>
+<slots>
+ <slot access="protected">deleteType()</slot>
+ <slot access="protected">exportType()</slot>
+ <slot>helpSlot()</slot>
+ <slot access="protected">importTypes()</slot>
+ <slot>okSlot()</slot>
+ <slot access="protected">editType()</slot>
+ <slot access="protected">contextMenuRequested( QListViewItem* i, const QPoint&amp; p, int c )</slot>
+ <slot>cancelSlot()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klistview.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kig/objects/Makefile.am b/kig/objects/Makefile.am
new file mode 100644
index 00000000..21a02c6f
--- /dev/null
+++ b/kig/objects/Makefile.am
@@ -0,0 +1,81 @@
+INCLUDES=$(all_includes)
+noinst_LTLIBRARIES=libobjects.la
+noinst_HEADERS=\
+ angle_type.h \
+ arc_type.h \
+ base_type.h \
+ bogus_imp.h \
+ circle_imp.h \
+ circle_type.h \
+ polygon_type.h \
+ common.h \
+ conic_imp.h \
+ conic_types.h \
+ cubic_imp.h \
+ cubic_type.h \
+ curve_imp.h \
+ intersection_types.h \
+ inversion_type.h \
+ line_imp.h \
+ line_type.h \
+ locus_imp.h \
+ object_calcer.h \
+ object_drawer.h \
+ object_factory.h \
+ object_holder.h \
+ object_imp.h \
+ object_imp_factory.h \
+ object_type.h \
+ object_type_factory.h \
+ other_imp.h \
+ other_type.h \
+ point_imp.h \
+ polygon_imp.h \
+ tangent_type.h \
+ centerofcurvature_type.h \
+ tests_type.h \
+ text_imp.h \
+ text_type.h \
+ transform_types.h \
+ vector_type.h
+libobjects_la_SOURCES=\
+ angle_type.cc \
+ arc_type.cc \
+ base_type.cc \
+ bogus_imp.cc \
+ circle_imp.cc \
+ circle_type.cc \
+ polygon_type.cc \
+ common.cc \
+ conic_imp.cc \
+ conic_types.cc \
+ cubic_imp.cc \
+ cubic_type.cc \
+ curve_imp.cc \
+ intersection_types.cc \
+ inversion_type.cc \
+ line_imp.cc \
+ line_type.cc \
+ locus_imp.cc \
+ object_calcer.cc \
+ object_drawer.cc \
+ object_factory.cc \
+ object_holder.cc \
+ object_imp.cc \
+ object_imp_factory.cc \
+ object_type.cc \
+ object_type_factory.cc \
+ other_imp.cc \
+ other_type.cc \
+ point_imp.cc \
+ point_type.cc \
+ polygon_imp.cc \
+ tangent_type.cc \
+ centerofcurvature_type.cc \
+ tests_type.cc \
+ text_imp.cc \
+ text_type.cc \
+ transform_types.cc \
+ vector_type.cc
+libobjects_la_LIBADD=-lm
+METASOURCES=AUTO
diff --git a/kig/objects/angle_type.cc b/kig/objects/angle_type.cc
new file mode 100644
index 00000000..89a17131
--- /dev/null
+++ b/kig/objects/angle_type.cc
@@ -0,0 +1,208 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "angle_type.h"
+
+#include "bogus_imp.h"
+#include "other_imp.h"
+#include "point_imp.h"
+#include "../misc/calcpaths.h"
+#include "../misc/common.h"
+#include "../misc/goniometry.h"
+#include "../misc/kiginputdialog.h"
+#include "../kig/kig_commands.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+
+#include <functional>
+#include <algorithm>
+#include <cmath>
+
+#include <qstringlist.h>
+
+static const char* constructanglethroughpoint =
+ I18N_NOOP( "Construct an angle through this point" );
+
+static const ArgsParser::spec argsspecAngle[] =
+{
+ { PointImp::stype(), constructanglethroughpoint,
+ I18N_NOOP( "Select a point that the first half-line of the angle should go through..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct an angle at this point" ),
+ I18N_NOOP( "Select the point to construct the angle in..." ), true },
+ { PointImp::stype(), constructanglethroughpoint,
+ I18N_NOOP( "Select a point that the second half-line of the angle should go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( AngleType )
+
+AngleType::AngleType()
+ : ArgsParserObjectType( "Angle", argsspecAngle, 3 )
+{
+}
+
+AngleType::~AngleType()
+{
+}
+
+const AngleType* AngleType::instance()
+{
+ static const AngleType t;
+ return &t;
+}
+
+ObjectImp* AngleType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> points;
+ for ( uint i = 0; i < parents.size(); ++i )
+ points.push_back(
+ static_cast<const PointImp*>( parents[i] )->coordinate() );
+
+ Coordinate lvect = points[0] - points[1];
+ Coordinate rvect;
+ if ( points.size() == 3 )
+ rvect = points[2] - points[1];
+ else
+ {
+ rvect = lvect.orthogonal();
+ }
+
+ double startangle = atan2( lvect.y, lvect.x );
+ double endangle = atan2( rvect.y, rvect.x );
+ double anglelength = endangle - startangle;
+ if ( anglelength < 0 ) anglelength += 2* M_PI;
+ if ( startangle < 0 ) startangle += 2*M_PI;
+
+ return new AngleImp( points[1], startangle, anglelength );
+}
+
+const ObjectImpType* AngleType::resultId() const
+{
+ return AngleImp::stype();
+}
+
+QStringList AngleType::specialActions() const
+{
+ QStringList ret;
+ ret << i18n( "Set Si&ze" );
+ return ret;
+}
+
+void AngleType::executeAction(
+ int i, ObjectHolder&, ObjectTypeCalcer& t,
+ KigPart& d, KigWidget& w, NormalMode& ) const
+{
+ assert( i == 0 );
+ // pretend to use this var..
+ (void) i;
+
+ std::vector<ObjectCalcer*> parents = t.parents();
+
+ assert( margsparser.checkArgs( parents ) );
+
+ Coordinate a = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+ Coordinate b = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
+ Coordinate c = static_cast<const PointImp*>( parents[2]->imp() )->coordinate();
+
+ Coordinate lvect = a - b;
+ Coordinate rvect = c - b;
+
+ double startangle = atan2( lvect.y, lvect.x );
+ double endangle = atan2( rvect.y, rvect.x );
+ double anglelength = endangle - startangle;
+ if ( anglelength < 0 ) anglelength += 2* M_PI;
+ if ( startangle < 0 ) startangle += 2*M_PI;
+
+ Goniometry go( anglelength, Goniometry::Rad );
+ go.convertTo( Goniometry::Deg );
+
+ bool ok;
+ Goniometry newsize = KigInputDialog::getAngle( &w, &ok, go );
+ if ( !ok )
+ return;
+ newsize.convertTo( Goniometry::Rad );
+
+ double newcangle = startangle + newsize.value();
+ Coordinate cdir( cos( newcangle ), sin( newcangle ) );
+ Coordinate nc = b + cdir.normalize( rvect.length() );
+
+ MonitorDataObjects mon( getAllParents( parents ) );
+ parents[2]->move( nc, d.document() );
+ KigCommand* kc = new KigCommand( d, i18n( "Resize Angle" ) );
+ mon.finish( kc );
+ d.history()->addCommand( kc );
+}
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( HalfAngleType )
+
+HalfAngleType::HalfAngleType()
+ : ArgsParserObjectType( "HalfAngle", argsspecAngle, 3 )
+{
+}
+
+HalfAngleType::~HalfAngleType()
+{
+}
+
+const HalfAngleType* HalfAngleType::instance()
+{
+ static const HalfAngleType t;
+ return &t;
+}
+
+ObjectImp* HalfAngleType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> points;
+ for ( uint i = 0; i < parents.size(); ++i )
+ points.push_back(
+ static_cast<const PointImp*>( parents[i] )->coordinate() );
+
+ Coordinate lvect = points[0] - points[1];
+ Coordinate rvect;
+ if ( points.size() == 3 )
+ rvect = points[2] - points[1];
+ else
+ {
+ rvect = lvect.orthogonal();
+ }
+
+ double startangle = atan2( lvect.y, lvect.x );
+ double endangle = atan2( rvect.y, rvect.x );
+ double anglelength = endangle - startangle;
+ if ( anglelength < 0 ) anglelength += 2 * M_PI;
+ if ( startangle < 0 ) startangle += 2 * M_PI;
+
+ if ( anglelength > M_PI )
+ {
+ startangle += anglelength;
+ anglelength = 2 * M_PI - anglelength;
+ if ( startangle > 2 * M_PI ) startangle -= 2 * M_PI;
+ if ( anglelength < 0 ) anglelength += 2 * M_PI;
+ }
+
+ return new AngleImp( points[1], startangle, anglelength );
+}
+
+const ObjectImpType* HalfAngleType::resultId() const
+{
+ return AngleImp::stype();
+}
+
diff --git a/kig/objects/angle_type.h b/kig/objects/angle_type.h
new file mode 100644
index 00000000..796143b4
--- /dev/null
+++ b/kig/objects/angle_type.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2003-2004 Dominique Devriese <devriese@kde.org>
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MISC_ANGLE_TYPE_H
+#define KIG_MISC_ANGLE_TYPE_H
+
+#include "base_type.h"
+
+class AngleType
+ : public ArgsParserObjectType
+{
+ AngleType();
+ ~AngleType();
+public:
+ static const AngleType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ QStringList specialActions() const;
+ void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& c,
+ KigPart& d, KigWidget& w, NormalMode& m ) const;
+};
+
+class HalfAngleType
+ : public ArgsParserObjectType
+{
+ HalfAngleType();
+ ~HalfAngleType();
+public:
+ static const HalfAngleType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/arc_type.cc b/kig/objects/arc_type.cc
new file mode 100644
index 00000000..f6c660f2
--- /dev/null
+++ b/kig/objects/arc_type.cc
@@ -0,0 +1,199 @@
+// Copyright (C) 2003-2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "arc_type.h"
+
+#include "bogus_imp.h"
+#include "other_imp.h"
+#include "point_imp.h"
+#include "line_imp.h"
+#include "locus_imp.h"
+
+#include "../misc/common.h"
+#include "../misc/calcpaths.h"
+#include "../misc/goniometry.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../kig/kig_commands.h"
+
+#include <functional>
+#include <algorithm>
+#include <cmath>
+
+using std::find;
+
+#include <qstringlist.h>
+
+static const char constructarcstartingstat[] = I18N_NOOP( "Construct an arc starting at this point" );
+
+static const ArgsParser::spec argsspecArcBTP[] =
+{
+ { PointImp::stype(), constructarcstartingstat,
+ I18N_NOOP( "Select the start point of the new arc..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct an arc through this point" ),
+ I18N_NOOP( "Select a point for the new arc to go through..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct an arc ending at this point" ),
+ I18N_NOOP( "Select the end point of the new arc..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ArcBTPType )
+
+ArcBTPType::ArcBTPType()
+ : ArgsParserObjectType( "ArcBTP", argsspecArcBTP, 3 )
+{
+}
+
+ArcBTPType::~ArcBTPType()
+{
+}
+
+const ArcBTPType* ArcBTPType::instance()
+{
+ static const ArcBTPType t;
+ return &t;
+}
+
+ObjectImp* ArcBTPType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args, 2 ) )
+ return new InvalidImp;
+
+ const Coordinate a =
+ static_cast<const PointImp*>( args[0] )->coordinate();
+ const Coordinate b =
+ static_cast<const PointImp*>( args[1] )->coordinate();
+ Coordinate center;
+ double angle = 0.;
+ double startangle = 0.;
+ if ( args.size() == 3 )
+ {
+ Coordinate c = static_cast<const PointImp*>( args[2] )->coordinate();
+ center = calcCenter( a, b, c );
+ if ( ! center.valid() ) return new InvalidImp;
+ Coordinate ad = a - center;
+ Coordinate bd = b - center;
+ Coordinate cd = c - center;
+ double anglea = atan2( ad.y, ad.x );
+ double angleb = atan2( bd.y, bd.x );
+ double anglec = atan2( cd.y, cd.x );
+
+ // anglea should be smaller than anglec
+ if ( anglea > anglec )
+ {
+ double t = anglea;
+ anglea = anglec;
+ anglec = t;
+ };
+ if ( angleb > anglec || angleb < anglea )
+ {
+ startangle = anglec;
+ angle = 2 * M_PI + anglea - startangle;
+ }
+ else
+ {
+ startangle = anglea;
+ angle = anglec - anglea;
+ };
+ }
+ else
+ {
+ // find a center and angles that look natural..
+ center = (b+a)/2 + .6*(b-a).orthogonal();
+ Coordinate bd = b - center;
+ Coordinate ad = a - center;
+ startangle = atan2( ad.y, ad.x );
+ double halfangle = atan2( bd.y, bd.x ) - startangle;
+ if ( halfangle < - M_PI ) halfangle += 2*M_PI;
+ angle = 2 * halfangle;
+ };
+
+ double radius = ( a - center ).length();
+ return new ArcImp( center, radius, startangle, angle );
+}
+
+const ObjectImpType* ArcBTPType::impRequirement( const ObjectImp*, const Args& ) const
+{
+ return PointImp::stype();
+}
+
+bool ArcBTPType::inherits( int type ) const
+{
+ return Parent::inherits( type );
+}
+
+const ObjectImpType* ArcBTPType::resultId() const
+{
+ return ArcImp::stype();
+}
+
+static const ArgsParser::spec argsspecArcBCPA[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Construct an arc with this center" ),
+ I18N_NOOP( "Select the center of the new arc..." ), true },
+ { PointImp::stype(), constructarcstartingstat,
+ I18N_NOOP( "Select the start point of the new arc..." ), true },
+ { AngleImp::stype(), I18N_NOOP( "Construct an arc with this angle" ),
+ I18N_NOOP( "Select the angle of the new arc..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ArcBCPAType )
+
+ArcBCPAType::ArcBCPAType()
+ : ArgsParserObjectType( "ArcBCPA", argsspecArcBCPA, 3 )
+{
+}
+
+ArcBCPAType::~ArcBCPAType()
+{
+}
+
+const ArcBCPAType* ArcBCPAType::instance()
+{
+ static const ArcBCPAType t;
+ return &t;
+}
+
+ObjectImp* ArcBCPAType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const Coordinate center = static_cast<const PointImp*>( args[0] )->coordinate();
+ const Coordinate p = static_cast<const PointImp*>( args[1] )->coordinate();
+ const AngleImp* a = static_cast<const AngleImp*>( args[2] );
+ const double angle = a->angle();
+ const Coordinate dir = p - center;
+ const double startangle = atan2( dir.y, dir.x );
+ const double radius = center.distance( p );
+
+ return new ArcImp( center, radius, startangle, angle );
+}
+
+const ObjectImpType* ArcBCPAType::impRequirement( const ObjectImp*, const Args& ) const
+{
+ return PointImp::stype();
+}
+
+bool ArcBCPAType::inherits( int type ) const
+{
+ return Parent::inherits( type );
+}
+
+const ObjectImpType* ArcBCPAType::resultId() const
+{
+ return ArcImp::stype();
+}
diff --git a/kig/objects/arc_type.h b/kig/objects/arc_type.h
new file mode 100644
index 00000000..cdfe0294
--- /dev/null
+++ b/kig/objects/arc_type.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2003-2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_ARC_TYPE_H
+#define KIG_OBJECTS_ARC_TYPE_H
+
+#include "base_type.h"
+#include "../misc/object_hierarchy.h"
+
+/**
+ * an arc by a start point, an intermediate point and an end point
+ */
+class ArcBTPType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ ArcBTPType();
+ ~ArcBTPType();
+public:
+ static const ArcBTPType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+
+ bool inherits( int type ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * an arc by a point (center), a starting point and an angle
+ */
+class ArcBCPAType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ ArcBCPAType();
+ ~ArcBCPAType();
+public:
+ static const ArcBCPAType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+
+ bool inherits( int type ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/base_type.cc b/kig/objects/base_type.cc
new file mode 100644
index 00000000..0f8eecec
--- /dev/null
+++ b/kig/objects/base_type.cc
@@ -0,0 +1,112 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "base_type.h"
+
+#include "point_imp.h"
+#include "line_imp.h"
+#include "bogus_imp.h"
+#include "object_calcer.h"
+
+#include "../misc/common.h"
+
+ObjectABType::ObjectABType( const char* fulltypename, const ArgsParser::spec* spec, int n )
+ : ArgsParserObjectType( fulltypename, spec, n )
+{
+}
+
+ObjectABType::~ObjectABType()
+{
+}
+
+ObjectImp* ObjectABType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) )
+ return new InvalidImp;
+
+ Coordinate a = static_cast<const PointImp*>( parents[0] )->coordinate();
+ Coordinate b = static_cast<const PointImp*>( parents[1] )->coordinate();
+
+ return calc( a, b );
+}
+
+bool ObjectABType::canMove( const ObjectTypeCalcer& o ) const
+{
+ return isFreelyTranslatable( o );
+/*
+ * as observed by domi: this object is actually movable also
+ * if one point is FreelyTranslatable and the other is
+ * only movable, but then the "move" itself requires some
+ * trickery.
+ */
+}
+
+bool ObjectABType::isFreelyTranslatable( const ObjectTypeCalcer& o ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ return parents[0]->isFreelyTranslatable() && parents[1]->isFreelyTranslatable();
+}
+
+void ObjectABType::move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ assert( margsparser.checkArgs( parents ) );
+ const Coordinate a = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+ const Coordinate b = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
+ const Coordinate dist = b - a;
+ if ( parents[0]->canMove() )
+ parents[0]->move( to, d );
+ if ( parents[1]->canMove() )
+ parents[1]->move( to + dist, d );
+}
+
+ObjectLPType::ObjectLPType( const char* fullname, const ArgsParser::spec* spec, int n )
+ : ArgsParserObjectType( fullname, spec, n )
+{
+}
+
+ObjectLPType::~ObjectLPType()
+{
+}
+
+ObjectImp* ObjectLPType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+ LineData l = static_cast<const AbstractLineImp*>( args[0] )->data();
+ Coordinate c = static_cast<const PointImp*>( args[1] )->coordinate();
+ return calc( l, c );
+}
+
+const Coordinate ObjectABType::moveReferencePoint( const ObjectTypeCalcer& o ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ assert( margsparser.checkArgs( parents ) );
+ return static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+}
+
+std::vector<ObjectCalcer*> ObjectABType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ std::vector<ObjectCalcer*> parents = ourobj.parents();
+ std::set<ObjectCalcer*> ret;
+ std::vector<ObjectCalcer*> tmp = parents[0]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ tmp = parents[1]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ ret.insert( parents.begin(), parents.end() );
+ return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
+}
diff --git a/kig/objects/base_type.h b/kig/objects/base_type.h
new file mode 100644
index 00000000..ff9c1983
--- /dev/null
+++ b/kig/objects/base_type.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_BASE_TYPE_H
+#define KIG_OBJECTS_BASE_TYPE_H
+
+#include "object_type.h"
+
+#include "../misc/argsparser.h"
+
+class LineData;
+
+class ObjectABType
+ : public ArgsParserObjectType
+{
+protected:
+ ObjectABType( const char* fulltypename, const ArgsParser::spec* argsspec, int n );
+ ~ObjectABType();
+public:
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ bool canMove( const ObjectTypeCalcer& o ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& o ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& o ) const;
+
+ virtual ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const = 0;
+};
+
+class ObjectLPType
+ : public ArgsParserObjectType
+{
+protected:
+ ObjectLPType( const char* fullname, const ArgsParser::spec* spec, int n );
+ ~ObjectLPType();
+public:
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+
+ virtual ObjectImp* calc( const LineData& a, const Coordinate& b ) const = 0;
+};
+
+#endif
diff --git a/kig/objects/bogus_imp.cc b/kig/objects/bogus_imp.cc
new file mode 100644
index 00000000..c1ed6526
--- /dev/null
+++ b/kig/objects/bogus_imp.cc
@@ -0,0 +1,388 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "bogus_imp.h"
+
+#include <qcstring.h>
+#include <qstringlist.h>
+#include <klocale.h>
+
+#include "../misc/rect.h"
+
+Coordinate BogusImp::attachPoint( ) const
+{
+ return Coordinate::invalidCoord();
+}
+
+void BogusImp::draw( KigPainter& ) const
+{
+}
+
+bool BogusImp::contains( const Coordinate&, int, const KigWidget& ) const
+{
+ return false;
+}
+
+bool BogusImp::inRect( const Rect&, int, const KigWidget& ) const
+{
+ return false;
+}
+
+DoubleImp::DoubleImp( const double d )
+ : mdata( d )
+{
+}
+
+IntImp::IntImp( const int d )
+ : mdata( d )
+{
+}
+
+StringImp::StringImp( const QString& d )
+ : mdata( d )
+{
+}
+
+DoubleImp* DoubleImp::copy() const
+{
+ return new DoubleImp( mdata );
+}
+
+IntImp* IntImp::copy() const
+{
+ return new IntImp( mdata );
+}
+
+StringImp* StringImp::copy() const
+{
+ return new StringImp( mdata );
+}
+
+ObjectImp* BogusImp::transform( const Transformation& ) const
+{
+ return copy();
+}
+
+InvalidImp* InvalidImp::copy() const
+{
+ return new InvalidImp();
+}
+
+InvalidImp::InvalidImp()
+{
+}
+
+void InvalidImp::fillInNextEscape( QString& s, const KigDocument& ) const
+{
+ s = s.arg( "[invalid]" );
+}
+
+void DoubleImp::fillInNextEscape( QString& s, const KigDocument& ) const
+{
+ s = s.arg( mdata );
+}
+
+void IntImp::fillInNextEscape( QString& s, const KigDocument& ) const
+{
+ s = s.arg( mdata );
+}
+
+void StringImp::fillInNextEscape( QString& s, const KigDocument& ) const
+{
+ s = s.arg( mdata );
+}
+
+HierarchyImp::HierarchyImp( const ObjectHierarchy& h )
+ : BogusImp(), mdata( h )
+{
+}
+
+HierarchyImp* HierarchyImp::copy() const
+{
+ return new HierarchyImp( mdata );
+}
+
+void InvalidImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void DoubleImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void IntImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void StringImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void HierarchyImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+TransformationImp::TransformationImp( const Transformation& h )
+ : mdata( h )
+{
+}
+
+TransformationImp* TransformationImp::copy() const
+{
+ return new TransformationImp( mdata );
+}
+
+void TransformationImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool InvalidImp::equals( const ObjectImp& rhs ) const
+{
+ return !rhs.valid();
+}
+
+bool DoubleImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( DoubleImp::stype() ) &&
+ static_cast<const DoubleImp&>( rhs ).data() == mdata;
+}
+
+bool IntImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( IntImp::stype() ) &&
+ static_cast<const IntImp&>( rhs ).data() == mdata;
+}
+
+bool StringImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( StringImp::stype() ) &&
+ static_cast<const StringImp&>( rhs ).data() == mdata;
+}
+
+bool HierarchyImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( HierarchyImp::stype() ) &&
+ static_cast<const HierarchyImp&>( rhs ).data() == mdata;
+}
+
+bool TransformationImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( TransformationImp::stype() ) &&
+ static_cast<const TransformationImp&>( rhs ).data() == mdata;
+}
+
+bool InvalidImp::canFillInNextEscape() const
+{
+ return true;
+}
+
+bool DoubleImp::canFillInNextEscape() const
+{
+ return true;
+}
+
+bool IntImp::canFillInNextEscape() const
+{
+ return true;
+}
+
+bool StringImp::canFillInNextEscape() const
+{
+ return true;
+}
+
+const ObjectImpType* InvalidImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "invalid", "", "", "", "", "", "", "", "", "" );
+ return &t;
+}
+
+const ObjectImpType* StringImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "string",
+ "string", "", "", "", "", "", "", "", "" );
+ return &t;
+}
+const ObjectImpType* HierarchyImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "hierarchy", "", "", "", "", "", "", "", "", "" );
+ return &t;
+}
+const ObjectImpType* TransformationImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "transformation", "", "", "", "", "", "", "", "", "");
+ return &t;
+}
+
+const ObjectImpType* InvalidImp::type() const
+{
+ return InvalidImp::stype();
+}
+
+const ObjectImpType* DoubleImp::type() const
+{
+ return DoubleImp::stype();
+}
+
+const ObjectImpType* IntImp::type() const
+{
+ return IntImp::stype();
+}
+
+const ObjectImpType* StringImp::type() const
+{
+ return StringImp::stype();
+}
+
+const ObjectImpType* HierarchyImp::type() const
+{
+ return HierarchyImp::stype();
+}
+
+const ObjectImpType* TransformationImp::type() const
+{
+ return TransformationImp::stype();
+}
+
+const ObjectImpType* DoubleImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "double",
+ "double", "", "", "", "", "", "", "", "" );
+ return &t;
+}
+
+const ObjectImpType* IntImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "int",
+ "int", "", "", "", "", "", "", "", "" );
+ return &t;
+}
+
+const ObjectImpType* BogusImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "bogus",
+ "", "", "", "", "", "", "", "", "" );
+ return &t;
+}
+
+const ObjectImpType* TestResultImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "testresult", "", "", "", "", "", "", "", "", "" );
+ return &t;
+
+}
+
+TestResultImp::TestResultImp( const QString& s )
+ : mdata( s )
+{
+}
+
+TestResultImp* TestResultImp::copy() const
+{
+ return new TestResultImp( mdata );
+}
+
+const ObjectImpType* TestResultImp::type() const
+{
+ return stype();
+}
+
+void TestResultImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool TestResultImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( TestResultImp::stype() ) &&
+ static_cast<const TestResultImp&>( rhs ).mdata == mdata;
+
+}
+
+const uint TestResultImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 1;
+}
+
+const QCStringList TestResultImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l << I18N_NOOP( "Test Result" );
+ assert( l.size() == TestResultImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList TestResultImp::propertiesInternalNames() const
+{
+ QCStringList s = Parent::propertiesInternalNames();
+ s << "test-result";
+ assert( s.size() == TestResultImp::numberOfProperties() );
+ return s;
+}
+
+ObjectImp* TestResultImp::property( uint which, const KigDocument& d ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, d );
+ if ( which == Parent::numberOfProperties() )
+ return new StringImp( data() );
+ else assert( false );
+ return new InvalidImp;
+}
+
+const char* TestResultImp::iconForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ if ( which == Parent::numberOfProperties() )
+ return ""; // test-result
+ else assert( false );
+ return "";
+}
+
+const ObjectImpType* TestResultImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return TestResultImp::stype();
+}
+
+bool TestResultImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return false;
+}
+
+Rect BogusImp::surroundingRect() const
+{
+ return Rect::invalidRect();
+}
diff --git a/kig/objects/bogus_imp.h b/kig/objects/bogus_imp.h
new file mode 100644
index 00000000..8e9386a8
--- /dev/null
+++ b/kig/objects/bogus_imp.h
@@ -0,0 +1,281 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef BOGUS_IMP_H
+#define BOGUS_IMP_H
+
+#include "object_imp.h"
+#include "../misc/object_hierarchy.h"
+#include "../misc/kigtransform.h"
+
+#include <qstring.h>
+
+/**
+ * This is the base class for the so-called BogusImp's. These
+ * ObjectImp's are not really ObjectImp's, in that they don't
+ * represent objects. They exist because ObjectImp's also serve
+ * another purpose, namely containing data. They can all be loaded
+ * and saved, and the only difference between these objects and normal
+ * objects are that these serve *only* to be loaded and saved. This
+ * approach adds a lot of flexibility to the Kig system, and has
+ * certainly proven itself very valuable.
+ */
+class BogusImp
+ : public ObjectImp
+{
+ typedef ObjectImp Parent;
+public:
+ /**
+ * Returns the ObjectImpType representing the BogusImp type.
+ */
+ static const ObjectImpType* stype();
+
+ Coordinate attachPoint( ) const;
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& w ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& w ) const;
+ Rect surroundingRect() const;
+
+ ObjectImp* transform( const Transformation& ) const;
+};
+
+/**
+ * This ObjectImp represents an invalid object. If a calculation
+ * fails, then often an InvalidImp is returned, indicating that the
+ * generated object is invalid.
+ */
+class InvalidImp
+ : public BogusImp
+{
+public:
+ /**
+ * Returns the ObjectImpType representing the InvalidImp type.
+ */
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ /**
+ * Construct a new InvalidImp.
+ */
+ InvalidImp();
+ InvalidImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool canFillInNextEscape() const;
+ void fillInNextEscape( QString& s, const KigDocument& ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+/**
+ * This ObjectImp is a BogusImp containing only a double value.
+ */
+class DoubleImp
+ : public BogusImp
+{
+ double mdata;
+public:
+ /**
+ * Returns the ObjectImpType representing the DoubleImp type.
+ */
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ /**
+ * Construct a new DoubleImp containing the value d.
+ */
+ DoubleImp( const double d );
+
+ /**
+ * Get hold of the contained data.
+ */
+ double data() const { return mdata; }
+ /**
+ * Set the contained data to d.
+ */
+ void setData( double d ) { mdata = d; }
+
+ DoubleImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool canFillInNextEscape() const;
+ void fillInNextEscape( QString& s, const KigDocument& ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+/**
+ * This ObjectImp is a BogusImp containing only an int value.
+ */
+class IntImp
+ : public BogusImp
+{
+ int mdata;
+public:
+ /**
+ * Returns the ObjectImpType representing the IntImp type..
+ */
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ /**
+ * Construct a new IntImp containing the value d.
+ */
+ IntImp( const int d );
+
+ /**
+ * Get hold of the contained data.
+ */
+ int data() const { return mdata; }
+ /**
+ * Set the contained data to d.
+ */
+ void setData( int d ) { mdata = d; }
+
+ IntImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool canFillInNextEscape() const;
+ void fillInNextEscape( QString& s, const KigDocument& ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+/**
+ * This ObjectImp is a BogusImp containing only a string value.
+ */
+class StringImp
+ : public BogusImp
+{
+ QString mdata;
+public:
+ /**
+ * Returns the ObjectImpType representing the StringImp type..
+ */
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ /**
+ * Construct a new StringImp containing the string d.
+ */
+ StringImp( const QString& d );
+
+ /**
+ * Get hold of the contained data.
+ */
+ const QString& data() const { return mdata; }
+ /**
+ * Set the contained data.
+ */
+ void setData( const QString& s ) { mdata = s; }
+
+ StringImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool canFillInNextEscape() const;
+ void fillInNextEscape( QString& s, const KigDocument& ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+class HierarchyImp
+ : public BogusImp
+{
+ ObjectHierarchy mdata;
+public:
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ HierarchyImp( const ObjectHierarchy& h );
+
+ const ObjectHierarchy& data() const { return mdata; }
+ void setData( const ObjectHierarchy& h ) { mdata = h; }
+
+ HierarchyImp* copy() const;
+ const char* baseName() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+/**
+ * \internal Don't mistake this imp for something that draws a
+ * transformed object. It does something completely different. It's
+ * a pure data Imp, like DoubleImp and friends that serves only to
+ * store the data of a transformation ( see the Transformation class
+ * in ../misc/kigtransform.h
+ */
+class TransformationImp
+ : public BogusImp
+{
+ Transformation mdata;
+public:
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ TransformationImp( const Transformation& h );
+
+ const Transformation& data() const { return mdata; }
+ void setData( const Transformation& h ) { mdata = h; }
+
+ TransformationImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+class TestResultImp
+ : public BogusImp
+{
+ const QString mdata;
+public:
+ static const ObjectImpType* stype();
+ typedef BogusImp Parent;
+
+ TestResultImp( const QString& s );
+
+ TestResultImp* copy() const;
+
+ const QString& data() const { return mdata; }
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& d ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+#endif
diff --git a/kig/objects/centerofcurvature_type.cc b/kig/objects/centerofcurvature_type.cc
new file mode 100644
index 00000000..8111410f
--- /dev/null
+++ b/kig/objects/centerofcurvature_type.cc
@@ -0,0 +1,304 @@
+// Copyright (C) 2004 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "centerofcurvature_type.h"
+
+#include "bogus_imp.h"
+#include "conic_imp.h"
+#include "cubic_imp.h"
+//#include "other_imp.h"
+#include "point_imp.h"
+//#include "line_imp.h"
+
+#include "../misc/common.h"
+#include "../misc/conic-common.h"
+//#include "../misc/calcpaths.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+
+static const char constructcenterofcurvaturepoint[] = "SHOULDNOTBESEEN";
+// I18N_NOOP( "Construct the center of curvature corresponding to this point" );
+static const char selectcoc1[] = I18N_NOOP( "Select the curve..." );
+static const char selectcoc2[] = I18N_NOOP( "Select a point on the curve..." );
+
+static const ArgsParser::spec argsspecCocConic[] =
+{
+ { ConicImp::stype(), "SHOULDNOTBESEEN", selectcoc1, false },
+ { PointImp::stype(), constructcenterofcurvaturepoint, selectcoc2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CocConicType )
+
+CocConicType::CocConicType()
+ : ArgsParserObjectType( "CocConic", argsspecCocConic, 2 )
+{
+}
+
+CocConicType::~CocConicType()
+{
+}
+
+const CocConicType* CocConicType::instance()
+{
+ static const CocConicType t;
+ return &t;
+}
+
+ObjectImp* CocConicType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const ConicImp* conic = static_cast<const ConicImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+
+ if ( !conic->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ double x = p.x;
+ double y = p.y;
+ ConicCartesianData data = conic->cartesianData();
+// double aconst = data.coeffs[5];
+ double ax = data.coeffs[3];
+ double ay = data.coeffs[4];
+ double axx = data.coeffs[0];
+ double axy = data.coeffs[2];
+ double ayy = data.coeffs[1];
+
+/*
+ * mp: we need to compute the normal vector and the curvature
+ * of the curve. The curve (conic) is given in implicit form
+ * f(x,y) = 0; the gradient of f gives the direction of the
+ * normal; for the curvature we can use the following formula:
+ * k = div(grad f/|grad f|)
+ *
+ * the hessian matrix has elements [hfxx, hfxy]
+ * [hfxy, hfyy]
+ *
+ * kgf is the curvature multiplied by the norm of grad f
+ */
+
+ double gradfx = 2*axx*x + axy*y + ax;
+ double gradfy = axy*x + 2*ayy*y + ay;
+ Coordinate gradf = Coordinate ( gradfx, gradfy );
+
+ double hfxx = 2*axx;
+ double hfyy = 2*ayy;
+ double hfxy = axy;
+
+ double kgf = hfxx + hfyy
+ - (hfxx*gradfx*gradfx + hfyy*gradfy*gradfy + 2*hfxy*gradfx*gradfy)
+ /(gradfx*gradfx + gradfy*gradfy);
+
+ bool ok = true;
+
+ const Coordinate coc = p - 1/kgf*gradf;
+
+ if ( !ok )
+ return new InvalidImp;
+
+ return new PointImp( coc );
+}
+
+const ObjectImpType* CocConicType::resultId() const
+{
+ return PointImp::stype();
+}
+
+/**** Cubic starts here ****/
+
+static const ArgsParser::spec argsspecCocCubic[] =
+{
+ { CubicImp::stype(), "SHOULDNOTBESEEN", selectcoc1, false },
+ { PointImp::stype(), constructcenterofcurvaturepoint, selectcoc2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CocCubicType )
+
+CocCubicType::CocCubicType()
+ : ArgsParserObjectType( "CocCubic", argsspecCocCubic, 2 )
+{
+}
+
+CocCubicType::~CocCubicType()
+{
+}
+
+const CocCubicType* CocCubicType::instance()
+{
+ static const CocCubicType t;
+ return &t;
+}
+
+ObjectImp* CocCubicType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const CubicImp* cubic = static_cast<const CubicImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+
+ if ( !cubic->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ double x = p.x;
+ double y = p.y;
+ CubicCartesianData data = cubic->data();
+// double aconst = data.coeffs[0];
+ double ax = data.coeffs[1];
+ double ay = data.coeffs[2];
+ double axx = data.coeffs[3];
+ double axy = data.coeffs[4];
+ double ayy = data.coeffs[5];
+ double axxx = data.coeffs[6];
+ double axxy = data.coeffs[7];
+ double axyy = data.coeffs[8];
+ double ayyy = data.coeffs[9];
+
+ /*
+ * we use here the same mechanism as for the
+ * conics, see above
+ */
+
+ double gradfx = 3*axxx*x*x + 2*axxy*x*y + axyy*y*y + 2*axx*x + axy*y + ax;
+ double gradfy = axxy*x*x + 2*axyy*x*y + 3*ayyy*y*y + axy*x + 2*ayy*y + ay;
+ Coordinate gradf = Coordinate ( gradfx, gradfy );
+
+ double hfxx = 6*axxx*x + 2*axxy*y + 2*axx;
+ double hfyy = 6*ayyy*y + 2*axyy*x + 2*ayy;
+ double hfxy = 2*axxy*x + 2*axyy*y + axy;
+
+ double kgf = hfxx + hfyy
+ - (hfxx*gradfx*gradfx + hfyy*gradfy*gradfy + 2*hfxy*gradfx*gradfy)
+ /(gradfx*gradfx + gradfy*gradfy);
+
+ bool ok = true;
+
+ const Coordinate coc = p - 1/kgf*gradf;
+
+ if ( !ok )
+ return new InvalidImp;
+
+ return new PointImp( coc );
+}
+
+const ObjectImpType* CocCubicType::resultId() const
+{
+ return PointImp::stype();
+}
+
+/**** Curve starts here ****/
+
+static const ArgsParser::spec argsspecCocCurve[] =
+{
+ { CurveImp::stype(), "SHOULDNOTBESEEN", selectcoc1, false },
+ { PointImp::stype(), constructcenterofcurvaturepoint, selectcoc2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CocCurveType )
+
+CocCurveType::CocCurveType()
+ : ArgsParserObjectType( "CocCurve", argsspecCocCurve, 2 )
+{
+}
+
+CocCurveType::~CocCurveType()
+{
+}
+
+const CocCurveType* CocCurveType::instance()
+{
+ static const CocCurveType t;
+ return &t;
+}
+
+ObjectImp* CocCurveType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const CurveImp* curve = static_cast<const CurveImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+
+ if ( !curve->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+
+ const double t = curve->getParam( p, doc );
+ const double tau0 = 5e-4;
+ const double sigmasq = 1e-12;
+ const int maxiter = 20;
+
+ double tau = tau0;
+ Coordinate gminus, g, gplus, tang, acc, curv, err;
+ double velsq, curvsq;
+ double tplus = t + tau;
+ double tminus = t - tau;
+ double t0 = t;
+ if ( tplus > 1 ) {tplus = 1; t0 = 1 - tau; tminus = 1 - 2*tau;}
+ if ( tminus < 0 ) {tminus = 0; t0 = tau; tplus = 2*tau;}
+ gminus = curve->getPoint( tminus, doc );
+ g = curve->getPoint( t0, doc );
+ gplus = curve->getPoint( tplus, doc );
+ tang = (gplus - gminus)/(2*tau);
+ acc = (gminus + gplus - 2*g)/(tau*tau);
+ velsq = tang.x*tang.x + tang.y*tang.y;
+ tang = tang/velsq;
+ Coordinate curvold = acc/velsq - (acc.x*tang.x + acc.y*tang.y)*tang;
+ curvsq = curvold.x*curvold.x + curvold.y*curvold.y;
+ curvold = curvold/curvsq;
+
+ for (int i = 0; i < maxiter; i++)
+ {
+ tau = tau/2;
+ tplus = t + tau;
+ tminus = t - tau;
+ t0 = t;
+ if ( tplus > 1 ) {tplus = 1; t0 = 1 - tau; tminus = 1 - 2*tau;}
+ if ( tminus < 0 ) {tminus = 0; t0 = tau; tplus = 2*tau;}
+
+ gminus = curve->getPoint( tminus, doc );
+ g = curve->getPoint( t0, doc );
+ gplus = curve->getPoint( tplus, doc );
+ tang = (gplus - gminus)/(2*tau);
+ acc = (gminus + gplus - 2*g)/(tau*tau);
+ velsq = tang.x*tang.x + tang.y*tang.y;
+ tang = tang/velsq;
+ curv = acc/velsq - (acc.x*tang.x + acc.y*tang.y)*tang;
+ curvsq = curv.x*curv.x + curv.y*curv.y;
+ curv = curv/curvsq;
+
+ err = (curvold - curv)/3;
+ /*
+ * curvsq is the inverse squared of the norm of curvsq
+ * so this is actually a relative test
+ * in the end we return an extrapolated value
+ */
+ if (err.squareLength() < sigmasq/curvsq)
+ {
+ curv = (4*curv - curvold)/3;
+ return new PointImp( p + curv );
+ }
+ curvold = curv;
+ }
+ return new InvalidImp;
+}
+
+const ObjectImpType* CocCurveType::resultId() const
+{
+ return PointImp::stype();
+}
diff --git a/kig/objects/centerofcurvature_type.h b/kig/objects/centerofcurvature_type.h
new file mode 100644
index 00000000..18dfc42a
--- /dev/null
+++ b/kig/objects/centerofcurvature_type.h
@@ -0,0 +1,68 @@
+// Copyright (C) 2004 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_CENTEROFCURVATURE_TYPE_H
+#define KIG_OBJECTS_CENTEROFCURVATURE_TYPE_H
+
+#include "base_type.h"
+
+/**
+ * the center of curvature of a conic at a point
+ */
+class CocConicType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ CocConicType();
+ ~CocConicType();
+public:
+ static const CocConicType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * the center of curvature of a cubic at a point
+ */
+class CocCubicType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ CocCubicType();
+ ~CocCubicType();
+public:
+ static const CocCubicType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * the center of curvature of a curve at a point
+ */
+class CocCurveType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ CocCurveType();
+ ~CocCurveType();
+public:
+ static const CocCurveType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/circle_imp.cc b/kig/objects/circle_imp.cc
new file mode 100644
index 00000000..13ceef93
--- /dev/null
+++ b/kig/objects/circle_imp.cc
@@ -0,0 +1,356 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "circle_imp.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+
+#include "../misc/kigtransform.h"
+#include "../misc/kigpainter.h"
+#include "../misc/coordinate_system.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+#include <math.h>
+
+CircleImp::CircleImp( const Coordinate& center, double radius )
+ : mcenter( center ), mradius( radius )
+{
+}
+
+CircleImp::~CircleImp()
+{
+}
+
+ObjectImp* CircleImp::transform( const Transformation& t ) const
+{
+ if ( t.isHomothetic() )
+ {
+ Coordinate nc = t.apply( mcenter );
+ double nr = t.apply( mradius );
+ if ( nc.valid() )
+ return new CircleImp( nc, nr );
+ else return new InvalidImp;
+ }
+ else
+ {
+ // domi: i should return a ConicImp here, but i don't know how to
+ // calculate it..
+ return Parent::transform( t );
+ };
+}
+
+void CircleImp::draw( KigPainter& p ) const
+{
+ p.drawCircle( mcenter, mradius );
+}
+
+bool CircleImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ return fabs((mcenter - p).length() - mradius) <= w.screenInfo().normalMiss( width );
+}
+
+bool CircleImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ // first we check if the rect contains at least one of the
+ // north/south/east/west points of the circle
+ if ( r.contains( mcenter + Coordinate( 0, -mradius ) ) ) return true;
+ if ( r.contains( mcenter + Coordinate( mradius, 0 ) ) ) return true;
+ if ( r.contains( mcenter + Coordinate( 0, mradius ) ) ) return true;
+ if ( r.contains( mcenter + Coordinate( -mradius, 0 ) ) ) return true;
+
+ // we allow a miss of some pixels ..
+ double miss = w.screenInfo().normalMiss( width );
+ double bigradius = mradius + miss;
+ bigradius *= bigradius;
+ double smallradius = mradius - miss;
+ smallradius *= smallradius;
+
+ const int in = -1;
+ const int undecided = 0;
+ const int out = 1;
+
+ int inorout = undecided;
+
+ Coordinate coords[4];
+ coords[0] = r.topLeft();
+ coords[1] = r.topRight();
+ coords[2] = r.bottomRight();
+ coords[3] = r.bottomLeft();
+
+ // we check if the corners of the rect are either
+ for ( Coordinate* i = coords; i < coords + 4; ++i )
+ {
+ double t = ( *i - mcenter ).squareLength();
+ if ( t >= bigradius )
+ {
+ if ( inorout == in ) return true;
+ inorout = out;
+ }
+ else if ( t <= smallradius )
+ {
+ if ( inorout == out ) return true;
+ inorout = in;
+ }
+ }
+ return inorout == undecided;
+}
+
+bool CircleImp::valid() const
+{
+ return true;
+}
+
+const uint CircleImp::numberOfProperties() const
+{
+ // We _intentionally_ do not use the Conic properties..
+ return CurveImp::numberOfProperties() + 7;
+}
+
+const QCStringList CircleImp::propertiesInternalNames() const
+{
+ QCStringList l = CurveImp::propertiesInternalNames();
+ l << "surface";
+ l << "circumference";
+ l << "radius";
+ l << "center";
+ l << "cartesian-equation";
+ l << "simply-cartesian-equation";
+ l << "polar-equation";
+ assert( l.size() == CircleImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList CircleImp::properties() const
+{
+ QCStringList l = CurveImp::properties();
+ l << I18N_NOOP( "Surface" );
+ l << I18N_NOOP( "Circumference" );
+ l << I18N_NOOP( "Radius" );
+ l << I18N_NOOP( "Center" );
+ l << I18N_NOOP( "Expanded Cartesian Equation" );
+ l << I18N_NOOP( "Cartesian Equation" );
+ l << I18N_NOOP( "Polar Equation" );
+ assert( l.size() == CircleImp::numberOfProperties() );
+ return l;
+}
+
+const ObjectImpType* CircleImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < CurveImp::numberOfProperties() )
+ return CurveImp::impRequirementForProperty( which );
+ else return CircleImp::stype();
+}
+
+const char* CircleImp::iconForProperty( uint which ) const
+{
+ assert( which < CircleImp::numberOfProperties() );
+ if ( which < CurveImp::numberOfProperties() )
+ return CurveImp::iconForProperty( which );
+ else if ( which == CurveImp::numberOfProperties() )
+ return "areaCircle"; // surface
+ else if ( which == CurveImp::numberOfProperties() + 1 )
+ return "circumference"; // circumference
+ else if ( which == CurveImp::numberOfProperties() + 2 )
+ return ""; //radius
+ else if ( which == CurveImp::numberOfProperties() + 3 )
+ return "baseCircle"; // circle center
+ else if ( which == CurveImp::numberOfProperties() + 4 )
+ return "kig_text"; // cartesian equation
+ else if ( which == CurveImp::numberOfProperties() + 5 )
+ return "kig_text"; // simply cartesian equation
+ else if ( which == CurveImp::numberOfProperties() + 6 )
+ return "kig_text"; // polar equation
+ else assert( false );
+ return "";
+}
+
+ObjectImp* CircleImp::property( uint which, const KigDocument& w ) const
+{
+ assert( which < CircleImp::numberOfProperties() );
+ if ( which < CurveImp::numberOfProperties() )
+ return CurveImp::property( which, w );
+ if ( which == CurveImp::numberOfProperties() )
+ return new DoubleImp( surface() );
+ else if ( which == CurveImp::numberOfProperties() + 1 )
+ return new DoubleImp( circumference() );
+ else if ( which == CurveImp::numberOfProperties() + 2 )
+ return new DoubleImp( radius() );
+ else if ( which == CurveImp::numberOfProperties() + 3 )
+ return new PointImp( center() );
+ else if ( which == CurveImp::numberOfProperties() + 4 )
+ return new StringImp( cartesianEquationString( w ) );
+ else if ( which == CurveImp::numberOfProperties() + 5 )
+ return new StringImp( simplyCartesianEquationString( w ) );
+ else if ( which == CurveImp::numberOfProperties() + 6 )
+ return new StringImp( polarEquationString( w ) );
+ else assert( false );
+ return new InvalidImp;
+}
+
+const Coordinate CircleImp::center() const
+{
+ return mcenter;
+}
+
+double CircleImp::radius() const
+{
+ return mradius;
+}
+
+double CircleImp::surface() const
+{
+ return M_PI * squareRadius();
+}
+
+double CircleImp::squareRadius() const
+{
+ return mradius * mradius;
+}
+
+double CircleImp::circumference() const
+{
+ return 2 * M_PI * radius();
+}
+
+QString CircleImp::polarEquationString( const KigDocument& w ) const
+{
+ QString ret = i18n( "rho = %1 [centered at %2]" );
+ ConicPolarData data = polarData();
+ ret = ret.arg( data.pdimen, 0, 'g', 3 );
+ ret = ret.arg( w.coordinateSystem().fromScreen( data.focus1, w ) );
+ return ret;
+}
+
+QString CircleImp::cartesianEquationString( const KigDocument& ) const
+{
+ QString ret = i18n( "x² + y² + %1 x + %2 y + %3 = 0" );
+ ConicCartesianData data = cartesianData();
+ ret = ret.arg( data.coeffs[3], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[4], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[5], 0, 'g', 3 );
+ return ret;
+}
+
+QString CircleImp::simplyCartesianEquationString( const KigDocument& ) const
+{
+ QString ret = i18n( "( x - %1 )² + ( y - %2 )² = %3" );
+ ret = ret.arg( mcenter.x, 0, 'g', 3 );
+ ret = ret.arg( mcenter.y, 0, 'g', 3 );
+ ret = ret.arg( mradius * mradius, 0, 'g', 3 );
+ return ret;
+}
+
+Coordinate CircleImp::focus1() const
+{
+ return center();
+}
+
+Coordinate CircleImp::focus2() const
+{
+ return center();
+}
+
+int CircleImp::conicType() const
+{
+ return 1;
+}
+
+const ConicCartesianData CircleImp::cartesianData() const
+{
+ Coordinate c = center();
+ double sqr = squareRadius();
+ ConicCartesianData data(
+ 1.0, 1.0, 0.0, -2*c.x, -2*c.y,
+ c.x*c.x + c.y*c.y - sqr );
+ return data;
+}
+
+const ConicPolarData CircleImp::polarData() const
+{
+ return ConicPolarData( center(), radius(), 0, 0 );
+}
+
+CircleImp* CircleImp::copy() const
+{
+ return new CircleImp( mcenter, mradius );
+}
+
+double CircleImp::getParam( const Coordinate& point, const KigDocument& ) const
+{
+ Coordinate tmp = point - mcenter;
+ double ret = atan2(tmp.y, tmp.x) / ( 2 * M_PI );
+ if ( ret > 0 ) return ret;
+ else return ret + 1;
+}
+
+const Coordinate CircleImp::getPoint( double p, const KigDocument& ) const
+{
+ return mcenter + Coordinate (cos(p * 2 * M_PI), sin(p * 2 * M_PI)) * mradius;
+}
+
+void CircleImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool CircleImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( CircleImp::stype() ) &&
+ static_cast<const CircleImp&>( rhs ).center() == center() &&
+ static_cast<const CircleImp&>( rhs ).radius() == radius();
+}
+
+const ObjectImpType* CircleImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "circle",
+ I18N_NOOP( "circle" ),
+ I18N_NOOP( "Select this circle" ),
+ I18N_NOOP( "Select circle %1" ),
+ I18N_NOOP( "Remove a Circle" ),
+ I18N_NOOP( "Add a Circle" ),
+ I18N_NOOP( "Move a Circle" ),
+ I18N_NOOP( "Attach to this circle" ),
+ I18N_NOOP( "Show a Circle" ),
+ I18N_NOOP( "Hide a Circle" )
+ );
+ return &t;
+}
+
+const ObjectImpType* CircleImp::type() const
+{
+ return CircleImp::stype();
+}
+
+bool CircleImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ assert( which < CircleImp::numberOfProperties() );
+ if ( which < CurveImp::numberOfProperties() )
+ return CurveImp::isPropertyDefinedOnOrThroughThisImp( which );
+ return false;
+}
+
+Rect CircleImp::surroundingRect() const
+{
+ Coordinate d( mradius, mradius );
+ return Rect( mcenter - d, mcenter + d );
+}
diff --git a/kig/objects/circle_imp.h b/kig/objects/circle_imp.h
new file mode 100644
index 00000000..d38716a6
--- /dev/null
+++ b/kig/objects/circle_imp.h
@@ -0,0 +1,125 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_CIRCLE_IMP_H
+#define KIG_OBJECTS_CIRCLE_IMP_H
+
+#include "conic_imp.h"
+
+/**
+ * An ObjectImp representing a circle. This class is a subclass of
+ * ConicImp, ensuring that a circle can be used as a conic.
+ */
+class CircleImp
+ : public ConicImp
+{
+ Coordinate mcenter;
+ double mradius;
+public:
+ typedef ConicImp Parent;
+ /**
+ * Returns the ObjectImpType representing the CircleImp type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct a Circle with a given center and radius.
+ */
+ CircleImp( const Coordinate& center, double radius );
+ ~CircleImp();
+ CircleImp* copy() const;
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ bool valid() const;
+ Rect surroundingRect() const;
+
+ double getParam( const Coordinate& point, const KigDocument& ) const;
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ /**
+ * Return the center of this circle.
+ */
+ const Coordinate center() const;
+ /**
+ * Return the radius of this circle.
+ */
+ double radius() const;
+ /**
+ * Return the square radius of this circle. Use this in preference
+ * to sqr( radius() ).
+ */
+ double squareRadius() const;
+ /**
+ * Return the surface of this circle.
+ */
+ double surface() const;
+ /**
+ * Return the circumference of this circle.
+ */
+ double circumference() const;
+
+ // trivial versions of the conic information functions..
+ /**
+ * Always returns 1, since a circle always is an ellipse.
+ */
+ int conicType() const;
+ const ConicCartesianData cartesianData() const;
+ const ConicPolarData polarData() const;
+ /**
+ * The first focus of a circle is simply its center.
+ */
+ Coordinate focus1() const;
+ /**
+ * The second focus of a circle is simply its center.
+ */
+ Coordinate focus2() const;
+
+ /**
+ * Return a string containing the cartesian equation of this circle.
+ * This will be of the form "x^2 + y^2 + a x + b y + c = 0"
+ */
+ QString cartesianEquationString( const KigDocument& w ) const;
+ /**
+ * Return a string containing the cartesian equation of this circle.
+ * This will be of the form "( x - x0 )^2 + ( y - y0 )^2 = r^2"
+ */
+ QString simplyCartesianEquationString( const KigDocument& w ) const;
+ /**
+ * Return a string containing the polar equation of this circle.
+ * This will be of the form "rho = r [centered at p]"
+ */
+ QString polarEquationString( const KigDocument& w ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+#endif
diff --git a/kig/objects/circle_type.cc b/kig/objects/circle_type.cc
new file mode 100644
index 00000000..97d2f615
--- /dev/null
+++ b/kig/objects/circle_type.cc
@@ -0,0 +1,181 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "circle_type.h"
+
+#include "circle_imp.h"
+#include "bogus_imp.h"
+#include "line_imp.h"
+#include "point_imp.h"
+
+#include "../misc/common.h"
+
+#include <klocale.h>
+
+static const char constructcirclethroughpointstat[] = I18N_NOOP( "Construct a circle through this point" );
+
+static const char constructcirclewithcenterstat[] = I18N_NOOP( "Construct a circle with this center" );
+
+static const ArgsParser::spec argsspecCircleBCP[] =
+{
+ { PointImp::stype(), constructcirclewithcenterstat,
+ I18N_NOOP( "Select the center of the new circle..." ), false },
+ { PointImp::stype(), constructcirclethroughpointstat,
+ I18N_NOOP( "Select a point for the new circle to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CircleBCPType )
+
+CircleBCPType::CircleBCPType()
+ : ObjectABType( "CircleBCP", argsspecCircleBCP, 2 )
+{
+}
+
+CircleBCPType::~CircleBCPType()
+{
+}
+
+const CircleBCPType* CircleBCPType::instance()
+{
+ static const CircleBCPType s;
+ return &s;
+}
+
+ObjectImp* CircleBCPType::calc( const Coordinate& a, const Coordinate& b ) const
+{
+ return new CircleImp( a, ( b - a ).length() );
+}
+
+const CircleBTPType* CircleBTPType::instance()
+{
+ static const CircleBTPType t;
+ return &t;
+}
+
+static const ArgsParser::spec argsspecCircleBTP[] =
+{
+ { PointImp::stype(), constructcirclethroughpointstat,
+ I18N_NOOP( "Select a point for the new circle to go through..." ), true },
+ { PointImp::stype(), constructcirclethroughpointstat,
+ I18N_NOOP( "Select a point for the new circle to go through..." ), true },
+ { PointImp::stype(), constructcirclethroughpointstat,
+ I18N_NOOP( "Select a point for the new circle to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CircleBTPType )
+
+CircleBTPType::CircleBTPType()
+ : ArgsParserObjectType( "CircleBTP", argsspecCircleBTP, 3 )
+{
+}
+
+CircleBTPType::~CircleBTPType()
+{
+}
+
+ObjectImp* CircleBTPType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args, 2 ) ) return new InvalidImp;
+
+ const Coordinate a = static_cast<const PointImp*>( args[0] )->coordinate();
+ const Coordinate b = static_cast<const PointImp*>( args[1] )->coordinate();
+ Coordinate c;
+ if ( args.size() == 3 )
+ c = static_cast<const PointImp*>( args[2] )->coordinate();
+ else
+ {
+ // we pick the third point so that the three points form a
+ // triangle with equal sides...
+
+ // midpoint:
+ Coordinate m = ( b + a ) / 2;
+ if ( b.y != a.y )
+ {
+ // direction of the perpend:
+ double d = -(b.x-a.x)/(b.y-a.y);
+
+ // length:
+ // sqrt( 3 ) == tan( 60° ) == sqrt( 2^2 - 1^2 )
+ double l = 1.73205080756 * (a-b).length() / 2;
+
+ double d2 = d*d;
+ double l2 = l*l;
+ double dx = sqrt( l2 / ( d2 + 1 ) );
+ double dy = sqrt( l2 * d2 / ( d2 + 1 ) );
+ if( d < 0 ) dy = -dy;
+
+ c.x = m.x + dx;
+ c.y = m.y + dy;
+ }
+ else
+ {
+ c.x = m.x;
+ c.y = m.y + ( a.x - b.x );
+ };
+ };
+
+ const Coordinate center = calcCenter( a, b, c );
+ if ( center.valid() )
+ return new CircleImp( center, (center - a ).length() );
+ else return new InvalidImp;
+}
+
+const ObjectImpType* CircleBCPType::resultId() const
+{
+ return CircleImp::stype();
+}
+
+const ObjectImpType* CircleBTPType::resultId() const
+{
+ return CircleImp::stype();
+}
+
+static const ArgsParser::spec argsspecCircleBPR[] =
+{
+ { PointImp::stype(), "SHOULD NOT BE SEEN", "SHOULD NOT BE SEEN", false },
+ { DoubleImp::stype(), "SHOULD NOT BE SEEN", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CircleBPRType )
+
+CircleBPRType::CircleBPRType()
+ : ArgsParserObjectType( "CircleBPR", argsspecCircleBPR, 2 )
+{
+}
+
+CircleBPRType::~CircleBPRType()
+{
+}
+
+const CircleBPRType* CircleBPRType::instance()
+{
+ static const CircleBPRType t;
+ return &t;
+}
+
+ObjectImp* CircleBPRType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+ const Coordinate c = static_cast<const PointImp*>( args[0] )->coordinate();
+ double r = static_cast<const DoubleImp*>( args[1] )->data();
+ return new CircleImp( c, r );
+}
+
+const ObjectImpType* CircleBPRType::resultId() const
+{
+ return CircleImp::stype();
+}
diff --git a/kig/objects/circle_type.h b/kig/objects/circle_type.h
new file mode 100644
index 00000000..874d0b69
--- /dev/null
+++ b/kig/objects/circle_type.h
@@ -0,0 +1,69 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_CIRCLE_TYPE_H
+#define KIG_OBJECTS_CIRCLE_TYPE_H
+
+#include "base_type.h"
+
+/**
+ * Circle by center and point
+ */
+class CircleBCPType
+ : public ObjectABType
+{
+ CircleBCPType();
+ ~CircleBCPType();
+public:
+ static const CircleBCPType* instance();
+
+ ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * Circle by point and radius.
+ */
+class CircleBPRType
+ : public ArgsParserObjectType
+{
+ CircleBPRType();
+ ~CircleBPRType();
+public:
+ static const CircleBPRType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * Circle by three points
+ */
+class CircleBTPType
+ : public ArgsParserObjectType
+{
+ CircleBTPType();
+ ~CircleBTPType();
+
+public:
+ static const CircleBTPType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/common.cc b/kig/objects/common.cc
new file mode 100644
index 00000000..9932734c
--- /dev/null
+++ b/kig/objects/common.cc
@@ -0,0 +1,43 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "common.h"
+#include "object_holder.h"
+
+std::vector<ObjectCalcer*> getAllCalcers( const std::vector<ObjectHolder*>& os )
+{
+ std::set<ObjectCalcer*> ret;
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ {
+ if ( ( *i )->nameCalcer() )
+ ret.insert( ( *i )->nameCalcer() );
+ ret.insert( ( *i )->calcer() );
+ }
+ return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
+}
+
+std::vector<ObjectCalcer*> getCalcers( const std::vector<ObjectHolder*>& os )
+{
+ std::vector<ObjectCalcer*> ret;
+ ret.reserve( os.size() );
+ for ( std::vector<ObjectHolder*>::const_iterator i = os.begin();
+ i != os.end(); ++i )
+ ret.push_back( ( *i )->calcer() );
+ return ret;
+}
+
diff --git a/kig/objects/common.h b/kig/objects/common.h
new file mode 100644
index 00000000..a26a92cd
--- /dev/null
+++ b/kig/objects/common.h
@@ -0,0 +1,107 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_COMMON_H
+#define KIG_OBJECTS_COMMON_H
+
+#include <set>
+#include <vector>
+#include <qcstring.h>
+#include <qvaluelist.h>
+#include <qstringlist.h>
+#include <cassert>
+#include <klocale.h>
+
+class Coordinate;
+class KigDocument;
+class KigPainter;
+class KigPart;
+class KigWidget;
+class NormalMode;
+class ObjectCalcer;
+class ObjectDrawer;
+class ObjectHolder;
+class ObjectImp;
+class ObjectImpType;
+class ObjectPropertyCalcer;
+class ObjectType;
+class ObjectTypeCalcer;
+class QDomDocument;
+class QDomElement;
+class Rect;
+class ScreenInfo;
+class Transformation;
+
+typedef std::vector<const ObjectImp*> Args;
+typedef QValueList<QCString> QCStringList;
+
+template<typename T>
+void delete_all( T begin, T end )
+{
+ for( ; begin != end; ++begin )
+ {
+ delete *begin;
+ }
+}
+
+/**
+ * get the calcers that the holders represent and their namecalcers
+ */
+std::vector<ObjectCalcer*> getAllCalcers( const std::vector<ObjectHolder*>& os );
+
+/**
+ * get the calcers that the holders represent ( not their namecalcers )
+ */
+std::vector<ObjectCalcer*> getCalcers( const std::vector<ObjectHolder*>& os );
+
+/**
+ * The below is a trick. ObjectType's implement the singleton
+ * pattern. There can be only one of them at each time. This one
+ * instance of them needs to be constructed at some time, within the
+ * following restrictions:
+ *
+ * 1. They need to be constructed in the right order: if one ObjectType
+ * uses another in its constructor, the other needs to be constructed
+ * first. To achieve this, we use a scheme with ::instance()
+ * functions, that have a static variable in the body of the function
+ * ( if we would define them static outside of the function body, C++
+ * would provide no guarantee on the order they would be called in ).
+ *
+ * 2. They need to be constructed before Kig tries to use them. They
+ * need to be added to the ObjectTypeFactory before anyone tries to
+ * use that class to fetch a type. The below is a trick to achieve
+ * that in combination with the previous. Basically, we add a fake
+ * static instance of an empty class that receives the instance of the
+ * ObjectType as an argument to its constructor. C++ then guarantees
+ * that these things will be constructed before main() is entered.
+ *
+ * Thus, for your own ObjectType classes: use the scheme with the
+ * static ::instance methods, and add
+ * \code
+ * KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( MyObjectType)
+ * \endcode
+ * to the .cpp file of your class.
+ */
+class FakeClass {
+public:
+ FakeClass( const ObjectType* ) {
+ }
+};
+
+#define KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( type ) static class FakeClass _fake_class_instance_##type( type::instance() );
+
+#endif
diff --git a/kig/objects/conic_imp.cc b/kig/objects/conic_imp.cc
new file mode 100644
index 00000000..a65d8511
--- /dev/null
+++ b/kig/objects/conic_imp.cc
@@ -0,0 +1,385 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "conic_imp.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+
+#include "../misc/kigpainter.h"
+#include "../misc/common.h"
+#include "../misc/coordinate_system.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+ObjectImp* ConicImp::transform( const Transformation& t ) const
+{
+ bool valid = true;
+ ConicCartesianData d = calcConicTransformation( cartesianData(), t, valid );
+ if ( ! valid ) return new InvalidImp;
+ else return new ConicImpCart( d );
+}
+
+void ConicImp::draw( KigPainter& p ) const
+{
+ p.drawCurve( this );
+}
+
+bool ConicImp::valid() const
+{
+ return true;
+}
+
+bool ConicImp::contains( const Coordinate& o, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( o, w.screenInfo().normalMiss( width ) );
+}
+
+bool ConicImp::inRect( const Rect&, int, const KigWidget& ) const
+{
+ // TODO
+ return false;
+}
+
+const uint ConicImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 5;
+}
+
+const QCStringList ConicImp::propertiesInternalNames() const
+{
+ QCStringList l = Parent::propertiesInternalNames();
+ l << "type";
+ l << "first-focus";
+ l << "second-focus";
+ l << "cartesian-equation";
+ l << "polar-equation";
+ assert( l.size() == ConicImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList ConicImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l << I18N_NOOP( "Conic Type" );
+ l << I18N_NOOP( "First Focus" );
+ l << I18N_NOOP( "Second Focus" );
+ l << I18N_NOOP( "Cartesian Equation" );
+ l << I18N_NOOP( "Polar Equation" );
+ assert( l.size() == ConicImp::numberOfProperties() );
+ return l;
+}
+
+const ObjectImpType* ConicImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return ConicImp::stype();
+}
+
+const char* ConicImp::iconForProperty( uint which ) const
+{
+ int pnum = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ if ( which == Parent::numberOfProperties() + pnum++ )
+ return "kig_text"; // conic type string
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return ""; // focus1
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return ""; // focus2
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return "kig_text"; // cartesian equation string
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return "kig_text"; // polar equation string
+ else assert( false );
+ return "";
+}
+
+ObjectImp* ConicImp::property( uint which, const KigDocument& w ) const
+{
+ int pnum = 0;
+
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ if ( which == Parent::numberOfProperties() + pnum++ )
+ return new StringImp( conicTypeString() );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new PointImp( focus1() );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new PointImp( focus2() );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new StringImp( cartesianEquationString( w ) );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new StringImp( polarEquationString( w ) );
+ else assert( false );
+ return new InvalidImp;
+}
+
+double ConicImp::getParam( const Coordinate& p, const KigDocument& ) const
+{
+ const ConicPolarData d = polarData();
+ Coordinate tmp = p - d.focus1;
+ double l = tmp.length();
+ double theta = atan2(tmp.y, tmp.x);
+ double costheta = cos(theta);
+ double sintheta = sin(theta);
+ double ecosthetamtheta0 = costheta*d.ecostheta0 + sintheta*d.esintheta0;
+ double esinthetamtheta0 = sintheta*d.ecostheta0 - costheta*d.esintheta0;
+ double oneplus = 1.0 + d.ecostheta0*d.ecostheta0 + d.esintheta0*d.esintheta0;
+ double fact = esinthetamtheta0*(1.0 - ecosthetamtheta0)/(oneplus - 2*ecosthetamtheta0);
+// fact is sin(a)*cos(a) where a is the angle between the ray from the first
+// focus and the normal to the conic. We need it in order to adjust the
+// angle according to the projection onto the conic of our point
+ double rho1 = d.pdimen / (1 - ecosthetamtheta0);
+ double rho2 = - d.pdimen / (1 + ecosthetamtheta0);
+ if (fabs(rho1 - l) < fabs(rho2 - l))
+ {
+ theta += (rho1 - l)*fact/rho1;
+ return fmod(theta / ( 2 * M_PI ) + 1, 1);
+ } else {
+ theta += (rho2 - l)*fact/rho2;
+ return fmod(theta / ( 2 * M_PI ) + 0.5, 1);
+ }
+}
+
+const Coordinate ConicImp::getPoint( double p, const KigDocument& ) const
+{
+ const ConicPolarData d = polarData();
+
+ double costheta = cos(p * 2 * M_PI);
+ double sintheta = sin(p * 2 * M_PI);
+ double rho = d.pdimen / (1 - costheta* d.ecostheta0 - sintheta* d.esintheta0);
+ return d.focus1 + Coordinate (costheta, sintheta) * rho;
+}
+
+int ConicImp::conicType() const
+{
+ const ConicPolarData d = polarData();
+ double ec = d.ecostheta0;
+ double es = d.esintheta0;
+ double esquare = ec*ec + es*es;
+ const double parabolamiss = 1e-3; // don't know what a good value could be
+
+ if (esquare < 1.0 - parabolamiss) return 1;
+ if (esquare > 1.0 + parabolamiss) return -1;
+
+ return 0;
+}
+
+QString ConicImp::conicTypeString() const
+{
+ switch (conicType())
+ {
+ case 1:
+ return i18n("Ellipse");
+ case -1:
+ return i18n("Hyperbola");
+ case 0:
+ return i18n("Parabola");
+ default:
+ assert( false );
+ return "";
+ }
+}
+
+QString ConicImp::cartesianEquationString( const KigDocument& ) const
+{
+ QString ret = i18n( "%1 x² + %2 y² + %3 xy + %4 x + %5 y + %6 = 0" );
+ ConicCartesianData data = cartesianData();
+ ret = ret.arg( data.coeffs[0], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[1], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[2], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[3], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[4], 0, 'g', 3 );
+ ret = ret.arg( data.coeffs[5], 0, 'g', 3 );
+ return ret;
+}
+
+QString ConicImp::polarEquationString( const KigDocument& w ) const
+{
+ QString ret = i18n( "rho = %1/(1 + %2 cos theta + %3 sin theta)\n [centered at %4]" );
+ const ConicPolarData data = polarData();
+
+ ret = ret.arg( data.pdimen, 0, 'g', 3 );
+ ret = ret.arg( -data.ecostheta0, 0, 'g', 3 );
+ ret = ret.arg( -data.esintheta0, 0, 'g', 3 );
+
+ ret = ret.arg( w.coordinateSystem().fromScreen( data.focus1, w ) );
+ return ret;
+}
+
+const ConicCartesianData ConicImp::cartesianData() const
+{
+ return ConicCartesianData( polarData() );
+}
+
+Coordinate ConicImp::focus1() const
+{
+ return polarData().focus1;
+}
+
+Coordinate ConicImp::focus2() const
+{
+ const ConicPolarData d = polarData();
+ double ec = d.ecostheta0;
+ double es = d.esintheta0;
+
+ double fact = 2*d.pdimen/(1 - ec*ec - es*es);
+
+ return d.focus1 + fact*Coordinate(ec, es);
+}
+
+const ConicPolarData ConicImpCart::polarData() const
+{
+ return mpolardata;
+}
+
+const ConicCartesianData ConicImpCart::cartesianData() const
+{
+ return mcartdata;
+}
+
+ConicImpCart::ConicImpCart( const ConicCartesianData& data )
+ : ConicImp(), mcartdata( data ), mpolardata( data )
+{
+ assert( data.valid() );
+}
+
+ConicImpPolar::ConicImpPolar( const ConicPolarData& data )
+ : ConicImp(), mdata( data )
+{
+}
+
+ConicImpPolar::~ConicImpPolar()
+{
+}
+
+const ConicPolarData ConicImpPolar::polarData() const
+{
+ return mdata;
+}
+
+ConicImpCart* ConicImpCart::copy() const
+{
+ return new ConicImpCart( mcartdata );
+}
+
+ConicImpPolar* ConicImpPolar::copy() const
+{
+ return new ConicImpPolar( mdata );
+}
+
+ConicImp::ConicImp()
+{
+}
+
+ConicImp::~ConicImp()
+{
+}
+
+ConicImpCart::~ConicImpCart()
+{
+}
+
+void ConicImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool ConicImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( ConicImp::stype() ) &&
+ static_cast<const ConicImp&>( rhs ).polarData() == polarData();
+}
+
+const ObjectImpType* ConicImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "conic",
+ I18N_NOOP( "conic" ),
+ I18N_NOOP( "Select this conic" ),
+ I18N_NOOP( "Select conic %1" ),
+ I18N_NOOP( "Remove a Conic" ),
+ I18N_NOOP( "Add a Conic" ),
+ I18N_NOOP( "Move a Conic" ),
+ I18N_NOOP( "Attach to this conic" ),
+ I18N_NOOP( "Show a Conic" ),
+ I18N_NOOP( "Hide a Conic" )
+ );
+ return &t;
+}
+
+const ObjectImpType* ConicImp::type() const
+{
+ return ConicImp::stype();
+}
+
+bool ConicImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ const ConicPolarData d = polarData();
+
+// the threshold is relative to the size of the conic (mp)
+ return internalContainsPoint( p, test_threshold*d.pdimen );
+}
+
+bool ConicImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ const ConicPolarData d = polarData();
+
+ Coordinate focus1 = d.focus1;
+ double ecostheta0 = d.ecostheta0;
+ double esintheta0 = d.esintheta0;
+ double pdimen = d.pdimen;
+
+ Coordinate pos = p - focus1;
+ double len = pos.length();
+ double costheta = pos.x / len;
+ double sintheta = pos.y / len;
+
+ double ecosthetamtheta0 = costheta*ecostheta0 + sintheta*esintheta0;
+ double rho = pdimen / (1.0 - ecosthetamtheta0);
+
+ double oneplus = 1.0 + ecostheta0*ecostheta0 + esintheta0*esintheta0;
+
+// fact is the cosine of the angle between the ray from the first focus
+// and the normal to the conic, so that we compute the real distance
+
+ double fact = (1.0 - ecosthetamtheta0)/sqrt(oneplus - 2*ecosthetamtheta0);
+ if ( fabs((len - rho)*fact) <= threshold ) return true;
+ rho = - pdimen / ( 1.0 + ecosthetamtheta0 );
+ fact = (1.0 + ecosthetamtheta0)/sqrt(oneplus + 2*ecosthetamtheta0);
+ return fabs(( len - rho )*fact) <= threshold;
+}
+
+bool ConicImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+ return false;
+}
+
+Rect ConicImp::surroundingRect() const
+{
+ // it's prolly possible to calculate this ( in the case that the
+ // conic is limited in size ), but for now we don't.
+
+ return Rect::invalidRect();
+}
diff --git a/kig/objects/conic_imp.h b/kig/objects/conic_imp.h
new file mode 100644
index 00000000..55ba65ca
--- /dev/null
+++ b/kig/objects/conic_imp.h
@@ -0,0 +1,157 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_CONIC_IMP_H
+#define KIG_OBJECTS_CONIC_IMP_H
+
+#include "curve_imp.h"
+
+#include "../misc/conic-common.h"
+
+/**
+ * An ObjectImp representing a conic.
+ *
+ * A conic is a general second degree curve, and some beautiful theory
+ * has been developed about it.. See a math book for more
+ * information. This class is in fact an abstract base class hiding
+ * the fact that a ConicImp can be constructed in two ways. If only
+ * its Cartesian equation is known, then you should use ConicImpCart,
+ * otherwise, you should use ConicImpPolar. If the other
+ * representation is needed, it will be calculated, but a cartesian
+ * representation is rarely needed, and not calculating saves some CPU
+ * cycles.
+ */
+class ConicImp
+ : public CurveImp
+{
+protected:
+ ConicImp();
+ ~ConicImp();
+public:
+ typedef CurveImp Parent;
+ /**
+ * Returns the ObjectImpType representing the ConicImp type.
+ */
+ static const ObjectImpType* stype();
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ bool valid() const;
+ Rect surroundingRect() const;
+
+ const uint numberOfProperties() const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ const char* iconForProperty( uint which ) const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+
+ double getParam( const Coordinate& point, const KigDocument& ) const;
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+
+ // information about ourselves.. These are all virtual, because a
+ // trivial subclass like CircleImp can override these with trivial
+ // versions..
+
+ /**
+ * Type of conic.
+ * Return what type of conic this is:
+ * -1 for a hyperbola
+ * 0 for a parabola
+ * 1 for an ellipse
+ */
+ virtual int conicType() const;
+ /**
+ * A string containing "Hyperbola", "Parabola" or "Ellipse".
+ */
+ virtual QString conicTypeString() const;
+ /**
+ * A string containing the cartesian equation of the conic. This
+ * will be of the form "a x^2 + b y^2 + c xy + d x + e y + f = 0".
+ */
+ virtual QString cartesianEquationString( const KigDocument& w ) const;
+ /**
+ * A string containing the polar equation of the conic. This will
+ * be of the form "rho = pdimen/(1 + ect cos( theta ) + est sin(
+ * theta ) )\n [centered at p]"
+ */
+ virtual QString polarEquationString( const KigDocument& w ) const;
+ /**
+ * Return the cartesian representation of this conic.
+ */
+ virtual const ConicCartesianData cartesianData() const;
+ /**
+ * Return the polar representation of this conic.
+ */
+ virtual const ConicPolarData polarData() const = 0;
+ /**
+ * Return the first focus of this conic.
+ */
+ virtual Coordinate focus1() const;
+ /**
+ * Return the second focus of this conic.
+ */
+ virtual Coordinate focus2() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+/**
+ * An implementation of ConicImp to be used when only the cartesian
+ * equation of the conic is known.
+ */
+class ConicImpCart
+ : public ConicImp
+{
+ ConicCartesianData mcartdata;
+ ConicPolarData mpolardata;
+public:
+ ConicImpCart( const ConicCartesianData& data );
+ ~ConicImpCart();
+ ConicImpCart* copy() const;
+
+ const ConicCartesianData cartesianData() const;
+ const ConicPolarData polarData() const;
+};
+
+/**
+ * An implementation of ConicImp to be used when only the cartesian
+ * equation of the conic is known.
+ */
+class ConicImpPolar
+ : public ConicImp
+{
+ ConicPolarData mdata;
+public:
+ ConicImpPolar( const ConicPolarData& data );
+ ~ConicImpPolar();
+ ConicImpPolar* copy() const;
+
+ const ConicPolarData polarData() const;
+};
+
+#endif
diff --git a/kig/objects/conic_types.cc b/kig/objects/conic_types.cc
new file mode 100644
index 00000000..6e32f844
--- /dev/null
+++ b/kig/objects/conic_types.cc
@@ -0,0 +1,689 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "conic_types.h"
+
+#include "bogus_imp.h"
+#include "conic_imp.h"
+#include "point_imp.h"
+#include "circle_imp.h"
+#include "line_imp.h"
+#include "object_calcer.h"
+#include "../misc/conic-common.h"
+#include "../misc/common.h"
+#include "../kig/kig_commands.h"
+#include "../kig/kig_part.h"
+
+#include <klocale.h>
+
+static const char conic_constructstatement[] = I18N_NOOP( "Construct a conic through this point" );
+
+static const struct ArgsParser::spec argsspecConicB5P[] =
+{
+ { PointImp::stype(), conic_constructstatement,
+ I18N_NOOP( "Select a point for the new conic to go through..." ), true },
+ { PointImp::stype(), conic_constructstatement,
+ I18N_NOOP( "Select a point for the new conic to go through..." ), true },
+ { PointImp::stype(), conic_constructstatement,
+ I18N_NOOP( "Select a point for the new conic to go through..." ), true },
+ { PointImp::stype(), conic_constructstatement,
+ I18N_NOOP( "Select a point for the new conic to go through..." ), true },
+ { PointImp::stype(), conic_constructstatement,
+ I18N_NOOP( "Select a point for the new conic to go through..." ),true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicB5PType )
+
+ConicB5PType::ConicB5PType()
+ : ArgsParserObjectType( "ConicB5P", argsspecConicB5P, 5 )
+{
+}
+
+ConicB5PType::~ConicB5PType()
+{
+}
+
+ObjectImp* ConicB5PType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 1 ) ) return new InvalidImp;
+ std::vector<Coordinate> points;
+
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ points.push_back( static_cast<const PointImp*>( *i )->coordinate() );
+
+ ConicCartesianData d =
+ calcConicThroughPoints( points, zerotilt, parabolaifzt, ysymmetry );
+ if ( d.valid() )
+ return new ConicImpCart( d );
+ else return new InvalidImp;
+}
+
+const ConicB5PType* ConicB5PType::instance()
+{
+ static const ConicB5PType t;
+ return &t;
+}
+
+static const ArgsParser::spec argsspecConicBAAP[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct a conic with this asymptote" ),
+ I18N_NOOP( "Select the first asymptote of the new conic..." ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct a conic with this asymptote" ),
+ I18N_NOOP( "Select the second asymptote of the new conic..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct a conic through this point" ),
+ I18N_NOOP( "Select a point for the new conic to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicBAAPType )
+
+ConicBAAPType::ConicBAAPType()
+ : ArgsParserObjectType( "ConicBAAP", argsspecConicBAAP, 3 )
+{
+}
+
+ConicBAAPType::~ConicBAAPType()
+{
+}
+
+const ConicBAAPType* ConicBAAPType::instance()
+{
+ static const ConicBAAPType t;
+ return &t;
+}
+
+ObjectImp* ConicBAAPType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) )
+ return new InvalidImp;
+ const LineData la = static_cast<const AbstractLineImp*>( parents[0] )->data();
+ const LineData lb = static_cast<const AbstractLineImp*>( parents[1] )->data();
+ const Coordinate c = static_cast<const PointImp*>( parents[2] )->coordinate();
+
+ return new ConicImpCart( calcConicByAsymptotes( la, lb, c ) );
+}
+
+ObjectImp* ConicBFFPType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+ std::vector<Coordinate> cs;
+
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ cs.push_back( static_cast<const PointImp*>( *i )->coordinate() );
+
+ return new ConicImpPolar( calcConicBFFP( cs, type() ) );
+}
+
+ConicBFFPType::ConicBFFPType( const char* fullname, const ArgsParser::spec* spec, int n )
+ : ArgsParserObjectType( fullname, spec, n )
+{
+}
+
+ConicBFFPType::~ConicBFFPType()
+{
+}
+
+static const char constructellipsewithfocusstat[] =
+ I18N_NOOP( "Construct an ellipse with this focus" );
+
+static const ArgsParser::spec argsspecEllipseBFFP[] =
+{
+ { PointImp::stype(), constructellipsewithfocusstat,
+ I18N_NOOP( "Select the first focus of the new ellipse..." ), false },
+ { PointImp::stype(), constructellipsewithfocusstat,
+ I18N_NOOP( "Select the second focus of the new ellipse..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct an ellipse through this point" ),
+ I18N_NOOP( "Select a point for the new ellipse to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( EllipseBFFPType )
+
+EllipseBFFPType::EllipseBFFPType()
+ : ConicBFFPType( "EllipseBFFP", argsspecEllipseBFFP, 3 )
+{
+}
+
+EllipseBFFPType::~EllipseBFFPType()
+{
+}
+
+int EllipseBFFPType::type() const
+{
+ return 1;
+}
+
+const EllipseBFFPType* EllipseBFFPType::instance()
+{
+ static const EllipseBFFPType t;
+ return &t;
+}
+
+static const char constructhyperbolawithfocusstat[] =
+ I18N_NOOP( "Construct a hyperbola with this focus" );
+
+static const ArgsParser::spec argsspecHyperbolaBFFP[] =
+{
+ { PointImp::stype(), constructhyperbolawithfocusstat,
+ I18N_NOOP( "Select the first focus of the new hyperbola..." ), false },
+ { PointImp::stype(), constructhyperbolawithfocusstat,
+ I18N_NOOP( "Select the second focus of the new hyperbola..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct a hyperbola through this point" ),
+ I18N_NOOP( "Select a point for the new hyperbola to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( HyperbolaBFFPType )
+
+HyperbolaBFFPType::HyperbolaBFFPType()
+ : ConicBFFPType( "HyperbolaBFFP", argsspecHyperbolaBFFP, 3 )
+{
+}
+
+HyperbolaBFFPType::~HyperbolaBFFPType()
+{
+}
+
+const HyperbolaBFFPType* HyperbolaBFFPType::instance()
+{
+ static const HyperbolaBFFPType t;
+ return &t;
+}
+
+int HyperbolaBFFPType::type() const
+{
+ return -1;
+}
+
+const ConicBDFPType* ConicBDFPType::instance()
+{
+ static const ConicBDFPType t;
+ return &t;
+}
+
+static const struct ArgsParser::spec argsspecConicBDFP[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct a conic with this line as directrix" ),
+ I18N_NOOP( "Select the directrix of the new conic..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct a conic with this point as focus" ),
+ I18N_NOOP( "Select the focus of the new conic..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct a conic through this point" ),
+ I18N_NOOP( "Select a point for the new conic to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicBDFPType )
+
+ConicBDFPType::ConicBDFPType()
+ : ArgsParserObjectType( "ConicBDFP", argsspecConicBDFP, 3 )
+{
+}
+
+ConicBDFPType::~ConicBDFPType()
+{
+}
+
+ObjectImp* ConicBDFPType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+
+ const LineData line = static_cast<const AbstractLineImp*>( parents[0] )->data();
+ const Coordinate focus =
+ static_cast<const PointImp*>( parents[1] )->coordinate();
+
+ Coordinate point;
+ if ( parents.size() == 3 )
+ point = static_cast<const PointImp*>( parents[2] )->coordinate();
+ else
+ {
+ /* !!!! costruisci point come punto medio dell'altezza tra fuoco e d. */
+ Coordinate ba = line.dir();
+ Coordinate fa = focus - line.b;
+ double balsq = ba.x*ba.x + ba.y*ba.y;
+ double scal = (fa.x*ba.x + fa.y*ba.y)/balsq;
+ point = 0.5*(line.a + focus + scal*ba);
+ };
+ return new ConicImpPolar( calcConicBDFP( line, focus, point ) );
+}
+
+static const char constructparabolathroughpointstat[] =
+ I18N_NOOP( "Construct a parabola through this point" );
+
+static const ArgsParser::spec argsspecParabolaBTP[] =
+{
+ { PointImp::stype(), constructparabolathroughpointstat,
+ I18N_NOOP( "Select a point for the new parabola to go through..." ), true },
+ { PointImp::stype(), constructparabolathroughpointstat,
+ I18N_NOOP( "Select a point for the new parabola to go through..." ), true },
+ { PointImp::stype(), constructparabolathroughpointstat,
+ I18N_NOOP( "Select a point for the new parabola to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ParabolaBTPType )
+
+ParabolaBTPType::ParabolaBTPType()
+ : ArgsParserObjectType( "ParabolaBTP", argsspecParabolaBTP, 3 )
+{
+}
+
+ParabolaBTPType::~ParabolaBTPType()
+{
+}
+
+const ParabolaBTPType* ParabolaBTPType::instance()
+{
+ static const ParabolaBTPType t;
+ return &t;
+}
+
+ObjectImp* ParabolaBTPType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> points;
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ points.push_back( static_cast<const PointImp*>( *i )->coordinate() );
+
+ ConicCartesianData d =
+ calcConicThroughPoints( points, zerotilt, parabolaifzt, ysymmetry );
+ if ( d.valid() )
+ return new ConicImpCart( d );
+ else
+ return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecConicPolarPoint[] =
+{
+ { ConicImp::stype(), I18N_NOOP( "Construct a polar point wrt. this conic" ),
+ I18N_NOOP( "Select the conic wrt. which you want to construct a polar point..." ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct the polar point of this line" ),
+ I18N_NOOP( "Select the line of which you want to construct the polar point..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicPolarPointType )
+
+ConicPolarPointType::ConicPolarPointType()
+ : ArgsParserObjectType( "ConicPolarPoint", argsspecConicPolarPoint, 2 )
+{
+}
+
+ConicPolarPointType::~ConicPolarPointType()
+{
+}
+
+const ConicPolarPointType* ConicPolarPointType::instance()
+{
+ static const ConicPolarPointType t;
+ return &t;
+}
+
+ObjectImp* ConicPolarPointType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const ConicCartesianData c = static_cast<const ConicImp*>( parents[0] )->cartesianData();
+ const LineData l = static_cast<const AbstractLineImp*>( parents[1] )->data();
+ const Coordinate p = calcConicPolarPoint( c, l );
+ if ( p.valid() ) return new PointImp( p );
+ else return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecConicPolarLine[] =
+{
+ { ConicImp::stype(), I18N_NOOP( "Construct a polar line wrt. this conic" ),
+ I18N_NOOP( "Select the conic wrt. which you want to construct a polar point..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct the polar line of this point" ),
+ I18N_NOOP( "Select the line of which you want to construct the polar point..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicPolarLineType )
+
+ConicPolarLineType::ConicPolarLineType()
+ : ArgsParserObjectType( "ConicPolarLine", argsspecConicPolarLine, 2 )
+{
+}
+
+ConicPolarLineType::~ConicPolarLineType()
+{
+}
+
+const ConicPolarLineType* ConicPolarLineType::instance()
+{
+ static const ConicPolarLineType t;
+ return &t;
+}
+
+ObjectImp* ConicPolarLineType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const ConicCartesianData c = static_cast<const ConicImp*>( parents[0] )->cartesianData();
+ const Coordinate p = static_cast<const PointImp*>( parents[1] )->coordinate();
+ bool valid = true;
+ const LineData l = calcConicPolarLine( c, p, valid );
+ if ( valid ) return new LineImp( l );
+ else return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecConicDirectrix[] =
+{
+ { ConicImp::stype(), I18N_NOOP( "Construct the directrix of this conic" ),
+ I18N_NOOP( "Select the conic of which you want to construct the directrix..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicDirectrixType )
+
+ConicDirectrixType::ConicDirectrixType()
+ : ArgsParserObjectType( "ConicDirectrix", argsspecConicDirectrix, 1 )
+{
+}
+
+ConicDirectrixType::~ConicDirectrixType()
+{
+}
+
+const ConicDirectrixType* ConicDirectrixType::instance()
+{
+ static const ConicDirectrixType t;
+ return &t;
+}
+
+ObjectImp* ConicDirectrixType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const ConicPolarData data =
+ static_cast<const ConicImp*>( parents[0] )->polarData();
+
+ double ec = data.ecostheta0;
+ double es = data.esintheta0;
+ double eccsq = ec*ec + es*es;
+
+ Coordinate a = data.focus1 - data.pdimen/eccsq*Coordinate(ec,es);
+ Coordinate b = a + Coordinate(-es,ec);
+ return new LineImp( a, b );
+}
+
+static const char hyperbolatpstatement[] = I18N_NOOP( "Construct a hyperbola through this point" );
+
+static const ArgsParser::spec argsspecHyperbolaB4P[] =
+{
+ { PointImp::stype(), hyperbolatpstatement,
+ I18N_NOOP( "Select a point for the new hyperbola to go through..." ), true },
+ { PointImp::stype(), hyperbolatpstatement,
+ I18N_NOOP( "Select a point for the new hyperbola to go through..." ), true },
+ { PointImp::stype(), hyperbolatpstatement,
+ I18N_NOOP( "Select a point for the new hyperbola to go through..." ), true },
+ { PointImp::stype(), hyperbolatpstatement,
+ I18N_NOOP( "Select a point for the new hyperbola to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( EquilateralHyperbolaB4PType )
+
+EquilateralHyperbolaB4PType::EquilateralHyperbolaB4PType()
+ : ArgsParserObjectType( "EquilateralHyperbolaB4P", argsspecHyperbolaB4P, 4 )
+{
+}
+
+EquilateralHyperbolaB4PType::~EquilateralHyperbolaB4PType()
+{
+}
+
+const EquilateralHyperbolaB4PType* EquilateralHyperbolaB4PType::instance()
+{
+ static const EquilateralHyperbolaB4PType t;
+ return &t;
+}
+
+ObjectImp* EquilateralHyperbolaB4PType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 1 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> pts;
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ pts.push_back( static_cast<const PointImp*>( *i )->coordinate() );
+
+ ConicCartesianData d = calcConicThroughPoints( pts, equilateral );
+ if ( d.valid() )
+ return new ConicImpCart( d );
+ else
+ return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecParabolaBDP[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct a parabola with this directrix" ),
+ I18N_NOOP( "Select the directrix of the new parabola..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct a parabola with this focus" ),
+ I18N_NOOP( "Select the focus of the new parabola..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ParabolaBDPType )
+
+ParabolaBDPType::ParabolaBDPType()
+ : ObjectLPType( "ParabolaBDP", argsspecParabolaBDP, 2 )
+{
+}
+
+ParabolaBDPType::~ParabolaBDPType()
+{
+}
+
+const ParabolaBDPType* ParabolaBDPType::instance()
+{
+ static const ParabolaBDPType t;
+ return &t;
+}
+
+ObjectImp* ParabolaBDPType::calc( const LineData& l, const Coordinate& c ) const
+{
+ ConicPolarData ret;
+ Coordinate ldir = l.dir();
+ ldir = ldir.normalize();
+ ret.focus1 = c;
+ ret.ecostheta0 = - ldir.y;
+ ret.esintheta0 = ldir.x;
+ Coordinate fa = c - l.a;
+ ret.pdimen = fa.y*ldir.x - fa.x*ldir.y;
+ ConicImpPolar* r = new ConicImpPolar( ret );
+ kdDebug() << k_funcinfo << r->conicTypeString() << endl;
+ return r;
+}
+
+static const ArgsParser::spec argsspecConicAsymptote[] =
+{
+ { ConicImp::stype(), I18N_NOOP( "Construct the asymptotes of this conic" ),
+ I18N_NOOP( "Select the conic of which you want to construct the asymptotes..." ), false },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicAsymptoteType )
+
+ConicAsymptoteType::ConicAsymptoteType()
+ : ArgsParserObjectType( "ConicAsymptote", argsspecConicAsymptote, 2 )
+{
+}
+
+ConicAsymptoteType::~ConicAsymptoteType()
+{
+}
+
+const ConicAsymptoteType* ConicAsymptoteType::instance()
+{
+ static const ConicAsymptoteType t;
+ return &t;
+}
+
+ObjectImp* ConicAsymptoteType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ bool valid = true;
+ const LineData ret = calcConicAsymptote(
+ static_cast<const ConicImp*>( parents[0] )->cartesianData(),
+ static_cast<const IntImp*>( parents[1] )->data(),
+ valid );
+
+ if ( valid )
+ return new LineImp( ret );
+ else
+ return new InvalidImp;
+}
+
+static const char radicallinesstatement[] = I18N_NOOP( "Construct the radical lines of this conic" );
+
+static const ArgsParser::spec argsspecConicRadical[] =
+{
+ { ConicImp::stype(), radicallinesstatement,
+ I18N_NOOP( "Select the first of the two conics of which you want to construct the radical line..." ), false },
+ { ConicImp::stype(), radicallinesstatement,
+ I18N_NOOP( "Select the other of the two conic of which you want to construct the radical line..." ), false },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicRadicalType )
+
+ConicRadicalType::ConicRadicalType()
+ : ArgsParserObjectType( "ConicRadical", argsspecConicRadical, 4 )
+{
+}
+
+const ConicRadicalType* ConicRadicalType::instance()
+{
+ static const ConicRadicalType t;
+ return &t;
+}
+
+ObjectImp* ConicRadicalType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ if ( parents[0]->inherits( CircleImp::stype() ) &&
+ parents[1]->inherits( CircleImp::stype() ) )
+ {
+ if( static_cast<const IntImp*>( parents[2] )->data() != 1 )
+ return new InvalidImp;
+ else
+ {
+ const CircleImp* c1 = static_cast<const CircleImp*>( parents[0] );
+ const CircleImp* c2 = static_cast<const CircleImp*>( parents[1] );
+ const Coordinate a = calcCircleRadicalStartPoint(
+ c1->center(), c2->center(), c1->squareRadius(), c2->squareRadius()
+ );
+ return new LineImp( a, calcPointOnPerpend(
+ LineData( c1->center(), c2->center() ), a ) );
+ };
+ }
+ else
+ {
+ bool valid = true;
+ const LineData l = calcConicRadical(
+ static_cast<const ConicImp*>( parents[0] )->cartesianData(),
+ static_cast<const ConicImp*>( parents[1] )->cartesianData(),
+ static_cast<const IntImp*>( parents[2] )->data(),
+ static_cast<const IntImp*>( parents[3] )->data(), valid );
+ if ( valid )
+ return new LineImp( l );
+ else
+ return new InvalidImp;
+ };
+}
+
+ConicRadicalType::~ConicRadicalType()
+{
+}
+
+const ObjectImpType* ConicB5PType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* ConicBAAPType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* ConicBFFPType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* ConicBDFPType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* ParabolaBTPType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* EquilateralHyperbolaB4PType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* ConicPolarPointType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* ConicPolarLineType::resultId() const
+{
+ return LineImp::stype();
+}
+
+const ObjectImpType* ConicDirectrixType::resultId() const
+{
+ return LineImp::stype();
+}
+
+const ObjectImpType* ParabolaBDPType::resultId() const
+{
+ return ConicImp::stype();
+}
+
+const ObjectImpType* ConicAsymptoteType::resultId() const
+{
+ return LineImp::stype();
+}
+
+const ObjectImpType* ConicRadicalType::resultId() const
+{
+ return LineImp::stype();
+}
+
+QStringList ConicRadicalType::specialActions() const
+{
+ QStringList ret;
+ ret << i18n( "Switch Radical Lines" );
+ return ret;
+}
+
+void ConicRadicalType::executeAction( int i, ObjectHolder&, ObjectTypeCalcer& t,
+ KigPart& d, KigWidget&, NormalMode& ) const
+{
+ assert( i == 0 );
+ std::vector<ObjectCalcer*> parents = t.parents();
+ assert( dynamic_cast<ObjectConstCalcer*>( parents[3] ) );
+ ObjectConstCalcer* zeroindexo = static_cast<ObjectConstCalcer*>( parents[3] );
+ MonitorDataObjects mon( zeroindexo );
+ assert( zeroindexo->imp()->inherits( IntImp::stype() ) );
+ int oldzeroindex = static_cast<const IntImp*>( zeroindexo->imp() )->data();
+ int newzeroindex = oldzeroindex % 3 + 1;
+ zeroindexo->setImp( new IntImp( newzeroindex ) );
+ KigCommand* kc = new KigCommand( d, "Switch Conic Radical Lines" );
+ mon.finish( kc );
+ d.history()->addCommand( kc );
+}
+
diff --git a/kig/objects/conic_types.h b/kig/objects/conic_types.h
new file mode 100644
index 00000000..e2a1881d
--- /dev/null
+++ b/kig/objects/conic_types.h
@@ -0,0 +1,184 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_CONIC_TYPES_H
+#define KIG_OBJECTS_CONIC_TYPES_H
+
+#include "base_type.h"
+
+class ConicB5PType
+ : public ArgsParserObjectType
+{
+ ConicB5PType();
+ ~ConicB5PType();
+public:
+ static const ConicB5PType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicBAAPType
+ : public ArgsParserObjectType
+{
+ ConicBAAPType();
+ ~ConicBAAPType();
+public:
+ static const ConicBAAPType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicBFFPType
+ : public ArgsParserObjectType
+{
+protected:
+ ConicBFFPType( const char* fullname, const ArgsParser::spec*, int n );
+ ~ConicBFFPType();
+public:
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+
+ /**
+ * -1 for hyperbola, 1 for ellipse..
+ */
+ virtual int type() const = 0;
+ const ObjectImpType* resultId() const;
+};
+
+class EllipseBFFPType
+ : public ConicBFFPType
+{
+ EllipseBFFPType();
+ ~EllipseBFFPType();
+public:
+ static const EllipseBFFPType* instance();
+ int type() const;
+};
+
+class HyperbolaBFFPType
+ : public ConicBFFPType
+{
+ HyperbolaBFFPType();
+ ~HyperbolaBFFPType();
+public:
+ static const HyperbolaBFFPType* instance();
+ int type() const;
+};
+
+class ConicBDFPType
+ : public ArgsParserObjectType
+{
+ ConicBDFPType();
+ ~ConicBDFPType();
+public:
+ static const ConicBDFPType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ParabolaBTPType
+ : public ArgsParserObjectType
+{
+ ParabolaBTPType();
+ ~ParabolaBTPType();
+public:
+ static const ParabolaBTPType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class EquilateralHyperbolaB4PType
+ : public ArgsParserObjectType
+{
+ EquilateralHyperbolaB4PType();
+ ~EquilateralHyperbolaB4PType();
+public:
+ static const EquilateralHyperbolaB4PType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicPolarPointType
+ : public ArgsParserObjectType
+{
+ ConicPolarPointType();
+ ~ConicPolarPointType();
+public:
+ static const ConicPolarPointType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicPolarLineType
+ : public ArgsParserObjectType
+{
+ ConicPolarLineType();
+ ~ConicPolarLineType();
+public:
+ static const ConicPolarLineType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicDirectrixType
+ : public ArgsParserObjectType
+{
+ ConicDirectrixType();
+ ~ConicDirectrixType();
+public:
+ static const ConicDirectrixType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ParabolaBDPType
+ : public ObjectLPType
+{
+ ParabolaBDPType();
+ ~ParabolaBDPType();
+public:
+ static const ParabolaBDPType* instance();
+ ObjectImp* calc( const LineData& l, const Coordinate& c ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicAsymptoteType
+ : public ArgsParserObjectType
+{
+ ConicAsymptoteType();
+ ~ConicAsymptoteType();
+public:
+ static const ConicAsymptoteType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConicRadicalType
+ : public ArgsParserObjectType
+{
+ ConicRadicalType();
+ ~ConicRadicalType();
+public:
+ static const ConicRadicalType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+ QStringList specialActions() const;
+ void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& t,
+ KigPart& d, KigWidget& w, NormalMode& m ) const;
+};
+
+#endif
+
diff --git a/kig/objects/cubic_imp.cc b/kig/objects/cubic_imp.cc
new file mode 100644
index 00000000..51bb5d9f
--- /dev/null
+++ b/kig/objects/cubic_imp.cc
@@ -0,0 +1,437 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "cubic_imp.h"
+
+#include "bogus_imp.h"
+
+#include "../misc/kigpainter.h"
+#include "../misc/screeninfo.h"
+#include "../misc/kignumerics.h"
+#include "../misc/common.h"
+#include "../kig/kig_view.h"
+
+#include <math.h>
+#include <klocale.h>
+
+CubicImp::CubicImp( const CubicCartesianData& data )
+ : CurveImp(), mdata( data )
+{
+}
+
+CubicImp::~CubicImp()
+{
+}
+
+ObjectImp* CubicImp::transform( const Transformation& t ) const
+{
+ bool valid = true;
+ CubicCartesianData d = calcCubicTransformation( data(), t, valid );
+ if ( valid ) return new CubicImp( d );
+ else return new InvalidImp;
+}
+
+void CubicImp::draw( KigPainter& p ) const
+{
+ p.drawCurve( this );
+}
+
+bool CubicImp::contains( const Coordinate& o, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( o, w.screenInfo().normalMiss( width ) );
+}
+
+bool CubicImp::inRect( const Rect&, int, const KigWidget& ) const
+{
+ // TODO ?
+ return false;
+}
+
+CubicImp* CubicImp::copy() const
+{
+ return new CubicImp( mdata );
+}
+
+double CubicImp::getParam( const Coordinate& p, const KigDocument& ) const
+{
+ double x = p.x;
+ double y = p.y;
+ double t;
+
+ double a000 = mdata.coeffs[0];
+ double a001 = mdata.coeffs[1];
+ double a002 = mdata.coeffs[2];
+ double a011 = mdata.coeffs[3];
+ double a012 = mdata.coeffs[4];
+ double a022 = mdata.coeffs[5];
+ double a111 = mdata.coeffs[6];
+ double a112 = mdata.coeffs[7];
+ double a122 = mdata.coeffs[8];
+ double a222 = mdata.coeffs[9];
+
+ /*
+ * first project p onto the cubic. This is done by computing the
+ * line through p in the direction of the gradient
+ */
+
+ double f = a000 + a001*x + a002*y + a011*x*x + a012*x*y + a022*y*y +
+ a111*x*x*x + a112*x*x*y + a122*x*y*y + a222*y*y*y;
+ if ( f != 0 )
+ {
+ double fx = a001 + 2*a011*x + a012*y + 3*a111*x*x + 2*a112*x*y + a122*y*y;
+ double fy = a002 + 2*a022*y + a012*x + 3*a222*y*y + 2*a122*x*y + a112*x*x;
+ Coordinate v = Coordinate (fx, fy);
+ if ( f < 0 ) v = -v; // the line points away from the intersection
+ double a, b, c, d;
+ calcCubicLineRestriction ( mdata, p, v, a, b, c, d );
+ if ( a < 0 )
+ {
+ a *= -1;
+ b *= -1;
+ c *= -1;
+ d *= -1;
+ }
+
+ // computing the coefficients of the Sturm sequence
+ double p1a = 2*b*b - 6*a*c;
+ double p1b = b*c - 9*a*d;
+ double p0a = c*p1a*p1a + p1b*(3*a*p1b - 2*b*p1a);
+ // compute the number of roots for negative lambda
+ int variations = calcCubicVariations ( 0, a, b, c, d, p1a, p1b, p0a );
+ bool valid;
+ int numroots;
+ double lambda = calcCubicRoot ( -1e10, 1e10, a, b, c, d, variations, valid,
+ numroots );
+ if ( valid )
+ {
+ Coordinate pnew = p + lambda*v;
+ x = pnew.x;
+ y = pnew.y;
+ }
+ }
+
+ if (x > 0) t = x/(1+x);
+ else t = x/(1-x);
+ t = 0.5*(t + 1);
+ t /= 3;
+
+ Coordinate p1 = getPoint ( t );
+ Coordinate p2 = getPoint ( t + 1.0/3.0 );
+ Coordinate p3 = getPoint ( t + 2.0/3.0 );
+
+ double mint = t;
+ double mindist = p1.valid() ? fabs ( y - p1.y ) : double_inf;
+ if ( p2.valid() && fabs ( y - p2.y ) < mindist )
+ {
+ mint = t + 1.0/3.0;
+ mindist = fabs ( y - p2.y );
+ }
+ if ( p3.valid() && fabs ( y - p3.y ) < mindist )
+ {
+ mint = t + 2.0/3.0;
+ }
+
+ return mint;
+}
+
+const Coordinate CubicImp::getPoint( double p, const KigDocument& ) const
+{
+ return getPoint( p );
+}
+
+const Coordinate CubicImp::getPoint( double p ) const
+{
+ /*
+ * this isn't really elegant...
+ * the magnitude of p tells which one of the maximum 3 intersections
+ * of the vertical line with the cubic to take.
+ */
+
+ p *= 3;
+ int root = (int) p;
+ assert ( root >= 0 );
+ assert ( root <= 3 );
+ if ( root == 3 ) root = 2;
+
+ p -= root;
+
+ assert ( 0 <= p && p <= 1 );
+ if ( p <= 0. ) p = 1e-6;
+ if ( p >= 1. ) p = 1 - 1e-6;
+ root++;
+ p = 2*p - 1;
+ double x;
+ if (p > 0) x = p/(1 - p);
+ else x = p/(1 + p);
+
+ // calc the third degree polynomial:
+ // compute the third degree polinomial:
+// double a000 = mdata.coeffs[0];
+// double a001 = mdata.coeffs[1];
+// double a002 = mdata.coeffs[2];
+// double a011 = mdata.coeffs[3];
+// double a012 = mdata.coeffs[4];
+// double a022 = mdata.coeffs[5];
+// double a111 = mdata.coeffs[6];
+// double a112 = mdata.coeffs[7];
+// double a122 = mdata.coeffs[8];
+// double a222 = mdata.coeffs[9];
+//
+// // first the y^3 coefficient, it coming only from a222:
+// double a = a222;
+// // next the y^2 coefficient (from a122 and a022):
+// double b = a122*x + a022;
+// // next the y coefficient (from a112, a012 and a002):
+// double c = a112*x*x + a012*x + a002;
+// // finally the constant coefficient (from a111, a011, a001 and a000):
+// double d = a111*x*x*x + a011*x*x + a001*x + a000;
+
+// commented out, since the bound is already computed when passing a huge
+// interval; the normalization is not needed also
+
+ // renormalize: positive a
+// if ( a < 0 )
+// {
+// a *= -1;
+// b *= -1;
+// c *= -1;
+// d *= -1;
+// }
+//
+// const double small = 1e-7;
+// int degree = 3;
+// if ( fabs(a) < small*fabs(b) ||
+// fabs(a) < small*fabs(c) ||
+// fabs(a) < small*fabs(d) )
+// {
+// degree = 2;
+// if ( fabs(b) < small*fabs(c) ||
+// fabs(b) < small*fabs(d) )
+// {
+// degree = 1;
+// }
+// }
+
+// and a bound for all the real roots:
+
+// double bound;
+// switch (degree)
+// {
+// case 3:
+// bound = fabs(d/a);
+// if ( fabs(c/a) + 1 > bound ) bound = fabs(c/a) + 1;
+// if ( fabs(b/a) + 1 > bound ) bound = fabs(b/a) + 1;
+// break;
+//
+// case 2:
+// bound = fabs(d/b);
+// if ( fabs(c/b) + 1 > bound ) bound = fabs(c/b) + 1;
+// break;
+//
+// case 1:
+// default:
+// bound = fabs(d/c) + 1;
+// break;
+// }
+
+ int numroots;
+ bool valid = true;
+ double y = calcCubicYvalue ( x, -double_inf, double_inf, root, mdata, valid,
+ numroots );
+ if ( ! valid ) return Coordinate::invalidCoord();
+ else return Coordinate(x,y);
+// if ( valid ) return Coordinate(x,y);
+// root--; if ( root <= 0) root += 3;
+// y = calcCubicYvalue ( x, -bound, bound, root, mdata, valid,
+// numroots );
+// if ( valid ) return Coordinate(x,y);
+// root--; if ( root <= 0) root += 3;
+// y = calcCubicYvalue ( x, -bound, bound, root, mdata, valid,
+// numroots );
+// assert ( valid );
+// return Coordinate(x,y);
+}
+
+const uint CubicImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 1;
+}
+
+const QCStringList CubicImp::propertiesInternalNames() const
+{
+ QCStringList l = Parent::propertiesInternalNames();
+ l << "cartesian-equation";
+ assert( l.size() == CubicImp::numberOfProperties() );
+ return l;
+
+}
+
+/*
+ * cartesian equation property contributed by Carlo Sardi
+ */
+
+const QCStringList CubicImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l << I18N_NOOP( "Cartesian Equation" );
+ assert( l.size() == CubicImp::numberOfProperties() );
+ return l;
+
+}
+
+const ObjectImpType* CubicImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return CubicImp::stype();
+}
+
+const char* CubicImp::iconForProperty( uint which ) const
+{
+ int pnum = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ if ( which == Parent::numberOfProperties() + pnum++ )
+ return "kig_text"; // cartesian equation string
+ else
+ assert( false );
+ return "";
+}
+
+ObjectImp* CubicImp::property( uint which, const KigDocument& w ) const
+{
+ int pnum = 0;
+
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ if ( which == Parent::numberOfProperties() + pnum++ )
+ return new StringImp( cartesianEquationString( w ) );
+ else
+ assert( false );
+ return new InvalidImp;
+}
+
+const CubicCartesianData CubicImp::data() const
+{
+ return mdata;
+}
+
+void CubicImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool CubicImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( CubicImp::stype() ) &&
+ static_cast<const CubicImp&>( rhs ).data() == data();
+}
+
+const ObjectImpType* CubicImp::type() const
+{
+ return CubicImp::stype();
+}
+
+const ObjectImpType* CubicImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "cubic",
+ I18N_NOOP( "cubic curve" ),
+ I18N_NOOP( "Select this cubic curve" ),
+ I18N_NOOP( "Select cubic curve %1" ),
+ I18N_NOOP( "Remove a Cubic Curve" ),
+ I18N_NOOP( "Add a Cubic Curve" ),
+ I18N_NOOP( "Move a Cubic Curve" ),
+ I18N_NOOP( "Attach to this cubic curve" ),
+ I18N_NOOP( "Show a Cubic Curve" ),
+ I18N_NOOP( "Hide a Cubic Curve" )
+ );
+ return &t;
+}
+
+bool CubicImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool CubicImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ double a000 = mdata.coeffs[0];
+ double a001 = mdata.coeffs[1];
+ double a002 = mdata.coeffs[2];
+ double a011 = mdata.coeffs[3];
+ double a012 = mdata.coeffs[4];
+ double a022 = mdata.coeffs[5];
+ double a111 = mdata.coeffs[6];
+ double a112 = mdata.coeffs[7];
+ double a122 = mdata.coeffs[8];
+ double a222 = mdata.coeffs[9];
+
+ double x = p.x;
+ double y = p.y;
+
+ double f = a000 + a001*x + a002*y + a011*x*x + a012*x*y + a022*y*y +
+ a111*x*x*x + a112*x*x*y + a122*x*y*y + a222*y*y*y;
+ double fx = a001 + 2*a011*x + a012*y + 3*a111*x*x + 2*a112*x*y + a122*y*y;
+ double fy = a002 + a012*x + 2*a022*y + a112*x*x + 2*a122*x*y + 3*a222*y*y;
+
+ double dist = fabs(f)/(fabs(fx) + fabs(fy));
+
+ return dist <= threshold;
+}
+
+bool CubicImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+}
+
+Rect CubicImp::surroundingRect() const
+{
+ // it's probably possible to calculate this if it exists, but for
+ // now we don't.
+ return Rect::invalidRect();
+}
+
+QString CubicImp::cartesianEquationString( const KigDocument& ) const
+{
+ /*
+ * unfortunately QStrings.arg method is limited to %1, %9, so we cannot
+ * treat all 10 arguments! Let's split the equation in two parts...
+ * Now this ends up also in the translation machinery, is this really
+ * necessary? Otherwise we could do a little bit of tidy up on the
+ * the equation (removal of zeros, avoid " ... + -1234 x ", etc.)
+ */
+
+ QString ret = i18n( "%6 x³ + %9 y³ + %7 x²y + %8 xy² + %5 y² + %3 x² + %4 xy + %1 x + %2 y" );
+ ret = ret.arg( mdata.coeffs[1], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[2], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[3], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[4], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[5], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[6], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[7], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[8], 0, 'g', 3 );
+ ret = ret.arg( mdata.coeffs[9], 0, 'g', 3 );
+
+ ret.append( i18n( " + %1 = 0" ) );
+ ret = ret.arg( mdata.coeffs[0], 0, 'g', 3 );
+
+ // we should find a common place to do this...
+ ret.replace( "+ -", "- " );
+ ret.replace( "+-", "-" );
+ return ret;
+}
diff --git a/kig/objects/cubic_imp.h b/kig/objects/cubic_imp.h
new file mode 100644
index 00000000..bb7d89c7
--- /dev/null
+++ b/kig/objects/cubic_imp.h
@@ -0,0 +1,81 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_CUBIC_IMP_H
+#define KIG_OBJECTS_CUBIC_IMP_H
+
+#include "curve_imp.h"
+
+#include "../misc/cubic-common.h"
+
+class LineData;
+
+/**
+ * An ObjectImp representing a cubic.
+ */
+class CubicImp
+ : public CurveImp
+{
+ const CubicCartesianData mdata;
+public:
+ typedef CurveImp Parent;
+ static const ObjectImpType* stype();
+
+ CubicImp( const CubicCartesianData& data );
+ ~CubicImp();
+
+ ObjectImp* transform( const Transformation& ) const;
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ Rect surroundingRect() const;
+ QString cartesianEquationString( const KigDocument& ) const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ CubicImp* copy() const;
+
+ double getParam( const Coordinate& point, const KigDocument& ) const;
+
+ // The getPoint function doesn't need the KigDocument argument, the
+ // first getPoint function is identical to the other one. It is
+ // only provided for implementing the CurveImp interface.
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+ const Coordinate getPoint( double param ) const;
+
+public:
+ /**
+ * Return the cartesian representation of this cubic.
+ */
+ const CubicCartesianData data() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+#endif
diff --git a/kig/objects/cubic_type.cc b/kig/objects/cubic_type.cc
new file mode 100644
index 00000000..c322b8c3
--- /dev/null
+++ b/kig/objects/cubic_type.cc
@@ -0,0 +1,185 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "cubic_type.h"
+
+#include "cubic_imp.h"
+#include "point_imp.h"
+#include "bogus_imp.h"
+
+#include <klocale.h>
+
+static const char cubictpstatement[] = I18N_NOOP( "Construct a cubic curve through this point" );
+
+static const struct ArgsParser::spec argsspecCubicB9P[] =
+{
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CubicB9PType )
+
+CubicB9PType::CubicB9PType()
+ : ArgsParserObjectType( "CubicB9P", argsspecCubicB9P, 9 )
+{
+}
+
+CubicB9PType::~CubicB9PType()
+{
+}
+
+const CubicB9PType* CubicB9PType::instance()
+{
+ static const CubicB9PType t;
+ return &t;
+}
+
+ObjectImp* CubicB9PType::calc( const Args& os, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( os, 2 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> points;
+ for ( uint i = 0; i < os.size(); ++i )
+ points.push_back( static_cast<const PointImp*>( os[i] )->coordinate() );
+
+ CubicCartesianData d = calcCubicThroughPoints( points );
+ if ( d.valid() )
+ return new CubicImp( d );
+ else
+ return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecCubicNodeB6P[] =
+{
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CubicNodeB6PType )
+
+CubicNodeB6PType::CubicNodeB6PType()
+ : ArgsParserObjectType( "CubicNodeB6P", argsspecCubicNodeB6P, 6 )
+{
+}
+
+CubicNodeB6PType::~CubicNodeB6PType()
+{
+}
+
+const CubicNodeB6PType* CubicNodeB6PType::instance()
+{
+ static const CubicNodeB6PType t;
+ return &t;
+}
+
+ObjectImp* CubicNodeB6PType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> points;
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ points.push_back( static_cast<const PointImp*>( *i )->coordinate() );
+
+ CubicCartesianData d = calcCubicNodeThroughPoints( points );
+ if ( d.valid() )
+ return new CubicImp( d );
+ else
+ return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecCubicCuspB4P[] =
+{
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true },
+ { PointImp::stype(), cubictpstatement,
+ I18N_NOOP( "Select a point for the new cubic to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CubicCuspB4PType )
+
+CubicCuspB4PType::CubicCuspB4PType()
+ : ArgsParserObjectType( "CubicCuspB4P", argsspecCubicCuspB4P, 4 )
+{
+}
+
+CubicCuspB4PType::~CubicCuspB4PType()
+{
+}
+
+const CubicCuspB4PType* CubicCuspB4PType::instance()
+{
+ static const CubicCuspB4PType t;
+ return &t;
+}
+
+ObjectImp* CubicCuspB4PType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 2 ) ) return new InvalidImp;
+
+ std::vector<Coordinate> points;
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ points.push_back( static_cast<const PointImp*>( *i )->coordinate() );
+
+ CubicCartesianData d = calcCubicCuspThroughPoints( points );
+ if ( d.valid() ) return new CubicImp( d );
+ else return new InvalidImp;
+}
+
+const ObjectImpType* CubicB9PType::resultId() const
+{
+ return CubicImp::stype();
+}
+
+const ObjectImpType* CubicNodeB6PType::resultId() const
+{
+ return CubicImp::stype();
+}
+
+const ObjectImpType* CubicCuspB4PType::resultId() const
+{
+ return CubicImp::stype();
+}
diff --git a/kig/objects/cubic_type.h b/kig/objects/cubic_type.h
new file mode 100644
index 00000000..39be7387
--- /dev/null
+++ b/kig/objects/cubic_type.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_CUBIC_TYPE_H
+#define KIG_OBJECTS_CUBIC_TYPE_H
+
+#include "object_type.h"
+
+class CubicB9PType
+ : public ArgsParserObjectType
+{
+ CubicB9PType();
+ ~CubicB9PType();
+public:
+ static const CubicB9PType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class CubicNodeB6PType
+ : public ArgsParserObjectType
+{
+ CubicNodeB6PType();
+ ~CubicNodeB6PType();
+public:
+ static const CubicNodeB6PType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class CubicCuspB4PType
+ : public ArgsParserObjectType
+{
+ CubicCuspB4PType();
+ ~CubicCuspB4PType();
+public:
+ static const CubicCuspB4PType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/curve_imp.cc b/kig/objects/curve_imp.cc
new file mode 100644
index 00000000..315cd8cb
--- /dev/null
+++ b/kig/objects/curve_imp.cc
@@ -0,0 +1,41 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "curve_imp.h"
+#include "../misc/coordinate.h"
+
+const ObjectImpType* CurveImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "curve",
+ I18N_NOOP( "curve" ),
+ I18N_NOOP( "Select this curve" ),
+ I18N_NOOP( "Select curve %1" ),
+ I18N_NOOP( "Remove a Curve" ),
+ I18N_NOOP( "Add a Curve" ),
+ I18N_NOOP( "Move a Curve" ),
+ I18N_NOOP( "Attach to this curve" ),
+ I18N_NOOP( "Show a Curve" ),
+ I18N_NOOP( "Hide a Curve" )
+ );
+ return &t;
+}
+
+Coordinate CurveImp::attachPoint() const
+{
+ return Coordinate::invalidCoord();
+}
diff --git a/kig/objects/curve_imp.h b/kig/objects/curve_imp.h
new file mode 100644
index 00000000..3a33a722
--- /dev/null
+++ b/kig/objects/curve_imp.h
@@ -0,0 +1,62 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_CURVE_IMP_H
+#define KIG_OBJECTS_CURVE_IMP_H
+
+#include "object_imp.h"
+
+/**
+ * This class represents a curve: something which is composed of
+ * points, like a line, a circle, a locus...
+ */
+class CurveImp
+ : public ObjectImp
+{
+public:
+ typedef ObjectImp Parent;
+
+ /**
+ * Returns the ObjectImpType representing the CurveImp type.
+ */
+ static const ObjectImpType* stype();
+
+ Coordinate attachPoint() const;
+
+ // param is between 0 and 1. Note that 0 and 1 should be the
+ // end-points. E.g. for a Line, getPoint(0) returns a more or less
+ // infinite point. getPoint(0.5) should return the point in the
+ // middle.
+ virtual double getParam( const Coordinate& point, const KigDocument& ) const = 0;
+ // this should be the inverse function of getPoint().
+ // Note that it should also do something reasonable when p is not on
+ // the curve. You can return an invalid Coordinate(
+ // Coordinate::invalidCoord() ) if you need to in some cases.
+ virtual const Coordinate getPoint( double param, const KigDocument& ) const = 0;
+
+ virtual CurveImp* copy() const = 0;
+
+ /**
+ * Return whether this Curve contains the given point. This is
+ * implemented as a numerical approximation. Implementations
+ * can/should use the value test_threshold in common.h as a
+ * threshold value.
+ */
+ virtual bool containsPoint( const Coordinate& p, const KigDocument& ) const = 0;
+};
+
+#endif
diff --git a/kig/objects/intersection_types.cc b/kig/objects/intersection_types.cc
new file mode 100644
index 00000000..804d498d
--- /dev/null
+++ b/kig/objects/intersection_types.cc
@@ -0,0 +1,338 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "intersection_types.h"
+
+#include "bogus_imp.h"
+#include "circle_imp.h"
+#include "conic_imp.h"
+#include "cubic_imp.h"
+#include "line_imp.h"
+#include "other_imp.h"
+#include "point_imp.h"
+
+#include <klocale.h>
+
+static const char intersectlinestat[] = I18N_NOOP( "Intersect with this line" );
+
+static const ArgsParser::spec argsspecConicLineIntersection[] =
+{
+ { ConicImp::stype(), I18N_NOOP( "Intersect with this conic" ),
+ "SHOULD NOT BE SEEN", true },
+ { AbstractLineImp::stype(), intersectlinestat, "SHOULD NOT BE SEEN", true },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicLineIntersectionType )
+
+ConicLineIntersectionType::ConicLineIntersectionType()
+ : ArgsParserObjectType( "ConicLineIntersection",
+ argsspecConicLineIntersection, 3 )
+{
+}
+
+ConicLineIntersectionType::~ConicLineIntersectionType()
+{
+}
+
+const ConicLineIntersectionType* ConicLineIntersectionType::instance()
+{
+ static const ConicLineIntersectionType t;
+ return &t;
+}
+
+ObjectImp* ConicLineIntersectionType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ int side = static_cast<const IntImp*>( parents[2] )->data();
+ assert( side == 1 || side == -1 );
+ const LineData line = static_cast<const AbstractLineImp*>( parents[1] )->data();
+
+ Coordinate ret;
+ if ( parents[0]->inherits( CircleImp::stype() ) )
+ {
+ // easy case..
+ const CircleImp* c = static_cast<const CircleImp*>( parents[0] );
+ ret = calcCircleLineIntersect(
+ c->center(), c->squareRadius(), line, side );
+ }
+ else
+ {
+ // harder case..
+ ret = calcConicLineIntersect(
+ static_cast<const ConicImp*>( parents[0] )->cartesianData(),
+ line, 0.0, side );
+ }
+ if ( ret.valid() ) return new PointImp( ret );
+ else return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecConicLineOtherIntersection[] =
+{
+ { ConicImp::stype(), I18N_NOOP( "Intersect with this conic" ),
+ "SHOULD NOT BE SEEN", true },
+ { AbstractLineImp::stype(), intersectlinestat, "SHOULD NOT BE SEEN", true },
+ { PointImp::stype(), I18N_NOOP( "Already computed intersection point"),
+ "SHOULD NOT BE SEEN", true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConicLineOtherIntersectionType )
+
+ConicLineOtherIntersectionType::ConicLineOtherIntersectionType()
+ : ArgsParserObjectType( "ConicLineOtherIntersection",
+ argsspecConicLineOtherIntersection, 3 )
+{
+}
+
+ConicLineOtherIntersectionType::~ConicLineOtherIntersectionType()
+{
+}
+
+const ConicLineOtherIntersectionType* ConicLineOtherIntersectionType::instance()
+{
+ static const ConicLineOtherIntersectionType t;
+ return &t;
+}
+
+ObjectImp* ConicLineOtherIntersectionType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ Coordinate p = static_cast<const PointImp*>( parents[2] )->coordinate();
+ const LineData line = static_cast<const AbstractLineImp*>( parents[1] )->data();
+
+ Coordinate ret;
+// if ( parents[0]->inherits( CircleImp::stype() ) )
+// {
+// // easy case..
+// const CircleImp* c = static_cast<const CircleImp*>( parents[0] );
+// ret = calcCircleLineIntersect(
+// c->center(), c->squareRadius(), line, side, valid );
+// }
+// else
+// {
+ // harder case..
+ double pax = p.x - line.a.x;
+ double pay = p.y - line.a.y;
+ double bax = line.b.x - line.a.x;
+ double bay = line.b.y - line.a.y;
+ double knownparam = (pax*bax + pay*bay)/(bax*bax + bay*bay);
+ ret = calcConicLineIntersect(
+ static_cast<const ConicImp*>( parents[0] )->cartesianData(),
+ line, knownparam, 0 );
+// }
+ if ( ret.valid() ) return new PointImp( ret );
+ else return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecLineLineIntersection[] =
+{
+ { AbstractLineImp::stype(), intersectlinestat, "SHOULD NOT BE SEEN", true },
+ { AbstractLineImp::stype(), intersectlinestat, "SHOULD NOT BE SEEN", true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LineLineIntersectionType )
+
+LineLineIntersectionType::LineLineIntersectionType()
+ : ArgsParserObjectType( "LineLineIntersection",
+ argsspecLineLineIntersection, 2 )
+{
+}
+
+LineLineIntersectionType::~LineLineIntersectionType()
+{
+}
+
+const LineLineIntersectionType* LineLineIntersectionType::instance()
+{
+ static const LineLineIntersectionType t;
+ return &t;
+}
+
+ObjectImp* LineLineIntersectionType::calc( const Args& parents, const KigDocument& d ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ Coordinate p =
+ calcIntersectionPoint(
+ static_cast<const AbstractLineImp*>( parents[0] )->data(),
+ static_cast<const AbstractLineImp*>( parents[1] )->data() );
+ if ( static_cast<const AbstractLineImp*>( parents[0] )->containsPoint( p, d ) &&
+ static_cast<const AbstractLineImp*>( parents[1] )->containsPoint( p, d ) )
+ return new PointImp( p );
+ else return new InvalidImp();
+}
+
+static const ArgsParser::spec argsspecLineCubicIntersection[] =
+{
+ { CubicImp::stype(), I18N_NOOP( "Intersect with this cubic curve" ),
+ "SHOULD NOT BE SEEN", true },
+ { AbstractLineImp::stype(), intersectlinestat, "SHOULD NOT BE SEEN", true },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LineCubicIntersectionType )
+
+LineCubicIntersectionType::LineCubicIntersectionType()
+ : ArgsParserObjectType( "LineCubicIntersection",
+ argsspecLineCubicIntersection, 3 )
+{
+}
+
+LineCubicIntersectionType::~LineCubicIntersectionType()
+{
+}
+
+const LineCubicIntersectionType* LineCubicIntersectionType::instance()
+{
+ static const LineCubicIntersectionType t;
+ return &t;
+}
+
+ObjectImp* LineCubicIntersectionType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ int which = static_cast<const IntImp*>( parents[2] )->data();
+ bool valid = true;
+ const Coordinate c = calcCubicLineIntersect(
+ static_cast<const CubicImp*>( parents[0] )->data(),
+ static_cast<const AbstractLineImp*>( parents[1] )->data(),
+ which, valid );
+ if ( valid ) return new PointImp( c );
+ else return new InvalidImp;
+}
+
+const ObjectImpType* ConicLineIntersectionType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* ConicLineOtherIntersectionType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* LineLineIntersectionType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* LineCubicIntersectionType::resultId() const
+{
+ return PointImp::stype();
+}
+
+static const ArgsParser::spec argsspecCircleCircleIntersection[] =
+{
+ { CircleImp::stype(), I18N_NOOP( "Intersect with this circle" ),
+ "SHOULD NOT BE SEEN", true },
+ { CircleImp::stype(), I18N_NOOP( "Intersect with this circle" ),
+ "SHOULD NOT BE SEEN", true },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CircleCircleIntersectionType )
+
+CircleCircleIntersectionType::CircleCircleIntersectionType()
+ : ArgsParserObjectType( "CircleCircleIntersection",
+ argsspecCircleCircleIntersection, 3 )
+{
+}
+
+CircleCircleIntersectionType::~CircleCircleIntersectionType()
+{
+}
+
+const CircleCircleIntersectionType* CircleCircleIntersectionType::instance()
+{
+ static const CircleCircleIntersectionType t;
+ return &t;
+}
+
+ObjectImp* CircleCircleIntersectionType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ int side = static_cast<const IntImp*>( parents[2] )->data();
+ assert( side == 1 || side == -1 );
+ const CircleImp* c1 = static_cast<const CircleImp*>( parents[0] );
+ const CircleImp* c2 = static_cast<const CircleImp*>( parents[1] );
+ const Coordinate o1 = c1->center();
+ const Coordinate o2 = c2->center();
+ const double r1sq = c1->squareRadius();
+ const Coordinate a = calcCircleRadicalStartPoint(
+ o1, o2, r1sq, c2->squareRadius()
+ );
+ const LineData line = LineData (a, Coordinate ( a.x -o2.y + o1.y, a.y + o2.x - o1.x ));
+ Coordinate ret = calcCircleLineIntersect( o1, r1sq, line, side );
+ if ( ret.valid() ) return new PointImp( ret );
+ else return new InvalidImp;
+}
+
+const ObjectImpType* CircleCircleIntersectionType::resultId() const
+{
+ return PointImp::stype();
+}
+
+static const ArgsParser::spec argsspecArcLineIntersection[] =
+{
+ { ArcImp::stype(), I18N_NOOP( "Intersect with this arc" ),
+ "SHOULD NOT BE SEEN", true },
+ { AbstractLineImp::stype(), intersectlinestat, "SHOULD NOT BE SEEN", true },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ArcLineIntersectionType )
+
+ArcLineIntersectionType::ArcLineIntersectionType()
+ : ArgsParserObjectType( "ArcLineIntersection",
+ argsspecArcLineIntersection, 3 )
+{
+}
+
+ArcLineIntersectionType::~ArcLineIntersectionType()
+{
+}
+
+const ArcLineIntersectionType* ArcLineIntersectionType::instance()
+{
+ static const ArcLineIntersectionType t;
+ return &t;
+}
+
+ObjectImp* ArcLineIntersectionType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ int side = static_cast<const IntImp*>( parents[2] )->data();
+ assert( side == 1 || side == -1 );
+ const LineData line = static_cast<const AbstractLineImp*>( parents[1] )->data();
+
+ const ArcImp* c = static_cast<const ArcImp*>( parents[0] );
+ const double r = c->radius();
+ Coordinate ret = calcArcLineIntersect( c->center(), r*r, c->startAngle(),
+ c->angle(), line, side );
+ if ( ret.valid() ) return new PointImp( ret );
+ else return new InvalidImp;
+}
+
+const ObjectImpType* ArcLineIntersectionType::resultId() const
+{
+ return PointImp::stype();
+}
diff --git a/kig/objects/intersection_types.h b/kig/objects/intersection_types.h
new file mode 100644
index 00000000..9e1df62e
--- /dev/null
+++ b/kig/objects/intersection_types.h
@@ -0,0 +1,105 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_INTERSECTION_TYPES_H
+#define KIG_OBJECTS_INTERSECTION_TYPES_H
+
+#include "object_type.h"
+
+/**
+ * conic line intersection. This also serves as circle-line
+ * intersection, in which case it uses the easier way to calc
+ * ... There is no separate CircleLineIntersectionPoint, since the
+ * difference between both types is quite small ( same number of
+ * intersections with a line, for example.. ), and since with
+ * transformations, Circles might dynamically change types to
+ * Conics..
+ */
+class ConicLineIntersectionType
+ : public ArgsParserObjectType
+{
+ ConicLineIntersectionType();
+ ~ConicLineIntersectionType();
+public:
+ static const ConicLineIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * conic line 'other' intersection. In case we already know one of the
+ * two intersections
+ */
+class ConicLineOtherIntersectionType
+ : public ArgsParserObjectType
+{
+ ConicLineOtherIntersectionType();
+ ~ConicLineOtherIntersectionType();
+public:
+ static const ConicLineOtherIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class LineLineIntersectionType
+ : public ArgsParserObjectType
+{
+ LineLineIntersectionType();
+ ~LineLineIntersectionType();
+public:
+ static const LineLineIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class LineCubicIntersectionType
+ : public ArgsParserObjectType
+{
+ LineCubicIntersectionType();
+ ~LineCubicIntersectionType();
+public:
+ static const LineCubicIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class CircleCircleIntersectionType
+ : public ArgsParserObjectType
+{
+ CircleCircleIntersectionType();
+ ~CircleCircleIntersectionType();
+public:
+ static const CircleCircleIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * arc line intersection.
+ */
+class ArcLineIntersectionType
+ : public ArgsParserObjectType
+{
+ ArcLineIntersectionType();
+ ~ArcLineIntersectionType();
+public:
+ static const ArcLineIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/inversion_type.cc b/kig/objects/inversion_type.cc
new file mode 100644
index 00000000..0ab77780
--- /dev/null
+++ b/kig/objects/inversion_type.cc
@@ -0,0 +1,412 @@
+// Copyright (C) 2005 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "inversion_type.h"
+#include "point_imp.h"
+#include "line_imp.h"
+#include "circle_imp.h"
+#include "other_imp.h"
+#include "bogus_imp.h"
+
+#include "../misc/common.h"
+
+#include <klocale.h>
+
+static const char str1[] = I18N_NOOP( "Invert with respect to this circle" );
+static const char str2[] = I18N_NOOP( "Select the circle we want to invert against..." );
+
+static const ArgsParser::spec argsspecInvertPoint[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Compute the inversion of this point" ),
+ I18N_NOOP( "Select the point to invert..." ), false },
+ { CircleImp::stype(), str1, str2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InvertPointType )
+
+InvertPointType::InvertPointType()
+ : ArgsParserObjectType( "InvertPoint", argsspecInvertPoint, 2 )
+{
+}
+
+InvertPointType::~InvertPointType()
+{
+}
+
+const InvertPointType* InvertPointType::instance()
+{
+ static const InvertPointType s;
+ return &s;
+}
+
+const ObjectImpType* InvertPointType::resultId() const
+{
+ return PointImp::stype();
+}
+
+ObjectImp* InvertPointType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const CircleImp* c = static_cast<const CircleImp*>( args[1] );
+ Coordinate center = c->center();
+ Coordinate relp = static_cast<const PointImp*>( args[0] )->coordinate() - center;
+ double radiussq = c->squareRadius();
+ double normsq = relp.x*relp.x + relp.y*relp.y;
+ if ( normsq == 0 ) return new InvalidImp;
+ return new PointImp( center + (radiussq/normsq)*relp );
+}
+
+/*
+ * inversion of a line
+ */
+
+static const ArgsParser::spec argsspecInvertLine[] =
+{
+ { LineImp::stype(), I18N_NOOP( "Compute the inversion of this line" ),
+ I18N_NOOP( "Select the line to invert..." ), false },
+ { CircleImp::stype(), str1, str2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InvertLineType )
+
+InvertLineType::InvertLineType()
+ : ArgsParserObjectType( "InvertLine", argsspecInvertLine, 2 )
+{
+}
+
+InvertLineType::~InvertLineType()
+{
+}
+
+const InvertLineType* InvertLineType::instance()
+{
+ static const InvertLineType s;
+ return &s;
+}
+
+const ObjectImpType* InvertLineType::resultId() const
+{
+ return CircleImp::stype();
+}
+
+ObjectImp* InvertLineType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const CircleImp* c = static_cast<const CircleImp*>( args[1] );
+ Coordinate center = c->center();
+ double radiussq = c->squareRadius();
+ const LineData line = static_cast<const AbstractLineImp*>( args[0] )->data();
+ Coordinate relb = line.b - center;
+ Coordinate ab = line.b - line.a;
+ double t = (relb.x*ab.x + relb.y*ab.y)/(ab.x*ab.x + ab.y*ab.y);
+ Coordinate relh = relb - t*ab;
+ double normhsq = relh.x*relh.x + relh.y*relh.y;
+ if ( normhsq < 1e-12*radiussq ) return new LineImp( line.a, line.b );
+ Coordinate newcenter = center + 0.5*radiussq/normhsq*relh;
+ double newradius = 0.5*radiussq/sqrt(normhsq);
+
+ return new CircleImp( newcenter, newradius );
+}
+
+/*
+ * inversion of a segment
+ */
+
+static const ArgsParser::spec argsspecInvertSegment[] =
+{
+ { SegmentImp::stype(), I18N_NOOP( "Compute the inversion of this segment" ),
+ I18N_NOOP( "Select the segment to invert..." ), false },
+ { CircleImp::stype(), str1, str2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InvertSegmentType )
+
+InvertSegmentType::InvertSegmentType()
+ : ArgsParserObjectType( "InvertSegment", argsspecInvertSegment, 2 )
+{
+}
+
+InvertSegmentType::~InvertSegmentType()
+{
+}
+
+const InvertSegmentType* InvertSegmentType::instance()
+{
+ static const InvertSegmentType s;
+ return &s;
+}
+
+const ObjectImpType* InvertSegmentType::resultId() const
+{
+ return ArcImp::stype();
+}
+
+ObjectImp* InvertSegmentType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const CircleImp* c = static_cast<const CircleImp*>( args[1] );
+ Coordinate center = c->center();
+ double radiussq = c->squareRadius();
+ const LineData line = static_cast<const AbstractLineImp*>( args[0] )->data();
+ Coordinate rela = line.a - center;
+ Coordinate relb = line.b - center;
+ Coordinate ab = relb - rela;
+ double t = (relb.x*ab.x + relb.y*ab.y)/(ab.x*ab.x + ab.y*ab.y);
+ Coordinate relh = relb - t*ab;
+ double normhsq = relh.x*relh.x + relh.y*relh.y;
+
+ /*
+ * compute the inversion of the two endpoints
+ */
+
+ Coordinate newcenterrel = 0.5*radiussq/normhsq*relh;
+ Coordinate relainv = radiussq/rela.squareLength() * rela;
+ Coordinate relbinv = radiussq/relb.squareLength() * relb;
+
+ if ( normhsq < 1e-12*radiussq )
+ {
+ if ( rela.squareLength() < 1e-12 )
+ {
+ return new RayImp( relbinv + center, 2*relbinv + center );
+ }
+ if ( relb.squareLength() < 1e-12 )
+ {
+ return new RayImp( relainv + center, 2*relainv + center );
+ }
+ if ( relb.x*rela.x + relb.y*rela.y > 0 )
+ {
+ return new SegmentImp( relainv + center, relbinv + center );
+ }
+ return new InvalidImp();
+ }
+ double newradius = 0.5*radiussq/sqrt(normhsq);
+
+ relainv -= newcenterrel;
+ relbinv -= newcenterrel;
+ double angle1 = atan2( relainv.y, relainv.x );
+ double angle2 = atan2( relbinv.y, relbinv.x );
+ double angle = angle2 - angle1;
+ if ( ab.x*rela.y - ab.y*rela.x > 0 )
+ {
+ angle1 = angle2;
+ angle = -angle;
+ }
+ while ( angle1 < 0 ) angle1 += 2*M_PI;
+ while ( angle1 >= 2*M_PI ) angle1 -= 2*M_PI;
+ while ( angle < 0 ) angle += 2*M_PI;
+ while ( angle >= 2*M_PI ) angle -= 2*M_PI;
+ return new ArcImp( newcenterrel + center, newradius, angle1, angle );
+}
+
+/*
+ * inversion of a circle
+ */
+
+static const ArgsParser::spec argsspecInvertCircle[] =
+{
+ { CircleImp::stype(), I18N_NOOP( "Compute the inversion of this circle" ),
+ I18N_NOOP( "Select the circle to invert..." ), false },
+ { CircleImp::stype(), str1, str2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InvertCircleType )
+
+InvertCircleType::InvertCircleType()
+ : ArgsParserObjectType( "InvertCircle", argsspecInvertCircle, 2 )
+{
+}
+
+InvertCircleType::~InvertCircleType()
+{
+}
+
+const InvertCircleType* InvertCircleType::instance()
+{
+ static const InvertCircleType s;
+ return &s;
+}
+
+const ObjectImpType* InvertCircleType::resultId() const
+{
+ return CircleImp::stype();
+}
+
+ObjectImp* InvertCircleType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const CircleImp* refcircle = static_cast<const CircleImp*>( args[1] );
+ Coordinate refc = refcircle->center();
+ double refrsq = refcircle->squareRadius();
+ const CircleImp* circle = static_cast<const CircleImp*>( args[0] );
+ Coordinate c = circle->center() - refc;
+ double clength = c.length();
+ Coordinate cnorm = Coordinate (1.,0.);
+ if ( clength != 0.0 ) cnorm = c/clength;
+ double r = circle->radius();
+ Coordinate tc = r*cnorm;
+ Coordinate b = c + tc; //(1 + t)*c;
+ double bsq = b.x*b.x + b.y*b.y;
+ Coordinate bprime = refrsq*b/bsq;
+ if ( std::fabs( clength - r ) < 1e-6*clength ) // circle through origin -> line
+ {
+ return new LineImp( bprime+refc, bprime+refc+Coordinate( -c.y, c.x ) );
+ }
+
+ Coordinate a = c - tc;
+ double asq = a.x*a.x + a.y*a.y;
+ Coordinate aprime = refrsq*a/asq;
+
+ Coordinate cprime = 0.5*(aprime + bprime);
+ double rprime = 0.5*( bprime - aprime ).length();
+
+ return new CircleImp( cprime + refc, rprime );
+}
+
+/*
+ * inversion of an arc
+ */
+
+static const ArgsParser::spec argsspecInvertArc[] =
+{
+ { ArcImp::stype(), I18N_NOOP( "Compute the inversion of this arc" ),
+ I18N_NOOP( "Select the arc to invert..." ), false },
+ { CircleImp::stype(), str1, str2, false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InvertArcType )
+
+InvertArcType::InvertArcType()
+ : ArgsParserObjectType( "InvertArc", argsspecInvertArc, 2 )
+{
+}
+
+InvertArcType::~InvertArcType()
+{
+}
+
+const InvertArcType* InvertArcType::instance()
+{
+ static const InvertArcType s;
+ return &s;
+}
+
+const ObjectImpType* InvertArcType::resultId() const
+{
+ return ArcImp::stype();
+}
+
+ObjectImp* InvertArcType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const CircleImp* refcircle = static_cast<const CircleImp*>( args[1] );
+ Coordinate refc = refcircle->center();
+ double refrsq = refcircle->squareRadius();
+ const ArcImp* arc = static_cast<const ArcImp*>( args[0] );
+ Coordinate c = arc->center() - refc;
+ double clength = c.length();
+ Coordinate cnorm = Coordinate (1.,0.);
+ if ( clength != 0.0 ) cnorm = c/clength;
+ double r = arc->radius();
+ /*
+ * r > clength means center of inversion circle inside of circle supporting arc
+ */
+ Coordinate tc = r*cnorm;
+ Coordinate b = c + tc;
+ double bsq = b.x*b.x + b.y*b.y;
+ Coordinate bprime = refrsq*b/bsq;
+ if ( std::fabs( clength - r ) < 1e-6*clength ) // support circle through origin ->
+ // segment, ray or invalid
+ // (reversed segment, union of two rays)
+ {
+ bool valid1 = false;
+ bool valid2 = false;
+ Coordinate ep1 = arc->firstEndPoint() - refc;
+ Coordinate ep2 = arc->secondEndPoint() - refc;
+ Coordinate ep1inv = Coordinate::invalidCoord();
+ Coordinate ep2inv = Coordinate::invalidCoord();
+ double ep1sq = ep1.squareLength();
+ if ( ep1sq > 1e-12 )
+ {
+ valid1 = true;
+ ep1inv = refrsq/ep1sq * ep1;
+ }
+ Coordinate rayendp = ep1inv;
+ int sign = 1;
+ double ep2sq = ep2.squareLength();
+ if ( ep2sq > 1e-12 )
+ {
+ valid2 = true;
+ ep2inv = refrsq/ep2sq * ep2;
+ rayendp = ep2inv;
+ sign = -1;
+ }
+ if ( valid1 || valid2 )
+ {
+ if ( valid1 && valid2 )
+ {
+ // this gives either a segment or the complement of a segment (relative
+ // to its support line). We return a segment in any case (fixme)
+ double ang = atan2( -c.y, -c.x );
+ double sa = arc->startAngle();
+ if ( ang < sa ) ang += 2*M_PI;
+ if ( ang - sa - arc->angle() < 0 ) return new InvalidImp();
+ return new SegmentImp( ep1inv + refc, ep2inv + refc );
+ } else
+ return new RayImp ( rayendp + refc,
+ rayendp + refc + sign*Coordinate( -c.y, c.x ) ); // this should give a Ray
+ } else
+ return new LineImp( bprime+refc, bprime+refc+Coordinate( -c.y, c.x ) );
+ }
+
+ Coordinate a = c - tc;
+ double asq = a.x*a.x + a.y*a.y;
+ Coordinate aprime = refrsq*a/asq;
+
+ Coordinate cprime = 0.5*(aprime + bprime);
+ double rprime = 0.5*( bprime - aprime ).length();
+
+ Coordinate ep1 = arc->firstEndPoint() - refc;
+ double ang1 = arc->startAngle();
+ double newstartangle = 2*atan2(ep1.y,ep1.x) - ang1;
+ Coordinate ep2 = arc->secondEndPoint() - refc;
+ double ang2 = ang1 + arc->angle();
+ double newendangle = 2*atan2(ep2.y,ep2.x) - ang2;
+ double newangle = newendangle - newstartangle;
+
+ /*
+ * newstartangle and newendangle might have to be exchanged:
+ * this is the case if the circle supporting our arc does not
+ * contain the center of the inversion circle
+ */
+ if ( r < clength )
+ {
+ newstartangle = newendangle - M_PI;
+ newangle = - newangle;
+ // newendangle is no-longer valid
+ }
+ while ( newstartangle < 0 ) newstartangle += 2*M_PI;
+ while ( newstartangle >= 2*M_PI ) newstartangle -= 2*M_PI;
+ while ( newangle < 0 ) newangle += 2*M_PI;
+ while ( newangle >= 2*M_PI ) newangle -= 2*M_PI;
+ return new ArcImp( cprime + refc, rprime, newstartangle, newangle );
+}
+
diff --git a/kig/objects/inversion_type.h b/kig/objects/inversion_type.h
new file mode 100644
index 00000000..d7b97957
--- /dev/null
+++ b/kig/objects/inversion_type.h
@@ -0,0 +1,86 @@
+// Copyright (C) 2005 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_INVERSION_TYPE_H
+#define KIG_OBJECTS_INVERSION_TYPE_H
+
+#include "base_type.h"
+
+/**
+ * Inversion of a point, line
+ */
+class InvertPointType
+ : public ArgsParserObjectType
+{
+ InvertPointType();
+ ~InvertPointType();
+public:
+ static const InvertPointType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class InvertLineType
+ : public ArgsParserObjectType
+{
+ InvertLineType();
+ ~InvertLineType();
+public:
+ static const InvertLineType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class InvertSegmentType
+ : public ArgsParserObjectType
+{
+ InvertSegmentType();
+ ~InvertSegmentType();
+public:
+ static const InvertSegmentType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class InvertCircleType
+ : public ArgsParserObjectType
+{
+ InvertCircleType();
+ ~InvertCircleType();
+public:
+ static const InvertCircleType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class InvertArcType
+ : public ArgsParserObjectType
+{
+ InvertArcType();
+ ~InvertArcType();
+public:
+ static const InvertArcType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/line_imp.cc b/kig/objects/line_imp.cc
new file mode 100644
index 00000000..6f3c6002
--- /dev/null
+++ b/kig/objects/line_imp.cc
@@ -0,0 +1,571 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "line_imp.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+
+#include "../misc/rect.h"
+#include "../misc/common.h"
+#include "../misc/kigtransform.h"
+#include "../misc/kigpainter.h"
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+#include <cmath>
+using namespace std;
+
+AbstractLineImp::AbstractLineImp( const Coordinate& a, const Coordinate& b )
+ : mdata( a, b )
+{
+}
+
+AbstractLineImp::~AbstractLineImp()
+{
+}
+
+bool AbstractLineImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ return lineInRect( r, mdata.a, mdata.b, width, this, w );
+}
+
+const uint AbstractLineImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 2;
+}
+
+const ObjectImpType* AbstractLineImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return AbstractLineImp::stype();
+}
+
+const char* AbstractLineImp::iconForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ if ( which == Parent::numberOfProperties() )
+ return "slope"; // slope
+ if ( which == Parent::numberOfProperties() + 1 )
+ return "kig_text"; // equation
+ else assert( false );
+ return "";
+}
+
+ObjectImp* AbstractLineImp::property( uint which, const KigDocument& w ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ if ( which == Parent::numberOfProperties() )
+ return new DoubleImp( slope() );
+ if ( which == Parent::numberOfProperties() + 1 )
+ return new StringImp( equationString() );
+ else assert( false );
+ return new InvalidImp;
+}
+
+const QCStringList AbstractLineImp::propertiesInternalNames() const
+{
+ QCStringList l = Parent::propertiesInternalNames();
+ l << "slope";
+ l << "equation";
+ assert( l.size() == AbstractLineImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList AbstractLineImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l << I18N_NOOP( "Slope" );
+ l << I18N_NOOP( "Equation" );
+ assert( l.size() == AbstractLineImp::numberOfProperties() );
+ return l;
+}
+
+const uint SegmentImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 4;
+}
+
+const QCStringList SegmentImp::propertiesInternalNames() const
+{
+ QCStringList s = Parent::propertiesInternalNames();
+ s << "length";
+ s << "mid-point";
+ s << "end-point-A";
+ s << "end-point-B";
+ assert( s.size() == SegmentImp::numberOfProperties() );
+ return s;
+}
+
+const QCStringList SegmentImp::properties() const
+{
+ QCStringList s = Parent::properties();
+ s << I18N_NOOP( "Length" );
+ s << I18N_NOOP( "Mid Point" );
+ s << I18N_NOOP( "First End Point" );
+ s << I18N_NOOP( "Second End Point" );
+ assert( s.size() == SegmentImp::numberOfProperties() );
+ return s;
+}
+
+const ObjectImpType* SegmentImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return SegmentImp::stype();
+}
+
+const char* SegmentImp::iconForProperty( uint which ) const
+{
+ int pnum = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return "distance"; // length
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return "segment_midpoint"; // mid point
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return "endpoint1"; // mid point
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return "endpoint2"; // mid point
+ else assert( false );
+ return "";
+}
+
+ObjectImp* SegmentImp::property( uint which, const KigDocument& w ) const
+{
+ int pnum = 0;
+
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new DoubleImp( mdata.dir().length() );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new PointImp( ( mdata.a + mdata.b ) / 2 );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new PointImp( mdata.a );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return new PointImp( mdata.b );
+ else assert( false );
+ return new InvalidImp;
+}
+
+double AbstractLineImp::slope() const
+{
+ Coordinate diff = mdata.dir();
+ return diff.y / diff.x;
+}
+
+const QString AbstractLineImp::equationString() const
+{
+ Coordinate p = mdata.a;
+ Coordinate q = mdata.b;
+
+ double m = ( q.y - p.y ) / ( q.x - p.x );
+ double r = - ( q.y - p.y ) * p.x / ( q.x - p.x ) + p.y;
+
+ QString ret = QString::fromUtf8( "y = %1x " ) +
+ QString::fromUtf8( r > 0 ? "+" : "-" ) +
+ QString::fromUtf8( " %2" );
+
+ ret = ret.arg( m, 0, 'g', 3 );
+ ret = ret.arg( abs( r ), 0, 'g', 3 );
+
+ return ret;
+}
+
+void SegmentImp::draw( KigPainter& p ) const
+{
+ p.drawSegment( mdata );
+}
+
+bool SegmentImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( p, w.screenInfo().normalMiss( width ) );
+}
+
+void RayImp::draw( KigPainter& p ) const
+{
+ p.drawRay( mdata );
+}
+
+bool RayImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( p, w.screenInfo().normalMiss( width ) );
+}
+
+void LineImp::draw( KigPainter& p ) const
+{
+ p.drawLine( mdata );
+}
+
+bool LineImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( p, w.screenInfo().normalMiss( width ) );
+}
+
+SegmentImp::SegmentImp( const Coordinate& a, const Coordinate& b )
+ : AbstractLineImp( a, b )
+{
+}
+
+RayImp::RayImp( const Coordinate& a, const Coordinate& b )
+ : AbstractLineImp( a, b )
+{
+}
+
+LineImp::LineImp( const Coordinate& a, const Coordinate& b )
+ : AbstractLineImp( a, b )
+{
+}
+
+SegmentImp* SegmentImp::copy() const
+{
+ return new SegmentImp( mdata );
+}
+
+RayImp* RayImp::copy() const
+{
+ return new RayImp( mdata );
+}
+
+LineImp* LineImp::copy() const
+{
+ return new LineImp( mdata );
+}
+
+const Coordinate SegmentImp::getPoint( double param, const KigDocument& ) const
+{
+ return mdata.a + mdata.dir()*param;
+}
+
+double SegmentImp::getParam( const Coordinate& p, const KigDocument& ) const
+{
+ Coordinate pt = calcPointOnPerpend( data(), p );
+ pt = calcIntersectionPoint( data(), LineData( p, pt ) );
+ // if pt is over the end of the segment ( i.e. it's on the line
+ // which the segment is a part of, but not of the segment itself..;
+ // ) we set it to one of the end points of the segment...
+ if ((pt - mdata.a).length() > mdata.dir().length() )
+ pt = mdata.b;
+ else if ( (pt- mdata.b).length() > mdata.dir().length() )
+ pt = mdata.a;
+ if (mdata.b == mdata.a) return 0;
+ return ((pt - mdata.a).length())/(mdata.dir().length());
+}
+
+LineData AbstractLineImp::data() const
+{
+ return mdata;
+}
+
+const Coordinate RayImp::getPoint( double param, const KigDocument& ) const
+{
+ param = 1.0/param - 1.0;
+ return mdata.a + mdata.dir()*param;
+}
+
+double RayImp::getParam( const Coordinate& p, const KigDocument& ) const
+{
+ const LineData ld = data();
+ Coordinate pt = calcPointOnPerpend( ld, p );
+ pt = calcIntersectionPoint( ld, LineData( p, pt ));
+ // if pt is over the end of the ray ( i.e. it's on the line
+ // which the ray is a part of, but not of the ray itself..;
+ // ) we set it to the start point of the ray...
+ Coordinate dir = ld.dir();
+ pt -= ld.a;
+ double param;
+ if ( dir.x != 0 ) param = pt.x / dir.x;
+ else if ( dir.y != 0 ) param = pt.y / dir.y;
+ else param = 0.;
+ if ( param < 0. ) param = 0.;
+
+ // mp: let's try with 1/(x+1), this reverses the mapping, but
+ // should allow to take advantage of the tightness of floating point
+ // numbers near zero, in order to get more possible positions near
+ // infinity
+
+ param = 1./( param + 1. );
+
+ assert( param >= 0. && param <= 1. );
+ return param;
+}
+
+const Coordinate LineImp::getPoint( double p, const KigDocument& ) const
+{
+ // inspired upon KSeg
+
+ // we need to spread the points over the line, it should also come near
+ // the (infinite) end of the line, but most points should be near
+ // the two points we contain...
+ if ( p <= 0. ) p = 1e-6;
+ if ( p >= 1. ) p = 1 - 1e-6;
+ p = 2*p - 1;
+ if (p > 0) p = p/(1 - p);
+ else p = p/(1 + p);
+// p *= 1024; // such multiplying factor could be useful in order to
+ // have more points near infinity, at the expense of
+ // points near ma and mb
+ return mdata.a + p*mdata.dir();
+}
+
+double LineImp::getParam( const Coordinate& point, const KigDocument& ) const
+{
+ // somewhat the reverse of getPoint, although it also supports
+ // points not on the line...
+
+ Coordinate pa = point - mdata.a;
+ Coordinate ba = mdata.dir();
+ double balsq = ba.x*ba.x + ba.y*ba.y;
+ assert (balsq > 0);
+
+ double p = (pa.x*ba.x + pa.y*ba.y)/balsq;
+// p /= 1024;
+ if (p > 0) p = p/(1+p);
+ else p = p/(1-p);
+
+ return 0.5*(p + 1);
+}
+
+ObjectImp* SegmentImp::transform( const Transformation& t ) const
+{
+ if ( ! t.isAffine() ) /* we need to check the position of the two points */
+ {
+ if ( t.getProjectiveIndicator( mdata.a ) *
+ t.getProjectiveIndicator( mdata.b ) < 0 )
+ return new InvalidImp();
+ }
+ Coordinate na = t.apply( mdata.a );
+ Coordinate nb = t.apply( mdata.b );
+ if( na.valid() && nb.valid() ) return new SegmentImp( na, nb );
+ else return new InvalidImp();
+}
+
+ObjectImp* LineImp::transform( const Transformation& t ) const
+{
+ Coordinate na = t.apply( mdata.a );
+ Coordinate nb = t.apply( mdata.b );
+ if ( na.valid() && nb.valid() ) return new LineImp( na, nb );
+ else return new InvalidImp();
+}
+
+ObjectImp* RayImp::transform( const Transformation& t ) const
+{
+ if ( ! t.isAffine() ) /* we need to check the position of the two points */
+ {
+ double pa = t.getProjectiveIndicator( mdata.a );
+ double pb = t.getProjectiveIndicator( mdata.b );
+ if ( pa < 0 ) pb = -pb;
+ if ( pb < fabs (pa) ) return new InvalidImp();
+ Coordinate na = t.apply( mdata.a );
+ Coordinate nb = t.apply0( mdata.b - mdata.a );
+ if ( na.valid() && nb.valid() ) return new SegmentImp( na, nb );
+ else return new InvalidImp();
+ }
+ Coordinate na = t.apply( mdata.a );
+ Coordinate nb = t.apply( mdata.b );
+ if ( na.valid() && nb.valid() ) return new RayImp( na, nb );
+ else return new InvalidImp();
+}
+
+AbstractLineImp::AbstractLineImp( const LineData& d )
+ : mdata( d )
+{
+}
+
+SegmentImp::SegmentImp( const LineData& d )
+ : AbstractLineImp( d )
+{
+}
+
+RayImp::RayImp( const LineData& d )
+ : AbstractLineImp( d )
+{
+}
+
+LineImp::LineImp( const LineData& d )
+ : AbstractLineImp( d )
+{
+}
+
+double SegmentImp::length() const
+{
+ return mdata.length();
+}
+
+void SegmentImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void RayImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void LineImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool AbstractLineImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.type() == type() &&
+ static_cast<const AbstractLineImp&>( rhs ).data() == data();
+}
+
+const ObjectImpType* AbstractLineImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "line", I18N_NOOP( "line" ),
+ I18N_NOOP( "Select a Line" ), 0, 0, 0, 0, 0, 0, 0 );
+ return &t;
+}
+
+const ObjectImpType* LineImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "line",
+ I18N_NOOP( "line" ),
+ I18N_NOOP( "Select this line" ),
+ I18N_NOOP( "Select line %1" ),
+ I18N_NOOP( "Remove a Line" ),
+ I18N_NOOP( "Add a Line" ),
+ I18N_NOOP( "Move a Line" ),
+ I18N_NOOP( "Attach to this line" ),
+ I18N_NOOP( "Show a Line" ),
+ I18N_NOOP( "Hide a Line" )
+ );
+ return &t;
+}
+
+const ObjectImpType* SegmentImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "segment",
+ I18N_NOOP( "segment" ),
+ I18N_NOOP( "Select this segment" ),
+ I18N_NOOP( "Select segment %1" ),
+ I18N_NOOP( "Remove a Segment" ),
+ I18N_NOOP( "Add a Segment" ),
+ I18N_NOOP( "Move a Segment" ),
+ I18N_NOOP( "Attach to this segment" ),
+ I18N_NOOP( "Show a Segment" ),
+ I18N_NOOP( "Hide a Segment" )
+ );
+ return &t;
+}
+
+const ObjectImpType* RayImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "ray",
+ I18N_NOOP( "half-line" ),
+ I18N_NOOP( "Select this half-line" ),
+ I18N_NOOP( "Select half-line %1" ),
+ I18N_NOOP( "Remove a Half-Line" ),
+ I18N_NOOP( "Add a Half-Line" ),
+ I18N_NOOP( "Move a Half-Line" ),
+ I18N_NOOP( "Attach to this half-line" ),
+ I18N_NOOP( "Show a Half-Line" ),
+ I18N_NOOP( "Hide a Half-Line" )
+ );
+ return &t;
+}
+
+const ObjectImpType* SegmentImp::type() const
+{
+ return SegmentImp::stype();
+}
+
+const ObjectImpType* RayImp::type() const
+{
+ return RayImp::stype();
+}
+
+const ObjectImpType* LineImp::type() const
+{
+ return LineImp::stype();
+}
+
+bool SegmentImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool SegmentImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ return isOnSegment( p, mdata.a, mdata.b, threshold );
+}
+
+bool RayImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool RayImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ return isOnRay( p, mdata.a, mdata.b, threshold );
+}
+
+bool LineImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool LineImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ return isOnLine( p, mdata.a, mdata.b, threshold );
+}
+
+bool AbstractLineImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ int pnum = 0;
+
+ if ( which < Parent::numberOfProperties() )
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return false;
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return true;
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return true;
+ else if ( which == Parent::numberOfProperties() + pnum++ )
+ return true;
+ else assert( false );
+ return false;
+}
+
+Rect SegmentImp::surroundingRect() const
+{
+ return Rect( mdata.a, mdata.b );
+}
+
+Rect RayImp::surroundingRect() const
+{
+ return Rect::invalidRect();
+}
+
+Rect LineImp::surroundingRect() const
+{
+ return Rect::invalidRect();
+}
diff --git a/kig/objects/line_imp.h b/kig/objects/line_imp.h
new file mode 100644
index 00000000..c9014613
--- /dev/null
+++ b/kig/objects/line_imp.h
@@ -0,0 +1,215 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_LINE_IMP_H
+#define KIG_OBJECTS_LINE_IMP_H
+
+#include "curve_imp.h"
+
+#include "../misc/common.h"
+
+class LineData;
+
+/**
+ * An ObjectImp class that is the base of the line-like ObjectImp's:
+ * SegmentImp, LineImp and RayImp..
+ */
+class AbstractLineImp
+ : public CurveImp
+{
+protected:
+ LineData mdata;
+ AbstractLineImp( const LineData& d );
+ AbstractLineImp( const Coordinate& a, const Coordinate& b );
+
+public:
+ typedef CurveImp Parent;
+ /**
+ * Returns the ObjectImpType representing the AbstractLineImp
+ * type..
+ */
+ static const ObjectImpType* stype();
+
+ ~AbstractLineImp();
+
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& d ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ /**
+ * Get the slope of this AbstractLineImp.. For a line through
+ * points a( xa, ya ) and b ( xb, yb ), this means the value ( yb -
+ * ya ) / ( xb - xa ).
+ */
+ double slope() const;
+ /**
+ * Get a string containing the equation of this line in the form "y
+ * = a * x + b ".
+ */
+ const QString equationString() const;
+ /**
+ * Get the LineData for this AbstractLineImp.
+ */
+ LineData data() const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+/**
+ * An ObjectImp representing a segment
+ */
+class SegmentImp
+ : public AbstractLineImp
+{
+public:
+ typedef AbstractLineImp Parent;
+ /**
+ * Returns the ObjectImpType representing the SegmentImp
+ * type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct a new segment from point a to point b.
+ */
+ SegmentImp( const Coordinate& a, const Coordinate& b );
+ /**
+ * Construct a new segment from a LineData.
+ */
+ SegmentImp( const LineData& d );
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& si ) const;
+ Rect surroundingRect() const;
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+ double getParam( const Coordinate&, const KigDocument& ) const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& d ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+
+ SegmentImp* copy() const;
+
+ /**
+ * Get the length of this segment.
+ */
+ double length() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+/**
+ * An ObjectImp representing a ray. This means half of a line, it is
+ * infinite in one direction, but ends at a certain point in the other
+ * direction..
+ */
+class RayImp
+ : public AbstractLineImp
+{
+public:
+ typedef AbstractLineImp Parent;
+ /**
+ * Returns the ObjectImpType representing the RayImp
+ * type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct a ray, starting at a, and going through b.
+ */
+ RayImp( const Coordinate& a, const Coordinate& b );
+ /**
+ * Construct a ray from a LineData.
+ */
+ RayImp( const LineData& d );
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& si ) const;
+ Rect surroundingRect() const;
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+ double getParam( const Coordinate&, const KigDocument& ) const;
+
+ RayImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+/**
+ * An ObjectImp representing a line.
+ */
+class LineImp
+ : public AbstractLineImp
+{
+public:
+ typedef AbstractLineImp Parent;
+
+ /**
+ * Returns the ObjectImpType representing the LineImp
+ * type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct a LineImp going through points a and b.
+ */
+ LineImp( const Coordinate& a, const Coordinate& b );
+ /**
+ * Construct a LineImp from a LineData.
+ */
+ LineImp( const LineData& d );
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& si ) const;
+ Rect surroundingRect() const;
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+ double getParam( const Coordinate&, const KigDocument& ) const;
+
+ LineImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+#endif
diff --git a/kig/objects/line_type.cc b/kig/objects/line_type.cc
new file mode 100644
index 00000000..a2c0734b
--- /dev/null
+++ b/kig/objects/line_type.cc
@@ -0,0 +1,334 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "line_type.h"
+
+#include "bogus_imp.h"
+#include "line_imp.h"
+#include "object_holder.h"
+#include "other_imp.h"
+#include "point_imp.h"
+
+#include "../kig/kig_view.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_commands.h"
+#include "../misc/common.h"
+#include "../misc/calcpaths.h"
+
+#include <qstringlist.h>
+
+#include <klocale.h>
+
+static const ArgsParser::spec argsspecSegmentAB[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Construct a segment starting at this point" ),
+ I18N_NOOP( "Select the start point of the new segment..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct a segment ending at this point" ),
+ I18N_NOOP( "Select the end point of the new segment..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( SegmentABType )
+
+SegmentABType::SegmentABType()
+ : ObjectABType( "SegmentAB", argsspecSegmentAB, 2 )
+{
+}
+
+SegmentABType::~SegmentABType()
+{
+}
+
+const SegmentABType* SegmentABType::instance()
+{
+ static const SegmentABType s;
+ return &s;
+}
+
+ObjectImp* SegmentABType::calc( const Coordinate& a, const Coordinate& b ) const
+{
+ return new SegmentImp( a, b );
+}
+
+static const char constructlineabstat[] = I18N_NOOP( "Construct a line through this point" );
+
+static const ArgsParser::spec argsspecLineAB[] =
+{
+ { PointImp::stype(), constructlineabstat,
+ I18N_NOOP( "Select a point for the line to go through..." ), true },
+ { PointImp::stype(), constructlineabstat,
+ I18N_NOOP( "Select another point for the line to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LineABType )
+
+LineABType::LineABType()
+ : ObjectABType( "LineAB", argsspecLineAB, 2 )
+{
+}
+
+LineABType::~LineABType()
+{
+}
+
+const LineABType* LineABType::instance()
+{
+ static const LineABType s;
+ return &s;
+}
+
+ObjectImp* LineABType::calc( const Coordinate& a, const Coordinate& b ) const
+{
+ return new LineImp( a, b );
+}
+
+static const char constructhalflinestartingstat[] = I18N_NOOP( "Construct a half-line starting at this point" );
+
+static const ArgsParser::spec argsspecRayAB[] =
+{
+ { PointImp::stype(), constructhalflinestartingstat,
+ I18N_NOOP( "Select the start point of the new half-line..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct a half-line through this point" ),
+ I18N_NOOP( "Select a point for the half-line to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( RayABType )
+
+RayABType::RayABType()
+ : ObjectABType( "RayAB", argsspecRayAB, 2 )
+{
+}
+
+RayABType::~RayABType()
+{
+}
+
+const RayABType* RayABType::instance()
+{
+ static const RayABType s;
+ return &s;
+}
+
+ObjectImp* RayABType::calc( const Coordinate& a, const Coordinate& b ) const
+{
+ return new RayImp( a, b );
+}
+
+LinePerpendLPType* LinePerpendLPType::instance()
+{
+ static LinePerpendLPType l;
+ return &l;
+}
+
+ObjectImp* LinePerpendLPType::calc(
+ const LineData& a,
+ const Coordinate& b ) const
+{
+ Coordinate p = calcPointOnPerpend( a, b );
+ return new LineImp( b, p );
+}
+
+static const ArgsParser::spec argsspecLineParallel[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct a line parallel to this line" ),
+ I18N_NOOP( "Select a line parallel to the new line..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct the parallel line through this point" ),
+ I18N_NOOP( "Select a point for the new line to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LineParallelLPType )
+
+LineParallelLPType::LineParallelLPType()
+ : ObjectLPType( "LineParallel", argsspecLineParallel, 2 )
+{
+}
+
+LineParallelLPType::~LineParallelLPType()
+{
+}
+
+LineParallelLPType* LineParallelLPType::instance()
+{
+ static LineParallelLPType l;
+ return &l;
+}
+
+ObjectImp* LineParallelLPType::calc(
+ const LineData& a,
+ const Coordinate& b ) const
+{
+ Coordinate r = calcPointOnParallel( a, b );
+ return new LineImp( r, b );
+}
+
+static const ArgsParser::spec argsspecLinePerpend[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Construct a line perpendicular to this line" ),
+ I18N_NOOP( "Select a line perpendicular to the new line..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct a perpendicular line through this point" ),
+ I18N_NOOP( "Select a point for the new line to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LinePerpendLPType )
+
+LinePerpendLPType::LinePerpendLPType()
+ : ObjectLPType( "LinePerpend", argsspecLinePerpend, 2 )
+{
+}
+
+LinePerpendLPType::~LinePerpendLPType()
+{
+}
+
+const ObjectImpType* SegmentABType::resultId() const
+{
+ return SegmentImp::stype();
+}
+
+const ObjectImpType* LineABType::resultId() const
+{
+ return LineImp::stype();
+}
+
+const ObjectImpType* RayABType::resultId() const
+{
+ return RayImp::stype();
+}
+
+const ObjectImpType* LinePerpendLPType::resultId() const
+{
+ return LineImp::stype();
+}
+
+const ObjectImpType* LineParallelLPType::resultId() const
+{
+ return LineImp::stype();
+}
+
+QStringList SegmentABType::specialActions() const
+{
+ QStringList ret;
+ ret << i18n( "Set &Length..." );
+ return ret;
+}
+
+void SegmentABType::executeAction( int i, ObjectHolder&, ObjectTypeCalcer& c,
+ KigPart& d, KigWidget& w, NormalMode& ) const
+{
+ assert( i == 0 );
+ // pretend to use this var..
+ (void) i;
+
+ std::vector<ObjectCalcer*> parents = c.parents();
+ assert( margsparser.checkArgs( parents ) );
+
+ Coordinate a = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+ Coordinate b = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
+
+ bool ok = true;
+ double length = getDoubleFromUser(
+ i18n( "Set Segment Length" ), i18n( "Choose the new length: " ),
+ (b-a).length(), &w, &ok, -2147483647, 2147483647, 3 );
+ if ( ! ok ) return;
+
+ Coordinate nb = a + ( b - a ).normalize( length );
+
+ MonitorDataObjects mon( getAllParents( parents ) );
+ parents[1]->move( nb, d.document() );
+ KigCommand* cd = new KigCommand( d, i18n( "Resize Segment" ) );
+ mon.finish( cd );
+ d.history()->addCommand( cd );
+}
+
+static const ArgsParser::spec argsspecLineByVector[] =
+{
+ { VectorImp::stype(), I18N_NOOP( "Construct a line by this vector" ),
+ I18N_NOOP( "Select a vector in the direction of the new line..." ), true },
+ { PointImp::stype(), constructlineabstat,
+ I18N_NOOP( "Select a point for the new line to go through..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LineByVectorType )
+
+LineByVectorType::LineByVectorType()
+ : ArgsParserObjectType( "LineByVector", argsspecLineByVector, 2 )
+{
+}
+
+LineByVectorType::~LineByVectorType()
+{
+}
+
+const LineByVectorType* LineByVectorType::instance()
+{
+ static const LineByVectorType s;
+ return &s;
+}
+
+ObjectImp* LineByVectorType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const VectorImp& a = *static_cast<const VectorImp*>( args[0] );
+ const PointImp& b = *static_cast<const PointImp*>( args[1] );
+
+ return new LineImp( b.coordinate(), b.coordinate() + a.dir() );
+}
+
+const ObjectImpType* LineByVectorType::resultId() const
+{
+ return LineImp::stype();
+}
+
+static const ArgsParser::spec argsspecHalflineByVector[] =
+{
+ { VectorImp::stype(), I18N_NOOP( "Construct a half-line by this vector" ),
+ I18N_NOOP( "Select a vector in the direction of the new half-line..." ), true },
+ { PointImp::stype(), constructhalflinestartingstat,
+ I18N_NOOP( "Select the start point of the new half-line..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( HalflineByVectorType )
+
+HalflineByVectorType::HalflineByVectorType()
+ : ArgsParserObjectType( "HalflineByVector", argsspecHalflineByVector, 2 )
+{
+}
+
+HalflineByVectorType::~HalflineByVectorType()
+{
+}
+
+const HalflineByVectorType* HalflineByVectorType::instance()
+{
+ static const HalflineByVectorType s;
+ return &s;
+}
+
+ObjectImp* HalflineByVectorType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const VectorImp& a = *static_cast<const VectorImp*>( args[0] );
+ const PointImp& b = *static_cast<const PointImp*>( args[1] );
+
+ return new RayImp( b.coordinate(), b.coordinate() + a.dir() );
+}
+
+const ObjectImpType* HalflineByVectorType::resultId() const
+{
+ return RayImp::stype();
+}
diff --git a/kig/objects/line_type.h b/kig/objects/line_type.h
new file mode 100644
index 00000000..a3ded322
--- /dev/null
+++ b/kig/objects/line_type.h
@@ -0,0 +1,110 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_SEGMENT_H
+#define KIG_OBJECTS_SEGMENT_H
+
+#include "base_type.h"
+
+class LineData;
+
+class SegmentABType
+ : public ObjectABType
+{
+ SegmentABType();
+ ~SegmentABType();
+public:
+ static const SegmentABType* instance();
+
+ ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+
+ QStringList specialActions() const;
+ /**
+ * execute the \p i 'th action from the specialActions above..
+ */
+ void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& c,
+ KigPart& d, KigWidget& w, NormalMode& m ) const;
+};
+
+class LineABType
+ : public ObjectABType
+{
+ LineABType();
+ ~LineABType();
+public:
+ static const LineABType* instance();
+ ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class RayABType
+ : public ObjectABType
+{
+ RayABType();
+ ~RayABType();
+public:
+ static const RayABType* instance();
+ ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class LinePerpendLPType
+ : public ObjectLPType
+{
+ LinePerpendLPType();
+ ~LinePerpendLPType();
+public:
+ static LinePerpendLPType* instance();
+ ObjectImp* calc( const LineData& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class LineParallelLPType
+ : public ObjectLPType
+{
+ LineParallelLPType();
+ ~LineParallelLPType();
+public:
+ static LineParallelLPType* instance();
+ ObjectImp* calc( const LineData& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class LineByVectorType
+ : public ArgsParserObjectType
+{
+ LineByVectorType();
+ ~LineByVectorType();
+public:
+ static const LineByVectorType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class HalflineByVectorType
+ : public ArgsParserObjectType
+{
+ HalflineByVectorType();
+ ~HalflineByVectorType();
+public:
+ static const HalflineByVectorType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/locus_imp.cc b/kig/objects/locus_imp.cc
new file mode 100644
index 00000000..edbdc88b
--- /dev/null
+++ b/kig/objects/locus_imp.cc
@@ -0,0 +1,397 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "locus_imp.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+#include "../misc/object_hierarchy.h"
+#include "../misc/kigpainter.h"
+#include "../misc/coordinate.h"
+#include "../misc/common.h"
+
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+#include <cmath>
+
+using namespace std;
+
+static double cachedparam = 0.0;
+
+LocusImp::~LocusImp()
+{
+ delete mcurve;
+}
+
+ObjectImp* LocusImp::transform( const Transformation& t ) const
+{
+ return new LocusImp( mcurve->copy(), mhier.transformFinalObject( t ) );
+}
+
+void LocusImp::draw( KigPainter& p ) const
+{
+ p.drawCurve( this );
+}
+
+bool LocusImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( p, w.screenInfo().normalMiss( width ), w.document() );
+}
+
+bool LocusImp::inRect( const Rect&, int, const KigWidget& ) const
+{
+ // TODO ?
+ return false;
+}
+
+const Coordinate LocusImp::getPoint( double param, const KigDocument& doc ) const
+{
+ Coordinate arg = mcurve->getPoint( param, doc );
+ if ( ! arg.valid() ) return arg;
+ PointImp argimp( arg );
+ Args args;
+ args.push_back( &argimp );
+ vector<ObjectImp*> calcret = mhier.calc( args, doc );
+ assert( calcret.size() == 1 );
+ ObjectImp* imp = calcret.front();
+ Coordinate ret;
+ if ( imp->inherits( PointImp::stype() ) )
+ {
+ cachedparam = param;
+ ret = static_cast<PointImp*>( imp )->coordinate();
+ }
+ else
+ ret = Coordinate::invalidCoord();
+
+ delete imp;
+ return ret;
+}
+
+LocusImp::LocusImp( CurveImp* curve, const ObjectHierarchy& hier )
+ : mcurve( curve ), mhier( hier )
+{
+}
+
+const uint LocusImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties();
+}
+
+const QCStringList LocusImp::propertiesInternalNames() const
+{
+ return Parent::propertiesInternalNames();
+}
+
+const QCStringList LocusImp::properties() const
+{
+ return Parent::properties();
+}
+
+const ObjectImpType* LocusImp::impRequirementForProperty( uint which ) const
+{
+ return Parent::impRequirementForProperty( which );
+}
+
+const char* LocusImp::iconForProperty( uint which ) const
+{
+ return Parent::iconForProperty( which );
+}
+
+ObjectImp* LocusImp::property( uint which, const KigDocument& w ) const
+{
+ return Parent::property( which, w );
+}
+
+LocusImp* LocusImp::copy() const
+{
+ return new LocusImp( mcurve->copy(), mhier );
+}
+
+const CurveImp* LocusImp::curve() const
+{
+ return mcurve;
+}
+
+const ObjectHierarchy& LocusImp::hierarchy() const
+{
+ return mhier;
+}
+
+/**
+ * This function returns the distance between the point with parameter
+ * param and point p. param is allowed to not be between 0 and 1, in
+ * which case we consider only the decimal part.
+ */
+double LocusImp::getDist(double param, const Coordinate& p, const KigDocument& doc) const
+{
+ param = fmod( param, 1 );
+ if( param < 0 ) param += 1.;
+ Coordinate p1 = getPoint( param, doc );
+ // i don't think the p1.valid() switch is really necessary, but I
+ // prefer to not take any chances :)
+ return p1.valid() ? ( p1 - p ).length() : +double_inf;
+}
+
+/**
+ * This function searches starting from x1 for the first interval in
+ * which the function of the distance from the point at coordinate x
+ * starts to increase. The range found is returned in the parameters
+ * x1 and x2: [x1,x2].
+ */
+void LocusImp::getInterval( double& x1, double& x2,
+ double incr,const Coordinate& p,
+ const KigDocument& doc) const
+{
+ double mm = getDist( x1, p, doc);
+ double mm1 = getDist( x2, p, doc);
+ if( mm <= mm1 ) return;
+ else
+ {
+ double x3 = x2 + incr;
+ double mm2 = getDist (x3, p, doc);
+ while( mm > mm1 & mm1 > mm2 )
+ {
+ x1 = x2;
+ x2 = x3;
+ x3 = x2 + incr;
+ mm = mm1;
+ mm1 = mm2;
+ mm2 = getDist (x3, p, doc);
+ }
+ x2=x3;
+ }
+}
+
+double LocusImp::getParam( const Coordinate& p, const KigDocument& doc ) const
+{
+ // this function ( and related functions like getInterval etc. ) is
+ // written by Franco Pasquarelli <pasqui@dmf.bs.unicatt.it>.
+ // I ( domi ) have adapted and documented it a bit.
+
+ if ( cachedparam >= 0. && cachedparam <= 1. &&
+ getPoint ( cachedparam, doc ) == p ) return cachedparam;
+
+ // consider the function that returns the distance for a point at
+ // parameter x to the locus for a given parameter x. What we do
+ // here is look for the global minimum of this function. We do that
+ // by dividing the range ( [0,1] ) into N parts, and start looking
+ // for a local minimum from there on. If we find one, we keep it if
+ // it is the lowest of all the ones we've already found..
+
+ const int N = 50;
+ const double incr = 1. / (double) N;
+
+ // xm is the best parameter we've found so far, fxm is the distance
+ // to the locus from that point. We start with some
+ // pseudo-values.
+ // (mp) note that if the distance is actually increasing in the
+ // whole interval [0,1] this value will be returned in the end.
+ double xm = 0.;
+ double fxm = getDist( xm, p, doc );
+
+ int j = 0;
+ double mm = fxm;
+
+ while( j < N )
+ {
+ // [x1,x2] is the range we're currently considering..
+ double x1 = j * incr;
+ double x2 = x1 + incr;
+
+ // check the range x1,x2 for the first local maximum..
+ double mm1 = getDist( x2, p, doc);
+ double mm2;
+ j++;
+ if( mm < mm1 )
+ mm = mm1;
+
+ else
+ {
+ if ( mm > mm1 )
+ {
+ double x3 = x2 + incr;
+ mm2 = getDist (x3, p, doc);
+ j++;
+ while( mm1 > mm2 & j <= N )
+ {
+ x1 = x2;
+ x2 = x3;
+ x3 = x2 + incr;
+ mm = mm1;
+ mm1 = mm2;
+ mm2 = getDist (x3, p, doc);
+ j++;
+ }
+ x2 = x3;
+ }
+ else
+ mm2 = mm1;
+
+ if ( mm1 <= mm2 )
+ {
+ mm = mm2;
+
+ double xm1 = getParamofmin( x1, x2, p, doc);
+ double fxm1 = getDist( xm1, p, doc );
+ if( fxm1 < fxm )
+ {
+ // we found a new minimum, save it..
+ xm=xm1;
+ fxm=fxm1;
+ }
+ }
+ }
+ }
+ return xm;
+}
+
+/**
+ * This function calculates the parameter of the point that realizes the
+ * minimum in [a,b] of the distance between the points of the locus and
+ * the point of coordinate p, using the golden ration method.
+ */
+double LocusImp::getParamofmin( double a, double b,
+ const Coordinate& p,
+ const KigDocument& doc ) const
+{
+ double epsilons = 1.e-08;
+ double epsilonl = 2.e-02;
+
+ //assert( a < b && a >= 0. && b <= 1.0);
+ assert( a < b && a >= 0.);
+
+ double r2 = ( sqrt( 5. ) - 1 ) / 2.; // golden ratio
+ double r1 = 1. - r2;
+
+ double t2 = a + r2 * ( b - a );
+ double t1 = a + r1 * ( b - a );
+ Coordinate p1 = getPoint( fmod( t1, 1. ), doc);
+ double f1 = (p1 - p).length();
+ Coordinate p2 = getPoint( fmod( t2, 1. ), doc);
+ double f2 = (p2 - p).length();
+
+ double fmin, tmin;
+ if (f1 < f2)
+ {
+ b = t2;
+ fmin = f1;
+ tmin = t1;
+ }
+ else
+ {
+ a = t1;
+ fmin = f2;
+ tmin = t2;
+ }
+
+ while ( ( b - a ) > epsilons &&
+ ( (p1 - p2).length() > 0.4 * fmin
+ || (b - a) > epsilonl) &&
+ fmin > 1.e-8 )
+ {
+ if ( f1 < f2 )
+ {
+ t2 = t1;
+ t1 = a + r1*(b - a);
+ f2 = f1;
+ p1 = getPoint( fmod( t1, 1. ), doc);
+ f1 = (p1 - p).length();
+ }
+ else
+ {
+ t1 = t2;
+ t2 = a + r2*(b - a);
+ f1 = f2;
+ p2 = getPoint( fmod( t2, 1. ), doc);
+ f2 = (p2 - p).length();
+ }
+ if ( f1 < f2 )
+ {
+ b = t2;
+ fmin = f1;
+ tmin = t1;
+ }
+ else
+ {
+ a = t1;
+ fmin = f2;
+ tmin = t2;
+ }
+ }
+
+ return(tmin);
+}
+
+void LocusImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool LocusImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( LocusImp::stype() ) &&
+ static_cast<const LocusImp&>( rhs ).curve()->equals( *curve() ) &&
+ static_cast<const LocusImp&>( rhs ).hierarchy() == hierarchy();
+}
+
+const ObjectImpType* LocusImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "locus",
+ I18N_NOOP( "locus" ),
+ I18N_NOOP( "Select this locus" ),
+ I18N_NOOP( "Select locus %1" ),
+ I18N_NOOP( "Remove a Locus" ),
+ I18N_NOOP( "Add a Locus" ),
+ I18N_NOOP( "Move a Locus" ),
+ I18N_NOOP( "Attach to this locus" ),
+ I18N_NOOP( "Show a Locus" ),
+ I18N_NOOP( "Hide a Locus" )
+ );
+ return &t;
+}
+
+const ObjectImpType* LocusImp::type() const
+{
+ return LocusImp::stype();
+}
+
+bool LocusImp::containsPoint( const Coordinate& p, const KigDocument& doc ) const
+{
+ return internalContainsPoint( p, test_threshold, doc );
+}
+
+bool LocusImp::internalContainsPoint( const Coordinate& p, double threshold, const KigDocument& doc ) const
+{
+ double param = getParam( p, doc );
+ double dist = getDist( param, p, doc );
+ return fabs( dist ) <= threshold;
+}
+
+bool LocusImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+}
+
+Rect LocusImp::surroundingRect() const
+{
+ // it's probably possible to calculate this, if it exists, but we
+ // don't for now.
+ return Rect::invalidRect();
+}
diff --git a/kig/objects/locus_imp.h b/kig/objects/locus_imp.h
new file mode 100644
index 00000000..568e0e7c
--- /dev/null
+++ b/kig/objects/locus_imp.h
@@ -0,0 +1,96 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_LOCUS_IMP_H
+#define KIG_OBJECTS_LOCUS_IMP_H
+
+#include "curve_imp.h"
+#include "../misc/object_hierarchy.h"
+
+/**
+ * LocusImp is an imp that consists of a copy of the curveimp that the
+ * moving point moves over, and an ObjectHierarchy that can calc (
+ * given a point, and optionally some more parent objects the position
+ * of the moving point. The hierarchy should take the moving point as
+ * its *first* argument and all others after that. The others are
+ * used to make it possible for Locus to be updated when some of the
+ * other objects that appear in the path from the moving point to the
+ * dependent point change.
+ *
+ * This may seem rather complicated, but I think it is absolutely
+ * necessary to support locuses using Kig's object system. It would
+ * be very bad for LocusImp to have to keep references to its parents
+ * as Objects ( since only the objects know how they are related to
+ * their parents ). This is how we used to do it, but the current
+ * method is far superior. First and foremost because the separation
+ * between ObjectImp and Object is something that Kig depends on very
+ * much, and because every ObjectImp should contain all the data it
+ * needs itself. ObjectImp's are entirely independent objects.
+ * That's also why we don't keep a pointer to the old CurveImp, but a
+ * copy of it..
+ *
+ * i hope this is a bit clear, if not, feel free to ask for
+ * explanation of what you don't understand..
+ */
+class LocusImp
+ : public CurveImp
+{
+ CurveImp* mcurve;
+ const ObjectHierarchy mhier;
+
+ double getDist(double param, const Coordinate& p, const KigDocument& doc) const;
+ void getInterval(double& x1,double& x2,double incr,const Coordinate& p, const KigDocument& doc) const;
+ double getParamofmin(double a, double b, const Coordinate& p, const KigDocument& doc) const;
+public:
+ typedef CurveImp Parent;
+ static const ObjectImpType* stype();
+
+ LocusImp( CurveImp*, const ObjectHierarchy& );
+ ~LocusImp();
+ LocusImp* copy() const;
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ Rect surroundingRect() const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ double getParam( const Coordinate& point, const KigDocument& ) const;
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+
+ // TODO ?
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ const CurveImp* curve() const;
+ const ObjectHierarchy& hierarchy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& d ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold, const KigDocument& doc ) const;
+};
+
+#endif
diff --git a/kig/objects/object_calcer.cc b/kig/objects/object_calcer.cc
new file mode 100644
index 00000000..40545ed1
--- /dev/null
+++ b/kig/objects/object_calcer.cc
@@ -0,0 +1,323 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "object_calcer.h"
+
+#include "object_holder.h"
+#include "object_imp.h"
+#include "object_type.h"
+#include "../misc/coordinate.h"
+#include "common.h"
+
+#include <algorithm>
+#include <set>
+
+void ObjectTypeCalcer::calc( const KigDocument& doc )
+{
+ Args a;
+ a.reserve( mparents.size() );
+ std::transform( mparents.begin(), mparents.end(),
+ std::back_inserter( a ), std::mem_fun( &ObjectCalcer::imp ) );
+ ObjectImp* n = mtype->calc( a, doc );
+ delete mimp;
+ mimp = n;
+}
+
+ObjectTypeCalcer::ObjectTypeCalcer( const ObjectType* type,
+ const std::vector<ObjectCalcer*>& parents, bool sort )
+ : mparents( ( sort )?type->sortArgs( parents ):parents ), mtype( type ), mimp( 0 )
+{
+ std::for_each( mparents.begin(), mparents.end(),
+ std::bind2nd( std::mem_fun( &ObjectCalcer::addChild ), this ) );
+}
+
+ObjectCalcer::~ObjectCalcer()
+{
+}
+
+ObjectConstCalcer::ObjectConstCalcer( ObjectImp* imp )
+ : mimp( imp )
+{
+}
+
+ObjectConstCalcer::~ObjectConstCalcer()
+{
+ delete mimp;
+}
+
+const ObjectImp* ObjectConstCalcer::imp() const
+{
+ return mimp;
+}
+
+void ObjectConstCalcer::calc( const KigDocument& )
+{
+}
+
+std::vector<ObjectCalcer*> ObjectConstCalcer::parents() const
+{
+ // we have no parents..
+ return std::vector<ObjectCalcer*>();
+}
+
+void ObjectCalcer::ref()
+{
+ ++refcount;
+}
+
+void ObjectCalcer::deref()
+{
+ if ( --refcount <= 0 ) delete this;
+}
+
+void intrusive_ptr_add_ref( ObjectCalcer* p )
+{
+ p->ref();
+}
+
+void intrusive_ptr_release( ObjectCalcer* p )
+{
+ p->deref();
+}
+
+const ObjectImp* ObjectTypeCalcer::imp() const
+{
+ return mimp;
+}
+
+std::vector<ObjectCalcer*> ObjectTypeCalcer::parents() const
+{
+ return mparents;
+}
+
+void ObjectCalcer::addChild( ObjectCalcer* c )
+{
+ mchildren.push_back( c );
+ ref();
+}
+
+void ObjectCalcer::delChild( ObjectCalcer* c )
+{
+ std::vector<ObjectCalcer*>::iterator i = std::find( mchildren.begin(), mchildren.end(), c );
+ assert( i != mchildren.end() );
+
+ mchildren.erase( i );
+ deref();
+}
+
+ObjectTypeCalcer::~ObjectTypeCalcer()
+{
+ std::for_each( mparents.begin(), mparents.end(),
+ std::bind2nd( std::mem_fun( &ObjectCalcer::delChild ), this ) );
+ delete mimp;
+}
+
+const ObjectType* ObjectTypeCalcer::type() const
+{
+ return mtype;
+}
+
+ObjectPropertyCalcer::ObjectPropertyCalcer( ObjectCalcer* parent, int propid )
+ : mimp( 0 ), mparent( parent ), mpropid( propid )
+{
+ // Some weird C++ thing prevents me from calling protected members
+ // of ObjectCalcer on mparent.. This is an ugly workaround..
+ ( mparent->*&ObjectCalcer::addChild )( this );
+ //mparent->addChild( this );
+}
+
+ObjectPropertyCalcer::~ObjectPropertyCalcer()
+{
+ // Some weird C++ thing prevents me from calling protected members
+ // of ObjectCalcer on mparent.. This is an ugly workaround..
+ ( mparent->*&ObjectCalcer::delChild )( this );
+ //mparent->delChild( this );
+ delete mimp;
+}
+
+const ObjectImp* ObjectPropertyCalcer::imp() const
+{
+ return mimp;
+}
+
+std::vector<ObjectCalcer*> ObjectPropertyCalcer::parents() const
+{
+ std::vector<ObjectCalcer*> ret;
+ ret.push_back( mparent );
+ return ret;
+}
+
+void ObjectPropertyCalcer::calc( const KigDocument& doc )
+{
+ ObjectImp* n = mparent->imp()->property( mpropid, doc );
+ delete mimp;
+ mimp = n;
+}
+
+ObjectImp* ObjectConstCalcer::switchImp( ObjectImp* newimp )
+{
+ ObjectImp* ret = mimp;
+ mimp = newimp;
+ return ret;
+}
+
+std::vector<ObjectCalcer*> ObjectCalcer::children() const
+{
+ return mchildren;
+}
+
+const ObjectImpType* ObjectPropertyCalcer::impRequirement(
+ ObjectCalcer*, const std::vector<ObjectCalcer*>& ) const
+{
+ return mparent->imp()->impRequirementForProperty( mpropid );
+}
+
+const ObjectImpType* ObjectConstCalcer::impRequirement(
+ ObjectCalcer*, const std::vector<ObjectCalcer*>& ) const
+{
+ assert( false );
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ObjectTypeCalcer::impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const
+{
+ Args args;
+ args.reserve( mparents.size() );
+ std::transform(
+ os.begin(), os.end(),
+ std::back_inserter( args ),
+ std::mem_fun( &ObjectCalcer::imp ) );
+ assert( std::find( args.begin(), args.end(), o->imp() ) != args.end() );
+ return mtype->impRequirement( o->imp(), args );
+}
+
+int ObjectPropertyCalcer::propId() const
+{
+ return mpropid;
+}
+
+void ObjectConstCalcer::setImp( ObjectImp* newimp )
+{
+ delete switchImp( newimp );
+}
+
+void ObjectTypeCalcer::setParents( const std::vector<ObjectCalcer*> np )
+{
+ std::for_each( np.begin(), np.end(),
+ std::bind2nd( std::mem_fun( &ObjectCalcer::addChild ), this ) );
+ std::for_each( mparents.begin(), mparents.end(),
+ std::bind2nd( std::mem_fun( &ObjectCalcer::delChild ), this ) );
+ mparents = np;
+}
+
+void ObjectTypeCalcer::setType( const ObjectType* t )
+{
+ mtype = t;
+}
+
+bool ObjectCalcer::canMove() const
+{
+ return false;
+}
+
+bool ObjectCalcer::isFreelyTranslatable() const
+{
+ return false;
+}
+
+Coordinate ObjectCalcer::moveReferencePoint() const
+{
+ assert( false );
+ return Coordinate::invalidCoord();
+}
+
+void ObjectCalcer::move( const Coordinate&, const KigDocument& )
+{
+ assert( false );
+}
+
+bool ObjectTypeCalcer::canMove() const
+{
+ return mtype->canMove( *this );
+}
+
+bool ObjectTypeCalcer::isFreelyTranslatable() const
+{
+ return mtype->isFreelyTranslatable( *this );
+}
+
+Coordinate ObjectTypeCalcer::moveReferencePoint() const
+{
+ return mtype->moveReferencePoint( *this );
+}
+
+void ObjectTypeCalcer::move( const Coordinate& to, const KigDocument& doc )
+{
+ // we need to check if type can in fact move, because this check is
+ // not done for us in all circumstances ( e.g. LineABType::move uses
+ // move on its parents to move them ), and the ObjectType's depend
+ // on move only being called if canMove() returns true..
+ if ( mtype->canMove( *this ) )
+ mtype->move( *this, to, doc );
+}
+
+ObjectCalcer* ObjectPropertyCalcer::parent() const
+{
+ return mparent;
+}
+
+ObjectCalcer::ObjectCalcer()
+ : refcount( 0 )
+{
+}
+
+std::vector<ObjectCalcer*> ObjectCalcer::movableParents() const
+{
+ return std::vector<ObjectCalcer*>();
+}
+
+std::vector<ObjectCalcer*> ObjectTypeCalcer::movableParents() const
+{
+ return mtype->movableParents( *this );
+}
+
+bool ObjectConstCalcer::isDefinedOnOrThrough( const ObjectCalcer* ) const
+{
+ return false;
+}
+
+bool ObjectPropertyCalcer::isDefinedOnOrThrough( const ObjectCalcer* o ) const
+{
+ return o == mparent &&
+ mparent->imp()->isPropertyDefinedOnOrThroughThisImp( propId() );
+}
+
+bool ObjectTypeCalcer::isDefinedOnOrThrough( const ObjectCalcer* o ) const
+{
+ Args args;
+ args.reserve( mparents.size() );
+ std::transform(
+ mparents.begin(), mparents.end(),
+ std::back_inserter( args ),
+ std::mem_fun( &ObjectCalcer::imp ) );
+ if ( std::find( args.begin(), args.end(), o->imp() ) == args.end() )
+ return false;
+
+ return mtype->isDefinedOnOrThrough( o->imp(), args );
+}
+
diff --git a/kig/objects/object_calcer.h b/kig/objects/object_calcer.h
new file mode 100644
index 00000000..6df94fe8
--- /dev/null
+++ b/kig/objects/object_calcer.h
@@ -0,0 +1,301 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_OBJECT_CALCER_H
+#define KIG_OBJECTS_OBJECT_CALCER_H
+
+#include "common.h"
+#include "../misc/boost_intrusive_pointer.hpp"
+
+class ObjectCalcer;
+
+void intrusive_ptr_add_ref( ObjectCalcer* p );
+void intrusive_ptr_release( ObjectCalcer* p );
+
+/**
+ * An ObjectCalcer is an object that represents an algorithm for
+ * calculating an ObjectImp from other ObjectImp's. It is also a node
+ * in the dependency graph of a certain document. E.g. a LineImp can
+ * be calculated from the two PointImp's it has to go through; every
+ * time either of them moves, this calculation is redone. In this
+ * case, there would be an ObjectCalcer that keeps a reference to its
+ * two parents ( the ObjectCalcer's representing the points ), and
+ * that will calculate its ObjectImp value every time it is asked to
+ * do so ( i.e. every time one of its parents moves.. ).
+ *
+ * Each ObjectHolder keeps its ObjectImp itself, and recalculates it
+ * from its parents in its calc() method ( if necessary ).
+ *
+ * Because of the complex relations that ObjectCalcer's hold to other
+ * ObjectCalcer's and to other classes, they have been made
+ * reference-counted. This means that they keep a count internally of
+ * how much times a pointer to them is held. If this count reaches 0,
+ * this means that nobody needs them anymore, and they delete
+ * themselves. E.g. an ObjectCalcer always keeps a reference to its
+ * parents, to ensure that those aren't deleted before it is deleted.
+ *
+ * At runtime, there will be an entire graph of ObjectCalcer that
+ * depend on their parents.. At the bottom, there are Calcer's that
+ * the user is aware of, and that are held by ObjectHolder's. At the
+ * top, there are Calcer's without parents that serve only to hold
+ * some data. Those are most likely ObjectConstCalcer's. There are
+ * some algorithms to work with the dependency graph in various ways
+ * in ../misc/calcpath.h
+ *
+ * ObjectCalcer's also decide how an object should be allowed to
+ * move. If the user selects a point, and tries to move it, then its
+ * ObjectCalcer will be asked whether it can move, and if so, will be
+ * asked to move. See below with the canMove(), move() and
+ * moveReferencePoint() methods..
+ */
+class ObjectCalcer
+{
+protected:
+ /**
+ * ObjectCalcer's are reference counted.. They all take a reference
+ * to their parents, and some other classes like ObjectHolder take a
+ * reference to some ObjectCalcer's that they don't want to see
+ * deleted..
+ */
+ friend void intrusive_ptr_add_ref( ObjectCalcer* p );
+ friend void intrusive_ptr_release( ObjectCalcer* p );
+ int refcount;
+ void ref();
+ void deref();
+
+ // we keep track of our children, so algorithms can easily walk over
+ // the dependency graph..
+
+ std::vector<ObjectCalcer*> mchildren;
+
+ ObjectCalcer();
+public:
+ /**
+ * a calcer should call this to register itself as a child of this
+ * calcer. This automatically takes a reference.
+ */
+ void addChild( ObjectCalcer* c );
+ /**
+ * a calcer should call this in its destructor, to inform its parent
+ * that it is no longer a child of this calcer. This will release
+ * the reference taken in addChild..
+ */
+ void delChild( ObjectCalcer* c );
+
+ // use this pointer type to keep a reference to an ObjectCalcer...
+ typedef myboost::intrusive_ptr<ObjectCalcer> shared_ptr;
+
+ /**
+ * Returns the child ObjectCalcer's of this ObjectCalcer.
+ */
+ std::vector<ObjectCalcer*> children() const;
+
+ virtual ~ObjectCalcer();
+ /**
+ * Returns the parent ObjectCalcer's of this ObjectCalcer.
+ */
+ virtual std::vector<ObjectCalcer*> parents() const = 0;
+ /**
+ * Returns the ObjectImp of this ObjectCalcer.
+ */
+ virtual const ObjectImp* imp() const = 0;
+ /**
+ * Makes the ObjectCalcer recalculate its ObjectImp from its
+ * parents.
+ */
+ virtual void calc( const KigDocument& ) = 0;
+
+ /**
+ * An ObjectCalcer expects its parents to have an ObjectImp of a
+ * certain type. This method returns the ObjectImpType that \p o
+ * should have. \p os is a list of all the parents in order, and
+ * \p o is part of it. This method will return the ObjectImpType
+ * that the parent should *at least* be. For example, a Translated
+ * object can translate any sort of object, so it will return
+ * ObjectImp::stype() here ( the topmost ObjectImpType, that all
+ * other ObjectImpType's inherit ).
+ */
+ virtual const ObjectImpType* impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const = 0;
+
+ /**
+ * Returns whether this ObjectCalcer supports moving.
+ */
+ virtual bool canMove() const;
+ /**
+ * Returns whether this ObjectCalcer can be translated at any position
+ * in the coordinate plane. Note that a ConstrainedPointType can be
+ * moved, but cannot be moved everywhere.
+ */
+ virtual bool isFreelyTranslatable() const;
+ /**
+ * Moving an object most of the time signifies invoking changes in
+ * some of its parents. This method returns the set of parents that
+ * will be changed in the move() method. The object itself should
+ * not be included.
+ */
+ virtual std::vector<ObjectCalcer*> movableParents() const;
+ /**
+ * In order to support simultaneously moving objects that are in
+ * different locations, we need for each object a location that it
+ * is assumed to be at, at the moment the moving starts. This
+ * method returns such a point.
+ */
+ virtual Coordinate moveReferencePoint() const;
+ /**
+ * This is the method that does the real moving work. It will be
+ * invoked to tell the object to move to the new location to. After
+ * this, the calc() method will be calced, so you only need to do
+ * the real changes in this method, updating the ObjectImp should be
+ * done in the calc() method, not here.
+ */
+ virtual void move( const Coordinate& to, const KigDocument& doc );
+
+ /**
+ * If this ObjectCalcer represents a curve, return true if the given
+ * point is by construction on this curve. If this ObjectCalcer
+ * represents a point, return true if this point is by construction
+ * on the given curve.
+ */
+ virtual bool isDefinedOnOrThrough( const ObjectCalcer* o ) const = 0;
+};
+
+/**
+ * This is an ObjectCalcer that uses one of the various ObjectType's
+ * to calculate its ObjectImp. It basically forwards all of its
+ * functionality to the ObjectType that it holds a pointer to.
+ */
+class ObjectTypeCalcer
+ : public ObjectCalcer
+{
+ std::vector<ObjectCalcer*> mparents;
+ const ObjectType* mtype;
+ ObjectImp* mimp;
+public:
+ typedef myboost::intrusive_ptr<ObjectTypeCalcer> shared_ptr;
+ /**
+ * Construct a new ObjectTypeCalcer with a given type and parents.
+ */
+// ObjectTypeCalcer( const ObjectType* type, const std::vector<ObjectCalcer*>& parents );
+ /**
+ * the sort boolean tells whether the sortArgs method should be invoked or not;
+ * if not present
+ */
+ ObjectTypeCalcer( const ObjectType* type, const std::vector<ObjectCalcer*>& parents, bool sort=true );
+ ~ObjectTypeCalcer();
+
+ const ObjectImp* imp() const;
+ std::vector<ObjectCalcer*> parents() const;
+ void calc( const KigDocument& doc );
+
+ /**
+ * Set the parents of this ObjectTypeCalcer to np. This object will
+ * release the reference it had to its old parents, and take a new
+ * one on the new parents.
+ */
+ void setParents( const std::vector<ObjectCalcer*> np );
+ void setType( const ObjectType* t );
+
+ const ObjectType* type() const;
+
+ const ObjectImpType* impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const;
+ bool isDefinedOnOrThrough( const ObjectCalcer* o ) const;
+ bool canMove() const;
+ bool isFreelyTranslatable() const;
+ std::vector<ObjectCalcer*> movableParents() const;
+ Coordinate moveReferencePoint() const;
+ void move( const Coordinate& to, const KigDocument& doc );
+};
+
+/**
+ * This is an ObjectCalcer that keeps an ObjectImp, and never
+ * calculates a new one. It is a trivial, but very useful
+ * ObjectCalcer. It is used often in Kig, for holding data to be used
+ * by other ObjectCalcer's.
+ */
+class ObjectConstCalcer
+ : public ObjectCalcer
+{
+ ObjectImp* mimp;
+public:
+ typedef myboost::intrusive_ptr<ObjectConstCalcer> shared_ptr;
+
+ /**
+ * Construct a new ObjectConstCalcer with the given imp as the
+ * stored ObjectImp.
+ *
+ * This class takes ownership of the imp you pass it, it should have
+ * been constructed using new, and this class is responsible for
+ * deleting it.
+ */
+ ObjectConstCalcer( ObjectImp* imp );
+ ~ObjectConstCalcer();
+
+ const ObjectImp* imp() const;
+ void calc( const KigDocument& doc );
+ std::vector<ObjectCalcer*> parents() const;
+
+ /**
+ * Set the ObjectImp of this ObjectConstCalcer to the given
+ * newimp. The old one will be deleted.
+ */
+ void setImp( ObjectImp* newimp );
+ /**
+ * Set the ObjectImp of this ObjectConstCalcer to the given
+ * newimp. The old one will not be deleted, but returned.
+ */
+ ObjectImp* switchImp( ObjectImp* newimp );
+
+ const ObjectImpType* impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const;
+ bool isDefinedOnOrThrough( const ObjectCalcer* o ) const;
+};
+
+/**
+ * This is an ObjectCalcer that has a single parent, and gets a
+ * certain property from it in its calc() method.
+ *
+ * \see ObjectImp::property
+ */
+class ObjectPropertyCalcer
+ : public ObjectCalcer
+{
+ ObjectImp* mimp;
+ ObjectCalcer* mparent;
+ int mpropid;
+public:
+ /**
+ * Construct a new ObjectPropertyCalcer, that will get the property
+ * from parent with number propid.
+ */
+ ObjectPropertyCalcer( ObjectCalcer* parent, int propid );
+ ~ObjectPropertyCalcer();
+
+ const ObjectImp* imp() const;
+ std::vector<ObjectCalcer*> parents() const;
+ void calc( const KigDocument& doc );
+
+ int propId() const;
+ ObjectCalcer* parent() const;
+
+ const ObjectImpType* impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const;
+ bool isDefinedOnOrThrough( const ObjectCalcer* o ) const;
+};
+
+#endif
diff --git a/kig/objects/object_drawer.cc b/kig/objects/object_drawer.cc
new file mode 100644
index 00000000..0989d4f2
--- /dev/null
+++ b/kig/objects/object_drawer.cc
@@ -0,0 +1,204 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "object_drawer.h"
+
+#include "object_imp.h"
+#include "../misc/kigpainter.h"
+
+#include <qpen.h>
+#include <qnamespace.h>
+#include <cassert>
+
+#include <kdebug.h>
+
+void ObjectDrawer::draw( const ObjectImp& imp, KigPainter& p, bool sel ) const
+{
+ bool nv = p.getNightVision( );
+ if ( mshown || nv )
+ {
+ p.setBrushStyle( Qt::NoBrush );
+ p.setBrushColor( sel ? Qt::red : ( mshown?mcolor:Qt::gray ) );
+ p.setPen( QPen ( sel ? Qt::red : ( mshown?mcolor:Qt::gray ), 1) );
+ p.setWidth( mwidth );
+ p.setStyle( mstyle );
+ p.setPointStyle( mpointstyle );
+ imp.draw( p );
+ }
+}
+
+bool ObjectDrawer::contains( const ObjectImp& imp, const Coordinate& pt, const KigWidget& w, bool nv ) const
+{
+ bool shownornv = mshown || nv;
+ return shownornv && imp.contains( pt, mwidth, w );
+}
+
+bool ObjectDrawer::shown( ) const
+{
+ return mshown;
+}
+
+QColor ObjectDrawer::color() const
+{
+ return mcolor;
+}
+
+ObjectDrawer* ObjectDrawer::getCopyShown( bool s ) const
+{
+ ObjectDrawer* ret = new ObjectDrawer;
+ ret->mcolor = mcolor;
+ ret->mshown = s;
+ ret->mwidth = mwidth;
+ ret->mstyle = mstyle;
+ ret->mpointstyle = mpointstyle;
+ return ret;
+}
+
+ObjectDrawer* ObjectDrawer::getCopyColor( const QColor& c ) const
+{
+ ObjectDrawer* ret = new ObjectDrawer;
+ ret->mcolor = c;
+ ret->mshown = mshown;
+ ret->mwidth = mwidth;
+ ret->mstyle = mstyle;
+ ret->mpointstyle = mpointstyle;
+ return ret;
+}
+
+ObjectDrawer* ObjectDrawer::getCopyWidth( int w ) const
+{
+ ObjectDrawer* ret = new ObjectDrawer;
+ ret->mcolor = mcolor;
+ ret->mshown = mshown;
+ ret->mwidth = w;
+ ret->mstyle = mstyle;
+ ret->mpointstyle = mpointstyle;
+ return ret;
+}
+
+ObjectDrawer* ObjectDrawer::getCopyStyle( Qt::PenStyle s ) const
+{
+ ObjectDrawer* ret = new ObjectDrawer;
+ ret->mcolor = mcolor;
+ ret->mshown = mshown;
+ ret->mwidth = mwidth;
+ ret->mstyle = s;
+ ret->mpointstyle = mpointstyle;
+ return ret;
+}
+
+ObjectDrawer* ObjectDrawer::getCopyPointStyle( int p ) const
+{
+ ObjectDrawer* ret = new ObjectDrawer;
+ ret->mcolor = mcolor;
+ ret->mshown = mshown;
+ ret->mwidth = mwidth;
+ ret->mstyle = mstyle;
+ ret->mpointstyle = p;
+ return ret;
+}
+
+int ObjectDrawer::width() const
+{
+ return mwidth;
+}
+
+Qt::PenStyle ObjectDrawer::style() const
+{
+ return mstyle;
+}
+
+int ObjectDrawer::pointStyle() const
+{
+ return mpointstyle;
+}
+
+ObjectDrawer::ObjectDrawer( const QColor& color, int width, bool shown, Qt::PenStyle style, int pointStyle )
+ : mcolor( color ), mshown( shown ), mwidth( width ), mstyle( style ), mpointstyle( pointStyle )
+{
+}
+
+ObjectDrawer::ObjectDrawer()
+ : mcolor( Qt::blue ), mshown( true ), mwidth( -1 ), mstyle( Qt::SolidLine ), mpointstyle( 0 )
+{
+}
+
+bool ObjectDrawer::inRect( const ObjectImp& imp, const Rect& r, const KigWidget& w ) const
+{
+ return mshown && imp.inRect( r, mwidth, w );
+}
+
+int ObjectDrawer::pointStyleFromString( const QString& style )
+{
+ if ( style == "Round" )
+ return 0;
+ else if ( style == "RoundEmpty" )
+ return 1;
+ else if ( style == "Rectangular" )
+ return 2;
+ else if ( style == "RectangularEmpty" )
+ return 3;
+ else if ( style == "Cross" )
+ return 4;
+ return 0;
+}
+
+QString ObjectDrawer::pointStyleToString() const
+{
+ if ( mpointstyle == 0 )
+ return "Round";
+ else if ( mpointstyle == 1 )
+ return "RoundEmpty";
+ else if ( mpointstyle == 2 )
+ return "Rectangular";
+ else if ( mpointstyle == 3 )
+ return "RectangularEmpty";
+ else if ( mpointstyle == 4 )
+ return "Cross";
+ assert( false );
+ return QString::null;
+}
+
+Qt::PenStyle ObjectDrawer::styleFromString( const QString& style )
+{
+ if ( style == "SolidLine" )
+ return Qt::SolidLine;
+ else if ( style == "DashLine" )
+ return Qt::DashLine;
+ else if ( style == "DotLine" )
+ return Qt::DotLine;
+ else if ( style == "DashDotLine" )
+ return Qt::DashDotLine;
+ else if ( style == "DashDotDotLine" )
+ return Qt::DashDotDotLine;
+ else return Qt::SolidLine;
+}
+
+QString ObjectDrawer::styleToString() const
+{
+ if ( mstyle == Qt::SolidLine )
+ return "SolidLine";
+ else if ( mstyle == Qt::DashLine )
+ return "DashLine";
+ else if ( mstyle == Qt::DotLine )
+ return "DotLine";
+ else if ( mstyle == Qt::DashDotLine )
+ return "DashDotLine";
+ else if ( mstyle == Qt::DashDotDotLine )
+ return "DashDotDotLine";
+ return "SolidLine";
+}
diff --git a/kig/objects/object_drawer.h b/kig/objects/object_drawer.h
new file mode 100644
index 00000000..2781acdc
--- /dev/null
+++ b/kig/objects/object_drawer.h
@@ -0,0 +1,146 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_OBJECT_DRAWER_H
+#define KIG_OBJECTS_OBJECT_DRAWER_H
+
+#include <qcolor.h>
+#include <qnamespace.h>
+
+class ObjectImp;
+class KigPainter;
+class Coordinate;
+class KigWidget;
+class Rect;
+
+/**
+ * A class holding some information about how a certain object is
+ * drawn on the window.
+ *
+ * An ObjectDrawer is used by an ObjectHolder to keep information
+ * about how to draw an ObjectImp on the window. It is really nothing
+ * more than a struct with some convenience methods. It does not have
+ * any virtual methods, or have any complex semantics. It keeps
+ * information like the thickness of an object, its color, and whether
+ * or not it is hidden.
+ *
+ * \note The default width of an object depends on its type. E.g. A
+ * point is by default drawn at width 5, a line at width 1.
+ * Therefore, there is a special width -1, which means "the default
+ * width for this object".
+ */
+class ObjectDrawer
+{
+ QColor mcolor;
+ bool mshown;
+ int mwidth;
+ Qt::PenStyle mstyle;
+ int mpointstyle;
+public:
+ /**
+ * Construct a new ObjectDrawer with a default color ( Qt::blue ),
+ * width ( -1 ), shown state ( true ), PenStyle ( Qt::SolidLine ),
+ * and pointstyle ( 0 )
+ */
+ ObjectDrawer();
+ ObjectDrawer( const QColor& color, int width = -1, bool shown = true, Qt::PenStyle = Qt::SolidLine, int pointStyle = 0 );
+ /**
+ * Draw the object \p imp on kigpainter \p p . If \p selected is true, it is
+ * drawn in red, otherwise in its normal color.
+ */
+ void draw( const ObjectImp& imp, KigPainter& p, bool selected ) const;
+ /**
+ * returns whether the object \p imp contains coordinate \p p . This is
+ * dependent on whether it is shown ( when it will never contain
+ * anything ), and on its width..
+ */
+ bool contains( const ObjectImp& imp, const Coordinate& pt, const KigWidget& w, bool nv = false ) const;
+ /**
+ * returns whether the object \p imp is in the rectangle \p r . This is
+ * dependent on whether it is shown and on its width..
+ */
+ bool inRect( const ObjectImp& imp, const Rect& r, const KigWidget& w ) const;
+
+ /**
+ * returns whether the object this ObjectDrawer is responsible for
+ * will be drawn or not..
+ */
+ bool shown() const;
+ /**
+ * returns the color that the object will be drawn in
+ */
+ QColor color() const;
+ /**
+ * return the width of the object
+ */
+ int width() const;
+ /**
+ * return PenStyle for all objects except points
+ */
+ Qt::PenStyle style() const;
+ /**
+ * return pointStyle for points
+ */
+ int pointStyle() const;
+ /**
+ * return pointStyle trasnformed in a string
+ */
+ QString pointStyleToString() const;
+ /**
+ * return style trasnformed in a string
+ */
+ QString styleToString() const;
+ /**
+ * returns a new ObjectDrawer that is identical to this one.. except
+ * that the shown state is set to \p s ..
+ */
+ ObjectDrawer* getCopyShown( bool s ) const;
+ /**
+ * returns a new ObjectDrawer that is identical to this one.. except
+ * that the color is set to \p c ..
+ */
+ ObjectDrawer* getCopyColor( const QColor& c ) const;
+ /**
+ * returns a new ObjectDrawer that is identical to this one.. except
+ * that the width is set to \p w ..
+ */
+ ObjectDrawer* getCopyWidth( int w ) const;
+ /**
+ * returns a new ObjectDrawer that is identical to this one.. except
+ * that the PenStyle state is set to \p s ..
+ */
+ ObjectDrawer* getCopyStyle( Qt::PenStyle s ) const;
+ /**
+ * returns a new ObjectDrawer that is identical to this one.. except
+ * that the pointStyle state is set to \p p ..
+ */
+ ObjectDrawer* getCopyPointStyle( int p ) const;
+ /**
+ * Note that this returns a valid point style in every case, even if
+ * the given \p style string is unknown. In that case it returns a
+ * default value.
+ */
+ static int pointStyleFromString( const QString& style );
+ /**
+ * Note that this returns a valid style in every case, even if the
+ * given \p style string is unknown. In that case it returns a default
+ * value.
+ */
+ static Qt::PenStyle styleFromString( const QString& style );
+};
+
+#endif
diff --git a/kig/objects/object_factory.cc b/kig/objects/object_factory.cc
new file mode 100644
index 00000000..a54e01f0
--- /dev/null
+++ b/kig/objects/object_factory.cc
@@ -0,0 +1,369 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "object_factory.h"
+
+#include "bogus_imp.h"
+#include "curve_imp.h"
+#include "intersection_types.h"
+#include "line_imp.h"
+#include "object_drawer.h"
+#include "object_holder.h"
+#include "other_type.h"
+#include "point_imp.h"
+#include "point_type.h"
+#include "text_type.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+#include "../misc/calcpaths.h"
+#include "../misc/coordinate.h"
+#include "../misc/object_hierarchy.h"
+
+#include <algorithm>
+#include <functional>
+
+ObjectHolder* ObjectFactory::fixedPoint( const Coordinate& c ) const
+{
+ ObjectHolder* o = new ObjectHolder( fixedPointCalcer( c ) );
+ return o;
+}
+
+ObjectTypeCalcer* ObjectFactory::fixedPointCalcer( const Coordinate& c ) const
+{
+ std::vector<ObjectCalcer*> args;
+ args.push_back( new ObjectConstCalcer( new DoubleImp( c.x ) ) );
+ args.push_back( new ObjectConstCalcer( new DoubleImp( c.y ) ) );
+ ObjectTypeCalcer* oc = new ObjectTypeCalcer( FixedPointType::instance(), args );
+ return oc;
+}
+
+ObjectTypeCalcer* ObjectFactory::cursorPointCalcer( const Coordinate& c ) const
+{
+ std::vector<ObjectCalcer*> args;
+ args.push_back( new ObjectConstCalcer( new DoubleImp( c.x ) ) );
+ args.push_back( new ObjectConstCalcer( new DoubleImp( c.y ) ) );
+ ObjectTypeCalcer* oc = new ObjectTypeCalcer( CursorPointType::instance(), args );
+ return oc;
+}
+
+const ObjectFactory* ObjectFactory::instance()
+{
+ static ObjectFactory f;
+ return &f;
+}
+
+ObjectTypeCalcer* ObjectFactory::sensiblePointCalcer(
+ const Coordinate& c, const KigDocument& d, const KigWidget& w ) const
+{
+ std::vector<ObjectHolder*> os = d.whatAmIOn( c, w );
+ if ( os.size() == 2 )
+ {
+ // we can calc intersection point *olny* between two objects...
+ std::vector<ObjectCalcer*> args;
+ args.push_back( os[0]->calcer() );
+ args.push_back( os[1]->calcer() );
+ // the simpliest case: two lines...
+ if ( ( os[0]->imp()->inherits( AbstractLineImp::stype() ) ) &&
+ ( os[1]->imp()->inherits( AbstractLineImp::stype() ) ) )
+ return new ObjectTypeCalcer( LineLineIntersectionType::instance(), args );
+ // other cases will follow...
+ }
+ for ( std::vector<ObjectHolder*>::iterator i = os.begin(); i != os.end(); ++i )
+ if ( (*i)->imp()->inherits( CurveImp::stype() ) )
+ return constrainedPointCalcer( (*i)->calcer(), c, d );
+ return fixedPointCalcer( c );
+}
+
+ObjectHolder* ObjectFactory::sensiblePoint(
+ const Coordinate& c, const KigDocument& d, const KigWidget& w ) const
+{
+ return new ObjectHolder( sensiblePointCalcer( c, d, w ) );
+}
+
+ObjectTypeCalcer* ObjectFactory::relativePointCalcer(
+ ObjectCalcer* o, const Coordinate& loc ) const
+{
+ Coordinate reference =
+ static_cast<const ObjectImp*>( o->imp() )->attachPoint();
+ assert( reference.valid() );
+
+ double x = 0.0;
+ double y = 0.0;
+ if ( loc.valid() )
+ {
+ x = loc.x - reference.x;
+ y = loc.y - reference.y;
+ }
+ std::vector<ObjectCalcer*> parents;
+ parents.push_back( new ObjectConstCalcer( new DoubleImp( x ) ) );
+ parents.push_back( new ObjectConstCalcer( new DoubleImp( y ) ) );
+ parents.push_back( o );
+ return new ObjectTypeCalcer( RelativePointType::instance(), parents );
+}
+
+ObjectTypeCalcer* ObjectFactory::constrainedPointCalcer(
+ ObjectCalcer* curve, double param ) const
+{
+ assert( curve->imp()->inherits( CurveImp::stype() ) );
+ std::vector<ObjectCalcer*> parents;
+ parents.push_back( new ObjectConstCalcer( new DoubleImp( param ) ) );
+ parents.push_back( curve );
+ return new ObjectTypeCalcer( ConstrainedPointType::instance(), parents );
+}
+
+ObjectHolder* ObjectFactory::constrainedPoint(
+ ObjectCalcer* curve, double param ) const
+{
+ return new ObjectHolder( constrainedPointCalcer( curve, param ) );
+}
+
+ObjectTypeCalcer* ObjectFactory::constrainedPointCalcer(
+ ObjectCalcer* curve, const Coordinate& c, const KigDocument& d ) const
+{
+ assert( curve->imp()->inherits( CurveImp::stype() ) );
+ double param = static_cast<const CurveImp*>( curve->imp() )->getParam( c, d );
+ return constrainedPointCalcer( curve, param );
+}
+
+ObjectHolder* ObjectFactory::constrainedPoint(
+ ObjectCalcer* curve, const Coordinate& c, const KigDocument& d ) const
+{
+ return new ObjectHolder( constrainedPointCalcer( curve, c, d ) );
+}
+
+ObjectTypeCalcer* ObjectFactory::locusCalcer(
+ ObjectCalcer* a, ObjectCalcer* b ) const
+{
+ assert( dynamic_cast<const ObjectTypeCalcer*>( a ) );
+ ObjectTypeCalcer* constrained = static_cast<ObjectTypeCalcer*>( a );
+ assert( constrained->type()->inherits( ObjectType::ID_ConstrainedPointType ) );
+ assert( constrained->parents().size() == 2 );
+ ObjectCalcer* curve = a->parents().back();
+
+ const ObjectCalcer* moving = b;
+
+ std::vector<ObjectCalcer*> hierparents;
+ hierparents.push_back( constrained );
+ std::vector<ObjectCalcer*> sideOfTree = sideOfTreePath( hierparents, moving );
+ std::copy( sideOfTree.begin(), sideOfTree.end(), std::back_inserter( hierparents ) );
+
+ ObjectHierarchy hier( hierparents, moving );
+
+ std::vector<ObjectCalcer*> realparents( 2 + sideOfTree.size(), 0 );
+ realparents[0] = new ObjectConstCalcer( new HierarchyImp( hier ) );
+ realparents[1] = curve;
+ copy( sideOfTree.begin(), sideOfTree.end(), realparents.begin() + 2 );
+
+ return new ObjectTypeCalcer( LocusType::instance(), realparents );
+}
+
+ObjectHolder* ObjectFactory::locus( ObjectCalcer* a, ObjectCalcer* b ) const
+{
+ return new ObjectHolder( locusCalcer( a, b ) );
+}
+
+ObjectHolder* ObjectFactory::label(
+ const QString& s, const Coordinate& loc,
+ bool needframe, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const
+{
+ return new ObjectHolder( labelCalcer( s, loc, needframe, parents, doc ) );
+}
+
+ObjectTypeCalcer* ObjectFactory::labelCalcer(
+ const QString& s, const Coordinate& loc,
+ bool needframe, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const
+{
+ return attachedLabelCalcer( s, 0, loc, needframe, parents, doc );
+}
+
+ObjectTypeCalcer* ObjectFactory::attachedLabelCalcer(
+ const QString& s, ObjectCalcer* p,
+ const Coordinate& loc, bool needframe,
+ const std::vector<ObjectCalcer*>& nparents,
+ const KigDocument& doc ) const
+{
+ std::vector<ObjectCalcer*> parents;
+ parents.reserve( nparents.size() + 3 );
+ parents.push_back( new ObjectConstCalcer( new IntImp( needframe ? 1 : 0 ) ) );
+
+ parents.push_back( getAttachPoint( p, loc, doc ) );
+
+ parents.push_back( new ObjectConstCalcer( new StringImp( s ) ) );
+ std::copy( nparents.begin(), nparents.end(), std::back_inserter( parents ) );
+ ObjectTypeCalcer* ret = new ObjectTypeCalcer( TextType::instance(), parents );
+ ret->calc( doc );
+ return ret;
+}
+
+ObjectCalcer* ObjectFactory::getAttachPoint(
+ ObjectCalcer* p,
+ const Coordinate& loc,
+ const KigDocument& doc ) const
+{
+/*
+ * mp: (changes to add relative-attachment). Now an object is tested
+ * as follows:
+ * - if attachPoint() returns a valid coordinate, then we use the new method
+ * - if it is a point: 'old-style' treatment (we can change this shortly)
+ * - if it is a curve: 'old-style' treatment (we could use the new approach,
+ * which can be better/worse depending on personal taste, I think)
+ *
+ * the first condition that matches determines the behaviour.
+ * the new method works similarly to the curve case, but we generate a new
+ * RelativePointType instead of a ConstrainedPointType; this will in turn make use
+ * of the new attachPoint() method for objects.
+ *
+ * changed the preference order 2005/01/21 (now attachPoint has preference over points)
+ *
+ * NOTE: changes in the tests performed should be matched also in
+ * modes/popup.cc (addNameLabel) and in label.cc (TextLabelModeBase::mouseMoved)
+ */
+
+ if ( p && p->imp()->attachPoint().valid() )
+ {
+ ObjectCalcer* o = relativePointCalcer( p, loc );
+ o->calc( doc );
+ return o;
+ }
+ else if ( p && p->imp()->inherits( PointImp::stype() ) )
+ {
+ return p;
+ }
+ else if ( p && p->imp()->inherits( CurveImp::stype() ) )
+ {
+ double param = 0.5;
+ if ( loc.valid() )
+ param = static_cast<const CurveImp*>( p->imp() )->getParam( loc, doc );
+
+ ObjectCalcer* o = constrainedPointCalcer( p, param );
+ o->calc( doc );
+ return o;
+ }
+ else
+ {
+ if ( loc.valid() )
+ return new ObjectConstCalcer( new PointImp( loc ) );
+ else
+ return new ObjectConstCalcer( new PointImp( Coordinate( 0, 0 ) ) );
+ }
+}
+
+ObjectHolder* ObjectFactory::attachedLabel(
+ const QString& s, ObjectCalcer* locationparent,
+ const Coordinate& loc, bool needframe,
+ const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const
+{
+ return new ObjectHolder( attachedLabelCalcer( s, locationparent, loc, needframe, parents, doc ) );
+}
+
+ObjectPropertyCalcer* ObjectFactory::propertyObjectCalcer(
+ ObjectCalcer* o, const char* p ) const
+{
+ int wp = o->imp()->propertiesInternalNames().findIndex( p );
+ if ( wp == -1 ) return 0;
+ return new ObjectPropertyCalcer( o, wp );
+}
+
+ObjectHolder* ObjectFactory::propertyObject(
+ ObjectCalcer* o, const char* p ) const
+{
+ return new ObjectHolder( propertyObjectCalcer( o, p ) );
+}
+
+void ObjectFactory::redefinePoint(
+ ObjectTypeCalcer* point, const Coordinate& c,
+ KigDocument& doc, const KigWidget& w ) const
+{
+ std::vector<ObjectHolder*> hos = doc.whatAmIOn( c, w );
+ std::vector<ObjectCalcer*> os;
+ ObjectCalcer* (ObjectHolder::*calcmeth)() = &ObjectHolder::calcer;
+ std::transform( hos.begin(), hos.end(), std::back_inserter( os ),
+ std::mem_fun( calcmeth ) );
+ ObjectCalcer* v = 0;
+
+ // we don't want one of our children as a parent...
+ std::set<ObjectCalcer*> children = getAllChildren( point );
+ for ( std::vector<ObjectCalcer*>::iterator i = os.begin();
+ i != os.end(); ++i )
+ if ( (*i)->imp()->inherits( CurveImp::stype() ) &&
+ children.find( *i ) == children.end() )
+ {
+ v = *i;
+ break;
+ };
+
+ if ( v )
+ {
+ // we want a constrained point...
+ const CurveImp* curveimp = static_cast<const CurveImp*>( v->imp() );
+ double newparam = curveimp->getParam( c, doc );
+
+ if ( point->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
+ {
+ // point already was constrained -> simply update the param
+ // DataObject and make sure point is on the right curve...
+ ObjectCalcer* dataobj = 0;
+ std::vector<ObjectCalcer*> parents = point->parents();
+ assert( parents.size() == 2 );
+ assert ( parents[0]->imp()->inherits( DoubleImp::stype() ) );
+ dataobj = parents[0];
+
+ parents.clear();
+ parents.push_back( dataobj );
+ parents.push_back( v );
+ point->setParents( parents );
+
+ assert( dynamic_cast<ObjectConstCalcer*>( dataobj ) );
+ static_cast<ObjectConstCalcer*>( dataobj )->setImp(
+ new DoubleImp( newparam ) );
+ }
+ else
+ {
+ // point used to be fixed -> add a new DataObject etc.
+ std::vector<ObjectCalcer*> args;
+ args.push_back( new ObjectConstCalcer( new DoubleImp( newparam ) ) );
+ args.push_back( v );
+ point->setType( ConstrainedPointType::instance() );
+ point->setParents( args );
+ }
+ }
+ else
+ {
+ // a fixed point...
+ if ( point->type()->inherits( ObjectType::ID_ConstrainedPointType ) )
+ {
+ // point used to be constrained..
+ std::vector<ObjectCalcer*> a;
+ a.push_back( new ObjectConstCalcer( new DoubleImp( c.x ) ) );
+ a.push_back( new ObjectConstCalcer( new DoubleImp( c.y ) ) );
+
+ point->setType( FixedPointType::instance() );
+ point->setParents( a );
+ }
+ else
+ {
+ // point used to be fixed -> simply update the DataObject's
+ // we can use the point's move function for that..
+ point->move( c, doc );
+ };
+ }
+}
+
diff --git a/kig/objects/object_factory.h b/kig/objects/object_factory.h
new file mode 100644
index 00000000..0ce6ce62
--- /dev/null
+++ b/kig/objects/object_factory.h
@@ -0,0 +1,145 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_OBJECT_FACTORY_H
+#define KIG_OBJECTS_OBJECT_FACTORY_H
+
+#include "common.h"
+
+class ObjectFactory
+{
+public:
+
+ static const ObjectFactory* instance();
+
+ /**
+ * this returns a fixed point. Note that the returned object is
+ * not added to the document..
+ */
+ ObjectHolder* fixedPoint( const Coordinate& c ) const;
+ ObjectTypeCalcer* fixedPointCalcer( const Coordinate& c ) const;
+
+ /**
+ * this returns a CursorPointType; this is used during special
+ * constructions (e.g. regular polygons) where the constructor
+ * wants to use the cursor position without actually generating
+ * an object depending on a new point there.
+ */
+ ObjectTypeCalcer* cursorPointCalcer( const Coordinate& c ) const;
+
+ /**
+ * this returns a relative point (to an object). Note that the returned object
+ * is not added to the document..
+ */
+ ObjectTypeCalcer* relativePointCalcer( ObjectCalcer* o, const Coordinate& loc ) const;
+
+ /**
+ * this returns a constrained point. Note that the returned object
+ * is not added to the document..
+ */
+ ObjectHolder* constrainedPoint( ObjectCalcer* curve, double param ) const;
+ ObjectTypeCalcer* constrainedPointCalcer( ObjectCalcer* curve, double param ) const;
+ /**
+ * \overload, changes nothing to the semantics, only calcs the param
+ * value for you..
+ */
+ ObjectTypeCalcer* constrainedPointCalcer(
+ ObjectCalcer* curve, const Coordinate& c, const KigDocument& ) const;
+ ObjectHolder* constrainedPoint(
+ ObjectCalcer* curve, const Coordinate& c, const KigDocument& ) const;
+
+ /**
+ * this returns a "sensible point".
+ * By a "sensible point", I mean a point that would be about what
+ * the user expects when he asks for a point at point \p c . This is a
+ * constrained point if \p c is on a curve, and otherwise a fixed
+ * point. I might add the possibility for an intersection point
+ * sometime.. Note that the returned object is not added to
+ * the document..
+ */
+ ObjectTypeCalcer* sensiblePointCalcer(
+ const Coordinate& c, const KigDocument& d, const KigWidget& w ) const;
+ ObjectHolder* sensiblePoint(
+ const Coordinate& c, const KigDocument& d, const KigWidget& w ) const;
+
+ /**
+ * set point to what sensiblePoint would have returned..
+ */
+ void redefinePoint( ObjectTypeCalcer* point, const Coordinate& c,
+ KigDocument& d, const KigWidget& w ) const;
+
+ /**
+ * return a locus, defined by the two points ( one constrained, and
+ * one following ) \p a and \p b . \p a should be the constrained point,
+ * and thus, it has to be of type ObjectTypeCalcer where a->type() is of
+ * type ConstrainedPointType. The semantics of LocusType are a bit
+ * weird ( but I believe correct :) ), so this function takes care
+ * of the complication there..
+ */
+ ObjectTypeCalcer* locusCalcer( ObjectCalcer* a, ObjectCalcer* b ) const;
+ ObjectHolder* locus( ObjectCalcer* a, ObjectCalcer* b ) const;
+
+ /**
+ * returns a label with text \p s at point \p c .. It ( and its parents )
+ * is calced already...
+ */
+ ObjectHolder* label(
+ const QString& s, const Coordinate& loc,
+ bool needframe, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const;
+ ObjectTypeCalcer* labelCalcer(
+ const QString& s, const Coordinate& loc,
+ bool needframe, const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const;
+
+ /**
+ * this one does the same as the above, only that the new label is
+ * attached to locationparent if it is non-null..
+ */
+ ObjectTypeCalcer* attachedLabelCalcer(
+ const QString& s, ObjectCalcer* locationparent,
+ const Coordinate& loc, bool needframe,
+ const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const;
+ /**
+ * this has been added because it comes handy when redefining
+ * a text label, we move here all the code for getting an
+ * attach point from the method above
+ */
+ ObjectCalcer* getAttachPoint(
+ ObjectCalcer* locationparent,
+ const Coordinate& loc,
+ const KigDocument& doc ) const;
+ ObjectHolder* attachedLabel(
+ const QString& s, ObjectCalcer* locationparent,
+ const Coordinate& loc, bool needframe,
+ const std::vector<ObjectCalcer*>& parents,
+ const KigDocument& doc ) const;
+
+ /**
+ * returns a property object for the property \p p of object \p o .
+ *
+ * \note
+ * \p o should have already been calc'd, or this will fail and
+ * return 0.. The returned object also needs to be calced after
+ * this..
+ */
+ ObjectPropertyCalcer* propertyObjectCalcer( ObjectCalcer* o, const char* p ) const;
+ ObjectHolder* propertyObject( ObjectCalcer* o, const char* p ) const;
+};
+
+#endif
diff --git a/kig/objects/object_holder.cc b/kig/objects/object_holder.cc
new file mode 100644
index 00000000..5a2c0765
--- /dev/null
+++ b/kig/objects/object_holder.cc
@@ -0,0 +1,164 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "object_holder.h"
+
+#include "bogus_imp.h"
+#include "object_calcer.h"
+#include "object_drawer.h"
+
+#include "../misc/coordinate.h"
+
+ObjectHolder::ObjectHolder( ObjectCalcer* calcer )
+ : mcalcer( calcer ), mdrawer( new ObjectDrawer ), mnamecalcer( 0 )
+{
+}
+
+ObjectHolder::ObjectHolder( ObjectCalcer* calcer, ObjectDrawer* drawer,
+ ObjectConstCalcer* namecalcer )
+ : mcalcer( calcer ), mdrawer( drawer ), mnamecalcer( namecalcer )
+{
+ assert( !namecalcer || namecalcer->imp()->inherits( StringImp::stype() ) );
+}
+
+ObjectHolder::ObjectHolder( ObjectCalcer* calcer, ObjectDrawer* drawer )
+ : mcalcer( calcer ), mdrawer( drawer ), mnamecalcer( 0 )
+{
+}
+
+ObjectHolder::~ObjectHolder()
+{
+ delete mdrawer;
+}
+
+const ObjectImp* ObjectHolder::imp() const
+{
+ return mcalcer->imp();
+}
+
+const ObjectCalcer* ObjectHolder::calcer() const
+{
+ return mcalcer.get();
+}
+
+const ObjectDrawer* ObjectHolder::drawer() const
+{
+ return mdrawer;
+}
+
+const ObjectConstCalcer* ObjectHolder::nameCalcer() const
+{
+ return mnamecalcer.get();
+}
+
+void ObjectHolder::setDrawer( ObjectDrawer* d )
+{
+ delete switchDrawer( d );
+}
+
+void ObjectHolder::calc( const KigDocument& d )
+{
+ mcalcer->calc( d );
+}
+
+void ObjectHolder::draw( KigPainter& p, bool selected ) const
+{
+ mdrawer->draw( *imp(), p, selected );
+}
+
+bool ObjectHolder::contains( const Coordinate& pt, const KigWidget& w, bool nv ) const
+{
+ return mdrawer->contains( *imp(), pt, w, nv );
+}
+
+bool ObjectHolder::inRect( const Rect& r, const KigWidget& w ) const
+{
+ return mdrawer->inRect( *imp(), r, w );
+}
+
+ObjectCalcer* ObjectHolder::calcer()
+{
+ return mcalcer.get();
+}
+
+ObjectDrawer* ObjectHolder::drawer()
+{
+ return mdrawer;
+}
+
+ObjectConstCalcer* ObjectHolder::nameCalcer()
+{
+ return mnamecalcer.get();
+}
+
+const Coordinate ObjectHolder::moveReferencePoint() const
+{
+ return mcalcer->moveReferencePoint();
+}
+
+void ObjectHolder::move( const Coordinate& to, const KigDocument& doc )
+{
+ mcalcer->move( to, doc );
+}
+
+bool ObjectHolder::canMove() const
+{
+ return mcalcer->canMove();
+}
+
+bool ObjectHolder::isFreelyTranslatable() const
+{
+ return mcalcer->isFreelyTranslatable();
+}
+
+ObjectDrawer* ObjectHolder::switchDrawer( ObjectDrawer* d )
+{
+ ObjectDrawer* tmp = mdrawer;
+ mdrawer = d;
+ return tmp;
+}
+
+bool ObjectHolder::shown( ) const
+{
+ return mdrawer->shown( );
+}
+
+const QString ObjectHolder::name() const
+{
+ if ( mnamecalcer )
+ {
+ assert( mnamecalcer->imp()->inherits( StringImp::stype() ) );
+ return static_cast<const StringImp*>( mnamecalcer->imp() )->data();
+ }
+ else
+ return QString::null;
+}
+
+void ObjectHolder::setNameCalcer( ObjectConstCalcer* namecalcer )
+{
+ assert( !mnamecalcer );
+ mnamecalcer = namecalcer;
+}
+
+QString ObjectHolder::selectStatement() const
+{
+ const QString n = name();
+ if ( n.isEmpty() )
+ return i18n( imp()->type()->selectStatement() );
+ else
+ return i18n( imp()->type()->selectNameStatement() ).arg( n );
+}
diff --git a/kig/objects/object_holder.h b/kig/objects/object_holder.h
new file mode 100644
index 00000000..9b30453d
--- /dev/null
+++ b/kig/objects/object_holder.h
@@ -0,0 +1,145 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_OBJECT_HOLDER_H
+#define KIG_OBJECTS_OBJECT_HOLDER_H
+
+#include "object_calcer.h"
+
+#include <qstring.h>
+
+/**
+ * An ObjectHolder represents an object as it is known to the
+ * document. It keeps a pointer to an ObjectCalcer, where it gets its
+ * data ( the ObjectImp that the ObjectCalcer holds ) from. It also
+ * holds information about how to draw this ObjectImp on the window,
+ * by keeping a pointer to an ObjectDrawer ( see below ). In its draw
+ * method, it gets the ObjectImp from the ObjectCalcer, and passes it
+ * to the ObjectDrawer, asking it to draw the ObjectImp on the window.
+ *
+ * The document ( check the KigDocument class ) holds a list of these
+ * ObjectHolder's. This is its only link with the ObjectCalcer
+ * dependency graph.
+ *
+ * An ObjectHolder keeps a reference to its * ObjectCalcer.
+ */
+class ObjectHolder
+{
+ ObjectCalcer::shared_ptr mcalcer;
+ ObjectDrawer* mdrawer;
+ ObjectConstCalcer::shared_ptr mnamecalcer;
+
+public:
+ /**
+ * Construct a new ObjectHolder with a given ObjectCalcer and
+ * ObjectDrawer, with a given name calcer.
+ */
+ ObjectHolder( ObjectCalcer* calcer, ObjectDrawer* drawer, ObjectConstCalcer* namecalcer );
+ /**
+ * Construct a new ObjectHolder with a given ObjectCalcer and
+ * ObjectDrawer.
+ */
+ ObjectHolder( ObjectCalcer* calcer, ObjectDrawer* drawer );
+ /**
+ * equivalent to the previous constructor, but with a default
+ * ObjectDrawer and no name.
+ */
+ ObjectHolder( ObjectCalcer* calcer );
+ ~ObjectHolder();
+
+ const ObjectImp* imp() const;
+ const ObjectCalcer* calcer() const;
+ ObjectCalcer* calcer();
+ const ObjectDrawer* drawer() const;
+ ObjectDrawer* drawer();
+ // the following two return zero if no name is set.
+ const ObjectConstCalcer* nameCalcer() const;
+ ObjectConstCalcer* nameCalcer();
+ /**
+ * Setting the namecalcer is only allowed if previously none was
+ * set. This way, we avoid keeping a useless namecalcer around if
+ * no name is set.
+ */
+ void setNameCalcer( ObjectConstCalcer* namecalcer );
+
+ /**
+ * returns QString::null if no name is set.
+ */
+ const QString name() const;
+ /**
+ * Set the ObjectDrawer of this ObjectHolder to \p d , the old
+ * ObjectDrawer is deleted.
+ */
+ void setDrawer( ObjectDrawer* d );
+ /**
+ * Set the ObjectDrawer of this ObjectHolder to \p d , the old
+ * ObjectDrawer is not deleted, but returned.
+ */
+ ObjectDrawer* switchDrawer( ObjectDrawer* d );
+
+ /**
+ * Make our ObjectCalcer recalculate its ObjectImp.
+ */
+ void calc( const KigDocument& );
+ /**
+ * Draw this object on the given KigPainter. If \p selected is true,
+ * then it will be drawn in red, instead of its normal color.
+ */
+ void draw( KigPainter& p, bool selected ) const;
+ /**
+ * Returns whether this object contains the point \p p .
+ */
+ bool contains( const Coordinate& p, const KigWidget& w, bool nv = false ) const;
+ /**
+ * Returns whether this object is in the rectangle \p r .
+ */
+ bool inRect( const Rect& r, const KigWidget& w ) const;
+ /**
+ * Returns whether this object is shown.
+ */
+ bool shown() const;
+
+ /**
+ * This call is simply forwarded to the ObjectCalcer. Check the
+ * documentation of ObjectCalcer::moveReferencePoint() for more info.
+ */
+ const Coordinate moveReferencePoint() const;
+ /**
+ * This call is simply forwarded to the ObjectCalcer. Check the
+ * documentation of ObjectCalcer::move() for more info.
+ */
+ void move( const Coordinate& to, const KigDocument& );
+ /**
+ * This call is simply forwarded to the ObjectCalcer. Check the
+ * documentation of ObjectCalcer::canMove() for more info.
+ */
+ bool canMove() const;
+ /**
+ * This call is simply forwarded to the ObjectCalcer. Check the
+ * documentation of ObjectCalcer::isFreelyTranslatable() for more info.
+ */
+ bool isFreelyTranslatable() const;
+
+ /**
+ * Return a statement saying something like "select this segment" or
+ * "select segment ab" depending on whether this ObjectHolder has a
+ * name.
+ */
+ QString selectStatement() const;
+};
+
+#endif
diff --git a/kig/objects/object_imp.cc b/kig/objects/object_imp.cc
new file mode 100644
index 00000000..6cb6650f
--- /dev/null
+++ b/kig/objects/object_imp.cc
@@ -0,0 +1,308 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "object_imp.h"
+
+#include "bogus_imp.h"
+
+#include "../misc/coordinate.h"
+
+#include <klocale.h>
+#include <map>
+
+class ObjectImpType::StaticPrivate
+{
+public:
+ std::map<QCString, const ObjectImpType*> namemap;
+};
+
+ObjectImp::ObjectImp()
+{
+}
+
+ObjectImp::~ObjectImp()
+{
+}
+
+bool ObjectImp::valid() const
+{
+ return ! type()->inherits( InvalidImp::stype() );
+}
+
+void ObjectImp::fillInNextEscape( QString&, const KigDocument& ) const
+{
+ assert( false );
+}
+
+const QCStringList ObjectImp::properties() const
+{
+ QCStringList ret;
+ ret << I18N_NOOP( "Object Type" );
+ return ret;
+}
+
+const uint ObjectImp::numberOfProperties() const
+{
+ return 1;
+}
+
+const QCStringList ObjectImp::propertiesInternalNames() const
+{
+ QCStringList ret;
+ ret << "base-object-type";
+ return ret;
+}
+
+ObjectImp* ObjectImp::property( uint i, const KigDocument& ) const
+{
+ if ( i == 0 ) return new StringImp( type()->translatedName() );
+ return new InvalidImp;
+}
+
+const ObjectImpType* ObjectImp::impRequirementForProperty( uint ) const
+{
+ return ObjectImp::stype();
+}
+
+void ObjectImpVisitor::visit( const ObjectImp* imp )
+{
+ imp->visit( this );
+}
+
+void ObjectImpVisitor::visit( const IntImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const DoubleImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const StringImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const InvalidImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const HierarchyImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const LineImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const PointImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const TextImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const AngleImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const VectorImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const LocusImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const CircleImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const ConicImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const CubicImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const SegmentImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const RayImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const ArcImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const PolygonImp* )
+{
+}
+
+ObjectImpVisitor::~ObjectImpVisitor()
+{
+
+}
+
+void ObjectImpVisitor::visit( const TransformationImp* )
+{
+}
+
+void ObjectImpVisitor::visit( const TestResultImp* )
+{
+}
+
+const char* ObjectImp::iconForProperty( uint ) const
+{
+ return "kig_text";
+}
+
+bool ObjectImp::canFillInNextEscape() const
+{
+ return false;
+}
+
+ObjectImpType::ObjectImpType( const ObjectImpType* parent,
+ const char* internalname,
+ const char* translatedname,
+ const char* selectstatement,
+ const char* selectnamestatement,
+ const char* removeastatement,
+ const char* addastatement,
+ const char* moveastatement,
+ const char* attachtothisstatement,
+ const char* showastatement,
+ const char* hideastatement )
+ : mparent( parent ), minternalname( internalname ),
+ mtranslatedname( translatedname ), mselectstatement( selectstatement ),
+ mselectnamestatement( selectnamestatement ),
+ mremoveastatement( removeastatement ), maddastatement( addastatement ),
+ mmoveastatement( moveastatement ),
+ mattachtothisstatement( attachtothisstatement ),
+ mshowastatement( showastatement ),
+ mhideastatement( hideastatement )
+{
+ sd()->namemap[minternalname] = this;
+}
+
+ObjectImpType::~ObjectImpType()
+{
+}
+
+bool ObjectImpType::inherits( const ObjectImpType* t ) const
+{
+ return t == this || (mparent && mparent->inherits( t ) );
+}
+
+const char* ObjectImpType::internalName() const
+{
+ return minternalname;
+}
+
+QString ObjectImpType::translatedName() const
+{
+ return i18n( mtranslatedname );
+}
+
+const char* ObjectImpType::selectStatement() const
+{
+ return mselectstatement;
+}
+
+const char* ObjectImpType::selectNameStatement() const
+{
+ return mselectnamestatement;
+}
+
+QString ObjectImpType::removeAStatement() const
+{
+ return i18n( mremoveastatement );
+}
+
+QString ObjectImpType::addAStatement() const
+{
+ return i18n( maddastatement );
+}
+
+QString ObjectImpType::moveAStatement() const
+{
+ return i18n( mmoveastatement );
+}
+
+const ObjectImpType* ObjectImpType::typeFromInternalName( const char* string )
+{
+ QCString s( string );
+ std::map<QCString, const ObjectImpType*>::iterator i = sd()->namemap.find( s );
+ if ( i == sd()->namemap.end() )
+ return 0;
+ else return i->second;
+}
+
+bool ObjectImp::inherits( const ObjectImpType* t ) const
+{
+ return type()->inherits( t );
+}
+
+const ObjectImpType* ObjectImp::stype()
+{
+ static const ObjectImpType t(
+ 0, "any",
+ I18N_NOOP( "Object" ),
+ I18N_NOOP( "Select this object" ),
+ I18N_NOOP( "Select object %1" ),
+ I18N_NOOP( "Remove an object" ),
+ I18N_NOOP( "Add an object" ),
+ I18N_NOOP( "Move an object" ),
+ I18N_NOOP( "Attach to this object" ),
+ I18N_NOOP( "Show an object" ),
+ I18N_NOOP( "Hide an object" ) );
+ return &t;
+}
+
+ObjectImpType::StaticPrivate* ObjectImpType::sd()
+{
+ static StaticPrivate d;
+ return &d;
+}
+
+bool ObjectImp::isCache() const
+{
+ return false;
+}
+
+QString ObjectImpType::attachToThisStatement() const
+{
+ return i18n( mattachtothisstatement );
+}
+
+QString ObjectImpType::showAStatement() const
+{
+ return i18n( mshowastatement );
+}
+
+QString ObjectImpType::hideAStatement() const
+{
+ return i18n( mhideastatement );
+}
+
+bool ObjectImp::isPropertyDefinedOnOrThroughThisImp( uint ) const
+{
+ return false;
+}
+
diff --git a/kig/objects/object_imp.h b/kig/objects/object_imp.h
new file mode 100644
index 00000000..2c032f99
--- /dev/null
+++ b/kig/objects/object_imp.h
@@ -0,0 +1,360 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_OBJECT_IMP_H
+#define KIG_OBJECTS_OBJECT_IMP_H
+
+#include "common.h"
+
+class IntImp;
+class DoubleImp;
+class StringImp;
+class InvalidImp;
+class HierarchyImp;
+class TransformationImp;
+class TestResultImp;
+class CurveImp;
+class LineImp;
+class PointImp;
+class TextImp;
+class AngleImp;
+class VectorImp;
+class LocusImp;
+class CircleImp;
+class ConicImp;
+class CubicImp;
+class SegmentImp;
+class RayImp;
+class ArcImp;
+class PolygonImp;
+
+/**
+ * \internal This is some OO magic commonly referred to as "double
+ * dispatch". If you need to do some action on an ObjectImp, and you
+ * need to do something different dependent on the type of o, then
+ * make a Visitor class that inherits this interface, and implements
+ * the appropriate functions properly, and call "o->visit( my_visitor
+ * );".
+ */
+class ObjectImpVisitor
+{
+public:
+ virtual ~ObjectImpVisitor();
+ void visit( const ObjectImp* imp );
+ virtual void visit( const IntImp* imp );
+ virtual void visit( const DoubleImp* imp );
+ virtual void visit( const StringImp* imp );
+ virtual void visit( const InvalidImp* imp );
+ virtual void visit( const HierarchyImp* imp );
+ virtual void visit( const TransformationImp* imp );
+ virtual void visit( const TestResultImp* imp );
+ virtual void visit( const LineImp* imp );
+ virtual void visit( const PointImp* imp );
+ virtual void visit( const TextImp* imp );
+ virtual void visit( const AngleImp* imp );
+ virtual void visit( const VectorImp* imp );
+ virtual void visit( const LocusImp* imp );
+ virtual void visit( const CircleImp* imp );
+ virtual void visit( const ConicImp* imp );
+ virtual void visit( const CubicImp* imp );
+ virtual void visit( const SegmentImp* imp );
+ virtual void visit( const RayImp* imp );
+ virtual void visit( const ArcImp* imp );
+ virtual void visit( const PolygonImp* imp );
+};
+
+typedef unsigned int uint;
+
+/**
+ * Instances of this class represent a certain ObjectImp type. Every
+ * ObjectImp type has a static ObjectImpType member, that it returns a
+ * reference to in its type() function.. Think of it as a nice enum,
+ * that you can also get some data from..
+ */
+class ObjectImpType
+{
+ const ObjectImpType* mparent;
+ const char* minternalname;
+ const char* mtranslatedname;
+ const char* mselectstatement;
+ const char* mselectnamestatement;
+ const char* mremoveastatement;
+ const char* maddastatement;
+ const char* mmoveastatement;
+ const char* mattachtothisstatement;
+ const char* mshowastatement;
+ const char* mhideastatement;
+ class StaticPrivate;
+ static StaticPrivate* sd();
+public:
+ /**
+ * Returns the type with name n.
+ *
+ * \internal Do *not* call this from functions that can be called at
+ * static initializer time ! It depends on information that is only
+ * available after that stage and will crash if used too early..
+ */
+ static const ObjectImpType* typeFromInternalName( const char* n );
+
+ /**
+ * \internal Construct an ObjectImpType, with a lot of data about
+ * your ObjectImp type.
+ *
+ * translatedname is a translatable string like "segment"
+ * selectstatement is a translatable string like "Select this segment"
+ * selectnamestatement is a translatable string like "Select segment %1"
+ * removeastatement is a translatable string like "Remove a Segment"
+ * addastatement is a translatable string like "Add a Segment"
+ * moveastatement is a translatable string like "Move a Segment"
+ * attachtothisstatement is a translatable string like "Attach to
+ * this segment"
+ * showastatement is a translatable string like "Show a Segment"
+ * hideastatement is a translatable string like "Hide a Segment"
+ *
+ * All translatable strings should have
+ * I18N_NOOP around them ! @param parent is the ObjectImpType of
+ * your parent ObjectImp type. Never give 0 as parent, except for
+ * the top ObjectImp ObjectImpType..
+ */
+ ObjectImpType(
+ const ObjectImpType* parent, const char* internalname,
+ const char* translatedname,
+ const char* selectstatement,
+ const char* selectnamestatement,
+ const char* removeastatement,
+ const char* addastatement,
+ const char* moveastatement,
+ const char* attachtothisstatement,
+ const char* showastatement,
+ const char* hideastatement );
+ ~ObjectImpType();
+
+ /**
+ * Does the ObjectImp type represented by this instance inherit the
+ * ObjectImp type represented by t ?
+ */
+ bool inherits( const ObjectImpType* t ) const;
+
+ /**
+ * Returns an internal name for this ObjectImp type. This name is
+ * guaranteed unique, and mostly corresponds with the class name of
+ * the corresponding ObjectImp..
+ */
+ const char* internalName() const;
+ /**
+ * The name of this type, translated to the currently used language.
+ */
+ QString translatedName() const;
+ /**
+ * Returns a translatable string of the form "Select this %1".
+ * E.g. "Select this segment". Note that users of this function
+ * should use i18n on the returned string before using it.
+ */
+ const char* selectStatement() const;
+
+ /**
+ * Returns a translatable string of the form "Select point %1". %1
+ * will be filled in by whomever calls this function with the name
+ * of the object in question. This function should be used as
+ * follows: i18n( x->selectNameStatement() ).arg( xname ).
+ */
+ const char* selectNameStatement() const;
+
+ /**
+ * Returns a translated string of the form "Remove a xxx".
+ * E.g. "Remove a Segment".
+ */
+ QString removeAStatement() const;
+ /**
+ * Returns a translated string of the form "Add a xxx".
+ * E.g. "Add a Segment".
+ */
+ QString addAStatement() const;
+ /**
+ * Returns a translated string of the form "Move a xxx".
+ * E.g. "Move a Segment".
+ */
+ QString moveAStatement() const;
+ /**
+ * Returns a translated string of the form "Attach to this xxx".
+ * E.g. "Attach to this segment".
+ * \internal This is used by the text label construction mode
+ */
+ QString attachToThisStatement() const;
+
+ /**
+ * Returns a translated string of the form "Show a xxx".
+ * E.g. "Show a Segment".
+ */
+ QString showAStatement() const;
+
+ /**
+ * Returns a translated string of the form "Hide a xxx".
+ * E.g. "Hide a Segment".
+ */
+ QString hideAStatement() const;
+};
+
+/**
+ * The ObjectImp class represents the behaviour of an object after it
+ * is calculated. This means how to draw() it, whether it claims to
+ * contain a certain point etc. It is also the class where the
+ * ObjectType's get their information from..
+ */
+class ObjectImp
+{
+protected:
+ ObjectImp();
+public:
+ /**
+ * The ObjectImpType representing the base ObjectImp class. All
+ * other ObjectImp's inherit from this type.
+ */
+ static const ObjectImpType* stype();
+
+ virtual ~ObjectImp();
+
+ /**
+ * Returns true if this ObjectImp inherits the ObjectImp type
+ * represented by t.
+ * E.g. you can check whether an ObjectImp is a LineImp by doing:
+ * \if creating-python-scripting-doc
+ * \code
+ * if object.inherits( LineImp.stype() ):
+ * \endcode
+ * \else
+ * \code
+ * if( object.inherits( LineImp::stype() )
+ * \endcode
+ * \endif
+ */
+ bool inherits( const ObjectImpType* t ) const;
+
+ /**
+ * Returns a reference point where to attach labels; when this
+ * returns an invalidCoord then the attachment is either not
+ * done at all, or done in a specific way (like for curves,
+ * or for points) The treatment of points could also take
+ * advantage of this attachment mechanism.
+ *
+ * If this method returns a valid Coordinate, then this is
+ * interpreted as a pivot point for the label, which can still
+ * be moved relative to that point, but follows the object when
+ * the object changes.
+ * In practice a new RelativePointType is created (position of
+ * the string), this type in turn depends on the object (to get
+ * its attachPoint) and two DoubleImp that are interpreted as
+ * relative displacement (x and y)
+ */
+ virtual Coordinate attachPoint( ) const = 0;
+
+ /**
+ * Return this ObjectImp, transformed by the transformation t.
+ */
+ virtual ObjectImp* transform( const Transformation& t ) const = 0;
+
+ virtual void draw( KigPainter& p ) const = 0;
+ virtual bool contains( const Coordinate& p, int width,
+ const KigWidget& si ) const = 0;
+ virtual bool inRect( const Rect& r, int width,
+ const KigWidget& si ) const = 0;
+ virtual Rect surroundingRect() const = 0;
+
+ /**
+ * Returns true if this is a valid ObjectImp.
+ * If you want to return an invalid ObjectImp, you should return an
+ * InvalidImp instance.
+ */
+ bool valid() const;
+
+ virtual const uint numberOfProperties() const;
+ // the names of the properties as perceived by the user.. put
+ // I18N_NOOP's around them here..
+ virtual const QCStringList properties() const;
+ // the names of the properties as known only by kig internally. No
+ // need for I18N_NOOP. Preferably choose some lowercase name with
+ // only letters and dashes, no spaces..
+ virtual const QCStringList propertiesInternalNames() const;
+ virtual ObjectImp* property( uint which, const KigDocument& d ) const;
+ // Sometimes we need to know which type an imp needs to be at least
+ // in order to have the imp with number which. Macro's need it
+ // foremost. This function answers that question..
+ virtual const ObjectImpType* impRequirementForProperty( uint which ) const;
+ // Return whether the property with number which is by construction
+ // always a point on this curve ( if this is a curve ), or always a
+ // curve through this point ( if this is a curve ).
+ virtual bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+ // What icon should be shown when talking about this property ?
+ virtual const char* iconForProperty( uint which ) const;
+
+ /**
+ * Returns the lowermost ObjectImpType that this object is an
+ * instantiation of.
+ * E.g. if you want to get a string containing the internal name of
+ * the type of an object, you can do:
+ * \if creating-python-scripting-doc
+ * \code
+ * tn = object.type().internalName()
+ * \endcode
+ * \else
+ * \code
+ * std::string typename = object.type()->internalName();
+ * \endcode
+ * \endif
+ */
+ virtual const ObjectImpType* type() const = 0;
+ virtual void visit( ObjectImpVisitor* vtor ) const = 0;
+
+ /**
+ * Returns a copy of this ObjectImp.
+ * The copy is an exact copy. Changes to the copy don't affect the
+ * original.
+ */
+ virtual ObjectImp* copy() const = 0;
+
+ // s is a string with at least one escape ( "%N" where N is a
+ // number ) somewhere. This function replaces the first escape it
+ // sees with the "value" of this imp ( using the QString::arg
+ // functions ). This is e.g. used by TextType to turn its variable
+ // args into strings..
+ // if you implement this, then you should return true in
+ // canFillInEscape() ( standard implementation returns false ), and
+ // override fillInNextEscape() ( standard implementation does an
+ // assert( false ) )..
+ virtual bool canFillInNextEscape() const;
+ virtual void fillInNextEscape( QString& s, const KigDocument& ) const;
+
+ /**
+ * Returns true if this ObjectImp is equal to rhs.
+ * This function checks whether rhs is of the same ObjectImp type,
+ * and whether it contains the same data as this ObjectImp.
+ * \internal It is used e.g. by the KigCommand stuff to see what the
+ * user has changed during a move..
+ */
+ virtual bool equals( const ObjectImp& rhs ) const = 0;
+
+ /**
+ * \internal Return true if this imp is just a cache imp. This
+ * means that it will never be considered to be stored in a file or
+ * in an ObjectHierarchy. This is useful for objects which cannot
+ * (easily and usefully) be (de)serialized, like e.g.
+ * PythonCompiledScriptImp.. For normal objects, the default
+ * implementation returns false, which is fine.
+ */
+ virtual bool isCache() const;
+};
+#endif
diff --git a/kig/objects/object_imp_factory.cc b/kig/objects/object_imp_factory.cc
new file mode 100644
index 00000000..bfeb1358
--- /dev/null
+++ b/kig/objects/object_imp_factory.cc
@@ -0,0 +1,510 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "object_imp_factory.h"
+
+#include "object_imp.h"
+#include "bogus_imp.h"
+#include "circle_imp.h"
+#include "conic_imp.h"
+#include "cubic_imp.h"
+#include "line_imp.h"
+#include "locus_imp.h"
+#include "other_imp.h"
+#include "point_imp.h"
+#include "text_imp.h"
+
+#include "../misc/coordinate.h"
+
+#include <qdom.h>
+
+#include <klocale.h>
+
+const ObjectImpFactory* ObjectImpFactory::instance()
+{
+ static const ObjectImpFactory t;
+ return &t;
+}
+
+ObjectImpFactory::ObjectImpFactory()
+{
+}
+
+ObjectImpFactory::~ObjectImpFactory()
+{
+}
+
+static void addXYElements( const Coordinate& c, QDomElement& parent, QDomDocument& doc )
+{
+ QDomElement xe = doc.createElement( "x" );
+ xe.appendChild(
+ doc.createTextNode(
+ QString::number( c.x ) ) );
+ parent.appendChild( xe );
+ QDomElement ye = doc.createElement( "y" );
+ ye.appendChild(
+ doc.createTextNode(
+ QString::number( c.y ) ) );
+ parent.appendChild( ye );
+}
+
+static void addDoubleElement( const char* name, double d, QDomElement& parent, QDomDocument& doc )
+{
+ QDomElement e = doc.createElement( name );
+ e.appendChild( doc.createTextNode( QString::number( d ) ) );
+ parent.appendChild( e );
+}
+
+static void addCoordinateElement( const char* name, const Coordinate& d, QDomElement& p, QDomDocument& doc )
+{
+ QDomElement e = doc.createElement( name );
+ addXYElements( d, e, doc );
+ p.appendChild( e );
+}
+
+QString ObjectImpFactory::serialize( const ObjectImp& d, QDomElement& parent,
+ QDomDocument& doc ) const
+{
+ if( d.inherits( IntImp::stype() ) )
+ {
+ parent.appendChild(
+ doc.createTextNode(
+ QString::number( static_cast<const IntImp&>( d ).data() ) ) );
+ return QString::fromLatin1( "int" );
+ }
+ else if ( d.inherits( DoubleImp::stype() ) )
+ {
+ parent.appendChild(
+ doc.createTextNode(
+ QString::number( static_cast<const DoubleImp&>( d ).data() ) ) );
+ return QString::fromLatin1( "double" );
+ }
+ else if( d.inherits( StringImp::stype() ) )
+ {
+ parent.appendChild(
+ doc.createTextNode(
+ static_cast<const StringImp&>( d ).data() ) );
+ return QString::fromLatin1( "string" );
+ }
+ else if ( d.inherits( TestResultImp::stype() ) )
+ {
+ parent.appendChild(
+ doc.createTextNode(
+ static_cast<const TestResultImp&>( d ).data() ) );
+ return QString::fromLatin1( "testresult" );
+ }
+ else if( d.inherits( HierarchyImp::stype() ) )
+ {
+ static_cast<const HierarchyImp&>( d ).data().serialize( parent, doc );
+ return QString::fromLatin1( "hierarchy" );
+ }
+ else if ( d.inherits( TransformationImp::stype() ) )
+ {
+ const Transformation& trans = static_cast<const TransformationImp&>( d ).data();
+
+ QDomElement matrixe = doc.createElement( "matrix" );
+ for ( int i = 0; i < 3; ++i )
+ {
+ for ( int j = 0; j < 3; ++j )
+ {
+ QDomElement elel = doc.createElement( "element" );
+ elel.setAttribute( "row", QString::number( i ) );
+ elel.setAttribute( "column", QString::number( j ) );
+ elel.appendChild( doc.createTextNode( QString::number( trans.data( i, j ) ) ) );
+ matrixe.appendChild( elel );
+ };
+ }
+ parent.appendChild( matrixe );
+
+ QDomElement homothetye = doc.createElement( "homothetic" );
+ const char* ishomothety = trans.isHomothetic() ? "true" : "false";
+ homothetye.appendChild( doc.createTextNode( ishomothety ) );
+ parent.appendChild( homothetye );
+
+ return QString::fromLatin1( "transformation" );
+ }
+ else if( d.inherits( AbstractLineImp::stype() ) )
+ {
+ LineData l = static_cast<const AbstractLineImp&>( d ).data();
+ addCoordinateElement( "a", l.a, parent, doc );
+ addCoordinateElement( "b", l.b, parent, doc );
+ if( d.inherits( SegmentImp::stype() ) )
+ return QString::fromLatin1( "segment" );
+ else if( d.inherits( RayImp::stype() ) )
+ return QString::fromLatin1( "ray" );
+ else return QString::fromLatin1( "line" );
+ }
+ else if( d.inherits( PointImp::stype() ) )
+ {
+ addXYElements( static_cast<const PointImp&>( d ).coordinate(),
+ parent, doc );
+ return QString::fromLatin1( "point" );
+ }
+ else if( d.inherits( TextImp::stype() ) )
+ {
+ QString text = static_cast<const TextImp&>( d ).text();
+ parent.appendChild(
+ doc.createTextNode( text ) );
+ return QString::fromLatin1( "text" );
+ }
+ else if( d.inherits( AngleImp::stype() ) )
+ {
+ addDoubleElement( "size", static_cast<const AngleImp&>( d ).size(), parent, doc );
+ return QString::fromLatin1( "angle" );
+ }
+ else if ( d.inherits( ArcImp::stype() ) )
+ {
+ const ArcImp& a = static_cast<const ArcImp&>( d );
+ addCoordinateElement( "center", a.center(), parent, doc );
+ addDoubleElement( "radius", a.radius(), parent, doc );
+ addDoubleElement( "startangle", a.startAngle(), parent, doc );
+ addDoubleElement( "angle", a.angle(), parent, doc );
+ return QString::fromLatin1( "arc" );
+ }
+ else if( d.inherits( VectorImp::stype() ) )
+ {
+ Coordinate dir = static_cast<const VectorImp&>( d ).dir();
+ addXYElements( dir, parent, doc );
+ return QString::fromLatin1( "vector" );
+ }
+ else if( d.inherits( LocusImp::stype() ) )
+ {
+ const LocusImp& locus = static_cast<const LocusImp&>( d );
+
+ // serialize the curve..
+ QDomElement curve = doc.createElement( "curve" );
+ const CurveImp& curveimp = *locus.curve();
+ QString type = serialize( curveimp, curve, doc );
+ curve.setAttribute( "type", type );
+ parent.appendChild( curve );
+
+ // serialize the hierarchy..
+ QDomElement hier = doc.createElement( "calculation" );
+ locus.hierarchy().serialize( hier, doc );
+ parent.appendChild( hier );
+
+ return QString::fromLatin1( "locus" );
+ }
+ else if( d.inherits( CircleImp::stype() ) )
+ {
+ const CircleImp& c = static_cast<const CircleImp&>( d );
+ addCoordinateElement( "center", c.center(), parent, doc );
+ addDoubleElement( "radius", c.radius(), parent, doc );
+ return QString::fromLatin1( "circle" );
+ }
+ else if( d.inherits( ConicImp::stype() ) )
+ {
+ const ConicPolarData data = static_cast<const ConicImp&>( d ).polarData();
+ addCoordinateElement( "focus1", data.focus1, parent, doc );
+ addDoubleElement( "pdimen", data.pdimen, parent, doc );
+ addDoubleElement( "ecostheta0", data.ecostheta0, parent, doc );
+ addDoubleElement( "esintheta0", data.esintheta0, parent, doc );
+ return QString::fromLatin1( "conic" );
+ }
+ else if( d.inherits( CubicImp::stype() ) )
+ {
+ const CubicCartesianData data = static_cast<const CubicImp&>( d ).data();
+ QDomElement coeffs = doc.createElement( "coefficients" );
+ addDoubleElement( "a000", data.coeffs[0], coeffs, doc );
+ addDoubleElement( "a001", data.coeffs[1], coeffs, doc );
+ addDoubleElement( "a002", data.coeffs[2], coeffs, doc );
+ addDoubleElement( "a011", data.coeffs[3], coeffs, doc );
+ addDoubleElement( "a012", data.coeffs[4], coeffs, doc );
+ addDoubleElement( "a022", data.coeffs[5], coeffs, doc );
+ addDoubleElement( "a111", data.coeffs[6], coeffs, doc );
+ addDoubleElement( "a112", data.coeffs[7], coeffs, doc );
+ addDoubleElement( "a122", data.coeffs[8], coeffs, doc );
+ addDoubleElement( "a222", data.coeffs[9], coeffs, doc );
+ parent.appendChild( coeffs );
+ return QString::fromLatin1( "cubic" );
+ }
+ assert( false );
+ return QString::null;
+}
+
+static Coordinate readXYElements( const QDomElement& e, bool& ok )
+{
+ double x, y;
+ ok = true;
+ QDomElement xe = e.firstChild().toElement();
+ if ( xe.isNull() || xe.tagName() != "x" )
+ {
+ ok = false;
+ return Coordinate();
+ }
+ else x = xe.text().toDouble( &ok );
+
+ QDomElement ye = xe.nextSibling().toElement();
+ if ( ye.isNull() || ye.tagName() != "y" )
+ {
+ ok = false;
+ return Coordinate();
+ }
+ else y = ye.text().toDouble( &ok );
+
+ return Coordinate( x, y );
+}
+
+static Coordinate readCoordinateElement( QDomNode n, bool& ok,
+ const char* tagname )
+{
+ QDomElement e = n.toElement();
+ if ( e.isNull() || e.tagName() != tagname )
+ {
+ ok = false;
+ Coordinate ret;
+ return ret;
+ }
+ return readXYElements( e, ok );
+}
+
+static double readDoubleElement( QDomNode n, bool& ok,
+ const char* tagname )
+{
+ QDomElement e = n.toElement();
+ if ( e.isNull() || e.tagName() != tagname )
+ {
+ ok = false;
+ return 0.;
+ };
+ return e.text().toDouble( &ok );
+}
+
+ObjectImp* ObjectImpFactory::deserialize( const QString& type,
+ const QDomElement& parent,
+ QString& error ) const
+{
+#define KIG_GENERIC_PARSE_ERROR \
+ { \
+ error = i18n( "An error was encountered at line %1 in file %2." ) \
+ .arg( __LINE__ ).arg( __FILE__ ); \
+ return 0; \
+ }
+
+ bool ok = true;
+ if ( type == "int" )
+ {
+ int ret = parent.text().toInt( &ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ return new IntImp( ret );
+ }
+ else if ( type == "double" )
+ {
+ double ret = parent.text().toDouble( &ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ return new DoubleImp( ret );
+ }
+ else if ( type == "string" )
+ {
+ return new StringImp( parent.text() );
+ }
+ else if ( type == "testresult" )
+ {
+ return new TestResultImp( parent.text() );
+ }
+ else if ( type == "hierarchy" )
+ {
+ ObjectHierarchy* hier = ObjectHierarchy::buildSafeObjectHierarchy( parent, error );
+ if ( ! hier ) return 0;
+ HierarchyImp* imp = new HierarchyImp( *hier );
+ delete hier;
+ return imp;
+ }
+ else if ( type == "transformation" )
+ {
+ double data[3][3];
+ bool homothetic = false;
+ for ( QDomElement childe = parent.firstChild().toElement();
+ ! childe.isNull(); childe = childe.nextSibling().toElement() )
+ {
+ if ( childe.tagName() == "matrix" )
+ {
+ for ( QDomElement elel = childe.firstChild().toElement();
+ ! elel.isNull(); elel = elel.nextSibling().toElement() )
+ {
+ if ( elel.tagName() != "element" ) KIG_GENERIC_PARSE_ERROR;
+ bool ok = true;
+ int row = elel.attribute( "row" ).toInt( &ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ int column = elel.attribute( "column" ).toInt( &ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ data[row][column] = elel.text().toDouble( &ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ };
+ }
+ else if ( childe.tagName() == "homothetic" )
+ {
+ homothetic = childe.text() == "true";
+ }
+ else continue;
+ };
+ Transformation trans( data, homothetic );
+ return new TransformationImp( trans );
+ }
+ else if ( type == "point" )
+ {
+ Coordinate ret = readXYElements( parent, ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ return new PointImp( ret );
+ }
+ else if ( type == "line" || type == "segment" || type == "ray" )
+ {
+ QDomNode n = parent.firstChild();
+ Coordinate a = readCoordinateElement( n, ok, "a" );
+ if ( !ok ) KIG_GENERIC_PARSE_ERROR;
+ n = n.nextSibling();
+ Coordinate b = readCoordinateElement( n, ok, "b" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ if ( type == "line" ) return new LineImp( a, b );
+ else if ( type == "segment" ) return new SegmentImp( a, b );
+ else return new RayImp( a, b );
+ }
+ else if( type == "angle" )
+ {
+ double size = readDoubleElement( parent.firstChild(), ok, "size" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ return new AngleImp( Coordinate(), 0, size );
+ }
+ else if ( type == "arc" )
+ {
+ QDomNode n = parent.firstChild();
+ Coordinate center = readCoordinateElement( n, ok, "center" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ n = n.nextSibling();
+ double radius = readDoubleElement( n, ok, "radius" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ n = n.nextSibling();
+ double startangle = readDoubleElement( n, ok, "startangle" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ n = n.nextSibling();
+ double angle = readDoubleElement( n, ok, "angle" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ return new ArcImp( center, radius, startangle, angle );
+ }
+ else if( type == "vector" )
+ {
+ Coordinate dir = readXYElements( parent, ok );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+ return new VectorImp( Coordinate(), dir );
+ }
+ else if( type == "locus" )
+ {
+ QDomElement curvee = parent.firstChild().toElement();
+ if ( curvee.isNull() || curvee.tagName() != "curve" ) KIG_GENERIC_PARSE_ERROR;
+ QString type = curvee.attribute( "type" );
+ ObjectImp* oi = deserialize( type, curvee, error );
+ if ( ! oi || ! oi->inherits( CurveImp::stype() ) ) KIG_GENERIC_PARSE_ERROR;
+ //CurveImp* curvei = static_cast<CurveImp*>( oi );
+
+ QDomElement hiere = curvee.nextSibling().toElement();
+ if ( hiere.isNull() || hiere.tagName() != "calculation" ) KIG_GENERIC_PARSE_ERROR;
+ assert( false ); // TODO
+// return new LocusImp( curvei, hier );
+ }
+ else if( type == "circle" )
+ {
+ QDomNode n = parent.firstChild();
+ Coordinate center = readCoordinateElement( n, ok, "center" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double radius = readDoubleElement( n, ok, "radius" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ return new CircleImp( center, radius );
+ }
+ else if( type == "conic" )
+ {
+ QDomNode n = parent.firstChild();
+ Coordinate focus1 = readCoordinateElement( n, ok, "focus1" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double pdimen = readDoubleElement( n, ok, "pdimen" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double ecostheta0 = readDoubleElement( n, ok, "ecostheta0" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double esintheta0 = readDoubleElement( n, ok, "esintheta0" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ return new ConicImpPolar(
+ ConicPolarData( focus1, pdimen, ecostheta0, esintheta0 ) );
+ }
+ else if( type == "cubic" )
+ {
+ QDomElement coeffse = parent.firstChild().toElement();
+ if ( coeffse.isNull() || coeffse.tagName() != "coefficients" )
+ KIG_GENERIC_PARSE_ERROR;
+
+ QDomNode n = coeffse.firstChild();
+ double a000 = readDoubleElement( n, ok, "a000" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a001 = readDoubleElement( n, ok, "a001" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a002 = readDoubleElement( n, ok, "a002" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a011 = readDoubleElement( n, ok, "a011" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a012 = readDoubleElement( n, ok, "a012" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a022 = readDoubleElement( n, ok, "a022" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a111 = readDoubleElement( n, ok, "a111" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a112 = readDoubleElement( n, ok, "a112" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a122 = readDoubleElement( n, ok, "a112" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ n = n.nextSibling();
+ double a222 = readDoubleElement( n, ok, "a222" );
+ if ( ! ok ) KIG_GENERIC_PARSE_ERROR;
+
+ return new CubicImp( CubicCartesianData( a000, a001, a002,
+ a011, a012, a022,
+ a111, a112, a122,
+ a222 ) );
+ }
+
+ error = i18n( "This Kig file uses an object of type \"%1\", "
+ "which this Kig version does not support."
+ "Perhaps you have compiled Kig without support "
+ "for this object type,"
+ "or perhaps you are using an older Kig version." ).arg( type );
+ return 0;
+}
+
diff --git a/kig/objects/object_imp_factory.h b/kig/objects/object_imp_factory.h
new file mode 100644
index 00000000..1ab82bb4
--- /dev/null
+++ b/kig/objects/object_imp_factory.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_OBJECT_IMP_FACTORY_H
+#define KIG_OBJECTS_OBJECT_IMP_FACTORY_H
+
+#include "common.h"
+
+class ObjectImpFactory
+{
+ ObjectImpFactory();
+ ~ObjectImpFactory();
+public:
+ static const ObjectImpFactory* instance();
+ /**
+ * loads data from \p parent , and returns a new ObjectImp from the type
+ * string \p type .
+ */
+ ObjectImp* deserialize( const QString& type, const QDomElement& parent, QString& error ) const;
+ /**
+ * adds data to \p parent , and returns a type string..
+ */
+ QString serialize( const ObjectImp& d, QDomElement& parent, QDomDocument& doc ) const;
+};
+
+#endif
diff --git a/kig/objects/object_type.cc b/kig/objects/object_type.cc
new file mode 100644
index 00000000..9ac2845b
--- /dev/null
+++ b/kig/objects/object_type.cc
@@ -0,0 +1,125 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "object_type.h"
+
+#include "bogus_imp.h"
+#include "object_type_factory.h"
+
+#include "../misc/coordinate.h"
+
+#include <qstringlist.h>
+
+#include <klocale.h>
+
+const char* ObjectType::fullName() const
+{
+ return mfulltypename;
+}
+
+ObjectType::~ObjectType()
+{
+}
+
+ObjectType::ObjectType( const char fulltypename[] )
+ : mfulltypename( fulltypename )
+{
+ ObjectTypeFactory::instance()->add( this );
+}
+
+bool ObjectType::canMove( const ObjectTypeCalcer& ) const
+{
+ return false;
+}
+
+bool ObjectType::isFreelyTranslatable( const ObjectTypeCalcer& ) const
+{
+ return false;
+}
+
+void ObjectType::move( ObjectTypeCalcer&, const Coordinate&, const KigDocument& ) const
+{
+ // we can't do an assert here, because sometimes ( like in
+ // ObjectABType::move, ObjectType::move is called without checking
+ // the object's canMove().
+// assert( false );
+}
+
+bool ObjectType::inherits( int ) const
+{
+ return false;
+}
+
+ArgsParserObjectType::ArgsParserObjectType( const char fulltypename[],
+ const struct ArgsParser::spec argsspec[],
+ int n )
+ : ObjectType( fulltypename ), margsparser( argsspec, n )
+{
+}
+
+const ObjectImpType* ArgsParserObjectType::impRequirement( const ObjectImp* o, const Args& parents ) const
+{
+ return margsparser.impRequirement( o, parents );
+}
+
+const ArgsParser& ArgsParserObjectType::argsParser() const
+{
+ return margsparser;
+}
+
+bool ObjectType::isTransform() const
+{
+ return false;
+}
+
+QStringList ObjectType::specialActions() const
+{
+ return QStringList();
+}
+
+void ObjectType::executeAction( int, ObjectHolder&, ObjectTypeCalcer&, KigPart&, KigWidget&,
+ NormalMode& ) const
+{
+ assert( false );
+}
+
+const Coordinate ObjectType::moveReferencePoint( const ObjectTypeCalcer& ) const
+{
+ assert( false );
+ return Coordinate::invalidCoord();
+}
+
+std::vector<ObjectCalcer*> ArgsParserObjectType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ return margsparser.parse( args );
+}
+
+Args ArgsParserObjectType::sortArgs( const Args& args ) const
+{
+ return margsparser.parse( args );
+}
+
+std::vector<ObjectCalcer*> ObjectType::movableParents( const ObjectTypeCalcer& ) const
+{
+ return std::vector<ObjectCalcer*>();
+}
+
+bool ArgsParserObjectType::isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const
+{
+ return margsparser.isDefinedOnOrThrough( o, parents );
+}
+
diff --git a/kig/objects/object_type.h b/kig/objects/object_type.h
new file mode 100644
index 00000000..f0ac49af
--- /dev/null
+++ b/kig/objects/object_type.h
@@ -0,0 +1,130 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_OBJECT_TYPE_H
+#define KIG_OBJECTS_OBJECT_TYPE_H
+
+#include "common.h"
+#include "../misc/argsparser.h"
+
+class ObjectTypeCalcer;
+
+/**
+ * The ObjectType class is a thing that represents the "behaviour" for
+ * a certain type.. This basically means that it decides what
+ * \ref ObjectImp the object gets in the calc() function, how the
+ * object move()'s etc.
+ */
+class ObjectType
+{
+ const char* mfulltypename;
+protected:
+ ObjectType( const char fulltypename[] );
+public:
+ virtual ~ObjectType();
+
+ enum {
+ ID_ConstrainedPointType,
+ ID_LocusType,
+ ID_FixedPointType
+ };
+
+ virtual bool inherits( int type ) const;
+
+ virtual ObjectImp* calc( const Args& parents, const KigDocument& d ) const = 0;
+
+ virtual bool canMove( const ObjectTypeCalcer& ourobj ) const;
+ virtual bool isFreelyTranslatable( const ObjectTypeCalcer& ourobj ) const;
+ virtual std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ virtual const Coordinate moveReferencePoint( const ObjectTypeCalcer& ourobj ) const;
+ virtual void move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& d ) const;
+
+ const char* fullName() const;
+
+ /**
+ * Supposing that \p parents would be given as parents to
+ * this type's calc function, this function returns the ObjectImp id
+ * that \p o should at least have.. ( \p o should be part of \p parents )
+ */
+ virtual const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const = 0;
+
+ /**
+ * Supposing that \p parents would be given as parents to this type's
+ * calc function, this function returns whether the returned
+ * ObjectImp will be, by construction, on \p o ( if \p o is a curve ), or
+ * through \p o ( if \p o is a point ).
+ */
+ virtual bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const = 0;
+
+ /**
+ * returns the ObjectImp id of the ObjectImp's produced by this
+ * ObjectType.. if the ObjectType can return different sorts of
+ * ObjectImp's, it should return the biggest common id, or
+ * ID_AnyImp..
+ */
+ virtual const ObjectImpType* resultId() const = 0;
+
+ virtual std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const = 0;
+
+ virtual Args sortArgs( const Args& args ) const = 0;
+
+ /**
+ * is this object type a transformation type. We want to know this
+ * cause transform types are shown separately in an object's RMB
+ * menu..
+ */
+ virtual bool isTransform() const;
+
+ // ObjectType's can define some special actions, that are strictly
+ // specific to the type at hand. E.g. a text label allows to toggle
+ // the display of a frame around the text. Constrained and fixed
+ // points can be redefined etc.
+
+ /**
+ * return i18n'd names for the special actions..
+ */
+ virtual QStringList specialActions() const;
+ /**
+ * execute the \p i 'th action from the specialActions above..
+ */
+ virtual void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& t,
+ KigPart& d, KigWidget& w, NormalMode& m ) const;
+};
+
+/**
+ * This is a convenience subclass of ObjectType that a type should
+ * inherit from if its parents can be specified in an ArgsParser..
+ */
+class ArgsParserObjectType
+ : public ObjectType
+{
+protected:
+ const ArgsParser margsparser;
+ ArgsParserObjectType( const char fulltypename[],
+ const struct ArgsParser::spec argsspec[],
+ int n );
+public:
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ const ArgsParser& argsParser() const;
+
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const;
+ Args sortArgs( const Args& args ) const;
+};
+
+#endif
diff --git a/kig/objects/object_type_factory.cc b/kig/objects/object_type_factory.cc
new file mode 100644
index 00000000..ee3024fd
--- /dev/null
+++ b/kig/objects/object_type_factory.cc
@@ -0,0 +1,148 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "object_type_factory.h"
+
+#include <config.h>
+
+#include "object_type.h"
+#include "circle_type.h"
+#include "conic_types.h"
+#include "cubic_type.h"
+#include "intersection_types.h"
+#include "line_type.h"
+#include "text_type.h"
+#include "other_type.h"
+#include "transform_types.h"
+#include "point_type.h"
+#include "tests_type.h"
+
+#ifdef KIG_ENABLE_PYTHON_SCRIPTING
+#include "../scripting/python_type.h"
+#endif
+
+#include <qdom.h>
+#include <string>
+
+ObjectTypeFactory::ObjectTypeFactory()
+ : malreadysetup( false )
+{
+ setupBuiltinTypes();
+}
+
+ObjectTypeFactory::~ObjectTypeFactory()
+{
+}
+
+ObjectTypeFactory* ObjectTypeFactory::instance()
+{
+ static ObjectTypeFactory fact;
+ return &fact;
+}
+
+void ObjectTypeFactory::add( const ObjectType* type )
+{
+ assert( mmap.find( std::string( type->fullName() ) ) == mmap.end() );
+ mmap[std::string( type->fullName() )] = type;
+}
+
+const ObjectType* ObjectTypeFactory::find( const char* name ) const
+{
+ maptype::const_iterator i = mmap.find( std::string( name ) );
+ if ( i == mmap.end() ) return 0;
+ else return i->second;
+}
+
+void ObjectTypeFactory::setupBuiltinTypes()
+{
+// assert( ! malreadysetup );
+// malreadysetup = true;
+
+// // circle_type.h
+// add( CircleBCPType::instance() );
+// add( CircleBPRType::instance() );
+// add( CircleBTPType::instance() );
+
+// // conic_types.h
+// add( ConicB5PType::instance() );
+// add( ConicBAAPType::instance() );
+// add( EllipseBFFPType::instance() );
+// add( HyperbolaBFFPType::instance() );
+// add( ConicBDFPType::instance() );
+// add( ParabolaBTPType::instance() );
+// add( EquilateralHyperbolaB4PType::instance() );
+// add( ConicPolarPointType::instance() );
+// add( ConicPolarLineType::instance() );
+// add( ConicDirectrixType::instance() );
+// add( ParabolaBDPType::instance() );
+// add( ConicAsymptoteType::instance() );
+// add( ConicRadicalType::instance() );
+
+// // cubic_type.h
+// add( CubicB9PType::instance() );
+// add( CubicNodeB6PType::instance() );
+// add( CubicCuspB4PType::instance() );
+
+// // intersection_types.h
+// add( ConicLineIntersectionType::instance() );
+// add( ConicLineOtherIntersectionType::instance() );
+// add( LineLineIntersectionType::instance() );
+// add( LineCubicIntersectionType::instance() );
+// add( CircleCircleIntersectionType::instance() );
+
+// // line_type.h
+// add( SegmentABType::instance() );
+// add( LineABType::instance() );
+// add( RayABType::instance() );
+// add( LinePerpendLPType::instance() );
+// add( LineParallelLPType::instance() );
+
+// // other_type.h
+// add( AngleType::instance() );
+// add( VectorType::instance() );
+// add( LocusType::instance() );
+// add( ArcBTPType::instance() );
+// add( CopyObjectType::instance() );
+
+// // point_type.h
+// add( FixedPointType::instance() );
+// add( ConstrainedPointType::instance() );
+// add( MidPointType::instance() );
+// add( MeasureTransportType::instance() );
+
+// // text_type.h
+// add( TextType::instance() );
+
+// // tests_type.h
+// add( AreParallelType::instance() );
+
+// // transform_types.h
+// add( TranslatedType::instance() );
+// add( PointReflectionType::instance() );
+// add( LineReflectionType::instance() );
+// add( RotationType::instance() );
+// add( ScalingOverCenterType::instance() );
+// add( ScalingOverLineType::instance() );
+// add( ProjectiveRotationType::instance() );
+// add( CastShadowType::instance() );
+
+// #ifdef KIG_ENABLE_PYTHON_SCRIPTING
+// // python types
+// add( PythonCompileType::instance() );
+// add( PythonExecuteType::instance() );
+// #endif
+}
diff --git a/kig/objects/object_type_factory.h b/kig/objects/object_type_factory.h
new file mode 100644
index 00000000..c1371d67
--- /dev/null
+++ b/kig/objects/object_type_factory.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef OBJECT_TYPE_FACTORY_H
+#define OBJECT_TYPE_FACTORY_H
+
+#include "common.h"
+
+#include <map>
+#include <string>
+
+class ObjectTypeFactory
+{
+ typedef std::map<std::string, const ObjectType*> maptype;
+ maptype mmap;
+ bool malreadysetup;
+ ObjectTypeFactory();
+ ~ObjectTypeFactory();
+ void setupBuiltinTypes();
+public:
+ static ObjectTypeFactory* instance();
+ void add( const ObjectType* type );
+ const ObjectType* find( const char* name ) const;
+};
+
+#endif
diff --git a/kig/objects/other_imp.cc b/kig/objects/other_imp.cc
new file mode 100644
index 00000000..137a3e93
--- /dev/null
+++ b/kig/objects/other_imp.cc
@@ -0,0 +1,710 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "other_imp.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+#include "line_imp.h"
+
+#include "../misc/screeninfo.h"
+#include "../misc/common.h"
+#include "../misc/kigtransform.h"
+#include "../misc/kigpainter.h"
+#include "../misc/goniometry.h"
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+#include <cmath>
+#include <utility>
+using namespace std;
+
+AngleImp::~AngleImp()
+{
+}
+
+ObjectImp* AngleImp::transform( const Transformation& ) const
+{
+ // TODO ?
+ return new InvalidImp;
+}
+
+void AngleImp::draw( KigPainter& p ) const
+{
+ p.drawAngle( mpoint, mstartangle, mangle );
+}
+
+AngleImp::AngleImp( const Coordinate& pt, double start_angle_in_radials,
+ double angle_in_radials )
+ : mpoint( pt ), mstartangle( start_angle_in_radials ),
+ mangle( angle_in_radials )
+{
+}
+
+bool AngleImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ double radius = 50*w.screenInfo().pixelWidth();
+
+ if ( fabs( (p-mpoint).length() - radius ) > w.screenInfo().normalMiss( width ) )
+ return false;
+
+ // and next we check if the angle is appropriate...
+ Coordinate vect = p - mpoint;
+ double angle = atan2( vect.y, vect.x );
+ while ( angle < mstartangle ) angle += 2*M_PI;
+ return angle <= mstartangle + mangle;
+}
+
+bool AngleImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ // TODO ?
+ return r.contains( mpoint, w.screenInfo().normalMiss( width ) );
+}
+
+Coordinate AngleImp::attachPoint() const
+{
+ return mpoint;
+}
+
+const uint AngleImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 3;
+}
+
+const QCStringList AngleImp::propertiesInternalNames() const
+{
+ QCStringList l = Parent::propertiesInternalNames();
+ l << "angle-radian";
+ l << "angle-degrees";
+ l << "angle-bisector";
+ assert( l.size() == AngleImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList AngleImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l << I18N_NOOP( "Angle in Radians" );
+ l << I18N_NOOP( "Angle in Degrees" );
+ l << I18N_NOOP( "Angle Bisector" );
+ assert( l.size() == AngleImp::numberOfProperties() );
+ return l;
+}
+
+const ObjectImpType* AngleImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return AngleImp::stype();
+}
+
+const char* AngleImp::iconForProperty( uint which ) const
+{
+ int numprop = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_size"; // size in radians
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_size"; // size in degrees
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_bisector"; // angle bisector..
+ else assert( false );
+ return "";
+}
+
+ObjectImp* AngleImp::property( uint which, const KigDocument& w ) const
+{
+ int numprop = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( size() );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( Goniometry::convert( size(), Goniometry::Rad, Goniometry::Deg ) );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ {
+ const double angle = mstartangle + mangle / 2;
+ Coordinate p2 = mpoint + Coordinate( cos( angle ), sin( angle ) ) * 10;
+ return new RayImp( mpoint, p2 );
+ }
+ else assert( false );
+ return new InvalidImp;
+}
+
+const double AngleImp::size() const
+{
+ return mangle;
+}
+
+ObjectImp* AngleImp::copy() const
+{
+ return new AngleImp( mpoint, mstartangle, mangle );
+}
+
+VectorImp::VectorImp( const Coordinate& a, const Coordinate& b )
+ : mdata( a, b )
+{
+}
+
+VectorImp::~VectorImp()
+{
+}
+
+ObjectImp* VectorImp::transform( const Transformation& t ) const
+{
+ Coordinate ta = t.apply( mdata.a );
+ Coordinate tb = t.apply( mdata.b );
+ if ( ta.valid() && tb.valid() ) return new VectorImp( ta, tb );
+ else return new InvalidImp;
+}
+
+void VectorImp::draw( KigPainter& p ) const
+{
+ p.drawVector( mdata.a, mdata.b );
+}
+
+bool VectorImp::contains( const Coordinate& o, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( o, w.screenInfo().normalMiss( width ) );
+}
+
+bool VectorImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ return lineInRect( r, mdata.a, mdata.b, width, this, w );
+}
+
+const uint VectorImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 5;
+}
+
+const QCStringList VectorImp::propertiesInternalNames() const
+{
+ QCStringList ret = Parent::propertiesInternalNames();
+ ret << "length";
+ ret << "vect-mid-point";
+ ret << "length-x";
+ ret << "length-y";
+ ret << "vector-opposite";
+ assert( ret.size() == VectorImp::numberOfProperties() );
+ return ret;
+}
+
+const QCStringList VectorImp::properties() const
+{
+ QCStringList ret = Parent::properties();
+ ret << I18N_NOOP( "Length" );
+ ret << I18N_NOOP( "Midpoint" );
+ ret << I18N_NOOP( "X length" );
+ ret << I18N_NOOP( "Y length" );
+ ret << I18N_NOOP( "Opposite Vector" );
+ assert( ret.size() == VectorImp::numberOfProperties() );
+ return ret;
+}
+
+const ObjectImpType* VectorImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return VectorImp::stype();
+}
+
+const char* VectorImp::iconForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ else if ( which == Parent::numberOfProperties() )
+ return "distance"; // length
+ else if ( which == Parent::numberOfProperties() + 1 )
+ return "bisection"; // mid point
+ else if ( which == Parent::numberOfProperties() + 2 )
+ return "distance"; // length-x
+ else if ( which == Parent::numberOfProperties() + 3 )
+ return "distance"; // length-y
+ else if ( which == Parent::numberOfProperties() + 4 )
+ return "opposite-vector"; // opposite vector
+ else assert( false );
+ return "";
+}
+
+ObjectImp* VectorImp::property( uint which, const KigDocument& w ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ else if ( which == Parent::numberOfProperties() )
+ return new DoubleImp( length() );
+ else if ( which == Parent::numberOfProperties() + 1 )
+ return new PointImp( ( mdata.a + mdata.b ) / 2 );
+ else if ( which == Parent::numberOfProperties() + 2 )
+ return new DoubleImp( fabs( mdata.a.x - mdata.b.x ) );
+ else if ( which == Parent::numberOfProperties() + 3 )
+ return new DoubleImp( fabs( mdata.a.y - mdata.b.y ) );
+ else if ( which == Parent::numberOfProperties() + 4 ) // opposite
+ return new VectorImp( mdata.a, 2*mdata.a-mdata.b );
+ else assert( false );
+ return new InvalidImp;
+}
+
+VectorImp* VectorImp::copy() const
+{
+ return new VectorImp( mdata.a, mdata.b );
+}
+
+const Coordinate VectorImp::dir() const
+{
+ return mdata.dir();
+}
+
+void AngleImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+void VectorImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+const double VectorImp::length() const
+{
+ return ( mdata.a - mdata.b ).length();
+}
+
+ArcImp::ArcImp( const Coordinate& center, const double radius,
+ const double startangle, const double angle )
+ : CurveImp(), mcenter( center ), mradius( radius ),
+ msa( startangle ), ma( angle )
+{
+ if ( ma < 0 )
+ {
+ // we want a positive angle..
+ msa = msa + ma;
+ ma = -ma;
+ };
+}
+
+ArcImp::~ArcImp()
+{
+}
+
+ArcImp* ArcImp::copy() const
+{
+ return new ArcImp( mcenter, mradius, msa, ma );
+}
+
+ObjectImp* ArcImp::transform( const Transformation& t ) const
+{
+ //
+ // we don't have conic arcs! So it is invalid to transform an arc
+ // with a nonhomothetic transformation
+ //
+ if ( ! t.isHomothetic() ) return new InvalidImp();
+
+ Coordinate nc = t.apply( mcenter );
+ double nr = t.apply( mradius );
+ // transform msa...
+ double nmsa = msa;
+ if ( t.getAffineDeterminant() > 0 )
+ {
+ nmsa = msa - t.getRotationAngle();
+ } else
+ {
+ Coordinate ar = t.apply2by2only( Coordinate( cos(msa), sin(msa) ) );
+ nmsa = atan2( ar.y, ar.x );
+ nmsa -= ma;
+ }
+ while ( nmsa < -M_PI ) nmsa += 2*M_PI;
+ while ( nmsa > M_PI ) nmsa -= 2*M_PI;
+ if ( nc.valid() ) return new ArcImp( nc, nr, nmsa, ma );
+ else return new InvalidImp;
+}
+
+void ArcImp::draw( KigPainter& p ) const
+{
+ p.drawArc( mcenter, mradius, msa, ma );
+}
+
+bool ArcImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ return internalContainsPoint( p, w.screenInfo().normalMiss( width ) );
+}
+
+bool ArcImp::inRect( const Rect&, int, const KigWidget& ) const
+{
+ // TODO
+ return false;
+}
+
+bool ArcImp::valid() const
+{
+ return true;
+}
+
+const uint ArcImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 9;
+}
+
+const QCStringList ArcImp::properties() const
+{
+ QCStringList ret = Parent::properties();
+ ret << I18N_NOOP( "Center" );
+ ret << I18N_NOOP( "Radius" );
+ ret << I18N_NOOP( "Angle" );
+ ret << I18N_NOOP( "Angle in Degrees" );
+ ret << I18N_NOOP( "Angle in Radians" );
+ ret << I18N_NOOP( "Sector Surface" );
+ ret << I18N_NOOP( "Arc Length" );
+ ret << I18N_NOOP( "First End Point" );
+ ret << I18N_NOOP( "Second End Point" );
+ assert( ret.size() == ArcImp::numberOfProperties() );
+ return ret;
+}
+
+const QCStringList ArcImp::propertiesInternalNames() const
+{
+ QCStringList ret = Parent::propertiesInternalNames();
+ ret << "center";
+ ret << "radius";
+ ret << "angle";
+ ret << "angle-degrees";
+ ret << "angle-radians";
+ ret << "sector-surface";
+ ret << "arc-length";
+ ret << "end-point-A";
+ ret << "end-point-B";
+ return ret;
+}
+
+const char* ArcImp::iconForProperty( uint which ) const
+{
+ int numprop = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "arc_center"; // center
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_size";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "angle_size";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return "";
+ else assert( false );
+ return "";
+}
+
+ObjectImp* ArcImp::property( uint which, const KigDocument& d ) const
+{
+ int numprop = 0;
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, d );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new PointImp( mcenter );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( mradius );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new AngleImp( mcenter, msa, ma );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new IntImp( static_cast<int>( Goniometry::convert( ma, Goniometry::Rad, Goniometry::Deg ) ) );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( ma );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( sectorSurface() );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new DoubleImp( mradius * ma );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new PointImp( firstEndPoint() );
+ else if ( which == Parent::numberOfProperties() + numprop++ )
+ return new PointImp( secondEndPoint() );
+ else assert( false );
+ return new InvalidImp;
+}
+
+const double ArcImp::sectorSurface() const
+{
+ return mradius * mradius * ma / 2;
+}
+
+const ObjectImpType* ArcImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else
+ return ArcImp::stype();
+}
+
+void ArcImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+double ArcImp::getParam( const Coordinate& c, const KigDocument& ) const
+{
+ Coordinate d = (c - mcenter).normalize();
+ double angle = atan2( d.y, d.x );
+ angle -= msa;
+// mp: problems with large arcs
+ while ( angle > ma/2 + M_PI ) angle -= 2*M_PI;
+ while ( angle < ma/2 - M_PI ) angle += 2*M_PI;
+//
+ angle = max( 0., min( angle, ma ) );
+ angle /= ma;
+ return angle;
+}
+
+const Coordinate ArcImp::getPoint( double p, const KigDocument& ) const
+{
+ double angle = msa + p * ma;
+ Coordinate d = Coordinate( cos( angle ), sin( angle ) ) * mradius;
+ return mcenter + d;
+}
+
+const Coordinate ArcImp::center() const
+{
+ return mcenter;
+}
+
+double ArcImp::radius() const
+{
+ return mradius;
+}
+
+double ArcImp::startAngle() const
+{
+ return msa;
+}
+
+double ArcImp::angle() const
+{
+ return ma;
+}
+
+Coordinate ArcImp::firstEndPoint() const
+{
+ double angle = msa;
+ return mcenter + Coordinate( cos( angle ), sin( angle ) ) * mradius;
+}
+
+Coordinate ArcImp::secondEndPoint() const
+{
+ double angle = msa + ma;
+ return mcenter + Coordinate( cos( angle ), sin( angle ) ) * mradius;
+}
+
+const Coordinate VectorImp::a() const
+{
+ return mdata.a;
+}
+
+const Coordinate VectorImp::b() const
+{
+ return mdata.b;
+}
+
+bool ArcImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( ArcImp::stype() ) &&
+ static_cast<const ArcImp&>( rhs ).radius() == radius() &&
+ static_cast<const ArcImp&>( rhs ).startAngle() == startAngle() &&
+ static_cast<const ArcImp&>( rhs ).angle() == angle();
+}
+
+bool AngleImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( AngleImp::stype() ) &&
+ static_cast<const AngleImp&>( rhs ).point() == point() &&
+ static_cast<const AngleImp&>( rhs ).startAngle() == startAngle() &&
+ static_cast<const AngleImp&>( rhs ).angle() == angle();
+}
+
+bool VectorImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( VectorImp::stype() ) &&
+ static_cast<const VectorImp&>( rhs ).a() == a() &&
+ static_cast<const VectorImp&>( rhs ).b() == b();
+}
+
+const ObjectImpType* AngleImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "angle",
+ I18N_NOOP( "angle" ),
+ I18N_NOOP( "Select this angle" ),
+ I18N_NOOP( "Select angle %1" ),
+ I18N_NOOP( "Remove an Angle" ),
+ I18N_NOOP( "Add an Angle" ),
+ I18N_NOOP( "Move an Angle" ),
+ I18N_NOOP( "Attach to this angle" ),
+ I18N_NOOP( "Show an Angle" ),
+ I18N_NOOP( "Hide an Angle" )
+ );
+ return &t;
+}
+const ObjectImpType* VectorImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "vector",
+ I18N_NOOP( "vector" ),
+ I18N_NOOP( "Select this vector" ),
+ I18N_NOOP( "Select vector %1" ),
+ I18N_NOOP( "Remove a Vector" ),
+ I18N_NOOP( "Add a Vector" ),
+ I18N_NOOP( "Move a Vector" ),
+ I18N_NOOP( "Attach to this vector" ),
+ I18N_NOOP( "Show a Vector" ),
+ I18N_NOOP( "Hide a Vector" )
+ );
+ return &t;
+}
+const ObjectImpType* ArcImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "arc",
+ I18N_NOOP( "arc" ),
+ I18N_NOOP( "Select this arc" ),
+ I18N_NOOP( "Select arc %1" ),
+ I18N_NOOP( "Remove an Arc" ),
+ I18N_NOOP( "Add an Arc" ),
+ I18N_NOOP( "Move an Arc" ),
+ I18N_NOOP( "Attach to this arc" ),
+ I18N_NOOP( "Show an Arc" ),
+ I18N_NOOP( "Hide an Arc" )
+ );
+ return &t;
+}
+
+const ObjectImpType* AngleImp::type() const
+{
+ return AngleImp::stype();
+}
+
+const ObjectImpType* VectorImp::type() const
+{
+ return VectorImp::stype();
+}
+
+const ObjectImpType* ArcImp::type() const
+{
+ return ArcImp::stype();
+}
+
+bool ArcImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool ArcImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ return isOnArc( p, mcenter, mradius, msa, ma, threshold );
+}
+
+bool AngleImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+ return false;
+}
+
+bool VectorImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+}
+
+bool ArcImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+ else if ( which == Parent::numberOfProperties() )
+ return true;
+ else
+ return false;
+}
+
+Rect AngleImp::surroundingRect() const
+{
+ return Rect( mpoint, 0, 0 );
+}
+
+Rect VectorImp::surroundingRect() const
+{
+ return Rect( mdata.a, mdata.b );
+}
+
+Rect ArcImp::surroundingRect() const
+{
+ // the returned rect should contain the center point(?), the two end
+ // points, and all extreme x and y positions in between.
+ //Rect ret( mcenter, 0, 0 );
+ double a = msa;
+ //ret.setContains( mcenter + mradius*Coordinate( cos( a ), sin( a ) ) );
+ Rect ret ( mcenter + mradius*Coordinate( cos( a ), sin( a ) ), 0, 0 );
+ a = msa + ma;
+ ret.setContains( mcenter + mradius*Coordinate( cos( a ), sin( a ) ) );
+ for ( a = -2*M_PI; a <= 2*M_PI; a+=M_PI/2 )
+ {
+ Coordinate d = mcenter + mradius*Coordinate( cos( a ), sin( a ) );
+ if ( msa <= a && a <= msa + ma )
+ ret.setContains( d );
+ }
+ return ret;
+}
+
+const Coordinate VectorImp::getPoint( double param, const KigDocument& ) const
+{
+ return mdata.a + mdata.dir() * param;
+}
+
+double VectorImp::getParam( const Coordinate& p, const KigDocument& ) const
+{
+ Coordinate pt = calcPointOnPerpend( mdata, p );
+ pt = calcIntersectionPoint( mdata, LineData( p, pt ) );
+ // if pt is over the end of the vector we set it to one of the end
+ // points of the vector...
+ if ( ( pt - mdata.a ).length() > dir().length() )
+ pt = mdata.b;
+ else if ( ( pt - mdata.b ).length() > dir().length() )
+ pt = mdata.a;
+ if ( mdata.b == mdata.a ) return 0;
+ return ( ( pt - mdata.a ).length() ) / ( dir().length() );
+}
+
+bool VectorImp::containsPoint( const Coordinate& p, const KigDocument& ) const
+{
+ return internalContainsPoint( p, test_threshold );
+}
+
+bool VectorImp::internalContainsPoint( const Coordinate& p, double threshold ) const
+{
+ return isOnSegment( p, mdata.a, mdata.b, threshold );
+}
+
+LineData VectorImp::data() const
+{
+ return mdata;
+}
diff --git a/kig/objects/other_imp.h b/kig/objects/other_imp.h
new file mode 100644
index 00000000..8e716fa6
--- /dev/null
+++ b/kig/objects/other_imp.h
@@ -0,0 +1,243 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_OTHER_IMP_H
+#define KIG_OBJECTS_OTHER_IMP_H
+
+#include "curve_imp.h"
+#include "../misc/common.h"
+#include "../misc/coordinate.h"
+
+/**
+ * An ObjectImp representing an angle.
+ */
+class AngleImp
+ : public ObjectImp
+{
+ const Coordinate mpoint;
+ const double mstartangle;
+ const double mangle;
+public:
+ typedef ObjectImp Parent;
+ /**
+ * Returns the ObjectImpType representing the AngleImp type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct an Angle with a given center, start angle and
+ * dimension (both in radians).
+ */
+ AngleImp( const Coordinate& pt, double start_angle_in_radials,
+ double angle_in_radials );
+ ~AngleImp();
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ Rect surroundingRect() const;
+
+ Coordinate attachPoint() const;
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ ObjectImp* copy() const;
+
+ /**
+ * Return the size in radians of this angle.
+ */
+ const double size() const;
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ /**
+ * Return the center of this angle.
+ */
+ const Coordinate point() const { return mpoint; }
+ /**
+ * Return the start angle in radians of this angle.
+ */
+ const double startAngle() const { return mstartangle; }
+ /**
+ * Return the dimension in radians of this angle.
+ */
+ const double angle() const { return mangle; }
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+/**
+ * An ObjectImp representing a vector.
+ */
+class VectorImp
+ : public CurveImp
+{
+ LineData mdata;
+public:
+ typedef CurveImp Parent;
+ /**
+ * Returns the ObjectImpType representing the VectorImp type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct a Vector with a given start point and end point.
+ */
+ VectorImp( const Coordinate& a, const Coordinate& b );
+ ~VectorImp();
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ const Coordinate getPoint( double param, const KigDocument& ) const;
+ double getParam( const Coordinate&, const KigDocument& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ Rect surroundingRect() const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ VectorImp* copy() const;
+
+ /**
+ * Return the direction of this vector.
+ */
+ const Coordinate dir() const;
+ /**
+ * Return the start point of this vector.
+ */
+ const Coordinate a() const;
+ /**
+ * Return the end point of this vector.
+ */
+ const Coordinate b() const;
+ /**
+ * Return the length of this vector.
+ */
+ const double length() const;
+ /**
+ * Get the LineData for this vector.
+ */
+ LineData data() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ bool equals( const ObjectImp& rhs ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+/**
+ * An ObjectImp representing an arc.
+ */
+class ArcImp
+ : public CurveImp
+{
+ Coordinate mcenter;
+ double mradius;
+ double msa;
+ double ma;
+public:
+ typedef CurveImp Parent;
+ /**
+ * Returns the ObjectImpType representing the ArcImp type..
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct an Arc with a given center, radius, start angle and
+ * dimension (both in radians).
+ */
+ ArcImp( const Coordinate& center, const double radius,
+ const double startangle, const double angle );
+ ~ArcImp();
+ ArcImp* copy() const;
+
+ ObjectImp* transform( const Transformation& t ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& w ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& si ) const;
+ Rect surroundingRect() const;
+ bool valid() const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& d ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ double getParam( const Coordinate& c, const KigDocument& d ) const;
+ const Coordinate getPoint( double p, const KigDocument& d ) const;
+
+ /**
+ * Return the center of this arc.
+ */
+ const Coordinate center() const;
+ /**
+ * Return the radius of this arc.
+ */
+ double radius() const;
+ /**
+ * Return the start angle in radians of this arc.
+ */
+ double startAngle() const;
+ /**
+ * Return the dimension in radians of this arc.
+ */
+ double angle() const;
+ /**
+ * Return the start point of this arc.
+ */
+ Coordinate firstEndPoint() const;
+ /**
+ * Return the end point of this arc.
+ */
+ Coordinate secondEndPoint() const;
+ /**
+ * Return the size of the sector surface of this arc.
+ */
+ const double sectorSurface() const;
+
+ bool equals( const ObjectImp& rhs ) const;
+
+ bool containsPoint( const Coordinate& p, const KigDocument& doc ) const;
+ bool internalContainsPoint( const Coordinate& p, double threshold ) const;
+};
+
+#endif
diff --git a/kig/objects/other_type.cc b/kig/objects/other_type.cc
new file mode 100644
index 00000000..27787986
--- /dev/null
+++ b/kig/objects/other_type.cc
@@ -0,0 +1,189 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "other_type.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+#include "locus_imp.h"
+
+#include "../misc/common.h"
+#include "../misc/calcpaths.h"
+#include "../misc/goniometry.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../kig/kig_commands.h"
+
+#include <functional>
+#include <algorithm>
+#include <cmath>
+
+using std::find;
+
+static const struct ArgsParser::spec argsspecLocus[] =
+{
+ { HierarchyImp::stype(), "hierarchy", "SHOULD NOT BE SEEN", false },
+ { CurveImp::stype(), "curve", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LocusType )
+
+LocusType::LocusType()
+ : ArgsParserObjectType( "Locus", argsspecLocus, 2 )
+{
+}
+
+LocusType::~LocusType()
+{
+}
+
+ObjectImp* LocusType::calc( const Args& args, const KigDocument& ) const
+{
+ using namespace std;
+
+ assert( args.size() >= 2 );
+ const Args firsttwo( args.begin(), args.begin() + 2 );
+ Args fixedargs( args.begin() + 2, args.end() );
+
+ if ( ! margsparser.checkArgs( firsttwo ) ) return new InvalidImp;
+ for ( Args::iterator i = fixedargs.begin(); i != fixedargs.end(); ++i )
+ if ( ! (*i)->valid() )
+ return new InvalidImp;
+
+ const ObjectHierarchy& hier =
+ static_cast<const HierarchyImp*>( args[0] )->data();
+ const CurveImp* curveimp = static_cast<const CurveImp*>( args[1] );
+
+ return new LocusImp( curveimp->copy(), hier.withFixedArgs( fixedargs ) );
+}
+
+bool LocusType::inherits( int type ) const
+{
+ return type == ID_LocusType ? true : Parent::inherits( type );
+}
+
+const ObjectImpType* LocusType::resultId() const
+{
+ return LocusImp::stype();
+}
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CopyObjectType )
+
+CopyObjectType::CopyObjectType()
+ : ObjectType( "Copy" )
+{
+}
+
+CopyObjectType::~CopyObjectType()
+{
+}
+
+CopyObjectType* CopyObjectType::instance()
+{
+ static CopyObjectType t;
+ return &t;
+}
+
+bool CopyObjectType::inherits( int ) const
+{
+ return false;
+}
+
+ObjectImp* CopyObjectType::calc( const Args& parents, const KigDocument& ) const
+{
+ assert( parents.size() == 1 );
+ return parents[0]->copy();
+}
+
+const ObjectImpType* CopyObjectType::impRequirement( const ObjectImp*, const Args& ) const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* CopyObjectType::resultId() const
+{
+ // we don't know what we return..
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* LocusType::impRequirement( const ObjectImp* o, const Args& parents ) const
+{
+ assert( parents.size() >= 2 );
+ Args firsttwo( parents.begin(), parents.begin() + 2 );
+ if ( o == parents[0] || o == parents[1] )
+ return margsparser.impRequirement( o, firsttwo );
+ else
+ {
+ const HierarchyImp* h = dynamic_cast<const HierarchyImp*>( parents[0] );
+ if ( h )
+ {
+ PointImp* p = new PointImp( Coordinate() );
+ Args hargs( parents.begin()+ 2, parents.end() );
+ hargs.push_back( p );
+ ArgsParser hparser = h->data().argParser();
+ const ObjectImpType* ret = hparser.impRequirement( o, hargs );
+ delete p;
+ return ret;
+ }
+ else
+ return ObjectImp::stype();
+ };
+}
+
+const LocusType* LocusType::instance()
+{
+ static const LocusType t;
+ return &t;
+}
+
+std::vector<ObjectCalcer*> CopyObjectType::sortArgs( const std::vector<ObjectCalcer*>& os ) const
+{
+ assert( os.size() == 1 );
+ return os;
+}
+
+std::vector<ObjectCalcer*> LocusType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ assert( args.size() >= 2 );
+ std::vector<ObjectCalcer*> firsttwo( args.begin(), args.begin() + 2 );
+ firsttwo = margsparser.parse( firsttwo );
+ std::copy( args.begin() + 2, args.end(), std::back_inserter( firsttwo ) );
+ return firsttwo;
+}
+
+Args LocusType::sortArgs( const Args& args ) const
+{
+ assert( args.size() >= 2 );
+ Args firsttwo( args.begin(), args.begin() + 2 );
+ firsttwo = margsparser.parse( firsttwo );
+ std::copy( args.begin() + 2, args.end(), std::back_inserter( firsttwo ) );
+ return firsttwo;
+}
+
+Args CopyObjectType::sortArgs( const Args& args ) const
+{
+ assert( args.size() == 1 );
+ return args;
+}
+
+bool CopyObjectType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
+{
+ // TODO: vragen aan parent ?
+ // TODO: translate the above TODO ?
+ return false;
+}
+
diff --git a/kig/objects/other_type.h b/kig/objects/other_type.h
new file mode 100644
index 00000000..6bbcead1
--- /dev/null
+++ b/kig/objects/other_type.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2003-2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_MISC_OTHER_TYPE_H
+#define KIG_MISC_OTHER_TYPE_H
+
+#include "base_type.h"
+#include "../misc/object_hierarchy.h"
+
+class LocusType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ LocusType();
+ ~LocusType();
+public:
+ static const LocusType* instance();
+
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+
+ bool inherits( int type ) const;
+ const ObjectImpType* resultId() const;
+
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const;
+ Args sortArgs( const Args& args ) const;
+};
+
+class CopyObjectType
+ : public ObjectType
+{
+protected:
+ CopyObjectType();
+ ~CopyObjectType();
+public:
+ static CopyObjectType* instance();
+ bool inherits( int type ) const;
+ ObjectImp* calc( const Args& parents, const KigDocument& d ) const;
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ const ObjectImpType* resultId() const;
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& os ) const;
+ Args sortArgs( const Args& args ) const;
+};
+
+#endif
diff --git a/kig/objects/point_imp.cc b/kig/objects/point_imp.cc
new file mode 100644
index 00000000..02d4d360
--- /dev/null
+++ b/kig/objects/point_imp.cc
@@ -0,0 +1,223 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "point_imp.h"
+
+#include "bogus_imp.h"
+#include "../misc/kigtransform.h"
+#include "../misc/kigpainter.h"
+#include "../misc/coordinate_system.h"
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+PointImp::PointImp( const Coordinate& c )
+ : mc( c )
+{
+}
+
+Coordinate PointImp::attachPoint() const
+{
+ return mc;
+// return Coordinate::invalidCoord();
+}
+
+void PointImp::draw( KigPainter& p ) const
+{
+ p.drawFatPoint( mc );
+}
+
+bool PointImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ int twidth = width == -1 ? 5 : width;
+ return (p - mc).length() - twidth*w.screenInfo().pixelWidth() < 0;
+}
+
+bool PointImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ double am = w.screenInfo().normalMiss( width );
+ return r.contains( mc, am );
+}
+
+const uint PointImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 3;
+}
+
+const QCStringList PointImp::propertiesInternalNames() const
+{
+ QCStringList l = Parent::propertiesInternalNames();
+ l << "coordinate";
+ l << "coordinate-x";
+ l << "coordinate-y";
+ assert( l.size() == PointImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList PointImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l << I18N_NOOP( "Coordinate" );
+ l << I18N_NOOP( "X coordinate" );
+ l << I18N_NOOP( "Y coordinate" );
+ assert( l.size() == PointImp::numberOfProperties() );
+ return l;
+}
+
+const ObjectImpType* PointImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return PointImp::stype();
+}
+
+const char* PointImp::iconForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ if ( which == Parent::numberOfProperties() )
+ return "pointxy"; // coordinate
+ if ( which == Parent::numberOfProperties() + 1 )
+ return "pointxy"; // coordinate-x
+ if ( which == Parent::numberOfProperties() + 2 )
+ return "pointxy"; // coordinate-y
+ else assert( false );
+ return "";
+}
+
+ObjectImp* PointImp::property( uint which, const KigDocument& d ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, d );
+ if ( which == Parent::numberOfProperties() )
+ return new PointImp( mc );
+ if ( which == Parent::numberOfProperties() + 1 )
+ return new DoubleImp( mc.x );
+ if ( which == Parent::numberOfProperties() + 2 )
+ return new DoubleImp( mc.y );
+// else assert( false );
+ return new InvalidImp;
+}
+
+PointImp::~PointImp()
+{
+}
+
+PointImp* PointImp::copy() const
+{
+ return new PointImp( mc );
+}
+
+ObjectImp* PointImp::transform( const Transformation& t ) const
+{
+ Coordinate nc = t.apply( mc );
+ if ( nc.valid() ) return new PointImp( nc );
+ else return new InvalidImp();
+}
+
+void PointImp::setCoordinate( const Coordinate& c )
+{
+ mc = c;
+}
+
+void PointImp::fillInNextEscape( QString& s, const KigDocument& doc ) const
+{
+ s = s.arg( doc.coordinateSystem().fromScreen( mc, doc ) );
+}
+
+void PointImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool PointImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( PointImp::stype() ) &&
+ static_cast<const PointImp&>( rhs ).coordinate() == coordinate();
+}
+
+bool PointImp::canFillInNextEscape() const
+{
+ return true;
+}
+
+const ObjectImpType* PointImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "point",
+ I18N_NOOP( "point" ),
+ I18N_NOOP( "Select this point" ),
+ I18N_NOOP( "Select point %1" ),
+ I18N_NOOP( "Remove a Point" ),
+ I18N_NOOP( "Add a Point" ),
+ I18N_NOOP( "Move a Point" ),
+ I18N_NOOP( "Attach to this point" ),
+ I18N_NOOP( "Show a Point" ),
+ I18N_NOOP( "Hide a Point" )
+ );
+ return &t;
+}
+
+const ObjectImpType* PointImp::type() const
+{
+ return PointImp::stype();
+}
+
+bool PointImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+}
+
+Rect PointImp::surroundingRect() const
+{
+ return Rect( mc, 0., 0. );
+}
+
+/*
+ */
+
+BogusPointImp::BogusPointImp( const Coordinate& c )
+ : PointImp( c )
+{
+}
+
+BogusPointImp::~BogusPointImp()
+{
+}
+
+const ObjectImpType* BogusPointImp::stype()
+{
+ static const ObjectImpType t(
+ 0, "boguspoint",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN",
+ "SHOULDNOTBESEEN"
+ );
+ return &t;
+}
+
+const ObjectImpType* BogusPointImp::type() const
+{
+ return BogusPointImp::stype();
+}
diff --git a/kig/objects/point_imp.h b/kig/objects/point_imp.h
new file mode 100644
index 00000000..a5e8eb98
--- /dev/null
+++ b/kig/objects/point_imp.h
@@ -0,0 +1,91 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_POINT_IMP_H
+#define KIG_OBJECTS_POINT_IMP_H
+
+#include "object_imp.h"
+#include "../misc/coordinate.h"
+
+/**
+ * An ObjectImp representing a point..
+ */
+class PointImp
+ : public ObjectImp
+{
+ Coordinate mc;
+public:
+ typedef ObjectImp Parent;
+ /**
+ * Returns the ObjectImpType representing PointImp's.
+ */
+ static const ObjectImpType* stype();
+
+ /**
+ * Construct a PointImp with coordinate c.
+ */
+ PointImp( const Coordinate& c );
+ ~PointImp();
+
+ Rect surroundingRect() const;
+ Coordinate attachPoint() const;
+
+ /**
+ * Get the coordinate of this PointImp.
+ */
+ const Coordinate& coordinate() const { return mc; }
+ /**
+ * Set the coordinate of this PointImp.
+ */
+ void setCoordinate( const Coordinate& c );
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& d ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ PointImp* copy() const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ void fillInNextEscape( QString& s, const KigDocument& ) const;
+ bool canFillInNextEscape() const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+class BogusPointImp
+ : public PointImp
+{
+public:
+ BogusPointImp( const Coordinate& c );
+ ~BogusPointImp();
+ static const ObjectImpType* stype();
+ const ObjectImpType* type() const;
+};
+
+#endif
diff --git a/kig/objects/point_type.cc b/kig/objects/point_type.cc
new file mode 100644
index 00000000..04f8272c
--- /dev/null
+++ b/kig/objects/point_type.cc
@@ -0,0 +1,665 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "point_type.h"
+
+#include "point_imp.h"
+#include "curve_imp.h"
+#include "line_imp.h"
+#include "other_imp.h"
+#include "bogus_imp.h"
+
+#include "../modes/moving.h"
+#include "../misc/coordinate_system.h"
+#include "../misc/common.h"
+#include "../misc/calcpaths.h"
+#include "../misc/kiginputdialog.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+#include "../kig/kig_commands.h"
+
+#include <klocale.h>
+
+static const ArgsParser::spec argsspecFixedPoint[] =
+{
+ { DoubleImp::stype(), "x", "SHOULD NOT BE SEEN", false },
+ { DoubleImp::stype(), "y", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( FixedPointType )
+
+FixedPointType::FixedPointType()
+ : ArgsParserObjectType( "FixedPoint", argsspecFixedPoint, 2 )
+{
+}
+
+FixedPointType::~FixedPointType()
+{
+}
+
+ObjectImp* FixedPointType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ double a = static_cast<const DoubleImp*>( parents[0] )->data();
+ double b = static_cast<const DoubleImp*>( parents[1] )->data();
+
+ return new PointImp( Coordinate( a, b ) );
+}
+
+static const ArgsParser::spec argsspecRelativePoint[] =
+{
+ { DoubleImp::stype(), "relative-x", "SHOULD NOT BE SEEN", false },
+ { DoubleImp::stype(), "relative-y", "SHOULD NOT BE SEEN", false },
+ { ObjectImp::stype(), "object", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( RelativePointType )
+
+RelativePointType::RelativePointType()
+ : ArgsParserObjectType( "RelativePoint", argsspecRelativePoint, 3 )
+{
+}
+
+RelativePointType::~RelativePointType()
+{
+}
+
+ObjectImp* RelativePointType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ if ( ! parents[2]->attachPoint().valid() ) return new InvalidImp;
+
+ Coordinate reference = static_cast<const ObjectImp*>( parents[2] )->attachPoint();
+ double a = static_cast<const DoubleImp*>( parents[0] )->data();
+ double b = static_cast<const DoubleImp*>( parents[1] )->data();
+
+ return new PointImp( reference + Coordinate( a, b ) );
+}
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CursorPointType )
+
+CursorPointType::CursorPointType()
+ : ObjectType( "CursorPoint" )
+{
+}
+
+CursorPointType::~CursorPointType()
+{
+}
+
+const CursorPointType* CursorPointType::instance()
+{
+ static const CursorPointType t;
+ return &t;
+}
+
+ObjectImp* CursorPointType::calc( const Args& parents, const KigDocument& ) const
+{
+ assert ( parents[0]->inherits( DoubleImp::stype() ) );
+ assert ( parents[1]->inherits( DoubleImp::stype() ) );
+ double a = static_cast<const DoubleImp*>( parents[0] )->data();
+ double b = static_cast<const DoubleImp*>( parents[1] )->data();
+
+ return new BogusPointImp( Coordinate( a, b ) );
+}
+
+const ObjectImpType* CursorPointType::resultId() const
+{
+ return BogusPointImp::stype();
+}
+
+ObjectImp* ConstrainedPointType::calc( const Args& parents, const KigDocument& doc ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ double param = static_cast<const DoubleImp*>( parents[0] )->data();
+ const Coordinate nc = static_cast<const CurveImp*>( parents[1] )->getPoint( param, doc );
+ if ( nc.valid() ) return new PointImp( nc );
+ else return new InvalidImp;
+}
+
+const ArgsParser::spec argsspecConstrainedPoint[] =
+{
+ { DoubleImp::stype(), "parameter", "SHOULD NOT BE SEEN", false },
+ { CurveImp::stype(), "Constrain the point to this curve", "SHOULD NOT BE SEEN", true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConstrainedPointType )
+
+ConstrainedPointType::ConstrainedPointType()
+ : ArgsParserObjectType( "ConstrainedPoint", argsspecConstrainedPoint, 2 )
+{
+}
+
+ConstrainedPointType::~ConstrainedPointType()
+{
+}
+
+void FixedPointType::move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const
+{
+ // fetch the old coord..;
+ std::vector<ObjectCalcer*> pa = ourobj.parents();
+ assert( margsparser.checkArgs( pa ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( pa.front() ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( pa.back() ) );
+
+ ObjectConstCalcer* ox = static_cast<ObjectConstCalcer*>( pa.front() );
+ ObjectConstCalcer* oy = static_cast<ObjectConstCalcer*>( pa.back() );
+
+ ox->setImp( new DoubleImp( to.x ) );
+ oy->setImp( new DoubleImp( to.y ) );
+}
+
+void RelativePointType::move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const
+{
+ // fetch the attach point..;
+ // this routine is tightly paired with what moveReferencePoint returns!
+ // right now moveReferencePoint always returns the origin
+ std::vector<ObjectCalcer*> pa = ourobj.parents();
+ assert( margsparser.checkArgs( pa ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( pa[0] ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( pa[1] ) );
+
+ ObjectConstCalcer* ox = static_cast<ObjectConstCalcer*>( pa[0] );
+ ObjectConstCalcer* oy = static_cast<ObjectConstCalcer*>( pa[1] );
+ ObjectCalcer* ob = static_cast<ObjectCalcer*>( pa[2] );
+
+ Coordinate attach = ob->imp()->attachPoint();
+ ox->setImp( new DoubleImp( to.x - attach.x ) );
+ oy->setImp( new DoubleImp( to.y - attach.y ) );
+}
+
+void CursorPointType::move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const
+{
+ // fetch the old coord..;
+
+ std::vector<ObjectCalcer*> pa = ourobj.parents();
+ assert( pa.size() == 2 );
+ assert( dynamic_cast<ObjectConstCalcer*>( pa.front() ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( pa.back() ) );
+
+ ObjectConstCalcer* ox = static_cast<ObjectConstCalcer*>( pa.front() );
+ ObjectConstCalcer* oy = static_cast<ObjectConstCalcer*>( pa.back() );
+
+ ox->setImp( new DoubleImp( to.x ) );
+ oy->setImp( new DoubleImp( to.y ) );
+}
+
+void ConstrainedPointType::move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& d ) const
+{
+ // fetch the CurveImp..
+ std::vector<ObjectCalcer*> parents = ourobj.parents();
+ assert( margsparser.checkArgs( parents ) );
+
+ assert( dynamic_cast<ObjectConstCalcer*>( parents[0] ) );
+ ObjectConstCalcer* paramo = static_cast<ObjectConstCalcer*>( parents[0] );
+ const CurveImp* ci = static_cast<const CurveImp*>( parents[1]->imp() );
+
+ // fetch the new param..
+ const double np = ci->getParam( to, d );
+
+ paramo->setImp( new DoubleImp( np ) );
+}
+
+bool ConstrainedPointType::canMove( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+bool ConstrainedPointType::isFreelyTranslatable( const ObjectTypeCalcer& ) const
+{
+ return false;
+}
+
+bool FixedPointType::canMove( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+bool FixedPointType::isFreelyTranslatable( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+bool RelativePointType::canMove( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+bool RelativePointType::isFreelyTranslatable( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+bool CursorPointType::canMove( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+static const ArgsParser::spec argsspecMidPoint[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Construct the midpoint of this point and another point" ),
+ I18N_NOOP( "Select the first of the two points of which you want to construct the midpoint..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct the midpoint of this point and another point" ),
+ I18N_NOOP( "Select the other of the two points of which you want to construct the midpoint..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( MidPointType )
+
+MidPointType::MidPointType()
+ : ObjectABType( "MidPoint", argsspecMidPoint, 2 )
+{
+}
+
+MidPointType::~MidPointType()
+{
+}
+
+const MidPointType* MidPointType::instance()
+{
+ static const MidPointType t;
+ return &t;
+}
+
+ObjectImp* MidPointType::calc( const Coordinate& a, const Coordinate& b ) const
+{
+ return new PointImp( ( a + b ) / 2 );
+}
+
+bool ConstrainedPointType::inherits( int type ) const
+{
+ return type == ID_ConstrainedPointType;
+}
+
+const ConstrainedPointType* ConstrainedPointType::instance()
+{
+ static const ConstrainedPointType t;
+ return &t;
+}
+
+bool FixedPointType::inherits( int type ) const
+{
+ return type == ID_FixedPointType;
+}
+
+const FixedPointType* FixedPointType::instance()
+{
+ static const FixedPointType t;
+ return &t;
+}
+
+const ObjectImpType* FixedPointType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const RelativePointType* RelativePointType::instance()
+{
+ static const RelativePointType t;
+ return &t;
+}
+
+const ObjectImpType* RelativePointType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* ConstrainedPointType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* CursorPointType::impRequirement( const ObjectImp* o, const Args& ) const
+{
+ if ( o->inherits( DoubleImp::stype() ) )
+ return DoubleImp::stype();
+
+ if ( o->inherits( PointImp::stype() ) )
+ return PointImp::stype();
+
+ return 0;
+}
+
+bool CursorPointType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
+{
+ return false;
+}
+
+std::vector<ObjectCalcer*> CursorPointType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ return args;
+}
+
+Args CursorPointType::sortArgs( const Args& args ) const
+{
+ return args;
+}
+
+const ObjectImpType* MidPointType::resultId() const
+{
+ return PointImp::stype();
+}
+
+QStringList FixedPointType::specialActions() const
+{
+ QStringList ret;
+ ret << i18n( "Set &Coordinate..." );
+ ret << i18n( "Redefine" );
+ return ret;
+}
+
+QStringList ConstrainedPointType::specialActions() const
+{
+ QStringList ret;
+ ret << i18n( "Set &Parameter..." );
+ ret << i18n( "Redefine" );
+ return ret;
+}
+
+static void redefinePoint( ObjectHolder* o, KigPart& d, KigWidget& w )
+{
+ PointRedefineMode pm( o, d, w );
+ d.runMode( &pm );
+}
+
+void FixedPointType::executeAction(
+ int i, ObjectHolder& oh, ObjectTypeCalcer& o,
+ KigPart& d, KigWidget& w, NormalMode& ) const
+{
+ switch( i )
+ {
+ case 0:
+ {
+ bool ok = true;
+ assert ( o.imp()->inherits( PointImp::stype() ) );
+ Coordinate oldc = static_cast<const PointImp*>( o.imp() )->coordinate();
+ KigInputDialog::getCoordinate(
+ i18n( "Set Coordinate" ),
+ i18n( "Enter the new coordinate." ) + QString::fromLatin1( "<br>" ) +
+ d.document().coordinateSystem().coordinateFormatNoticeMarkup(),
+ &w, &ok, d.document(), &oldc );
+ if ( ! ok ) break;
+
+ MonitorDataObjects mon( getAllParents( &o ) );
+ o.move( oldc, d.document() );
+ KigCommand* kc = new KigCommand( d, PointImp::stype()->moveAStatement() );
+ mon.finish( kc );
+
+ d.history()->addCommand( kc );
+ break;
+ };
+ case 1:
+ redefinePoint( &oh, d, w );
+ break;
+ default:
+ assert( false );
+ };
+}
+
+void ConstrainedPointType::executeAction(
+ int i, ObjectHolder& oh, ObjectTypeCalcer& o, KigPart& d, KigWidget& w,
+ NormalMode& ) const
+{
+ switch( i )
+ {
+ case 1:
+ redefinePoint( &oh, d, w );
+ break;
+ case 0:
+ {
+ std::vector<ObjectCalcer*> parents = o.parents();
+ assert( dynamic_cast<ObjectConstCalcer*>( parents[0] ) &&
+ parents[0]->imp()->inherits( DoubleImp::stype() ) );
+
+ ObjectConstCalcer* po = static_cast<ObjectConstCalcer*>( parents[0] );
+ double oldp = static_cast<const DoubleImp*>( po->imp() )->data();
+
+ bool ok = true;
+ double newp = getDoubleFromUser(
+ i18n( "Set Point Parameter" ), i18n( "Choose the new parameter: " ),
+ oldp, &w, &ok, 0, 1, 4 );
+ if ( ! ok ) return;
+
+ MonitorDataObjects mon( parents );
+ po->setImp( new DoubleImp( newp ) );
+ KigCommand* kc = new KigCommand( d, i18n( "Change Parameter of Constrained Point" ) );
+ mon.finish( kc );
+ d.history()->addCommand( kc );
+ break;
+ };
+ default:
+ assert( false );
+ };
+}
+
+const Coordinate FixedPointType::moveReferencePoint( const ObjectTypeCalcer& ourobj ) const
+{
+ assert( ourobj.imp()->inherits( PointImp::stype() ) );
+ return static_cast<const PointImp*>( ourobj.imp() )->coordinate();
+}
+
+const Coordinate RelativePointType::moveReferencePoint( const ObjectTypeCalcer& ourobj ) const
+{
+ assert( ourobj.imp()->inherits( PointImp::stype() ) );
+// return static_cast<const PointImp*>( ourobj.imp() )->coordinate();
+ return Coordinate( 0., 0. );
+}
+
+const Coordinate ConstrainedPointType::moveReferencePoint( const ObjectTypeCalcer& ourobj ) const
+{
+ assert( ourobj.imp()->inherits( PointImp::stype() ) );
+ return static_cast<const PointImp*>( ourobj.imp() )->coordinate();
+}
+
+std::vector<ObjectCalcer*> FixedPointType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ return ourobj.parents();
+}
+
+std::vector<ObjectCalcer*> RelativePointType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ std::vector<ObjectCalcer*> ret;
+ ret.push_back( ourobj.parents()[0] );
+ ret.push_back( ourobj.parents()[1] );
+ return ret;
+}
+
+std::vector<ObjectCalcer*> ConstrainedPointType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ std::vector<ObjectCalcer*> ret;
+ ret.push_back( ourobj.parents()[0] );
+ return ret;
+}
+
+/* ----------------- Transport of measure ------------------------------ */
+
+ObjectImp* MeasureTransportType::calc( const Args& parents, const KigDocument& doc ) const
+{
+ double measure;
+
+ if ( parents.size() != 3 ) return new InvalidImp;
+
+ if ( parents[0]->inherits (SegmentImp::stype()) )
+ {
+ const SegmentImp* s = static_cast<const SegmentImp*>( parents[0] );
+ measure = s->length();
+ } else if ( parents[0]->inherits (ArcImp::stype()) )
+ {
+ const ArcImp* s = static_cast<const ArcImp*>( parents[0] );
+ measure = s->radius()*s->angle();
+ } else return new InvalidImp;
+
+ const Coordinate& p = static_cast<const PointImp*>( parents[2] )->coordinate();
+ if ( parents[1]->inherits (LineImp::stype()) )
+ {
+ const LineImp* c = static_cast<const LineImp*>( parents[1] );
+
+ if ( !c->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ const LineData line = c->data();
+ const Coordinate dir = line.dir()/line.length();
+ const Coordinate nc = p + measure*dir;
+
+ if ( nc.valid() ) return new PointImp( nc );
+ else return new InvalidImp;
+ } else if ( parents[1]->inherits (CircleImp::stype()) )
+ {
+ const CircleImp* c = static_cast<const CircleImp*>( parents[1] );
+ if ( !c->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ double param = c->getParam( p, doc );
+ measure /= 2*c->radius()*M_PI;
+ param += measure;
+ while (param > 1) param -= 1;
+
+ const Coordinate nc = c->getPoint( param, doc );
+ if ( nc.valid() ) return new PointImp( nc );
+ else return new InvalidImp;
+ }
+
+ return new InvalidImp;
+}
+
+// I18N_NOOP( "Select the segment/arc to transport on the circle/line..." ), false },
+// I18N_NOOP( "Select the circle/line on which to transport a measure..." ), true },
+// I18N_NOOP( "Select a point on the circle/line..." ), false }
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( MeasureTransportType )
+
+MeasureTransportType::MeasureTransportType()
+ : ObjectType( "TransportOfMeasure" )
+{
+}
+
+MeasureTransportType::~MeasureTransportType()
+{
+}
+
+const MeasureTransportType* MeasureTransportType::instance()
+{
+ static const MeasureTransportType t;
+ return &t;
+}
+
+const ObjectImpType* MeasureTransportType::resultId() const
+{
+ return PointImp::stype();
+}
+
+const ObjectImpType* MeasureTransportType::impRequirement( const ObjectImp* obj, const Args& ) const
+{
+ if ( obj->inherits( PointImp::stype () ) )
+ return PointImp::stype ();
+
+ if ( obj->inherits( LineImp::stype () ) )
+ return LineImp::stype ();
+
+ if ( obj->inherits( CircleImp::stype () ) )
+ return CircleImp::stype ();
+
+ if ( obj->inherits( SegmentImp::stype () ) )
+ return SegmentImp::stype ();
+
+ if ( obj->inherits( ArcImp::stype () ) )
+ return ArcImp::stype ();
+
+ return 0;
+}
+
+bool MeasureTransportType::isDefinedOnOrThrough( const ObjectImp* o, const Args& ) const
+{
+ if ( o->inherits( LineImp::stype() ) ) return true;
+ if ( o->inherits( CircleImp::stype() ) ) return true;
+ return false;
+}
+
+std::vector<ObjectCalcer*> MeasureTransportType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ return args; /* should already be in correct order */
+}
+
+Args MeasureTransportType::sortArgs( const Args& args ) const
+{
+ return args;
+}
+
+/* - transport of measure (old, for compatibility with prev. kig files) - */
+
+ObjectImp* MeasureTransportTypeOld::calc( const Args& parents, const KigDocument& doc ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const CircleImp* c = static_cast<const CircleImp*>( parents[0] );
+ const Coordinate& p = static_cast<const PointImp*>( parents[1] )->coordinate();
+
+ if ( !c->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ const SegmentImp* s = static_cast<const SegmentImp*>( parents[2] );
+ double param = c->getParam( p, doc );
+ double measure = s->length();
+ measure /= 2*c->radius()*M_PI;
+ param += measure;
+ while (param > 1) param -= 1;
+
+ const Coordinate nc = c->getPoint( param, doc );
+ if ( nc.valid() ) return new PointImp( nc );
+ else return new InvalidImp;
+}
+
+static const ArgsParser::spec argsspecMeasureTransportOld[] =
+{
+ { CircleImp::stype(), "Transport a measure on this circle",
+ I18N_NOOP( "Select the circle on which to transport a measure..." ), true },
+ { PointImp::stype(), "Start transport from this point of the circle",
+ I18N_NOOP( "Select a point on the circle..." ), false },
+ { SegmentImp::stype(), "Segment to transport",
+ I18N_NOOP( "Select the segment to transport on the circle..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( MeasureTransportTypeOld )
+
+MeasureTransportTypeOld::MeasureTransportTypeOld()
+ : ArgsParserObjectType( "MeasureTransport", argsspecMeasureTransportOld, 3 )
+{
+}
+
+MeasureTransportTypeOld::~MeasureTransportTypeOld()
+{
+}
+
+const MeasureTransportTypeOld* MeasureTransportTypeOld::instance()
+{
+ static const MeasureTransportTypeOld t;
+ return &t;
+}
+
+const ObjectImpType* MeasureTransportTypeOld::resultId() const
+{
+ return PointImp::stype();
+}
+
+/* ----------------- end transport of measure ------------------------- */
+
diff --git a/kig/objects/point_type.h b/kig/objects/point_type.h
new file mode 100644
index 00000000..231ad6c5
--- /dev/null
+++ b/kig/objects/point_type.h
@@ -0,0 +1,159 @@
+// Copyright (C) 2002 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_POINT_TYPE_H
+#define KIG_OBJECTS_POINT_TYPE_H
+
+#include "base_type.h"
+#include "common.h"
+#include "circle_imp.h"
+
+class FixedPointType
+ : public ArgsParserObjectType
+{
+ FixedPointType();
+ ~FixedPointType();
+
+ static const ArgsParser::spec argsspec[1];
+public:
+ static const FixedPointType* instance();
+
+ bool inherits( int type ) const;
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ bool canMove( const ObjectTypeCalcer& ourobj ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& ourobj ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ QStringList specialActions() const;
+ void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& t,
+ KigPart& d, KigWidget& w, NormalMode& m ) const;
+};
+
+class RelativePointType
+ : public ArgsParserObjectType
+{
+ RelativePointType();
+ ~RelativePointType();
+
+ static const ArgsParser::spec argsspec[1];
+public:
+ static const RelativePointType* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ bool canMove( const ObjectTypeCalcer& ourobj ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& ourobj ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+// QStringList specialActions() const;
+// void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& t,
+// KigPart& d, KigWidget& w, NormalMode& m ) const;
+};
+
+class CursorPointType
+ : public ObjectType
+{
+ CursorPointType();
+ ~CursorPointType();
+
+public:
+ static const CursorPointType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const;
+ Args sortArgs( const Args& args ) const;
+ bool canMove( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConstrainedPointType
+ : public ArgsParserObjectType
+{
+ ConstrainedPointType();
+ ~ConstrainedPointType();
+public:
+ static const ConstrainedPointType* instance();
+
+ bool inherits( int type ) const;
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+
+ bool canMove( const ObjectTypeCalcer& ourobj ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& ourobj ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ QStringList specialActions() const;
+ void executeAction( int i, ObjectHolder&, ObjectTypeCalcer& o, KigPart& d, KigWidget& w,
+ NormalMode& m ) const;
+};
+
+class MidPointType
+ : public ObjectABType
+{
+ MidPointType();
+ ~MidPointType();
+public:
+ static const MidPointType* instance();
+ ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class MeasureTransportType
+ : public ObjectType
+{
+ MeasureTransportType();
+ ~MeasureTransportType();
+public:
+ static const MeasureTransportType* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args )const;
+ Args sortArgs( const Args& args ) const;
+};
+
+class MeasureTransportTypeOld
+ : public ArgsParserObjectType
+{
+ MeasureTransportTypeOld();
+ ~MeasureTransportTypeOld();
+public:
+ static const MeasureTransportTypeOld* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/polygon_imp.cc b/kig/objects/polygon_imp.cc
new file mode 100644
index 00000000..08215bfb
--- /dev/null
+++ b/kig/objects/polygon_imp.cc
@@ -0,0 +1,550 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "polygon_imp.h"
+
+#include "bogus_imp.h"
+#include "line_imp.h"
+#include "point_imp.h"
+
+#include "../misc/common.h"
+#include "../misc/coordinate.h"
+#include "../misc/kigpainter.h"
+#include "../misc/kigtransform.h"
+
+#include "../kig/kig_document.h"
+#include "../kig/kig_view.h"
+
+#include <klocale.h>
+
+#include <cmath>
+
+PolygonImp::PolygonImp( uint npoints, const std::vector<Coordinate>& points,
+ const Coordinate& centerofmass )
+ : mnpoints( npoints ), mpoints( points ), mcenterofmass( centerofmass )
+{
+// mpoints = points;
+}
+
+PolygonImp::PolygonImp( const std::vector<Coordinate>& points )
+{
+ uint npoints = points.size();
+ Coordinate centerofmassn = Coordinate( 0, 0 );
+
+ for ( uint i = 0; i < npoints; ++i )
+ {
+ centerofmassn += points[i];
+ }
+ mpoints = points;
+ mcenterofmass = centerofmassn/npoints;
+ mnpoints = npoints;
+}
+
+PolygonImp::~PolygonImp()
+{
+}
+
+Coordinate PolygonImp::attachPoint() const
+{
+ return mcenterofmass;
+}
+
+ObjectImp* PolygonImp::transform( const Transformation& t ) const
+{
+/*mp:
+ * any projective transformation makes sense for a polygon,
+ * since segments transform into segments (but see below...)
+ * of course regular polygons will no longer be
+ * regular if t is not homothetic.
+ * for projective transformations the polygon could transform to
+ * an unbounded nonconnected polygon; this happens if some side
+ * of the polygon crosses the critical line that maps to infinity
+ * this can be easily checked using the getProjectiveIndicator
+ * function
+ */
+// if ( ! t.isHomothetic() )
+// return new InvalidImp();
+
+ if ( ! t.isAffine() ) /* in this case we need a more extensive test */
+ {
+ double maxp = -1.0;
+ double minp = 1.0;
+ for ( uint i = 0; i < mpoints.size(); ++i )
+ {
+ double p = t.getProjectiveIndicator( mpoints[i] );
+ if ( p > maxp ) maxp = p;
+ if ( p < minp ) minp = p;
+ }
+ if ( maxp > 0 && minp < 0 ) return new InvalidImp;
+ }
+ std::vector<Coordinate> np;
+ for ( uint i = 0; i < mpoints.size(); ++i )
+ {
+ Coordinate nc = t.apply( mpoints[i] );
+ if ( !nc.valid() )
+ return new InvalidImp;
+ np.push_back( nc );
+ }
+ return new PolygonImp( np );
+}
+
+void PolygonImp::draw( KigPainter& p ) const
+{
+ p.drawPolygon( mpoints );
+}
+
+bool PolygonImp::isInPolygon( const Coordinate& p ) const
+{
+ // (algorithm sent to me by domi)
+ // We intersect with the horizontal ray from point to the right and
+ // count the number of intersections. That, along with some
+ // minor optimalisations of the intersection test..
+ bool inside_flag = false;
+ double cx = p.x;
+ double cy = p.y;
+
+ Coordinate prevpoint = mpoints.back();
+ bool prevpointbelow = mpoints.back().y >= cy;
+ for ( uint i = 0; i < mpoints.size(); ++i )
+ {
+ Coordinate point = mpoints[i];
+ bool pointbelow = point.y >= cy;
+ if ( prevpointbelow != pointbelow )
+ {
+ // possibility of intersection: points on different side from
+ // the X axis
+ //bool rightofpt = point.x >= cx;
+ // mp: we need to be a little bit more conservative here, in
+ // order to treat properly the case when the point is on the
+ // boundary
+ //if ( rightofpt == ( prevpoint.x >= cx ) )
+ if ( ( point.x - cx )*(prevpoint.x - cx ) > 0 )
+ {
+ // points on same side of Y axis -> easy to test intersection
+ // intersection iff one point to the right of c
+ if ( point.x >= cx )
+ inside_flag = !inside_flag;
+ }
+ else
+ {
+ // points on different sides of Y axis -> we need to calculate
+ // the intersection.
+ // mp: we want to check if the point is on the boundary, and
+ // return false in such case
+ double num = ( point.y - cy )*( prevpoint.x - point.x );
+ double den = prevpoint.y - point.y;
+ if ( num == den*( point.x - cx ) ) return false;
+ if ( num/den <= point.x - cx )
+ inside_flag = !inside_flag;
+ }
+ }
+ prevpoint = point;
+ prevpointbelow = pointbelow;
+ }
+ return inside_flag;
+}
+#define selectpolygonwithinside 1
+#ifdef selectpolygonwithinside
+bool PolygonImp::contains( const Coordinate& p, int, const KigWidget& ) const
+{
+ return isInPolygon( p );
+}
+#else
+bool PolygonImp::contains( const Coordinate& p, int width, const KigWidget& w ) const
+{
+ bool ret = false;
+ uint reduceddim = mpoints.size() - 1;
+ for ( uint i = 0; i < reduceddim; ++i )
+ {
+ ret |= isOnSegment( p, mpoints[i], mpoints[i+1], w.screenInfo().normalMiss( width ) );
+ }
+ ret |= isOnSegment( p, mpoints[reduceddim], mpoints[0], w.screenInfo().normalMiss( width ) );
+
+ return ret;
+}
+#endif
+
+bool PolygonImp::inRect( const Rect& r, int width, const KigWidget& w ) const
+{
+ bool ret = false;
+ uint reduceddim = mpoints.size() - 1;
+ for ( uint i = 0; i < reduceddim; ++i )
+ {
+ SegmentImp* s = new SegmentImp( mpoints[i], mpoints[i+1] );
+ ret |= lineInRect( r, mpoints[i], mpoints[i+1], width, s, w );
+ delete s;
+ s = 0;
+ }
+ SegmentImp* t = new SegmentImp( mpoints[reduceddim], mpoints[0] );
+ ret |= lineInRect( r, mpoints[reduceddim], mpoints[0], width, t, w );
+ delete t;
+ t = 0;
+
+ return ret;
+}
+
+bool PolygonImp::valid() const
+{
+ return true;
+}
+
+const uint PolygonImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 5;
+}
+
+const QCStringList PolygonImp::propertiesInternalNames() const
+{
+ QCStringList l = Parent::propertiesInternalNames();
+ l += "polygon-number-of-sides";
+ l += "polygon-perimeter";
+ l += "polygon-surface";
+ l += "polygon-center-of-mass";
+ l += "polygon-winding-number";
+ assert( l.size() == PolygonImp::numberOfProperties() );
+ return l;
+}
+
+const QCStringList PolygonImp::properties() const
+{
+ QCStringList l = Parent::properties();
+ l += I18N_NOOP( "Number of sides" );
+ l += I18N_NOOP( "Perimeter" );
+ l += I18N_NOOP( "Surface" );
+ l += I18N_NOOP( "Center of Mass of the Vertices" );
+ l += I18N_NOOP( "Winding Number" );
+ assert( l.size() == PolygonImp::numberOfProperties() );
+ return l;
+}
+
+const ObjectImpType* PolygonImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ else return PolygonImp::stype();
+}
+
+const char* PolygonImp::iconForProperty( uint which ) const
+{
+ assert( which < PolygonImp::numberOfProperties() );
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ else if ( which == Parent::numberOfProperties() )
+ return "en"; // number of sides
+ else if ( which == Parent::numberOfProperties() + 1 )
+ return "circumference"; // perimeter
+ else if ( which == Parent::numberOfProperties() + 2 )
+ return "areaCircle"; // surface
+ else if ( which == Parent::numberOfProperties() + 3 )
+ return "point"; // center of mass
+ else if ( which == Parent::numberOfProperties() + 4 )
+ return "w"; // winding number
+ else assert( false );
+ return "";
+}
+
+ObjectImp* PolygonImp::property( uint which, const KigDocument& w ) const
+{
+ assert( which < PolygonImp::numberOfProperties() );
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ else if ( which == Parent::numberOfProperties() )
+ {
+ // number of points
+ return new IntImp( mnpoints );
+ }
+ else if ( which == Parent::numberOfProperties() + 1)
+ {
+ double circumference = 0.;
+ // circumference
+ for ( uint i = 0; i < mpoints.size(); ++i )
+ {
+ uint prev = ( i + mpoints.size() - 1 ) % mpoints.size();
+ circumference += ( mpoints[i] - mpoints[prev] ).length();
+ }
+ return new DoubleImp( circumference );
+ }
+ else if ( which == Parent::numberOfProperties() + 2)
+ {
+ int wn = windingNumber (); // not able to compute area for such polygons...
+ if ( wn < 0 ) wn = -wn;
+ if ( wn != 1 ) return new InvalidImp;
+ double surface2 = 0.0;
+ Coordinate prevpoint = mpoints.back();
+ for ( uint i = 0; i < mpoints.size(); ++i )
+ {
+ Coordinate point = mpoints[i];
+ surface2 += ( point.x - prevpoint.x ) * ( point.y + prevpoint.y );
+ prevpoint = point;
+ }
+ return new DoubleImp( fabs( surface2 / 2 ) );
+ }
+ else if ( which == Parent::numberOfProperties() + 3 )
+ {
+ return new PointImp( mcenterofmass );
+ }
+ else if ( which == Parent::numberOfProperties() + 4 )
+ {
+ // winding number
+ return new IntImp( windingNumber() );
+ }
+ else assert( false );
+ return new InvalidImp;
+}
+
+const std::vector<Coordinate> PolygonImp::points() const
+{
+ std::vector<Coordinate> np;
+ np.reserve( mpoints.size() );
+ std::copy( mpoints.begin(), mpoints.end(), std::back_inserter( np ) );
+ return np;
+}
+
+const uint PolygonImp::npoints() const
+{
+ return mnpoints;
+}
+
+PolygonImp* PolygonImp::copy() const
+{
+ return new PolygonImp( mpoints );
+}
+
+void PolygonImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+bool PolygonImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( PolygonImp::stype() ) &&
+ static_cast<const PolygonImp&>( rhs ).points() == mpoints;
+}
+
+const ObjectImpType* PolygonImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "polygon",
+ I18N_NOOP( "polygon" ),
+ I18N_NOOP( "Select this polygon" ),
+ I18N_NOOP( "Select polygon %1" ),
+ I18N_NOOP( "Remove a Polygon" ),
+ I18N_NOOP( "Add a Polygon" ),
+ I18N_NOOP( "Move a Polygon" ),
+ I18N_NOOP( "Attach to this polygon" ),
+ I18N_NOOP( "Show a Polygon" ),
+ I18N_NOOP( "Hide a Polygon" )
+ );
+
+ return &t;
+}
+
+const ObjectImpType* PolygonImp::stype3()
+{
+ static const ObjectImpType t3(
+ PolygonImp::stype(), "triangle",
+ I18N_NOOP( "triangle" ),
+ I18N_NOOP( "Select this triangle" ),
+ I18N_NOOP( "Select triangle %1" ),
+ I18N_NOOP( "Remove a Triangle" ),
+ I18N_NOOP( "Add a Triangle" ),
+ I18N_NOOP( "Move a Triangle" ),
+ I18N_NOOP( "Attach to this triangle" ),
+ I18N_NOOP( "Show a Triangle" ),
+ I18N_NOOP( "Hide a Triangle" )
+ );
+
+ return &t3;
+}
+
+const ObjectImpType* PolygonImp::stype4()
+{
+ static const ObjectImpType t4(
+ PolygonImp::stype(), "quadrilateral",
+ I18N_NOOP( "quadrilateral" ),
+ I18N_NOOP( "Select this quadrilateral" ),
+ I18N_NOOP( "Select quadrilateral %1" ),
+ I18N_NOOP( "Remove a Quadrilateral" ),
+ I18N_NOOP( "Add a Quadrilateral" ),
+ I18N_NOOP( "Move a Quadrilateral" ),
+ I18N_NOOP( "Attach to this quadrilateral" ),
+ I18N_NOOP( "Show a Quadrilateral" ),
+ I18N_NOOP( "Hide a Quadrilateral" )
+ );
+
+ return &t4;
+}
+
+const ObjectImpType* PolygonImp::type() const
+{
+ uint n = mpoints.size();
+
+ if ( n == 3 ) return PolygonImp::stype3();
+ if ( n == 4 ) return PolygonImp::stype4();
+ return PolygonImp::stype();
+}
+
+bool PolygonImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ assert( which < PolygonImp::numberOfProperties() );
+ if ( which < Parent::numberOfProperties() )
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+ return false;
+}
+
+Rect PolygonImp::surroundingRect() const
+{
+ Rect r( 0., 0., 0., 0. );
+ for ( uint i = 0; i < mpoints.size(); ++i )
+ {
+ r.setContains( mpoints[i] );
+ }
+ return r;
+}
+
+int PolygonImp::windingNumber() const
+{
+ /*
+ * this is defined as the sum of the external angles while at
+ * all vertices, then normalized by 2pi. The external angle
+ * is the angle we steer at each vertex while we walk along the
+ * boundary of the polygon.
+ * In the end we only need to count how many time we cross the (1,0)
+ * direction (positive x-axis) with a positive sign if we cross while
+ * steering left and a negative sign viceversa
+ */
+
+ int winding = 0;
+ uint npoints = mpoints.size();
+ Coordinate prevside = mpoints[0] - mpoints[npoints-1];
+ for ( uint i = 0; i < npoints; ++i )
+ {
+ uint nexti = i + 1;
+ if ( nexti >= npoints ) nexti = 0;
+ Coordinate side = mpoints[nexti] - mpoints[i];
+ double vecprod = side.x*prevside.y - side.y*prevside.x;
+ int steeringdir = ( vecprod > 0 ) ? 1 : -1;
+ if ( vecprod == 0.0 || side.y*prevside.y > 0 )
+ {
+ prevside = side;
+ continue; // cannot cross the (1,0) direction
+ }
+ if ( side.y*steeringdir < 0 && prevside.y*steeringdir >= 0 )
+ winding -= steeringdir;
+ prevside = side;
+ }
+ return winding;
+}
+
+bool PolygonImp::isMonotoneSteering() const
+{
+ /*
+ * returns true if while walking along the boundary,
+ * steering is always in the same direction
+ */
+
+ uint npoints = mpoints.size();
+ Coordinate prevside = mpoints[0] - mpoints[npoints-1];
+ int prevsteeringdir = 0;
+ for ( uint i = 0; i < npoints; ++i )
+ {
+ uint nexti = i + 1;
+ if ( nexti >= npoints ) nexti = 0;
+ Coordinate side = mpoints[nexti] - mpoints[i];
+ double vecprod = side.x*prevside.y - side.y*prevside.x;
+ int steeringdir = ( vecprod > 0 ) ? 1 : -1;
+ if ( vecprod == 0.0 )
+ {
+ prevside = side;
+ continue; // going straight
+ }
+ if ( prevsteeringdir*steeringdir < 0 ) return false;
+ prevside = side;
+ prevsteeringdir = steeringdir;
+ }
+ return true;
+}
+
+bool PolygonImp::isConvex() const
+{
+ if ( ! isMonotoneSteering() ) return false;
+ int winding = windingNumber();
+ if ( winding < 0 ) winding = -winding;
+ assert ( winding > 0 );
+ return winding == 1;
+}
+
+std::vector<Coordinate> computeConvexHull( const std::vector<Coordinate>& points )
+{
+ /*
+ * compute the convex hull of the set of points, the resulting list
+ * is the vertices of the resulting polygon listed in a counter clockwise
+ * order. This algorithm is on order n^2, probably suboptimal, but
+ * we don't expect to have large values for n.
+ */
+
+ if ( points.size() < 3 ) return points;
+ std::vector<Coordinate> worklist = points;
+ std::vector<Coordinate> result;
+
+ double ymin = worklist[0].y;
+ uint imin = 0;
+ for ( uint i = 1; i < worklist.size(); ++i )
+ {
+ if ( worklist[i].y < ymin )
+ {
+ ymin = worklist[i].y;
+ imin = i;
+ }
+ }
+
+ // worklist[imin] is definitely on the convex hull, let's start from there
+ result.push_back( worklist[imin] );
+ Coordinate startpoint = worklist[imin];
+ Coordinate apoint = worklist[imin];
+ double aangle = 0.0;
+
+ while ( ! worklist.empty() )
+ {
+ int besti = -1;
+ double anglemin = 10000.0;
+ for ( uint i = 0; i < worklist.size(); ++i )
+ {
+ if ( worklist[i] == apoint ) continue;
+ Coordinate v = worklist[i] - apoint;
+ double angle = std::atan2( v.y, v.x );
+ while ( angle < aangle ) angle += 2*M_PI;
+ if ( angle < anglemin )
+ { // found a better point
+ besti = i;
+ anglemin = angle;
+ }
+ }
+
+ if ( besti < 0 ) return result; // this happens, e.g. if all points coincide
+ apoint = worklist[besti];
+ aangle = anglemin;
+ if ( apoint == startpoint )
+ {
+ return result;
+ }
+ result.push_back( apoint );
+ worklist.erase( worklist.begin() + besti, worklist.begin() + besti + 1 );
+ }
+ assert( false );
+ return result;
+}
diff --git a/kig/objects/polygon_imp.h b/kig/objects/polygon_imp.h
new file mode 100644
index 00000000..9a25d516
--- /dev/null
+++ b/kig/objects/polygon_imp.h
@@ -0,0 +1,94 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_POLYGON_IMP_H
+#define KIG_OBJECTS_POLYGON_IMP_H
+
+#include "object_imp.h"
+#include "../misc/coordinate.h"
+#include <vector>
+
+/**
+ * An ObjectImp representing a polygon.
+ */
+class PolygonImp
+ : public ObjectImp
+{
+ uint mnpoints;
+ std::vector<Coordinate> mpoints;
+ Coordinate mcenterofmass;
+public:
+ typedef ObjectImp Parent;
+ /**
+ * Returns the ObjectImpType representing the PolygonImp type..
+ */
+ static const ObjectImpType* stype();
+ static const ObjectImpType* stype3();
+ static const ObjectImpType* stype4();
+
+ /**
+ * Constructs a polygon.
+ */
+ PolygonImp( const std::vector<Coordinate>& points );
+ PolygonImp( const uint nsides, const std::vector<Coordinate>& points,
+ const Coordinate& centerofmass );
+ ~PolygonImp();
+ PolygonImp* copy() const;
+
+ Coordinate attachPoint() const;
+ ObjectImp* transform( const Transformation& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ bool valid() const;
+ Rect surroundingRect() const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ /**
+ * Returns the vector with polygon points.
+ */
+ const std::vector<Coordinate> points() const;
+ /**
+ * Returns the center of mass of the polygon.
+ */
+ const Coordinate centerOfMass() const;
+ /**
+ * Returns the number of points of this polygon.
+ */
+ const uint npoints() const;
+
+ bool equals( const ObjectImp& rhs ) const;
+ bool isInPolygon( const Coordinate& p ) const;
+ int windingNumber() const;
+ bool isMonotoneSteering() const;
+ bool isConvex() const;
+};
+
+std::vector<Coordinate> computeConvexHull( const std::vector<Coordinate>& points );
+
+#endif
diff --git a/kig/objects/polygon_type.cc b/kig/objects/polygon_type.cc
new file mode 100644
index 00000000..bca867da
--- /dev/null
+++ b/kig/objects/polygon_type.cc
@@ -0,0 +1,669 @@
+// Copyright (C) 2003 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "polygon_type.h"
+
+#include "bogus_imp.h"
+#include "line_imp.h"
+#include "point_imp.h"
+#include "polygon_imp.h"
+#include "object_calcer.h"
+
+#include "../misc/common.h"
+
+#include <klocale.h>
+#include <cmath>
+#include <vector>
+
+/*
+ * triangle by its vertices
+ */
+
+static const char triangle_constructstatement[] = I18N_NOOP( "Construct a triangle with this vertex" );
+static const char triangle_constructstatement2[] = I18N_NOOP( "Select a point to be a vertex of the new triangle..." );
+
+static const struct ArgsParser::spec argsspecTriangleB3P[] =
+{
+ { PointImp::stype(), triangle_constructstatement, triangle_constructstatement2, true },
+ { PointImp::stype(), triangle_constructstatement, triangle_constructstatement2, true },
+ { PointImp::stype(), triangle_constructstatement, triangle_constructstatement2, true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TriangleB3PType )
+
+TriangleB3PType::TriangleB3PType()
+ : ArgsParserObjectType( "TriangleB3P", argsspecTriangleB3P, 3 )
+{
+}
+
+TriangleB3PType::~TriangleB3PType()
+{
+}
+
+const TriangleB3PType* TriangleB3PType::instance()
+{
+ static const TriangleB3PType s;
+ return &s;
+}
+
+ObjectImp* TriangleB3PType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents, 1 ) ) return new InvalidImp;
+ std::vector<Coordinate> points;
+
+ Coordinate centerofmass3 = Coordinate( 0, 0 );
+ for ( Args::const_iterator i = parents.begin(); i != parents.end(); ++i )
+ {
+ Coordinate point = static_cast<const PointImp*>( *i )->coordinate();
+ centerofmass3 += point;
+ points.push_back( point );
+ }
+ return new PolygonImp( 3, points, centerofmass3/3 );
+}
+
+const ObjectImpType* TriangleB3PType::resultId() const
+{
+ return PolygonImp::stype();
+}
+
+bool TriangleB3PType::canMove( const ObjectTypeCalcer& o ) const
+{
+ return isFreelyTranslatable( o );
+}
+
+bool TriangleB3PType::isFreelyTranslatable( const ObjectTypeCalcer& o ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ return parents[0]->isFreelyTranslatable() &&
+ parents[1]->isFreelyTranslatable() &&
+ parents[2]->isFreelyTranslatable();
+}
+
+void TriangleB3PType::move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ assert( margsparser.checkArgs( parents ) );
+ const Coordinate a = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+ const Coordinate b = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
+ const Coordinate c = static_cast<const PointImp*>( parents[2]->imp() )->coordinate();
+ if ( parents[0]->canMove() )
+ parents[0]->move( to, d );
+ if ( parents[1]->canMove() )
+ parents[1]->move( to + b - a, d );
+ if ( parents[2]->canMove() )
+ parents[2]->move( to + c - a, d );
+}
+
+const Coordinate TriangleB3PType::moveReferencePoint( const ObjectTypeCalcer& o ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ assert( margsparser.checkArgs( parents ) );
+ return static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+}
+
+std::vector<ObjectCalcer*> TriangleB3PType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ std::vector<ObjectCalcer*> parents = ourobj.parents();
+ std::set<ObjectCalcer*> ret;
+ std::vector<ObjectCalcer*> tmp = parents[0]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ tmp = parents[1]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ tmp = parents[2]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ ret.insert( parents.begin(), parents.end() );
+ return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
+}
+
+/*
+ * generic polygon
+ */
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonBNPType )
+
+PolygonBNPType::PolygonBNPType()
+ : ObjectType( "PolygonBNP" )
+{
+}
+
+PolygonBNPType::~PolygonBNPType()
+{
+}
+
+const PolygonBNPType* PolygonBNPType::instance()
+{
+ static const PolygonBNPType s;
+ return &s;
+}
+
+ObjectImp* PolygonBNPType::calc( const Args& parents, const KigDocument& ) const
+{
+ uint count = parents.size();
+ assert (count >= 3); /* non sono ammessi poligoni con meno di tre lati */
+// if ( parents[0] != parents[count] ) return new InvalidImp;
+ std::vector<Coordinate> points;
+
+ uint npoints = 0;
+ Coordinate centerofmassn = Coordinate( 0, 0 );
+
+ for ( uint i = 0; i < count; ++i )
+ {
+ npoints++;
+ if ( ! parents[i]->inherits( PointImp::stype() ) ) return new InvalidImp;
+ Coordinate point = static_cast<const PointImp*>( parents[i] )->coordinate();
+ centerofmassn += point;
+ points.push_back( point );
+ }
+ return new PolygonImp( npoints, points, centerofmassn/npoints );
+}
+
+const ObjectImpType* PolygonBNPType::resultId() const
+{
+ return PolygonImp::stype();
+}
+
+const ObjectImpType* PolygonBNPType::impRequirement( const ObjectImp*, const Args& ) const
+{
+ return PointImp::stype();
+}
+
+bool PolygonBNPType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
+{
+ return false; /* should be true? */
+}
+
+std::vector<ObjectCalcer*> PolygonBNPType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ return args; /* should already be in correct order */
+}
+
+Args PolygonBNPType::sortArgs( const Args& args ) const
+{
+ return args;
+}
+
+bool PolygonBNPType::canMove( const ObjectTypeCalcer& o ) const
+{
+ return isFreelyTranslatable( o );
+}
+
+bool PolygonBNPType::isFreelyTranslatable( const ObjectTypeCalcer& o ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ for ( uint i = 0; i < parents.size(); ++i )
+ {
+ if ( !parents[i]->isFreelyTranslatable() ) return false;
+ }
+ return true;
+}
+
+void PolygonBNPType::move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ const Coordinate ref = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+ for ( uint i = 0; i < parents.size(); ++i )
+ {
+ const Coordinate a = static_cast<const PointImp*>( parents[i]->imp() )->coordinate();
+ parents[i]->move( to + a - ref, d );
+ }
+}
+
+const Coordinate PolygonBNPType::moveReferencePoint( const ObjectTypeCalcer& o
+) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ return static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+}
+
+std::vector<ObjectCalcer*> PolygonBNPType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ std::vector<ObjectCalcer*> parents = ourobj.parents();
+ std::set<ObjectCalcer*> ret;
+ for ( uint i = 0; i < parents.size(); ++i )
+ {
+ std::vector<ObjectCalcer*> tmp = parents[i]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ }
+ ret.insert( parents.begin(), parents.end() );
+ return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
+}
+
+/*
+ * regular polygon by center and vertex
+ */
+
+//static const char constructpoligonthroughpointstat[] = I18N_NOOP( "Construct a polygon with this vertex" );
+//
+//static const char constructpoligonwithcenterstat[] = I18N_NOOP( "Construct a polygon with this center" );
+//
+//static const ArgsParser::spec argsspecPoligonBCV[] =
+//{
+// { PointImp::stype(), constructpoligonwithcenterstat,
+// I18N_NOOP( "Select the center of the new polygon..." ), false },
+// { PointImp::stype(), constructpoligonthroughpointstat,
+// I18N_NOOP( "Select a vertex for the new polygon..." ), true },
+// { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+//};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonBCVType )
+
+PolygonBCVType::PolygonBCVType()
+ : ObjectType( "PoligonBCV" )
+// we keep the name "PoligonBCV" although syntactically incorrect for
+// compatibility reasons with old kig files
+// : ArgsParserObjectType( "PoligonBCV", argsspecPoligonBCV, 3 )
+{
+}
+
+PolygonBCVType::~PolygonBCVType()
+{
+}
+
+const PolygonBCVType* PolygonBCVType::instance()
+{
+ static const PolygonBCVType s;
+ return &s;
+}
+
+ObjectImp* PolygonBCVType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( parents.size() < 3 || parents.size() > 4 ) return new InvalidImp;
+
+ if ( ( ! parents[0]->inherits( PointImp::stype() ) ) ||
+ ( ! parents[1]->inherits( PointImp::stype() ) ) ||
+ ( ! parents[2]->inherits( IntImp::stype() ) ) )
+ return new InvalidImp;
+
+ const Coordinate center =
+ static_cast<const PointImp*>( parents[0] )->coordinate();
+ const Coordinate vertex =
+ static_cast<const PointImp*>( parents[1] )->coordinate();
+ const int sides =
+ static_cast<const IntImp*>( parents[2] )->data();
+ int twist = 1;
+ if ( parents.size() == 4 )
+ {
+ if ( ! parents[3]->inherits( IntImp::stype() ) ) return new InvalidImp;
+ twist = static_cast<const IntImp*>( parents[3] )->data();
+ }
+ std::vector<Coordinate> vertexes;
+
+ double dx = vertex.x - center.x;
+ double dy = vertex.y - center.y;
+
+ for ( int i = 1; i <= sides; i++ )
+ {
+ double alfa = 2*twist*M_PI/sides;
+ double theta1 = alfa*i - alfa;
+ double ctheta1 = cos(theta1);
+ double stheta1 = sin(theta1);
+
+ Coordinate v1 = center + Coordinate( ctheta1*dx - stheta1*dy,
+ stheta1*dx + ctheta1*dy );
+ vertexes.push_back( v1 );
+ }
+ return new PolygonImp( uint (sides), vertexes, center );
+}
+
+const ObjectImpType* PolygonBCVType::resultId() const
+{
+ return SegmentImp::stype();
+}
+
+const ObjectImpType* PolygonBCVType::impRequirement( const ObjectImp* obj, const Args& ) const
+{
+ if ( obj->inherits( PointImp::stype() ) )
+ return PointImp::stype();
+
+ if ( obj->inherits( IntImp::stype() ) )
+ return IntImp::stype();
+
+ return 0;
+}
+
+bool PolygonBCVType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
+{
+ return false; /* should be true? */
+}
+
+std::vector<ObjectCalcer*> PolygonBCVType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ return args; /* should already be in correct order */
+}
+
+Args PolygonBCVType::sortArgs( const Args& args ) const
+{
+ return args;
+}
+
+bool PolygonBCVType::canMove( const ObjectTypeCalcer& o ) const
+{
+ return isFreelyTranslatable( o );
+}
+
+bool PolygonBCVType::isFreelyTranslatable( const ObjectTypeCalcer& o ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ return parents[0]->isFreelyTranslatable() &&
+ parents[1]->isFreelyTranslatable();
+}
+
+void PolygonBCVType::move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ // assert( margsparser.checkArgs( parents ) );
+ if ( ! parents[0]->imp()->inherits( PointImp::stype() ) ||
+ ! parents[1]->imp()->inherits( PointImp::stype() ) ) return;
+
+ const Coordinate a = static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+ const Coordinate b = static_cast<const PointImp*>( parents[1]->imp() )->coordinate();
+ parents[0]->move( to, d );
+ parents[1]->move( to + b - a, d );
+}
+
+const Coordinate PolygonBCVType::moveReferencePoint( const ObjectTypeCalcer& o) const
+{
+ std::vector<ObjectCalcer*> parents = o.parents();
+ // assert( margsparser.checkArgs( parents ) );
+ if ( ! parents[0]->imp()->inherits( PointImp::stype() ) ) return Coordinate::invalidCoord();
+
+ return static_cast<const PointImp*>( parents[0]->imp() )->coordinate();
+}
+
+std::vector<ObjectCalcer*> PolygonBCVType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ std::vector<ObjectCalcer*> parents = ourobj.parents();
+ std::set<ObjectCalcer*> ret;
+ std::vector<ObjectCalcer*> tmp = parents[0]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ tmp = parents[1]->movableParents();
+ ret.insert( tmp.begin(), tmp.end() );
+ ret.insert( &parents[0], &parents[1] );
+ return std::vector<ObjectCalcer*>( ret.begin(), ret.end() );
+}
+
+/* polygon-line intersection */
+
+static const ArgsParser::spec argsspecPolygonLineIntersection[] =
+{
+ { PolygonImp::stype(), I18N_NOOP( "Intersect this polygon with a line" ),
+ I18N_NOOP( "Select the polygon of which you want the intersection with a line..." ), false },
+ { AbstractLineImp::stype(), "Intersect this line with a polygon", "Select the line of which you want the intersection with a polygon...", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonLineIntersectionType )
+
+PolygonLineIntersectionType::PolygonLineIntersectionType()
+ : ArgsParserObjectType( "PolygonLineIntersection", argsspecPolygonLineIntersection, 2 )
+{
+}
+
+PolygonLineIntersectionType::~PolygonLineIntersectionType()
+{
+}
+
+const PolygonLineIntersectionType* PolygonLineIntersectionType::instance()
+{
+ static const PolygonLineIntersectionType t;
+ return &t;
+}
+
+/*
+ * Intersection of a polygon and a line/ray/segment.
+ *
+ * geometrically speaking the result is always a collection of
+ * collinear nonintersecting open segments (at most one if the
+ * polygon is convex). Since we don't know in advance how many
+ * segments will result, the obvious choice is to return an
+ * InvalidImp in cases when the result is *not* a single segment
+ *
+ * computing the two ends of this segment is more tricky then one
+ * expects especially when intersecting segments/rays.
+ *
+ * particularly "difficult" situations are those where we intersect
+ * a segment/ray with an/the endpoint coinciding with a vertex of
+ * the polygon, especially if that vertex is a "reentrant" (concave)
+ * vertex of the polygon.
+ */
+
+ObjectImp* PolygonLineIntersectionType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const PolygonImp* polygon = static_cast<const PolygonImp*>( parents[0] );
+ const std::vector<Coordinate> ppoints = polygon->points();
+ const LineData line = static_cast<const AbstractLineImp*>( parents[1] )->data();
+ Coordinate intersections[2];
+ uint whichintersection = 0;
+
+ bool boundleft = false;
+ bool boundright = false;
+ if ( parents[1]->inherits( SegmentImp::stype() ) )
+ {
+ boundleft = boundright = true;
+ }
+ if ( parents[1]->inherits( RayImp::stype() ) )
+ {
+ boundleft = true;
+ }
+ Coordinate a = line.a;
+ double abx = line.b.x - a.x;
+ double aby = line.b.y - a.y;
+
+ double leftendinside = false;
+ double rightendinside = false;
+ Coordinate prevpoint = ppoints.back() - a;
+ bool prevpointbelow = ( abx*prevpoint.y <= aby*prevpoint.x );
+ for ( uint i = 0; i < ppoints.size(); ++i )
+ {
+ Coordinate point = ppoints[i] - a;
+ bool pointbelow = ( abx*point.y <= aby*point.x );
+ if ( pointbelow != prevpointbelow )
+ {
+ /* found an intersection with the support line
+ * compute the value of the parameter...
+ */
+ double dcx = point.x - prevpoint.x;
+ double dcy = point.y - prevpoint.y;
+ double num = point.x*dcy - point.y*dcx;
+ double den = abx*dcy - aby*dcx;
+ if ( std::fabs( den ) <= 1.e-6*std::fabs( num ) ) continue; //parallel
+ double t = num/den;
+ if ( boundleft && t <= 0 )
+ {
+ leftendinside = !leftendinside;
+ }
+ else if ( boundright && t >= 1 )
+ {
+ rightendinside = !rightendinside;
+ }
+ else
+ {
+ if ( whichintersection >= 2 ) return new InvalidImp;
+ intersections[whichintersection++] = a + t*Coordinate( abx, aby );
+ }
+ }
+ prevpoint = point;
+ prevpointbelow = pointbelow;
+ }
+
+ if ( leftendinside )
+ {
+ if ( whichintersection >= 2 ) return new InvalidImp;
+ intersections[whichintersection++] = a;
+ }
+
+ if ( rightendinside )
+ {
+ if ( whichintersection >= 2 ) return new InvalidImp;
+ intersections[whichintersection++] = line.b;
+ }
+
+ switch (whichintersection)
+ {
+ case 1: /* just for completeness: this should never happen */
+ return new PointImp( intersections[0] );
+ break;
+ case 2:
+ return new SegmentImp( intersections[0], intersections[1] );
+ break;
+ case 0:
+ default:
+ return new InvalidImp;
+ break;
+ }
+}
+
+const ObjectImpType* PolygonLineIntersectionType::resultId() const
+{
+ return SegmentImp::stype();
+}
+
+/* polygon vertices */
+
+static const ArgsParser::spec argsspecPolygonVertex[] =
+{
+ { PolygonImp::stype(), I18N_NOOP( "Construct the vertices of this polygon" ),
+ I18N_NOOP( "Select the polygon of which you want to construct the vertices..." ), true },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonVertexType )
+
+PolygonVertexType::PolygonVertexType()
+ : ArgsParserObjectType( "PolygonVertex", argsspecPolygonVertex, 2 )
+{
+}
+
+PolygonVertexType::~PolygonVertexType()
+{
+}
+
+const PolygonVertexType* PolygonVertexType::instance()
+{
+ static const PolygonVertexType t;
+ return &t;
+}
+
+ObjectImp* PolygonVertexType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const std::vector<Coordinate> ppoints = static_cast<const PolygonImp*>( parents[0] )->points();
+ const uint i = static_cast<const IntImp*>( parents[1] )->data();
+
+ if ( i >= ppoints.size() ) return new InvalidImp;
+
+ return new PointImp( ppoints[i] );
+}
+
+const ObjectImpType* PolygonVertexType::resultId() const
+{
+ return PointImp::stype();
+}
+
+/* polygon sides */
+
+static const ArgsParser::spec argsspecPolygonSide[] =
+{
+ { PolygonImp::stype(), I18N_NOOP( "Construct the sides of this polygon" ),
+ I18N_NOOP( "Select the polygon of which you want to construct the sides..." ), false },
+ { IntImp::stype(), "param", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PolygonSideType )
+
+PolygonSideType::PolygonSideType()
+ : ArgsParserObjectType( "PolygonSide", argsspecPolygonSide, 2 )
+{
+}
+
+PolygonSideType::~PolygonSideType()
+{
+}
+
+const PolygonSideType* PolygonSideType::instance()
+{
+ static const PolygonSideType t;
+ return &t;
+}
+
+ObjectImp* PolygonSideType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const std::vector<Coordinate> ppoints = static_cast<const PolygonImp*>( parents[0] )->points();
+ const uint i = static_cast<const IntImp*>( parents[1] )->data();
+
+ if ( i >= ppoints.size() ) return new InvalidImp;
+
+ uint nexti = i + 1;
+ if ( nexti >= ppoints.size() ) nexti = 0;
+
+ return new SegmentImp( ppoints[i], ppoints[nexti] );
+}
+
+const ObjectImpType* PolygonSideType::resultId() const
+{
+ return SegmentImp::stype();
+}
+
+/* convex hull of a polygon */
+
+static const ArgsParser::spec argsspecConvexHull[] =
+{
+ { PolygonImp::stype(), I18N_NOOP( "Construct the convex hull of this polygon" ),
+ I18N_NOOP( "Select the polygon of which you want to construct the convex hull..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConvexHullType )
+
+ConvexHullType::ConvexHullType()
+ : ArgsParserObjectType( "ConvexHull", argsspecConvexHull, 1 )
+{
+}
+
+ConvexHullType::~ConvexHullType()
+{
+}
+
+const ConvexHullType* ConvexHullType::instance()
+{
+ static const ConvexHullType t;
+ return &t;
+}
+
+ObjectImp* ConvexHullType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+
+ const std::vector<Coordinate> ppoints = static_cast<const PolygonImp*>( parents[0] )->points();
+
+ if ( ppoints.size() < 3 ) return new InvalidImp;
+
+ std::vector<Coordinate> hull = computeConvexHull( ppoints );
+ if ( hull.size() < 3 ) return new InvalidImp;
+ return new PolygonImp( hull );
+}
+
+const ObjectImpType* ConvexHullType::resultId() const
+{
+ return PolygonImp::stype();
+}
diff --git a/kig/objects/polygon_type.h b/kig/objects/polygon_type.h
new file mode 100644
index 00000000..a49100bd
--- /dev/null
+++ b/kig/objects/polygon_type.h
@@ -0,0 +1,139 @@
+// Copyright (C) 2003 Maurizio Paolini <paolini@dmf.unicatt.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_POLIGON_TYPE_H
+#define KIG_OBJECTS_POLIGON_TYPE_H
+
+#include "base_type.h"
+
+/**
+ * Triangle by its vertices
+ */
+class TriangleB3PType
+ : public ArgsParserObjectType
+{
+ TriangleB3PType();
+ ~TriangleB3PType();
+public:
+ static const TriangleB3PType* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+ bool canMove( const ObjectTypeCalcer& o ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& o ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& o ) const;
+};
+
+/**
+ * Polygon by its vertices
+ */
+class PolygonBNPType
+ : public ObjectType
+{
+ PolygonBNPType();
+ ~PolygonBNPType();
+public:
+ static const PolygonBNPType* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const;
+ Args sortArgs( const Args& args ) const;
+
+ bool canMove( const ObjectTypeCalcer& o ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& o ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& o ) const;
+};
+
+/**
+ * Polygon by center and vertex
+ */
+class PolygonBCVType
+ : public ObjectType
+{
+ PolygonBCVType();
+ ~PolygonBCVType();
+public:
+ static const PolygonBCVType* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const;
+ Args sortArgs( const Args& args ) const;
+ bool canMove( const ObjectTypeCalcer& o ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& o ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& o, const Coordinate& to,
+ const KigDocument& d ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& o ) const;
+};
+
+class PolygonLineIntersectionType
+ : public ArgsParserObjectType
+{
+ PolygonLineIntersectionType();
+ ~PolygonLineIntersectionType();
+public:
+ static const PolygonLineIntersectionType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class PolygonVertexType
+ : public ArgsParserObjectType
+{
+ PolygonVertexType();
+ ~PolygonVertexType();
+public:
+ static const PolygonVertexType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class PolygonSideType
+ : public ArgsParserObjectType
+{
+ PolygonSideType();
+ ~PolygonSideType();
+public:
+ static const PolygonSideType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConvexHullType
+ : public ArgsParserObjectType
+{
+ ConvexHullType();
+ ~ConvexHullType();
+public:
+ static const ConvexHullType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+#endif
diff --git a/kig/objects/special_calcers.cc b/kig/objects/special_calcers.cc
new file mode 100644
index 00000000..e70bd4e9
--- /dev/null
+++ b/kig/objects/special_calcers.cc
@@ -0,0 +1,84 @@
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "special_calcers.h"
+
+static const ArgsParser::spec argsspecMeasureTransport[] =
+{
+ { CircleImp::stype(), I18N_NOOP( "Transport a measure on this circle" ) },
+ { PointImp::stype(), I18N_NOOP( "Project this point onto the circle" ) },
+ { SegmentImp::stype(), I18N_NOOP( "Segment to transport" ) }
+};
+
+static ArgsParser measuretransportargsparser( argsspecMeasureTransport, 3 );
+
+std::vector<ObjectCalcer*> MeasureTransportCalcer::parents() const
+{
+ std::vector<ObjectCalcer*> ret;
+ ret.push_back( mcircle );
+ ret.push_back( mpoint );
+ ret.push_back( msegment );
+ return ret;
+}
+
+MeasureTransportCalcer::MeasureTransportCalcer(ObjectCalcer* circle, ObjectCalcer* point, ObjectCalcer* segment )
+ : mcircle( circle ), mpoint( point ), msegment( segment ), mimp( 0 )
+{
+}
+
+MeasureTransportCalcer::~MeasureTransportCalcer()
+{
+}
+
+void MeasureTransportCalcer::calc( const KigDocument& )
+{
+ if ( ! measuretransportargsparser.checkArgs( parents() ) )
+ return new InvalidImp();
+
+ if ( ! isPointOnCurve( mpoint, mcircle ) )
+ return new InvalidImp();
+
+ const CircleImp* c = static_cast<const CircleImp*>( mcircle->imp() );
+ const PointImp* p = static_cast<const PointImp*>( mpoint->imp() );
+ const SegmentImp* s = static_cast<const SegmentImp*>( msegment->imp() );
+ double param = c->getParam( p->coordinate(), doc );
+ double measure = s->length();
+ measure /= 2*c->radius()*M_PI;
+ param += measure;
+ while (param > 1) param -= 1;
+
+ const Coordinate nc = c->getPoint( param, doc );
+ if ( nc.valid() ) return new PointImp( nc );
+ else return new InvalidImp;
+}
+
+const ObjectImpType* MeasureTransportCalcer::impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const
+{
+ if ( o->imp()->inherits( CircleImp::stype() ) )
+ return CircleImp::stype();
+ else if ( o->imp()->inherits( PointImp::stype() ) )
+ return PointImp::stype();
+ else if ( o->imp()->inherits( SegmentImp::stype() ) )
+ return SegmentImp::stype();
+ else
+ {
+ assert( false );
+ return 0;
+ }
+}
+
diff --git a/kig/objects/special_calcers.h b/kig/objects/special_calcers.h
new file mode 100644
index 00000000..640587cc
--- /dev/null
+++ b/kig/objects/special_calcers.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_SPECIAL_CALCERS_H
+#define KIG_OBJECTS_SPECIAL_CALCERS_H
+
+class MeasureTransportCalcer
+ : public ObjectCalcer
+{
+ ObjectCalcer* mcircle;
+ ObjectCalcer* mpoint;
+ ObjectCalcer* msegment;
+ ObjectImp* mimp;
+public:
+ MeasureTransportCalcer(ObjectCalcer* circle, ObjectCalcer* point, ObjectCalcer* segment );
+ ~MeasureTransportCalcer();
+
+ std::vector<ObjectCalcer*> parents() const;
+ void calc( const KigDocument& );
+ const ObjectImpType* impRequirement(
+ ObjectCalcer* o, const std::vector<ObjectCalcer*>& os ) const;
+};
+
+#endif
diff --git a/kig/objects/tangent_type.cc b/kig/objects/tangent_type.cc
new file mode 100644
index 00000000..12ebda23
--- /dev/null
+++ b/kig/objects/tangent_type.cc
@@ -0,0 +1,285 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "tangent_type.h"
+
+#include "bogus_imp.h"
+#include "conic_imp.h"
+#include "cubic_imp.h"
+#include "curve_imp.h"
+#include "other_imp.h"
+#include "point_imp.h"
+#include "line_imp.h"
+
+#include "../misc/common.h"
+#include "../misc/conic-common.h"
+//#include "../misc/calcpaths.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+
+static const char constructlinetangentpoint[] = "SHOULDNOTBESEEN";
+static const char selecttangent1[] =
+ I18N_NOOP( "Select the curve..." );
+static const char selecttangent2[] =
+ I18N_NOOP( "Select the point for the tangent to go through..." );
+
+static const ArgsParser::spec argsspecTangentConic[] =
+{
+ { ConicImp::stype(), "SHOULDNOTBESEEN", selecttangent1, false },
+ { PointImp::stype(), constructlinetangentpoint, selecttangent2, true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TangentConicType )
+
+TangentConicType::TangentConicType()
+ : ArgsParserObjectType( "TangentConic", argsspecTangentConic, 2 )
+{
+}
+
+TangentConicType::~TangentConicType()
+{
+}
+
+const TangentConicType* TangentConicType::instance()
+{
+ static const TangentConicType t;
+ return &t;
+}
+
+ObjectImp* TangentConicType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const ConicImp* c = static_cast<const ConicImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+
+ if ( !c->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ bool ok;
+ const LineData tangent = calcConicPolarLine( c->cartesianData(), p, ok );
+
+ if ( !ok )
+ return new InvalidImp;
+
+ return new LineImp( tangent );
+}
+
+const ObjectImpType* TangentConicType::resultId() const
+{
+ return LineImp::stype();
+}
+
+/*** Arc starts here ***/
+
+static const ArgsParser::spec argsspecTangentArc[] =
+{
+ { ArcImp::stype(), "SHOULDNOTBESEEN", selecttangent1, false },
+ { PointImp::stype(), constructlinetangentpoint, selecttangent2, true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TangentArcType )
+
+TangentArcType::TangentArcType()
+ : ArgsParserObjectType( "TangentArc", argsspecTangentArc, 2 )
+{
+}
+
+TangentArcType::~TangentArcType()
+{
+}
+
+const TangentArcType* TangentArcType::instance()
+{
+ static const TangentArcType t;
+ return &t;
+}
+
+ObjectImp* TangentArcType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const ArcImp* arc = static_cast<const ArcImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+
+ if ( !arc->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ Coordinate c = arc->center();
+ double sqr = arc->radius();
+ sqr *= sqr;
+ ConicCartesianData data( 1.0, 1.0, 0.0, -2*c.x, -2*c.y, c.x*c.x + c.y*c.y - sqr );
+
+ bool ok;
+ const LineData tangent = calcConicPolarLine( data, p, ok );
+
+ if ( !ok )
+ return new InvalidImp;
+
+ return new LineImp( tangent );
+}
+
+const ObjectImpType* TangentArcType::resultId() const
+{
+ return LineImp::stype();
+}
+
+/**** Cubic starts here ****/
+
+static const ArgsParser::spec argsspecTangentCubic[] =
+{
+ { CubicImp::stype(), "SHOULDNOTBESEEN", selecttangent1, false },
+ { PointImp::stype(), constructlinetangentpoint, selecttangent2, true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TangentCubicType )
+
+TangentCubicType::TangentCubicType()
+ : ArgsParserObjectType( "TangentCubic", argsspecTangentCubic, 2 )
+{
+}
+
+TangentCubicType::~TangentCubicType()
+{
+}
+
+const TangentCubicType* TangentCubicType::instance()
+{
+ static const TangentCubicType t;
+ return &t;
+}
+
+ObjectImp* TangentCubicType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const CubicImp* cubic = static_cast<const CubicImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+
+ if ( !cubic->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ double x = p.x;
+ double y = p.y;
+ CubicCartesianData data = cubic->data();
+// double aconst = data.coeffs[0];
+ double ax = data.coeffs[1];
+ double ay = data.coeffs[2];
+ double axx = data.coeffs[3];
+ double axy = data.coeffs[4];
+ double ayy = data.coeffs[5];
+ double axxx = data.coeffs[6];
+ double axxy = data.coeffs[7];
+ double axyy = data.coeffs[8];
+ double ayyy = data.coeffs[9];
+
+ /* mp: the tangent vector (-gy,gx) is orthogonal to the gradient (gx,gy)
+ * which is easy to compute from the CartesianData
+ *
+ * note: same thing could be done for conics, which would be
+ * much more efficient...
+ */
+
+ Coordinate tangvec = Coordinate (
+ - axxy*x*x - 2*axyy*x*y - 3*ayyy*y*y - axy*x - 2*ayy*y - ay,
+ 3*axxx*x*x + 2*axxy*x*y + axyy*y*y + 2*axx*x + axy*y + ax
+ );
+ const LineData tangent = LineData( p, p + tangvec );
+
+ return new LineImp( tangent );
+}
+
+const ObjectImpType* TangentCubicType::resultId() const
+{
+ return LineImp::stype();
+}
+
+/**** Curve (locus) starts here ****/
+
+static const ArgsParser::spec argsspecTangentCurve[] =
+{
+ { CurveImp::stype(), "SHOULDNOTBESEEN", selecttangent1, false },
+ { PointImp::stype(), constructlinetangentpoint, selecttangent2, true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TangentCurveType )
+
+TangentCurveType::TangentCurveType()
+ : ArgsParserObjectType( "TangentCurve", argsspecTangentCurve, 2 )
+{
+}
+
+TangentCurveType::~TangentCurveType()
+{
+}
+
+const TangentCurveType* TangentCurveType::instance()
+{
+ static const TangentCurveType t;
+ return &t;
+}
+
+ObjectImp* TangentCurveType::calc( const Args& args, const KigDocument& doc ) const
+{
+ if ( !margsparser.checkArgs( args ) )
+ return new InvalidImp;
+
+ const CurveImp* curve = static_cast<const CurveImp*>( args[0] );
+ const Coordinate& p = static_cast<const PointImp*>( args[1] )->coordinate();
+ if ( !curve->containsPoint( p, doc ) )
+ return new InvalidImp;
+
+ const double t = curve->getParam( p, doc );
+ const double tau0 = 1e-3;
+ const double sigma = 1e-5;
+ const int maxiter = 20;
+
+ double tau = tau0;
+ Coordinate tang, err;
+ double tplus = t + tau;
+ double tminus = t - tau;
+ if ( tplus > 1 ) {tplus = 1; tminus = 1 - 2*tau;}
+ if ( tminus < 0 ) {tminus = 0; tplus = 2*tau;}
+ Coordinate tangold = (curve->getPoint( tplus, doc ) - curve->getPoint( tminus, doc ))/(2*tau);
+
+ for (int i = 0; i < maxiter; i++)
+ {
+ tau = tau/2;
+ tplus = t + tau;
+ tminus = t - tau;
+ if ( tplus > 1 ) {tplus = 1; tminus = 1 - 2*tau;}
+ if ( tminus < 0 ) {tminus = 0; tplus = 2*tau;}
+ tang = (curve->getPoint( tplus, doc ) - curve->getPoint( tminus, doc ))/(2*tau);
+ err = (tangold - tang)/3;
+ if (err.length() < sigma)
+ {
+ tang = (4*tang - tangold)/3;
+ const LineData tangent = LineData( p, p + tang );
+ return new LineImp( tangent );
+ }
+ tangold = tang;
+ }
+ return new InvalidImp;
+}
+
+const ObjectImpType* TangentCurveType::resultId() const
+{
+ return LineImp::stype();
+}
diff --git a/kig/objects/tangent_type.h b/kig/objects/tangent_type.h
new file mode 100644
index 00000000..ccc00dea
--- /dev/null
+++ b/kig/objects/tangent_type.h
@@ -0,0 +1,83 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_TANGENT_TYPE_H
+#define KIG_OBJECTS_TANGENT_TYPE_H
+
+#include "base_type.h"
+
+/**
+ * the line tangent to a generic conic
+ */
+class TangentConicType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ TangentConicType();
+ ~TangentConicType();
+public:
+ static const TangentConicType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * the line tangent to an arc
+ */
+class TangentArcType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ TangentArcType();
+ ~TangentArcType();
+public:
+ static const TangentArcType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * the line tangent to a cubic
+ */
+class TangentCubicType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ TangentCubicType();
+ ~TangentCubicType();
+public:
+ static const TangentCubicType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+/**
+ * the line tangent to a curve
+ */
+class TangentCurveType
+ : public ArgsParserObjectType
+{
+ typedef ArgsParserObjectType Parent;
+ TangentCurveType();
+ ~TangentCurveType();
+public:
+ static const TangentCurveType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/tests_type.cc b/kig/objects/tests_type.cc
new file mode 100644
index 00000000..e85c111e
--- /dev/null
+++ b/kig/objects/tests_type.cc
@@ -0,0 +1,382 @@
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "tests_type.h"
+
+#include "line_imp.h"
+#include "polygon_imp.h"
+#include "point_imp.h"
+#include "bogus_imp.h"
+#include "other_imp.h"
+
+#include <cmath>
+
+static const ArgsParser::spec argsspecAreParallel[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Is this line parallel?" ),
+ I18N_NOOP( "Select the first of the two possibly parallel lines..." ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Parallel to this line?" ),
+ I18N_NOOP( "Select the other of the two possibly parallel lines..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( AreParallelType )
+
+AreParallelType::AreParallelType()
+ : ArgsParserObjectType( "AreParallel",
+ argsspecAreParallel, 2 )
+{
+}
+
+AreParallelType::~AreParallelType()
+{
+}
+
+const AreParallelType* AreParallelType::instance()
+{
+ static const AreParallelType t;
+ return &t;
+}
+
+ObjectImp* AreParallelType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const LineData& l1 = static_cast<const AbstractLineImp*>( parents[0] )->data();
+ const LineData& l2 = static_cast<const AbstractLineImp*>( parents[1] )->data();
+
+ if ( l1.isParallelTo( l2 ) )
+ return new TestResultImp( i18n( "These lines are parallel." ) );
+ else
+ return new TestResultImp( i18n( "These lines are not parallel." ) );
+
+}
+
+const ObjectImpType* AreParallelType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+static const ArgsParser::spec argsspecAreOrthogonal[] =
+{
+ { AbstractLineImp::stype(), I18N_NOOP( "Is this line orthogonal?" ),
+ I18N_NOOP( "Select the first of the two possibly orthogonal lines..." ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Orthogonal to this line?" ),
+ I18N_NOOP( "Select the other of the two possibly orthogonal lines..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( AreOrthogonalType )
+
+AreOrthogonalType::AreOrthogonalType()
+ : ArgsParserObjectType( "AreOrthogonal",
+ argsspecAreOrthogonal, 2 )
+{
+}
+
+AreOrthogonalType::~AreOrthogonalType()
+{
+}
+
+const AreOrthogonalType* AreOrthogonalType::instance()
+{
+ static const AreOrthogonalType t;
+ return &t;
+}
+
+ObjectImp* AreOrthogonalType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const LineData& l1 = static_cast<const AbstractLineImp*>( parents[0] )->data();
+ const LineData& l2 = static_cast<const AbstractLineImp*>( parents[1] )->data();
+
+ if ( l1.isOrthogonalTo( l2 ) )
+ return new TestResultImp( i18n( "These lines are orthogonal." ) );
+ else
+ return new TestResultImp( i18n( "These lines are not orthogonal." ) );
+
+}
+
+const ObjectImpType* AreOrthogonalType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+static const ArgsParser::spec argsspecAreCollinear[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Check collinearity of this point" ),
+ I18N_NOOP( "Select the first of the three possibly collinear points..." ), false },
+ { PointImp::stype(), I18N_NOOP( "and this second point" ),
+ I18N_NOOP( "Select the second of the three possibly collinear points..." ), false },
+ { PointImp::stype(), I18N_NOOP( "with this third point" ),
+ I18N_NOOP( "Select the last of the three possibly collinear points..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( AreCollinearType )
+
+AreCollinearType::AreCollinearType()
+ : ArgsParserObjectType( "AreCollinear",
+ argsspecAreCollinear, 3 )
+{
+}
+
+AreCollinearType::~AreCollinearType()
+{
+}
+
+const AreCollinearType* AreCollinearType::instance()
+{
+ static const AreCollinearType t;
+ return &t;
+}
+
+ObjectImp* AreCollinearType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const Coordinate& p1 = static_cast<const PointImp*>( parents[0] )->coordinate();
+ const Coordinate& p2 = static_cast<const PointImp*>( parents[1] )->coordinate();
+ const Coordinate& p3 = static_cast<const PointImp*>( parents[2] )->coordinate();
+
+ if ( areCollinear( p1, p2, p3 ) )
+ return new TestResultImp( i18n( "These points are collinear." ) );
+ else
+ return new TestResultImp( i18n( "These points are not collinear." ) );
+}
+
+const ObjectImpType* AreCollinearType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+static const ArgsParser::spec containsTestArgsSpec[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Check whether this point is on a curve" ),
+ I18N_NOOP( "Select the point you want to test..." ), false },
+ { CurveImp::stype(), I18N_NOOP( "Check whether the point is on this curve" ),
+ I18N_NOOP( "Select the curve that the point might be on..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ContainsTestType )
+
+ContainsTestType::ContainsTestType()
+ : ArgsParserObjectType( "ContainsTest", containsTestArgsSpec, 2 )
+{
+}
+
+ContainsTestType::~ContainsTestType()
+{
+}
+
+const ContainsTestType* ContainsTestType::instance()
+{
+ static const ContainsTestType t;
+ return &t;
+}
+
+ObjectImp* ContainsTestType::calc( const Args& parents, const KigDocument& doc ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const Coordinate& p = static_cast<const PointImp*>( parents[0] )->coordinate();
+ const CurveImp* c = static_cast<const CurveImp*>( parents[1] );
+
+ if ( c->containsPoint( p, doc ) )
+ return new TestResultImp( i18n( "This curve contains the point." ) );
+ else
+ return new TestResultImp( i18n( "This curve does not contain the point." ) );
+}
+
+const ObjectImpType* ContainsTestType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+/*
+ * containment test of a point in a polygon
+ */
+
+static const ArgsParser::spec InPolygonTestArgsSpec[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Check whether this point is in a polygon" ),
+ I18N_NOOP( "Select the point you want to test..." ), false },
+ { PolygonImp::stype(), I18N_NOOP( "Check whether the point is in this polygon" ),
+ I18N_NOOP( "Select the polygon that the point might be in..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( InPolygonTestType )
+
+InPolygonTestType::InPolygonTestType()
+ : ArgsParserObjectType( "InPolygonTest", InPolygonTestArgsSpec, 2 )
+{
+}
+
+InPolygonTestType::~InPolygonTestType()
+{
+}
+
+const InPolygonTestType* InPolygonTestType::instance()
+{
+ static const InPolygonTestType t;
+ return &t;
+}
+
+ObjectImp* InPolygonTestType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const Coordinate& p = static_cast<const PointImp*>( parents[0] )->coordinate();
+ const PolygonImp* pol = static_cast<const PolygonImp*>( parents[1] );
+
+ if ( pol->isInPolygon( p ) )
+ return new TestResultImp( i18n( "This polygon contains the point." ) );
+ else
+ return new TestResultImp( i18n( "This polygon does not contain the point." ) );
+}
+
+const ObjectImpType* InPolygonTestType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+/*
+ * test if a polygon is convex
+ */
+
+static const ArgsParser::spec ConvexPolygonTestArgsSpec[] =
+{
+ { PolygonImp::stype(), I18N_NOOP( "Check whether this polygon is convex" ),
+ I18N_NOOP( "Select the polygon you want to test for convexity..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ConvexPolygonTestType )
+
+ConvexPolygonTestType::ConvexPolygonTestType()
+ : ArgsParserObjectType( "ConvexPolygonTest", ConvexPolygonTestArgsSpec, 1 )
+{
+}
+
+ConvexPolygonTestType::~ConvexPolygonTestType()
+{
+}
+
+const ConvexPolygonTestType* ConvexPolygonTestType::instance()
+{
+ static const ConvexPolygonTestType t;
+ return &t;
+}
+
+ObjectImp* ConvexPolygonTestType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const PolygonImp* pol = static_cast<const PolygonImp*>( parents[0] );
+
+ if ( pol->isConvex() )
+ return new TestResultImp( i18n( "This polygon is convex." ) );
+ else
+ return new TestResultImp( i18n( "This polygon is not convex." ) );
+}
+
+const ObjectImpType* ConvexPolygonTestType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+/*
+ * same distance test
+ */
+
+static const ArgsParser::spec argsspecSameDistanceType[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Check if this point has the same distance" ),
+ I18N_NOOP( "Select the point which might have the same distance from two other points..." ), false },
+ { PointImp::stype(), I18N_NOOP( "from this point" ),
+ I18N_NOOP( "Select the first of the two other points..." ), false },
+ { PointImp::stype(), I18N_NOOP( "and from this second point" ),
+ I18N_NOOP( "Select the other of the two other points..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( SameDistanceType )
+
+SameDistanceType::SameDistanceType()
+ : ArgsParserObjectType( "SameDistanceType", argsspecSameDistanceType, 3 )
+{
+}
+
+SameDistanceType::~SameDistanceType()
+{
+}
+
+const SameDistanceType* SameDistanceType::instance()
+{
+ static const SameDistanceType t;
+ return &t;
+}
+
+ObjectImp* SameDistanceType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const Coordinate& p1 = static_cast<const PointImp*>( parents[0] )->coordinate();
+ const Coordinate& p2 = static_cast<const PointImp*>( parents[1] )->coordinate();
+ const Coordinate& p3 = static_cast<const PointImp*>( parents[2] )->coordinate();
+
+ if ( fabs( ( p1 - p2 ).length() - ( p1 - p3 ).length() ) < 10e-5 )
+ return new TestResultImp( i18n( "The two distances are the same." ) );
+ else
+ return new TestResultImp( i18n( "The two distances are not the same." ) );
+}
+
+const ObjectImpType* SameDistanceType::resultId() const
+{
+ return TestResultImp::stype();
+}
+
+static const ArgsParser::spec vectorEqualityArgsSpec[] =
+{
+ { VectorImp::stype(), I18N_NOOP( "Check whether this vector is equal to another vector" ),
+ I18N_NOOP( "Select the first of the two possibly equal vectors..." ), false },
+ { VectorImp::stype(), I18N_NOOP( "Check whether this vector is equal to the other vector" ),
+ I18N_NOOP( "Select the other of the two possibly equal vectors..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( VectorEqualityTestType )
+
+VectorEqualityTestType::VectorEqualityTestType()
+ : ArgsParserObjectType( "VectorEquality", vectorEqualityArgsSpec, 2 )
+{
+}
+
+VectorEqualityTestType::~VectorEqualityTestType()
+{
+}
+
+const VectorEqualityTestType* VectorEqualityTestType::instance()
+{
+ static const VectorEqualityTestType t;
+ return &t;
+}
+
+ObjectImp* VectorEqualityTestType::calc( const Args& parents, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( parents ) ) return new InvalidImp;
+ const Coordinate& v1 = static_cast<const VectorImp*>( parents[0] )->dir();
+ const Coordinate& v2 = static_cast<const VectorImp*>( parents[1] )->dir();
+
+ if ( ( v1 - v2 ).length() < 10e-5 )
+ return new TestResultImp( i18n( "The two vectors are the same." ) );
+ else
+ return new TestResultImp( i18n( "The two vectors are not the same." ) );
+}
+
+const ObjectImpType* VectorEqualityTestType::resultId() const
+{
+ return TestResultImp::stype();
+}
diff --git a/kig/objects/tests_type.h b/kig/objects/tests_type.h
new file mode 100644
index 00000000..7498fc4f
--- /dev/null
+++ b/kig/objects/tests_type.h
@@ -0,0 +1,111 @@
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_TESTS_TYPE_H
+#define KIG_OBJECTS_TESTS_TYPE_H
+
+#include "base_type.h"
+
+class AreParallelType
+ : public ArgsParserObjectType
+{
+ AreParallelType();
+ ~AreParallelType();
+public:
+ static const AreParallelType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class AreOrthogonalType
+ : public ArgsParserObjectType
+{
+ AreOrthogonalType();
+ ~AreOrthogonalType();
+public:
+ static const AreOrthogonalType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class AreCollinearType
+ : public ArgsParserObjectType
+{
+ AreCollinearType();
+ ~AreCollinearType();
+public:
+ static const AreCollinearType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ContainsTestType
+ : public ArgsParserObjectType
+{
+ ContainsTestType();
+ ~ContainsTestType();
+public:
+ static const ContainsTestType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class InPolygonTestType
+ : public ArgsParserObjectType
+{
+ InPolygonTestType();
+ ~InPolygonTestType();
+public:
+ static const InPolygonTestType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class ConvexPolygonTestType
+ : public ArgsParserObjectType
+{
+ ConvexPolygonTestType();
+ ~ConvexPolygonTestType();
+public:
+ static const ConvexPolygonTestType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class SameDistanceType
+ : public ArgsParserObjectType
+{
+ SameDistanceType();
+ ~SameDistanceType();
+public:
+ static const SameDistanceType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class VectorEqualityTestType
+ : public ArgsParserObjectType
+{
+ VectorEqualityTestType();
+ ~VectorEqualityTestType();
+public:
+ static const VectorEqualityTestType* instance();
+ ObjectImp* calc( const Args& parents, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/objects/text_imp.cc b/kig/objects/text_imp.cc
new file mode 100644
index 00000000..f7b2f1be
--- /dev/null
+++ b/kig/objects/text_imp.cc
@@ -0,0 +1,173 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "text_imp.h"
+
+#include "bogus_imp.h"
+#include "../misc/kigpainter.h"
+
+TextImp::TextImp( const QString& text, const Coordinate& loc, bool frame )
+ : mtext( text), mloc( loc ), mframe( frame ), mboundrect( Rect::invalidRect() )
+{
+}
+
+TextImp* TextImp::copy() const
+{
+ return new TextImp( mtext, mloc );
+}
+
+TextImp::~TextImp()
+{
+}
+
+Coordinate TextImp::attachPoint() const
+{
+ return Coordinate::invalidCoord();
+}
+
+ObjectImp* TextImp::transform( const Transformation& t ) const
+{
+ Coordinate nloc = t.apply( mloc );
+ return new TextImp( mtext, nloc, mframe );
+}
+
+void TextImp::draw( KigPainter& p ) const
+{
+ mboundrect = p.simpleBoundingRect( mloc, mtext );
+ p.drawTextFrame( mboundrect, mtext, mframe );
+}
+
+bool TextImp::contains( const Coordinate& p, int, const KigWidget& ) const
+{
+ return mboundrect.contains( p );
+}
+
+bool TextImp::inRect( const Rect& r, int, const KigWidget& ) const
+{
+ return mboundrect.intersects( r );
+}
+
+bool TextImp::valid() const
+{
+ return true;
+}
+
+const uint TextImp::numberOfProperties() const
+{
+ return Parent::numberOfProperties() + 1;
+}
+
+const QCStringList TextImp::propertiesInternalNames() const
+{
+ QCStringList ret = Parent::propertiesInternalNames();
+ ret << "kig_text";
+ return ret;
+}
+
+const QCStringList TextImp::properties() const
+{
+ QCStringList ret = Parent::properties();
+ ret << I18N_NOOP( "Text" );
+ return ret;
+}
+
+const ObjectImpType* TextImp::impRequirementForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::impRequirementForProperty( which );
+ return TextImp::stype();
+}
+
+const char* TextImp::iconForProperty( uint which ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::iconForProperty( which );
+ else if ( which == Parent::numberOfProperties() )
+ return "text"; // text
+ else assert( false );
+ return "";
+}
+
+ObjectImp* TextImp::property( uint which, const KigDocument& w ) const
+{
+ if ( which < Parent::numberOfProperties() )
+ return Parent::property( which, w );
+ else if ( which == Parent::numberOfProperties() )
+ return new StringImp( text() );
+ else assert( false );
+ return new InvalidImp;
+}
+
+QString TextImp::text() const
+{
+ return mtext;
+}
+
+void TextImp::visit( ObjectImpVisitor* vtor ) const
+{
+ vtor->visit( this );
+}
+
+const Coordinate TextImp::coordinate() const
+{
+ return mloc;
+}
+
+bool TextImp::equals( const ObjectImp& rhs ) const
+{
+ return rhs.inherits( TextImp::stype() ) &&
+ static_cast<const TextImp&>( rhs ).coordinate() == coordinate() &&
+ static_cast<const TextImp&>( rhs ).text() == text() &&
+ static_cast<const TextImp&>( rhs ).hasFrame() == hasFrame();
+}
+
+bool TextImp::hasFrame() const
+{
+ return mframe;
+}
+
+const ObjectImpType* TextImp::stype()
+{
+ static const ObjectImpType t(
+ Parent::stype(), "label",
+ I18N_NOOP( "label" ),
+ I18N_NOOP( "Select this label" ),
+ I18N_NOOP( "Select label %1" ),
+ I18N_NOOP( "Remove a Label" ),
+ I18N_NOOP( "Add a Label" ),
+ I18N_NOOP( "Move a Label" ),
+ I18N_NOOP( "Attach to this label" ),
+ I18N_NOOP( "Show a Label" ),
+ I18N_NOOP( "Hide a Label" )
+ );
+ return &t;
+}
+
+const ObjectImpType* TextImp::type() const
+{
+ return TextImp::stype();
+}
+
+bool TextImp::isPropertyDefinedOnOrThroughThisImp( uint which ) const
+{
+ return Parent::isPropertyDefinedOnOrThroughThisImp( which );
+}
+
+Rect TextImp::surroundingRect() const
+{
+ return mboundrect;
+}
diff --git a/kig/objects/text_imp.h b/kig/objects/text_imp.h
new file mode 100644
index 00000000..8ad92b84
--- /dev/null
+++ b/kig/objects/text_imp.h
@@ -0,0 +1,70 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_TEXT_IMP_H
+#define KIG_OBJECTS_TEXT_IMP_H
+
+#include "object_imp.h"
+
+#include "../misc/coordinate.h"
+#include "../misc/rect.h"
+
+class TextImp
+ : public ObjectImp
+{
+ QString mtext;
+ Coordinate mloc;
+ bool mframe;
+ // with this var, we keep track of the place we drew in, for use in
+ // the contains() function..
+ mutable Rect mboundrect;
+public:
+ typedef ObjectImp Parent;
+ static const ObjectImpType* stype();
+
+ Coordinate attachPoint() const;
+ TextImp( const QString& text, const Coordinate& loc, bool frame = false );
+ TextImp* copy() const;
+ ~TextImp();
+
+ ObjectImp* transform( const Transformation& ) const;
+
+ void draw( KigPainter& p ) const;
+ bool contains( const Coordinate& p, int width, const KigWidget& ) const;
+ bool inRect( const Rect& r, int width, const KigWidget& ) const;
+ bool valid() const;
+ Rect surroundingRect() const;
+
+ const uint numberOfProperties() const;
+ const QCStringList properties() const;
+ const QCStringList propertiesInternalNames() const;
+ ObjectImp* property( uint which, const KigDocument& w ) const;
+ const char* iconForProperty( uint which ) const;
+ const ObjectImpType* impRequirementForProperty( uint which ) const;
+ bool isPropertyDefinedOnOrThroughThisImp( uint which ) const;
+
+ const ObjectImpType* type() const;
+ void visit( ObjectImpVisitor* vtor ) const;
+
+ QString text() const;
+ const Coordinate coordinate() const;
+ bool hasFrame() const;
+
+ bool equals( const ObjectImp& rhs ) const;
+};
+
+#endif
diff --git a/kig/objects/text_type.cc b/kig/objects/text_type.cc
new file mode 100644
index 00000000..6594c05a
--- /dev/null
+++ b/kig/objects/text_type.cc
@@ -0,0 +1,215 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "text_type.h"
+
+#include "text_imp.h"
+#include "bogus_imp.h"
+#include "point_imp.h"
+#include "line_imp.h"
+
+#include "../kig/kig_view.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_commands.h"
+#include "../modes/label.h"
+#include "../misc/coordinate_system.h"
+
+#include <algorithm>
+
+#include <qclipboard.h>
+#include <qstringlist.h>
+
+#include <kapplication.h>
+
+#include <cmath>
+
+static const ArgsParser::spec arggspeccs[] =
+{
+ { IntImp::stype(), "UNUSED", "SHOULD NOT BE SEEN", false },
+ { PointImp::stype(), "UNUSED", "SHOULD NOT BE SEEN", false },
+ { StringImp::stype(), "UNUSED", "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TextType )
+
+TextType::TextType()
+ : ObjectType( "Label" ), mparser( arggspeccs, 3 )
+{
+}
+
+TextType::~TextType()
+{
+}
+
+const TextType* TextType::instance()
+{
+ static const TextType t;
+ return &t;
+}
+
+const ObjectImpType* TextType::resultId() const
+{
+ return TextImp::stype();
+}
+
+const ObjectImpType* TextType::impRequirement( const ObjectImp* o, const Args& args ) const
+{
+ assert( args.size() >= 3 );
+ Args firstthree( args.begin(), args.begin() + 3 );
+ if ( o == args[0] || o == args[1] || o == args[2] )
+ return mparser.impRequirement( o, firstthree );
+ else
+ return ObjectImp::stype();
+}
+
+ObjectImp* TextType::calc( const Args& parents, const KigDocument& doc ) const
+{
+ if( parents.size() < 3 ) return new InvalidImp;
+ Args firstthree( parents.begin(), parents.begin() + 3 );
+ Args varargs( parents.begin() + 3, parents.end() );
+
+ if ( ! mparser.checkArgs( firstthree ) ) return new InvalidImp;
+
+ int frame = static_cast<const IntImp*>( firstthree[0] )->data();
+ bool needframe = frame != 0;
+ const Coordinate t = static_cast<const PointImp*>( firstthree[1] )->coordinate();
+ QString s = static_cast<const StringImp*>( firstthree[2] )->data();
+
+ for ( Args::iterator i = varargs.begin(); i != varargs.end(); ++i )
+ (*i)->fillInNextEscape( s, doc );
+
+ return new TextImp( s, t, needframe );
+}
+
+bool TextType::canMove( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+bool TextType::isFreelyTranslatable( const ObjectTypeCalcer& ) const
+{
+ return true;
+}
+
+void TextType::move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& d ) const
+{
+ const std::vector<ObjectCalcer*> parents = ourobj.parents();
+ assert( parents.size() >= 3 );
+ const std::vector<ObjectCalcer*> firstthree( parents.begin(), parents.begin() + 3 );
+ if( dynamic_cast<ObjectConstCalcer*>( firstthree[1] ) )
+ {
+ ObjectConstCalcer* c = static_cast<ObjectConstCalcer*>( firstthree[1] );
+ c->setImp( new PointImp( to ) );
+ }
+ else
+ firstthree[1]->move( to, d );
+}
+
+QStringList TextType::specialActions() const
+{
+ QStringList ret;
+ ret << i18n( "&Copy Text" );
+ ret << i18n( "&Toggle Frame" );
+ ret << i18n( "&Redefine..." );
+ return ret;
+}
+
+void TextType::executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& c,
+ KigPart& doc, KigWidget&,
+ NormalMode& ) const
+{
+ std::vector<ObjectCalcer*> parents = c.parents();
+ assert( parents.size() >= 3 );
+
+ std::vector<ObjectCalcer*> firstthree( parents.begin(), parents.begin() + 3 );
+
+ assert( mparser.checkArgs( firstthree ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( firstthree[0] ) );
+ assert( dynamic_cast<ObjectConstCalcer*>( firstthree[2] ) );
+
+ if ( i == 0 )
+ {
+ QClipboard* cb = kapp->clipboard();
+
+ // copy the text into the clipboard
+ const TextImp* ti = static_cast<const TextImp*>( c.imp() );
+ cb->setText( ti->text(), QClipboard::Clipboard );
+ }
+ else if ( i == 1 )
+ {
+ // toggle label frame
+ int n = (static_cast<const IntImp*>( firstthree[0]->imp() )->data() + 1) % 2;
+ KigCommand* kc = new KigCommand( doc, i18n( "Toggle Label Frame" ) );
+ kc->addTask( new ChangeObjectConstCalcerTask(
+ static_cast<ObjectConstCalcer*>( firstthree[0] ),
+ new IntImp( n ) ) );
+ doc.history()->addCommand( kc );
+ }
+ else if ( i == 2 )
+ {
+ assert( dynamic_cast<ObjectTypeCalcer*>( o.calcer() ) );
+ // redefine..
+ TextLabelRedefineMode m( doc, static_cast<ObjectTypeCalcer*>( o.calcer() ) );
+ doc.runMode( &m );
+ }
+ else assert( false );
+}
+
+const ArgsParser& TextType::argParser() const
+{
+ return mparser;
+}
+
+const Coordinate TextType::moveReferencePoint( const ObjectTypeCalcer& ourobj ) const
+{
+ assert( ourobj.imp()->inherits( TextImp::stype() ) );
+ return static_cast<const TextImp*>( ourobj.imp() )->coordinate();
+}
+
+std::vector<ObjectCalcer*> TextType::sortArgs( const std::vector<ObjectCalcer*>& os ) const
+{
+ assert( os.size() >= 3 );
+ std::vector<ObjectCalcer*> ret( os.begin(), os.begin() + 3 );
+ ret = mparser.parse( ret );
+ std::copy( os.begin() + 3, os.end(), std::back_inserter( ret ) );
+ return ret;
+}
+
+Args TextType::sortArgs( const Args& args ) const
+{
+ assert( args.size() >= 3 );
+ Args ret( args.begin(), args.begin() + 3 );
+ ret = mparser.parse( ret );
+ std::copy( args.begin() + 3, args.end(), std::back_inserter( ret ) );
+ return ret;
+}
+
+std::vector<ObjectCalcer*> TextType::movableParents( const ObjectTypeCalcer& ourobj ) const
+{
+ const std::vector<ObjectCalcer*> parents = ourobj.parents();
+ assert( parents.size() >= 3 );
+ std::vector<ObjectCalcer*> ret = parents[1]->movableParents();
+ ret.push_back( parents[1] );
+ return ret;
+}
+
+bool TextType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
+{
+ return false;
+}
+
diff --git a/kig/objects/text_type.h b/kig/objects/text_type.h
new file mode 100644
index 00000000..6368cafa
--- /dev/null
+++ b/kig/objects/text_type.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_TEXT_TYPE_H
+#define KIG_OBJECTS_TEXT_TYPE_H
+
+#include "object_type.h"
+
+class TextType
+ : public ObjectType
+{
+ const ArgsParser mparser;
+ TextType();
+ ~TextType();
+public:
+ static const TextType* instance();
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ const ObjectImpType* resultId() const;
+
+ ObjectImp* calc( const Args& parents, const KigDocument& d ) const;
+
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& os ) const;
+ Args sortArgs( const Args& args ) const;
+
+ bool canMove( const ObjectTypeCalcer& ourobj ) const;
+ bool isFreelyTranslatable( const ObjectTypeCalcer& ourobj ) const;
+ std::vector<ObjectCalcer*> movableParents( const ObjectTypeCalcer& ourobj ) const;
+ const Coordinate moveReferencePoint( const ObjectTypeCalcer& ourobj ) const;
+ void move( ObjectTypeCalcer& ourobj, const Coordinate& to,
+ const KigDocument& ) const;
+
+ QStringList specialActions() const;
+ void executeAction( int i, ObjectHolder& o, ObjectTypeCalcer& c,
+ KigPart& d, KigWidget& w, NormalMode& m ) const;
+
+ const ArgsParser& argParser() const;
+};
+
+#endif
diff --git a/kig/objects/transform_types.cc b/kig/objects/transform_types.cc
new file mode 100644
index 00000000..3a8d32db
--- /dev/null
+++ b/kig/objects/transform_types.cc
@@ -0,0 +1,874 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "transform_types.h"
+
+#include "bogus_imp.h"
+#include "point_imp.h"
+#include "line_imp.h"
+#include "other_imp.h"
+#include "polygon_imp.h"
+#include "../misc/coordinate.h"
+#include "../misc/kigtransform.h"
+
+#include <cmath>
+
+static const ArgsParser::spec argsspecTranslation[] =
+{
+ { ObjectImp::stype(), I18N_NOOP("Translate this object"),
+ I18N_NOOP( "Select the object to translate..." ), false },
+ { VectorImp::stype(), I18N_NOOP("Translate by this vector"),
+ I18N_NOOP( "Select the vector to translate by..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( TranslatedType )
+
+TranslatedType::TranslatedType()
+ : ArgsParserObjectType( "Translation", argsspecTranslation, 2 )
+{
+}
+
+TranslatedType::~TranslatedType()
+{
+}
+
+const TranslatedType* TranslatedType::instance()
+{
+ static const TranslatedType t;
+ return &t;
+}
+
+ObjectImp* TranslatedType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate dir = static_cast<const VectorImp*>( args[1] )->dir();
+ Transformation t = Transformation::translation( dir );
+
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecPointReflection[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Reflect this object" ),
+ I18N_NOOP( "Select the object to reflect..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Reflect in this point" ),
+ I18N_NOOP( "Select the point to reflect in..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PointReflectionType )
+
+PointReflectionType::PointReflectionType()
+ : ArgsParserObjectType( "PointReflection", argsspecPointReflection, 2 )
+{
+}
+
+PointReflectionType::~PointReflectionType()
+{
+}
+
+const PointReflectionType* PointReflectionType::instance()
+{
+ static const PointReflectionType t;
+ return &t;
+}
+
+ObjectImp* PointReflectionType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate center = static_cast<const PointImp*>( args[1] )->coordinate();
+ Transformation t = Transformation::pointReflection( center );
+
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecLineReflection[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Reflect this object" ),
+ I18N_NOOP( "Select the object to reflect..." ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Reflect in this line" ),
+ I18N_NOOP( "Select the line to reflect in..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( LineReflectionType )
+
+LineReflectionType::LineReflectionType()
+ : ArgsParserObjectType( "LineReflection", argsspecLineReflection, 2 )
+{
+}
+
+LineReflectionType::~LineReflectionType()
+{
+}
+
+const LineReflectionType* LineReflectionType::instance()
+{
+ static const LineReflectionType t;
+ return &t;
+}
+
+ObjectImp* LineReflectionType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ LineData d = static_cast<const AbstractLineImp*>( args[1] )->data();
+ Transformation t = Transformation::lineReflection( d );
+
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecRotation[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Rotate this object" ),
+ I18N_NOOP( "Select the object to rotate..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Rotate around this point" ),
+ I18N_NOOP( "Select the center point of the rotation..." ), false },
+ { AngleImp::stype(), I18N_NOOP( "Rotate by this angle" ),
+ I18N_NOOP( "Select the angle of the rotation..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( RotationType )
+
+RotationType::RotationType()
+ : ArgsParserObjectType( "Rotation", argsspecRotation, 3 )
+{
+}
+
+RotationType::~RotationType()
+{
+}
+
+const RotationType* RotationType::instance()
+{
+ static const RotationType t;
+ return &t;
+}
+
+ObjectImp* RotationType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate center = static_cast<const PointImp*>( args[1] )->coordinate();
+ double angle = static_cast<const AngleImp*>( args[2] )->size();
+
+ return args[0]->transform( Transformation::rotation( angle, center ) );
+}
+
+static const ArgsParser::spec argsspecScalingOverCenter[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Scale this object" ),
+ I18N_NOOP( "Select the object to scale..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Scale with this center" ),
+ I18N_NOOP( "Select the center point of the scaling..." ), false },
+ { SegmentImp::stype(), I18N_NOOP( "Scale by the length of this segment" ),
+ I18N_NOOP( "Select a segment whose length is the factor of the scaling..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ScalingOverCenterType )
+
+ScalingOverCenterType::ScalingOverCenterType()
+ : ArgsParserObjectType( "ScalingOverCenter", argsspecScalingOverCenter, 3 )
+{
+}
+
+ScalingOverCenterType::~ScalingOverCenterType()
+{
+}
+
+const ScalingOverCenterType* ScalingOverCenterType::instance()
+{
+ static const ScalingOverCenterType t;
+ return &t;
+}
+
+ObjectImp* ScalingOverCenterType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate center = static_cast<const PointImp*>( args[1] )->coordinate();
+ double ratio = static_cast<const SegmentImp*>( args[2] )->length();
+
+ return args[0]->transform( Transformation::scalingOverPoint( ratio, center ) );
+}
+
+static const ArgsParser::spec argsspecScalingOverCenter2[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Scale this object" ),
+ I18N_NOOP( "Select the object to scale..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Scale with this center" ),
+ I18N_NOOP( "Select the center point of the scaling..." ), false },
+ { SegmentImp::stype(), I18N_NOOP( "Scale the length of this segment..." ),
+ I18N_NOOP( "Select the first of two segments whose ratio is the factor of the scaling..." ), false },
+ { SegmentImp::stype(), I18N_NOOP( "...to the length of this other segment" ),
+ I18N_NOOP( "Select the second of two segments whose ratio is the factor of the scaling..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ScalingOverCenter2Type )
+
+ScalingOverCenter2Type::ScalingOverCenter2Type()
+ : ArgsParserObjectType( "ScalingOverCenter2", argsspecScalingOverCenter2, 4 )
+{
+}
+
+ScalingOverCenter2Type::~ScalingOverCenter2Type()
+{
+}
+
+const ScalingOverCenter2Type* ScalingOverCenter2Type::instance()
+{
+ static const ScalingOverCenter2Type t;
+ return &t;
+}
+
+ObjectImp* ScalingOverCenter2Type::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate center = static_cast<const PointImp*>( args[1] )->coordinate();
+ double ratio = static_cast<const SegmentImp*>( args[3] )->length()/
+ static_cast<const SegmentImp*>( args[2] )->length();
+
+ return args[0]->transform( Transformation::scalingOverPoint( ratio, center ) );
+}
+
+static const ArgsParser::spec argsspecScalingOverLine[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Scale this object" ), I18N_NOOP( "Select the object to scale" ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Scale over this line" ), I18N_NOOP( "Select the line to scale over" ), false },
+ { SegmentImp::stype(), I18N_NOOP( "Scale by the length of this segment" ), I18N_NOOP( "Select a segment whose length is the factor for the scaling" ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ScalingOverLineType )
+
+ScalingOverLineType::ScalingOverLineType()
+ : ArgsParserObjectType( "ScalingOverLine", argsspecScalingOverLine, 3 )
+{
+}
+
+ScalingOverLineType::~ScalingOverLineType()
+{
+}
+
+const ScalingOverLineType* ScalingOverLineType::instance()
+{
+ static const ScalingOverLineType t;
+ return &t;
+}
+
+ObjectImp* ScalingOverLineType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ LineData line = static_cast<const AbstractLineImp*>( args[1] )->data();
+ double ratio = static_cast<const SegmentImp*>( args[2] )->length();
+
+ return args[0]->transform( Transformation::scalingOverLine( ratio, line ) );
+}
+
+static const ArgsParser::spec argsspecScalingOverLine2[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Scale this object" ), I18N_NOOP( "Select the object to scale" ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Scale over this line" ), I18N_NOOP( "Select the line to scale over" ), false },
+ { SegmentImp::stype(), I18N_NOOP( "Scale the length of this segment..." ), I18N_NOOP( "Select the first of two segments whose ratio is the factor for the scaling" ), false },
+ { SegmentImp::stype(), I18N_NOOP( "...to the length of this segment" ), I18N_NOOP( "Select the second of two segments whose ratio is the factor for the scaling" ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ScalingOverLine2Type )
+
+ScalingOverLine2Type::ScalingOverLine2Type()
+ : ArgsParserObjectType( "ScalingOverLine2", argsspecScalingOverLine2, 4 )
+{
+}
+
+ScalingOverLine2Type::~ScalingOverLine2Type()
+{
+}
+
+const ScalingOverLine2Type* ScalingOverLine2Type::instance()
+{
+ static const ScalingOverLine2Type t;
+ return &t;
+}
+
+ObjectImp* ScalingOverLine2Type::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ LineData line = static_cast<const AbstractLineImp*>( args[1] )->data();
+ double ratio = static_cast<const SegmentImp*>( args[3] )->length()/
+ static_cast<const SegmentImp*>( args[2] )->length();
+
+ return args[0]->transform( Transformation::scalingOverLine( ratio, line ) );
+}
+
+static const ArgsParser::spec argsspecProjectiveRotation[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Projectively rotate this object" ), I18N_NOOP( "Select the object to rotate projectively" ), false },
+ { RayImp::stype(), I18N_NOOP( "Projectively rotate with this half-line" ), I18N_NOOP( "Select the half line of the projective rotation that you want to apply to the object" ), false },
+ { AngleImp::stype(), I18N_NOOP( "Projectively rotate by this angle" ), I18N_NOOP( "Select the angle of the projective rotation that you want to apply to the object" ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ProjectiveRotationType )
+
+ProjectiveRotationType::ProjectiveRotationType()
+ : ArgsParserObjectType( "ProjectiveRotation", argsspecProjectiveRotation, 3 )
+{
+}
+
+ProjectiveRotationType::~ProjectiveRotationType()
+{
+}
+
+const ProjectiveRotationType* ProjectiveRotationType::instance()
+{
+ static const ProjectiveRotationType t;
+ return &t;
+}
+
+ObjectImp* ProjectiveRotationType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const RayImp* ray = static_cast<const RayImp*>( args[1] );
+ Coordinate c1 = ray->data().a;
+ Coordinate dir = ray->data().dir().normalize();
+ double alpha = static_cast<const AngleImp*>( args[2] )->size();
+
+ return args[0]->transform(
+ Transformation::projectiveRotation( alpha, dir, c1 ) );
+}
+
+static const ArgsParser::spec argsspecHarmonicHomology[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Harmonic Homology of this object" ),
+ I18N_NOOP( "Select the object to transform..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Harmonic Homology with this center" ),
+ I18N_NOOP( "Select the center point of the harmonic homology..." ), false },
+ { AbstractLineImp::stype(), I18N_NOOP( "Harmonic Homology with this axis" ),
+ I18N_NOOP( "Select the axis of the harmonic homology..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( HarmonicHomologyType )
+
+HarmonicHomologyType::HarmonicHomologyType()
+ : ArgsParserObjectType( "HarmonicHomology", argsspecHarmonicHomology, 3 )
+{
+}
+
+HarmonicHomologyType::~HarmonicHomologyType()
+{
+}
+
+const HarmonicHomologyType* HarmonicHomologyType::instance()
+{
+ static const HarmonicHomologyType t;
+ return &t;
+}
+
+ObjectImp* HarmonicHomologyType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate center = static_cast<const PointImp*>( args[1] )->coordinate();
+ LineData axis = static_cast<const AbstractLineImp*>( args[2] )->data();
+ return args[0]->transform(
+ Transformation::harmonicHomology( center, axis ) );
+}
+
+static const ArgsParser::spec argsspecAffinityB2Tr[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Generic affinity of this object" ),
+ I18N_NOOP( "Select the object to transform..." ), false },
+ { PolygonImp::stype3(), I18N_NOOP( "Map this triangle" ),
+ I18N_NOOP( "Select the triangle that has to be transformed onto a given triangle..." ), false },
+ { PolygonImp::stype3(), I18N_NOOP( "onto this other triangle" ),
+ I18N_NOOP( "Select the triangle that is the image by the affinity of the first triangle..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( AffinityB2TrType )
+
+AffinityB2TrType::AffinityB2TrType()
+ : ArgsParserObjectType( "AffinityB2Tr", argsspecAffinityB2Tr, 3 )
+{
+}
+
+AffinityB2TrType::~AffinityB2TrType()
+{
+}
+
+const AffinityB2TrType* AffinityB2TrType::instance()
+{
+ static const AffinityB2TrType t;
+ return &t;
+}
+
+ObjectImp* AffinityB2TrType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ std::vector<Coordinate> frompoints = static_cast<const PolygonImp*>( args[1] )->points();
+ std::vector<Coordinate> topoints = static_cast<const PolygonImp*>( args[2] )->points();
+
+ bool valid = true;
+ Transformation t = Transformation::affinityGI3P( frompoints, topoints,
+ valid );
+
+ if (valid == false) return new InvalidImp;
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecAffinityGI3P[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Generic affinity of this object" ),
+ I18N_NOOP( "Select the object to transform..." ), false },
+ { PointImp::stype(), I18N_NOOP( "First of 3 starting points" ),
+ I18N_NOOP( "Select the first of the three starting points of the generic affinity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Second of 3 starting points" ),
+ I18N_NOOP( "Select the second of the three starting points of the generic affinity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Third of 3 starting points" ),
+ I18N_NOOP( "Select the third of the three starting points of the generic affinity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of first point" ),
+ I18N_NOOP( "Select the first of the three end points of the generic affinity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of second point" ),
+ I18N_NOOP( "Select the second of the three end points of the generic affinity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of third point" ),
+ I18N_NOOP( "Select the third of the three end points of the generic affinity..." ), false },
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( AffinityGI3PType )
+
+AffinityGI3PType::AffinityGI3PType()
+ : ArgsParserObjectType( "AffinityGI3P", argsspecAffinityGI3P, 7 )
+{
+}
+
+AffinityGI3PType::~AffinityGI3PType()
+{
+}
+
+const AffinityGI3PType* AffinityGI3PType::instance()
+{
+ static const AffinityGI3PType t;
+ return &t;
+}
+
+ObjectImp* AffinityGI3PType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ std::vector<Coordinate> frompoints;
+ std::vector<Coordinate> topoints;
+ for ( uint i = 0; i < 3; ++i )
+ {
+ frompoints.push_back(
+ static_cast<const PointImp*>( args[i+1] )->coordinate() );
+ topoints.push_back(
+ static_cast<const PointImp*>( args[i+4] )->coordinate() );
+ }
+
+ bool valid = true;
+ Transformation t = Transformation::affinityGI3P( frompoints, topoints,
+ valid );
+
+ if (valid == false) return new InvalidImp;
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecProjectivityB2Qu[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Generic projective transformation of this object" ),
+ I18N_NOOP( "Select the object to transform..." ), false },
+ { PolygonImp::stype4(), I18N_NOOP( "Map this quadrilateral" ),
+ I18N_NOOP( "Select the quadrilateral that has to be transformed onto a given quadrilateral..." ), false },
+ { PolygonImp::stype4(), I18N_NOOP( "onto this other quadrilateral" ),
+ I18N_NOOP( "Select the quadrilateral that is the image by the projective transformation of the first quadrilateral..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ProjectivityB2QuType )
+
+ProjectivityB2QuType::ProjectivityB2QuType()
+ : ArgsParserObjectType( "ProjectivityB2Qu", argsspecProjectivityB2Qu, 3 )
+{
+}
+
+ProjectivityB2QuType::~ProjectivityB2QuType()
+{
+}
+
+const ProjectivityB2QuType* ProjectivityB2QuType::instance()
+{
+ static const ProjectivityB2QuType t;
+ return &t;
+}
+
+ObjectImp* ProjectivityB2QuType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ std::vector<Coordinate> frompoints = static_cast<const PolygonImp*>( args[1] )->points();
+ std::vector<Coordinate> topoints = static_cast<const PolygonImp*>( args[2] )->points();
+
+ bool valid = true;
+ Transformation t = Transformation::projectivityGI4P( frompoints, topoints,
+ valid );
+
+ if (valid == false) return new InvalidImp;
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecProjectivityGI4P[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Generic projective transformation of this object" ),
+ I18N_NOOP( "Select the object to transform..." ), false },
+ { PointImp::stype(), I18N_NOOP( "First of 4 starting points" ),
+ I18N_NOOP( "Select the first of the four starting points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Second of 4 starting points" ),
+ I18N_NOOP( "Select the second of the four starting points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Third of 4 starting points" ),
+ I18N_NOOP( "Select the third of the four starting points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Fourth of 4 starting points" ),
+ I18N_NOOP( "Select the fourth of the four starting points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of first point" ),
+ I18N_NOOP( "Select the first of the four end points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of second point" ),
+ I18N_NOOP( "Select the second of the four end points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of third point" ),
+ I18N_NOOP( "Select the third of the four end points of the generic projectivity..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Transformed position of fourth point" ),
+ I18N_NOOP( "Select the fourth of the four end points of the generic projectivity..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ProjectivityGI4PType )
+
+ProjectivityGI4PType::ProjectivityGI4PType()
+ : ArgsParserObjectType( "ProjectivityGI4P", argsspecProjectivityGI4P, 9 )
+{
+}
+
+ProjectivityGI4PType::~ProjectivityGI4PType()
+{
+}
+
+const ProjectivityGI4PType* ProjectivityGI4PType::instance()
+{
+ static const ProjectivityGI4PType t;
+ return &t;
+}
+
+ObjectImp* ProjectivityGI4PType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ std::vector<Coordinate> frompoints;
+ std::vector<Coordinate> topoints;
+ for ( uint i = 0; i < 4; ++i )
+ {
+ frompoints.push_back(
+ static_cast<const PointImp*>( args[i+1] )->coordinate() );
+ topoints.push_back(
+ static_cast<const PointImp*>( args[i+5] )->coordinate() );
+ }
+
+ bool valid = true;
+ Transformation t = Transformation::projectivityGI4P( frompoints, topoints,
+ valid );
+
+ if (valid == false) return new InvalidImp;
+ return args[0]->transform( t );
+}
+
+static const ArgsParser::spec argsspecCastShadow[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Cast the shadow of this object" ),
+ I18N_NOOP( "Select the object of which you want to construct the shadow..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Cast a shadow from this light source" ),
+ I18N_NOOP( "Select the light source from which the shadow should originate..." ), false },
+ { AbstractLineImp::stype(),
+ I18N_NOOP( "Cast a shadow on the horizon represented by this line" ),
+ I18N_NOOP( "Select the horizon for the shadow..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( CastShadowType )
+
+CastShadowType::CastShadowType()
+ : ArgsParserObjectType( "CastShadow", argsspecCastShadow, 3 )
+{
+}
+
+CastShadowType::~CastShadowType()
+{
+}
+
+const CastShadowType* CastShadowType::instance()
+{
+ static const CastShadowType t;
+ return &t;
+}
+
+ObjectImp* CastShadowType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate lightsrc = static_cast<const PointImp*>( args[1] )->coordinate();
+ LineData d = static_cast<const AbstractLineImp*>( args[2] )->data();
+ return args[0]->transform(
+ Transformation::castShadow( lightsrc, d ) );
+}
+
+const ObjectImpType* TranslatedType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* PointReflectionType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* LineReflectionType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* RotationType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ScalingOverCenterType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ScalingOverCenter2Type::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ScalingOverLineType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ScalingOverLine2Type::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ProjectiveRotationType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* HarmonicHomologyType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* AffinityB2TrType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* AffinityGI3PType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ProjectivityB2QuType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* ProjectivityGI4PType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const ObjectImpType* CastShadowType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+bool TranslatedType::isTransform() const
+{
+ return true;
+}
+
+bool PointReflectionType::isTransform() const
+{
+ return true;
+}
+
+bool LineReflectionType::isTransform() const
+{
+ return true;
+}
+
+bool RotationType::isTransform() const
+{
+ return true;
+}
+
+bool ScalingOverCenterType::isTransform() const
+{
+ return true;
+}
+
+bool ScalingOverCenter2Type::isTransform() const
+{
+ return true;
+}
+
+bool ScalingOverLineType::isTransform() const
+{
+ return true;
+}
+
+bool ScalingOverLine2Type::isTransform() const
+{
+ return true;
+}
+
+bool ProjectiveRotationType::isTransform() const
+{
+ return true;
+}
+
+bool HarmonicHomologyType::isTransform() const
+{
+ return true;
+}
+
+bool AffinityB2TrType::isTransform() const
+{
+ return true;
+}
+
+bool AffinityGI3PType::isTransform() const
+{
+ return true;
+}
+
+bool ProjectivityB2QuType::isTransform() const
+{
+ return true;
+}
+
+bool ProjectivityGI4PType::isTransform() const
+{
+ return true;
+}
+
+bool CastShadowType::isTransform() const
+{
+ return true;
+}
+
+static const ArgsParser::spec argsspecApplyTransformation[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Transform this object" ), "SHOULD NOT BE SEEN", false },
+ { TransformationImp::stype(), I18N_NOOP( "Transform using this transformation" ), "SHOULD NOT BE SEEN", false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( ApplyTransformationObjectType )
+
+ApplyTransformationObjectType::ApplyTransformationObjectType()
+ : ArgsParserObjectType( "ApplyTransformation", argsspecApplyTransformation, 2 )
+{
+}
+
+ApplyTransformationObjectType::~ApplyTransformationObjectType()
+{
+}
+
+const ApplyTransformationObjectType* ApplyTransformationObjectType::instance()
+{
+ static const ApplyTransformationObjectType t;
+ return &t;
+}
+
+ObjectImp* ApplyTransformationObjectType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+ return args[0]->transform( static_cast<const TransformationImp*>( args[1] )->data() );
+}
+
+const ObjectImpType* ApplyTransformationObjectType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+bool ApplyTransformationObjectType::isTransform() const
+{
+ return true;
+}
+
+bool SimilitudeType::isTransform() const
+{
+ return true;
+}
+
+const ObjectImpType* SimilitudeType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+const SimilitudeType* SimilitudeType::instance()
+{
+ static const SimilitudeType t;
+ return &t;
+}
+
+ObjectImp* SimilitudeType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ Coordinate c = static_cast<const PointImp*>( args[1] )->coordinate();
+ Coordinate a = static_cast<const PointImp*>( args[2] )->coordinate();
+ Coordinate b = static_cast<const PointImp*>( args[3] )->coordinate();
+ a -= c;
+ b -= c;
+ double factor = sqrt( b.squareLength()/a.squareLength() );
+ double theta = atan2( b.y, b.x ) - atan2( a.y, a.x );
+
+ return args[0]->transform( Transformation::similitude( c, theta, factor ) );
+}
+
+SimilitudeType::~SimilitudeType()
+{
+}
+
+static const ArgsParser::spec argsspecSimilitude[] =
+{
+ { ObjectImp::stype(), I18N_NOOP( "Apply a similitude to this object" ),
+ I18N_NOOP( "Select the object to transform..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Apply a similitude with this center" ),
+ I18N_NOOP( "Select the center for the similitude..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Apply a similitude mapping this point onto another point" ),
+ I18N_NOOP( "Select the point which the similitude should map onto another point..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Apply a similitude mapping a point onto this point" ),
+ I18N_NOOP( "Select the point onto which the similitude should map the first point..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( SimilitudeType )
+
+SimilitudeType::SimilitudeType()
+ : ArgsParserObjectType( "Similitude", argsspecSimilitude, 4 )
+{
+}
diff --git a/kig/objects/transform_types.h b/kig/objects/transform_types.h
new file mode 100644
index 00000000..038be068
--- /dev/null
+++ b/kig/objects/transform_types.h
@@ -0,0 +1,243 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_TRANSFORM_TYPES_H
+#define KIG_OBJECTS_TRANSFORM_TYPES_H
+
+#include "object_type.h"
+
+class TranslatedType
+ : public ArgsParserObjectType
+{
+ TranslatedType();
+ ~TranslatedType();
+public:
+ static const TranslatedType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class PointReflectionType
+ : public ArgsParserObjectType
+{
+ PointReflectionType();
+ ~PointReflectionType();
+public:
+ static const PointReflectionType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class LineReflectionType
+ : public ArgsParserObjectType
+{
+ LineReflectionType();
+ ~LineReflectionType();
+public:
+ static const LineReflectionType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class RotationType
+ : public ArgsParserObjectType
+{
+ RotationType();
+ ~RotationType();
+public:
+ static const RotationType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ScalingOverCenterType
+ : public ArgsParserObjectType
+{
+ ScalingOverCenterType();
+ ~ScalingOverCenterType();
+public:
+ static const ScalingOverCenterType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ScalingOverCenter2Type
+ : public ArgsParserObjectType
+{
+ ScalingOverCenter2Type();
+ ~ScalingOverCenter2Type();
+public:
+ static const ScalingOverCenter2Type* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ScalingOverLineType
+ : public ArgsParserObjectType
+{
+ ScalingOverLineType();
+ ~ScalingOverLineType();
+public:
+ static const ScalingOverLineType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ScalingOverLine2Type
+ : public ArgsParserObjectType
+{
+ ScalingOverLine2Type();
+ ~ScalingOverLine2Type();
+public:
+ static const ScalingOverLine2Type* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ProjectiveRotationType
+ : public ArgsParserObjectType
+{
+ ProjectiveRotationType();
+ ~ProjectiveRotationType();
+public:
+ static const ProjectiveRotationType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class HarmonicHomologyType
+ : public ArgsParserObjectType
+{
+ HarmonicHomologyType();
+ ~HarmonicHomologyType();
+public:
+ static const HarmonicHomologyType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class AffinityB2TrType
+ : public ArgsParserObjectType
+{
+ AffinityB2TrType();
+ ~AffinityB2TrType();
+public:
+ static const AffinityB2TrType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class AffinityGI3PType
+ : public ArgsParserObjectType
+{
+ AffinityGI3PType();
+ ~AffinityGI3PType();
+public:
+ static const AffinityGI3PType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ProjectivityB2QuType
+ : public ArgsParserObjectType
+{
+ ProjectivityB2QuType();
+ ~ProjectivityB2QuType();
+public:
+ static const ProjectivityB2QuType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ProjectivityGI4PType
+ : public ArgsParserObjectType
+{
+ ProjectivityGI4PType();
+ ~ProjectivityGI4PType();
+public:
+ static const ProjectivityGI4PType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class CastShadowType
+ : public ArgsParserObjectType
+{
+ CastShadowType();
+ ~CastShadowType();
+public:
+ static const CastShadowType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+class ApplyTransformationObjectType
+ : public ArgsParserObjectType
+{
+ ApplyTransformationObjectType();
+ ~ApplyTransformationObjectType();
+public:
+ static const ApplyTransformationObjectType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+ bool isTransform() const;
+};
+
+class SimilitudeType
+ : public ArgsParserObjectType
+{
+ SimilitudeType();
+ ~SimilitudeType();
+public:
+ static const SimilitudeType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+
+ bool isTransform() const;
+};
+
+#endif
diff --git a/kig/objects/vector_type.cc b/kig/objects/vector_type.cc
new file mode 100644
index 00000000..d96be07b
--- /dev/null
+++ b/kig/objects/vector_type.cc
@@ -0,0 +1,100 @@
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "vector_type.h"
+
+#include "point_imp.h"
+#include "other_imp.h"
+#include "bogus_imp.h"
+
+static const ArgsParser::spec argsspecVector[] =
+{
+ { PointImp::stype(), I18N_NOOP( "Construct a vector from this point" ),
+ I18N_NOOP( "Select the start point of the new vector..." ), true },
+ { PointImp::stype(), I18N_NOOP( "Construct a vector to this point" ),
+ I18N_NOOP( "Select the end point of the new vector..." ), true }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( VectorType )
+
+VectorType::VectorType()
+ : ObjectABType( "Vector", argsspecVector, 2 )
+{
+}
+
+VectorType::~VectorType()
+{
+}
+
+const VectorType* VectorType::instance()
+{
+ static const VectorType t;
+ return &t;
+}
+
+ObjectImp* VectorType::calc( const Coordinate& a, const Coordinate& b ) const
+{
+ return new VectorImp( a, b );
+}
+
+const ObjectImpType* VectorType::resultId() const
+{
+ return VectorImp::stype();
+}
+
+static const ArgsParser::spec argsspecVectorSum[] =
+{
+ { VectorImp::stype(), I18N_NOOP( "Construct the vector sum of this vector and another one." ),
+ I18N_NOOP( "Select the first of the two vectors of which you want to construct the sum..." ), false },
+ { VectorImp::stype(), I18N_NOOP( "Construct the vector sum of this vector and the other one." ),
+ I18N_NOOP( "Select the other of the two vectors of which you want to construct the sum..." ), false },
+ { PointImp::stype(), I18N_NOOP( "Construct the vector sum starting at this point." ),
+ I18N_NOOP( "Select the point to construct the sum vector in..." ), false }
+};
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( VectorSumType )
+
+VectorSumType::VectorSumType()
+ : ArgsParserObjectType( "VectorSum", argsspecVectorSum, 3 )
+{
+}
+
+VectorSumType::~VectorSumType()
+{
+}
+
+const VectorSumType* VectorSumType::instance()
+{
+ static const VectorSumType t;
+ return &t;
+}
+
+ObjectImp* VectorSumType::calc( const Args& args, const KigDocument& ) const
+{
+ if ( ! margsparser.checkArgs( args ) ) return new InvalidImp;
+
+ const VectorImp& a = *static_cast<const VectorImp*>( args[0] );
+ const VectorImp& b = *static_cast<const VectorImp*>( args[1] );
+ const PointImp& p = *static_cast<const PointImp*>( args[2] );
+
+ return new VectorImp( p.coordinate(), p.coordinate() + a.dir() + b.dir() );
+}
+
+const ObjectImpType* VectorSumType::resultId() const
+{
+ return VectorImp::stype();
+}
diff --git a/kig/objects/vector_type.h b/kig/objects/vector_type.h
new file mode 100644
index 00000000..e1756ba5
--- /dev/null
+++ b/kig/objects/vector_type.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2004 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_OBJECTS_VECTOR_TYPE_H
+#define KIG_OBJECTS_VECTOR_TYPE_H
+
+#include "base_type.h"
+
+class VectorType
+ : public ObjectABType
+{
+ VectorType();
+ ~VectorType();
+public:
+ static const VectorType* instance();
+ ObjectImp* calc( const Coordinate& a, const Coordinate& b ) const;
+ const ObjectImpType* resultId() const;
+};
+
+class VectorSumType
+ : public ArgsParserObjectType
+{
+ VectorSumType();
+ ~VectorSumType();
+public:
+ static const VectorSumType* instance();
+ ObjectImp* calc( const Args& args, const KigDocument& ) const;
+ const ObjectImpType* resultId() const;
+};
+
+#endif
diff --git a/kig/package-kig.sh.in b/kig/package-kig.sh.in
new file mode 100644
index 00000000..7f3d609e
--- /dev/null
+++ b/kig/package-kig.sh.in
@@ -0,0 +1,28 @@
+#! /bin/bash
+
+# this is mostly a log for myself for remembering how to build the kig
+# packages.
+
+OLDPWD=$(pwd)
+
+VERSION="@KIGVERSION@"
+NAME="kig"
+
+TEMPDIR="/tmp/$NAME-package-temp"
+rm -rf $TEMPDIR
+mkdir $TEMPDIR
+cd $TEMPDIR
+
+~domi/src/kdesdk/scripts/cvs2dist \
+ --name "$NAME" \
+ --version "$VERSION" \
+ --log="$TEMPDIR/log" \
+ ~/src/package/kdeedu kig
+
+cd $OLDPWD
+
+echo " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! "
+echo "Don't forget to change #MIN_CONFIG in "
+echo "configure.in.in to "
+echo "#MIN_CONFIG( 3.0 ) on packaging, so kig "
+echo "won't depend on Qt 3.1 but 3.0."
diff --git a/kig/pykig/API.txt b/kig/pykig/API.txt
new file mode 100644
index 00000000..e775ac76
--- /dev/null
+++ b/kig/pykig/API.txt
@@ -0,0 +1,182 @@
+Version 0.2.4
+
+There are two way to use pykig.py:
+- as a program:
+ $ pykig.py <nameprog>.kpy
+- as a Python library within a Python program:
+ from pykig import *
+
+A ".kpy" file is a "python" script.
+
+A new object is created by callig a python "constructor";
+the result can be stored in a python variable for later
+use. E.g.:
+
+ a = Point(0.5, 1.5, name="A")
+
+to create a point with coordinates (0.5, 1.5), give it a
+the name "A" (at kig level) and recall it in the python
+variable a. See the examples for practical use.
+
+All constructors accept some optional parameters:
+
+shown = HIDDEN | VISIBLE default value: VISIBLE
+name = string a name to refer to the object within
+ kig
+internal = bool this object is internal and cannot be
+ made visible
+width = integer the line width
+pointstyle = "Round"|"RoundEmpty"|"Rectangular"|"RectangularEmpty"|"Cross"
+linestyle = "SolidLine"|"DashLine"|"DashDotLine"|"DashDotDotLine"|"DotLine"
+color = "#RRGGBB" where RR, GG, BB are three numbers
+ wich represent the red, green, blue
+ components
+
+The kigdocument is a global object to allow two methods for modify Kig look and
+default behaviour:
+
+kigdocument.noaxes()
+kigdocument.nogrid()
+kigdocument.hideobjects()
+kigdocument.showobjects()
+kigdocument.setwidth()
+kigdocument.setpointstyle()
+kigdocument.setname()
+kigdocument.setlinestyle()
+kigdocument.setshown()
+kigdocument.setcolor()
+kigdocument.setinternal()
+
+
+Generic methods for objects:
+
+obj.hide()
+obj.show() hide/show given object
+obj.setwidth(width) set obj width
+obj.setpointstyle(self, pointstyle) set obj point style
+obj.setlinestyle(self, linestyle) set obj line style
+obj.setcolor(self, color) set obj color
+obj.setname() set obj name
+obj.type() return obj type
+
+Some objects have other methods:
+
+obj.coordinate() for points
+obj.xcoord()
+obj.ycoord()
+obj.midpoint() for segments
+obj.endpointA()
+obj.endpointB()
+obj.length()
+obj.equation()
+obj.slope()
+obj.numofsides() for polygons
+obj.perimeter()
+obj.surface()
+obj.centerofmass()
+obj.windingnumber()
+obj.center() for circles
+obj.bisector() for angles
+obj.support()
+
+====================================================================
+
+Properties:
+
+Type(object) type of object
+Coordinate(point) coordinate of point
+XCoord(point)
+YCoord(point)
+MidPoints(a, b) midpoint of two points a and b
+MidPoint(segment) midpoint of a segment
+EndPointA(segment)
+EndPointB(segment)
+Length(segment)
+Equation(segment)
+Slope(segment)
+NumOfSides(poly)
+Perimeter(poly)
+Surface(poly)
+CenterOfMass(poly)
+WindingNumber(poly)
+Center(circle)
+Bisector(angle)
+Support(object)
+====================================================================
+
+Objects:
+
+Point(x, y) free (unconstrained) point
+ConstrainedPoint(t, curve) constrained point on 'curve'; t
+ *must* be in [0,1]; for segments and
+ arcs the position of the point is
+ proportional to the value of t
+Line(a, b) straight line through a and b
+Ray(a, b) halfline starting in a through b
+Segment(a, b) segment from a to b
+Orthogonal(line, point) line through 'point' orthogonal to
+ 'line'
+
+Circle(center, point)
+CircleByCenterRadius(center, radius)
+CircleBy3Points(p1, p2, p3)
+ArcBy3Points(p1, p2, p3)
+ArcByCenterPointAngle(center, point, angle)
+
+ParabolaByDirectrixFocus(directrix, focus)
+VerticalCubic(p1, p2, p3, p4)
+ConicArc(p1, p2, p3, center)
+
+LineLineIntersection(line1, line2) produces a point
+CircleCircleIntersection(c1, c2, which) c1 and c2 are two circles, 'which'
+ is an integer that can only be +1
+ or -1 and tells which one of the
+ two intersections has to be created.
+ To have both you must call this
+ function twice.
+ConicLineIntersection(conic, line, which) conic can also be a circle; which
+ has the same meaning as for the
+ CircleCircleIntersection
+
+Polygon((p1, p2,..., pn)) A polygon with the given vertices
+PolygonBCV(center, vertex, n) A regular polygon with 'n' sides
+PolygonVertex(polygon, i) Generate the i-th vertex of the
+ given polygon
+PolygonSide(polygon, i) Generate the i-th side of the given
+ polygon
+
+Vector(p1, p2)
+Angle(p1, center, p2)
+
+Text(point, string, boxed) point is a Point or a tuple of
+ two numbers
+ boxed is a integer in [0, 1] telling
+ if we want the frame
+VarText(point, string, vars, boxed) point is a Point or a tuple of
+ two numbers
+ vars hold variables parts
+Label(obj, displ, string, boxed) is a Text connected tu a object
+VarLabel(obj, displ, string, vars, boxed)
+
+PythonScript(script, argvec) "script" is a string containing the
+ python script
+
+Translate(object, vector) The result is an object of the same
+ kind as 'object'
+CentralSymmetry(object, center)
+AxialSymmetry(object, line)
+Rotate(object,center, angle)
+Scale(object,center, segment) The length of the segment is the
+ scaling ratio
+Scale2(object, center, s1, s2) The ratio of the lengths of s1 and
+ s2 is the scaling ratio
+InvertPoint(point, circle) Circular invertion of: a point
+InvertLine(line, circle) ... an other object
+InvertCircle(circle, circle)
+InvertArc(arc, circle)
+InvertSegment(segment, circle)
+CircularInversion(object, circle)
+
+-------------------------------------------------------------------------------
+
+
diff --git a/kig/pykig/Makefile.am b/kig/pykig/Makefile.am
new file mode 100644
index 00000000..40402a36
--- /dev/null
+++ b/kig/pykig/Makefile.am
@@ -0,0 +1 @@
+bin_SCRIPTS = pykig.py
diff --git a/kig/pykig/VERSION b/kig/pykig/VERSION
new file mode 100644
index 00000000..d3b5ba4b
--- /dev/null
+++ b/kig/pykig/VERSION
@@ -0,0 +1 @@
+0.2.11
diff --git a/kig/pykig/changelog.txt b/kig/pykig/changelog.txt
new file mode 100644
index 00000000..94c604c0
--- /dev/null
+++ b/kig/pykig/changelog.txt
@@ -0,0 +1,64 @@
+0.2.10
+Aggiunte alcune virgole mancanti
+cambiato il nome dell'oggetti da InvertObject a CircularInversion
+0.2.9
+Eliminati gli oggetti: InvertLine, InvertCircle, InvertArc, InvertSegment
+Aggiunto gli oggetti InvertObject, VerticalCubic, ConicArc
+Aggiunta la proproietà support
+Modificati alcuni esempi
+0.2.8
+Aggiunte a Triangle le proprietà dei poligoni.
+0.2.7
+Aggiunta, al manuale, la sezione sui metodi di kigdocument.
+E sugli oggetti Punto, Linea, Circonferenza, Parabola.
+Corretto un bug sul valore di default di internal.
+0.2.6
+Aggiustata la codifica dei caratteri nel manuale.
+0.2.5
+Scritti i primi 3 capitoli del manuale.
+Modificato gli esempi in modo che funzionino.
+7 nuovi metodi in KigDocument per settare i valori di default.
+eliminate la funzioni per settare i valori di default-
+Semplificata la gerarchia di classi con l'eliminazione di KigOut.
+0.2.4
+Aggiunti: gli oggetti "InvertArc" e "InvertSegment"
+Predisposte le tuple per l'aggiunta di propietà di alcuni oggetti.
+0.2.3
+Corretta la generazione del file .kig
+Aggiunta la proprietà "Bisector"
+Aggiunto il metodo "bisector"
+Aggiunti 4 nuovi esempi.
+Nell'esempio 1170Circocentro2.kpy è inserito un esempio di OOP
+ in 3 righe di codice:
+ la cerazione della classe Segmento che estende la classe "Segment"
+0.2.2
+Modificato il nome del programma: da pykig a pykig.py
+Modificato il nome della funzione main() ora si chiama prog()
+Modificato l'impianto del programma in modo che possa essere eseguito sia
+ come programma, sia come libreria.
+In particolare: modificati i metodi di KigDocument: __init__() e close()
+Inseriti dei controlli sugli errori in scrittura del file
+Aggiunti gli esempi esempi01, equivalenti a quelli di esempi00, che
+ utilizzano pykig.py come libreria
+Rinominata la directory con gli esempi seri in esempi02.
+Rimodificato il comportamento di pykig.py, quando si chiede di avere un file
+ in output non chiama Kig.
+Ora le stringhe visualizzano correttamente le lettere accentate.
+Modificata la funzione convstr(s), aggiunta la costante DICT.
+Aggiunto l'oggetto Label che associa una stringa ad un oggetto.
+Aggiornato il file API.txt per allinearlo ai cambiamenti.
+0.2.1:
+Modificato il numero di versione, per renderlo coerente tra codice e nome
+del file compresso.
+Modificata la gerarchia di classi con l'aggiunta di KigOut
+Modificati i nomi di variabili che hanno visibilità all'interno dei file .pyk
+Riunito tutte le istruzioni di scrittura sul file in un'unica procedura:
+ KigDocument.close()
+Resa inutile la chiamata a kigopen()
+Aggiunte le due funzioni noaxes() e nogrid()
+Riuniti una sequenza di comandi nella funzione main() che viene eseguita
+ quando pykig viene chiamato come programma.
+Modificata la costruzione di alcuni oggetti: dove è richiesto un punto di tipo
+ internal si può passare una tupla con le due coordinate.
+Modificati gli esempi in modo da farli funzionere con le nuove
+ caratteristiche.
diff --git a/kig/pykig/pykig.pth b/kig/pykig/pykig.pth
new file mode 100644
index 00000000..203b81d4
--- /dev/null
+++ b/kig/pykig/pykig.pth
@@ -0,0 +1,2 @@
+#
+pykig
diff --git a/kig/pykig/pykig.py b/kig/pykig/pykig.py
new file mode 100755
index 00000000..106c8a0c
--- /dev/null
+++ b/kig/pykig/pykig.py
@@ -0,0 +1,824 @@
+#!/usr/bin/env python
+# -*- coding: iso-8859-15 -*-
+#-------------------------------python------------------------pykig.py--#
+# #
+# Da Python a Kig #
+# #
+#--Maurizio Paolini-Daniele Zambelli-----------------------------2005---#
+#
+# (licenza GPL)
+
+version="0.2.11"
+
+#####
+# Type constant
+#####
+TI=type(0)
+TF=type(0.)
+TS=type("")
+TT=type((0, 0))
+
+#####
+# Constants: Point Style, Line Style, defaults values...
+#####
+PS=("Round", "RoundEmpty", "Rectangular", "RectangularEmpty", "Cross")
+LS=("SolidLine", "DashLine", "DashDotLine", "DashDotDotLine", "DotLine")
+KIGTRUE="true"
+KIGFALSE="false"
+DEFWIDTH=-1
+DEFCOLOR="#0000ff"
+DEFNAME="none"
+PROPERTY_INI="Property which"
+OBJECT_INI="Object type"
+PROPERTY_END="Property"
+OBJECT_END="Object"
+DICT=(("&","&amp;"), ("<","&lt;"), (">","&gt;"),
+ ("à","à"), ("è","è"), ("ì","ì"), ("ò","ò"), ("ù","ù"), ("é","é"))
+
+#
+# this is a trick to allow definitions like "p=Point(0,0,HIDDEN)"
+#
+HIDDEN=KIGFALSE
+VISIBLE=KIGTRUE
+
+#####
+# Validation parameters
+#####
+
+def parameter(val, defval):
+ if val==None: return defval
+ else: return val
+
+def validshown(shown):
+ if shown==KIGTRUE or shown==KIGFALSE: return shown
+
+def validwidth(width):
+ if type(width)==TI: return width
+
+def validpointstyle(ps):
+ if ps in PS: return ps
+
+def validname(name):
+ if type(name)==TS: return name
+
+def validlinestyle(ls):
+ if ls in LS: return ls
+
+def validcolor(color):
+ if type(color)==TS: return color
+
+#####
+# if as function
+#####
+
+def rif(condition, val1, val2):
+ """Return val1 if condition is True else return val2."""
+ if condition: return val1
+ else: return val2
+
+#####
+# Force some Python variables as kig variables
+#####
+
+def kig_double(val):
+ tp=type(val)
+ if tp==TI or tp==TF: return Double(val)
+ else: return val
+
+def kig_int(val):
+ tp=type(val)
+ if tp==TI: return Int(val)
+ else: return val
+
+def kig_string(val):
+ tp=type(val)
+ if tp==TS: return String(val)
+ else: return val
+
+def kig_point(val):
+ tp=type(val)
+ if tp==TT:
+ x, y = val
+ return Point(x, y, internal=True)
+ else:
+ return val
+
+def kig_relpoint(obj, displ):
+ x, y = displ
+ return RelativePoint(x, y, obj, internal=True)
+
+#####
+# base classes
+#####
+
+#####
+# Classe KigDocument
+#####
+
+class KigDocument(object):
+ """ Classe che produce il documento kig.
+
+ genealogia:
+ KigDocument <- object
+
+ attributi di classe:
+
+ attributi:
+ axes
+ grid
+ outfilename
+ outfile
+ callkig
+ of
+ viewkig
+ hierarchy
+ internal
+ width
+ pointstyle
+ name
+ linestyle
+ shown
+ color
+
+ metodi:
+ viewappend
+ hierarchyappend
+ setcallkig
+ setof
+ str_open
+ close
+ noaxes
+ nogrid
+ hideobjects
+ showobjects
+ setwidth
+ setpointstyle
+ setname
+ setlinestyle
+ setshown
+ setcolor
+ setinternal
+ """
+
+ def __init__(self, outfilename, callkig=True, of=False):
+# print "KigDocument.__init__()"
+ self.axes = "1"
+ self.grid = "1"
+ self.outfilename=outfilename
+ self.callkig=callkig
+ self.of=of
+ try:
+ self.outfile = open(outfilename, 'w')
+ except IOError, value:
+# print >> sys.stderr, outfilename, 'unwritable'
+ print >> sys.stderr, value
+ sys.exit(2)
+# KigOut._kigdocument=self
+ KigDOP._kd=self
+ KigView._kd=self
+ self.viewkig=[]
+ self.hierarchy=[]
+# Defaults values
+ self.internal=False
+ self.width=DEFWIDTH
+ self.pointstyle=PS[0]
+ self.name=DEFNAME
+ self.linestyle=LS[0]
+ self.shown=VISIBLE
+ self.color=DEFCOLOR
+
+
+ def viewappend(self, e): self.viewkig.append(e)
+ def hierarchyappend(self, e): self.hierarchy.append(e)
+ def setcallkig(v): self.callkig=v
+ def setof(v): self.of=v
+
+ def str_open(self):
+ return """<!DOCTYPE KigDocument>
+<KigDocument axes="%s" grid="%s" CompatibilityVersion="0.7.0" Version="0.9.1" >
+ <CoordinateSystem>Euclidean</CoordinateSystem>
+ <Hierarchy>
+""" % (self.axes, self.grid)
+
+ def close(self):
+ try:
+ self.outfile.write(self.str_open())
+ self.outfile.writelines(self.hierarchy)
+ self.outfile.write(" </Hierarchy>\n <View>\n")
+ for f in self.viewkig:
+ self.outfile.write(f.str_view())
+ self.outfile.write(" </View>\n</KigDocument>\n")
+ if self.outfile != sys.stdout:
+ self.outfile.close()
+ except IOError, value:
+ print >> sys.stderr, value
+ sys.exit(2)
+ try:
+ if self.callkig:
+ err = os.system('kig --nofork ' + self.outfilename)
+ except Exception, value:
+ print >> sys.stderr, value
+ if not self.of:
+ os.system('rm ' + self.outfilename)
+
+ def noaxes(self): self.axes="0"
+ def nogrid(self): self.grid="0"
+ def hideobjects(self): self.shown=HIDDEN
+ def showobjects(self): self.shown=VISIBLE
+ def setwidth(self, w): self.width=w
+ def setpointstyle(self, ps): self.pointstyle=ps
+ def setname(self, n): self.name=n
+ def setlinestyle(self, ls): self.linestyle=ls
+ def setshown(self, s): self.shown=s
+ def setcolor(self, c): self.color=c
+ def setinternal(self, v): self.internal=v
+
+#####
+# Classe KigDOP
+#####
+
+#class KigDOP(KigOut):
+class KigDOP(object):
+ """Classe da cui deriva ogni elemento che ha un id: Data, Object, Property.
+
+ genealogia:
+ kigDOP <- object
+
+ attributo di classe:
+ id-counter
+
+ attributi:
+ id
+ type
+
+ metodi:
+ getid
+ str_hierarchy
+ """
+ _kd=None
+ _id_counter=0
+
+ def __init__(self, type):
+ KigDOP._id_counter+=1
+ self.id=KigDOP._id_counter
+ self._type=type
+# self.getkigdocument().hierarchyappend(self.str_hierarchy())
+ KigDOP._kd.hierarchyappend(self.str_hierarchy())
+
+ def getid(self): return str(self.id)
+ def str_hierarchy(self): pass
+
+#####
+# Classe KigView
+#####
+
+#class KigView(KigOut):
+class KigView(object):
+ """ Classe con i dati di visualizzazione
+
+ genealogia:
+ KigView <- object
+
+ attributi di classe:
+ _kd
+
+ attributi:
+ shown
+ width
+ style
+ color
+ name
+ pointstyle
+
+ metodi:
+ str_view
+ show
+ hide
+ """
+ _kd=None
+
+ def __init__(self, object, shown, name, width, pointstyle, linestyle, color):
+ self.object=object
+ self.shown = parameter(shown, KigView._kd.shown)
+ self.width = parameter(width, KigView._kd.width)
+ self.pointstyle = parameter(pointstyle, KigView._kd.pointstyle)
+ self.linestyle = parameter(linestyle, KigView._kd.linestyle)
+ self.color = parameter(color, KigView._kd.color)
+ self.name = parameter(name, KigView._kd.name)
+ KigView._kd.viewappend(self)
+
+ def str_view(self):
+ """Produce la stringa che viene scritta sotto <View>.
+
+ esempio:
+ <Draw width="-1" point-style="Round" namecalcer="none"
+style="SolidLine" shown=None color="#0000ff" object="3" />
+"""
+
+ return ' <Draw width="%s" point-style="%s" namecalcer="%s"\
+ style="%s" shown="%s" color="%s" object="%s" />\n' %\
+ (self.width, self.pointstyle, self.name,
+ self.linestyle, self.shown, self.color, self.object.getid())
+
+#####
+# Classe Data
+#####
+
+class Data(KigDOP):
+ """ Classe da cui deriva ogni elemento Data
+
+ genealogia:
+ Data <- KigDOP <- object
+
+ attributi:
+ val
+
+ metodi:
+ str_hierarchy
+"""
+ def __init__(self, type, val):
+ self.val=val
+ KigDOP.__init__(self, type)
+
+ def str_hierarchy(self):
+ """Produce la stringa che viene scritta sotto <Data>.
+
+ esempio:
+ <Data type="double" id="170" >0.1</Data>
+"""
+ return ' <Data type="%s" id="%s" >%s</Data>\n' % \
+ (self._type, self.getid(), self.val)
+
+#####
+# Classe PropObj
+#####
+
+class PropObj(KigDOP):
+ """ Classe da cui deriva ogni elemento visibile
+
+ genealogia:
+ PropObj <- KigDOP <- object
+
+ attributi di classe:
+
+ attributi:
+ prop
+ objvec
+ view
+
+ metodi:
+ str_hierarchy
+ showname(self, n)
+ show(self)
+ hide(self)
+ setwidth(self, width)
+ setcolor(self, color)
+ setlinestyle(self, linestyle)
+ setpointstyle(self, pointstyle)
+ setname(self, n)
+ setshown(self, s)
+ getwidth(self)
+ getcolor(self)
+ getlinestyle(self)
+ getpointstyle(self)
+ """
+
+ def __init__(self, prop, type, objvec, shown, name, internal,
+ width, pointstyle, linestyle, color):
+ self.prop=prop
+ self.objvec=objvec
+ self.n_lb=None
+ KigDOP.__init__(self, type)
+ internal=parameter(internal, KigDOP._kd.internal)
+ if internal:
+ self.view = None
+ else:
+# Qui si assume che, se viene dato un nome ad un oggetto,
+# si voglia anche visualizzare questo nome
+ if name: n_id=self.showname(name, shown, width, pointstyle, linestyle,
+ color)
+ else: n_id=None
+ self.view = KigView(self, shown, n_id, width, pointstyle, linestyle,
+ color)
+
+ def str_hierarchy(self):
+ """Produce la stringa che viene scritta sotto <Data>.
+
+ esempio:
+ <Property which="mid-point" id="170" >
+ <Parent id="..." />
+ </Property>
+
+ oppure:
+ <Object type="ConstrainedPoint" id="14" >
+ <Parent id="13" />
+ <Parent id="10" />
+ </Object>
+"""
+ retstring = ' <%s="%s" id="%s" >' %\
+ ((self.prop and PROPERTY_INI or OBJECT_INI),
+ self._type, self.getid())
+ for p in self.objvec:
+ retstring = retstring + '\n <Parent id="%s" />' % p.getid()
+ retstring = retstring + '\n </%s>\n' % (self.prop and PROPERTY_END or
+ OBJECT_END)
+ return retstring
+
+ def showname(self, name, shown, width, pointstyle, linestyle, color):
+ n=String(name)
+ self.n_lb=Label(self, (0, 0), n, 0, shown, None, False,
+ width, pointstyle, linestyle, color)
+ return n.getid()
+
+ def show(self):
+ if self.view: self.view.shown=None
+ def hide(self):
+ if self.view: self.view.shown=KIGFALSE
+ def setwidth(self, width): self.view.width=width
+ def setcolor(self, color): self.view.color=color
+ def setlinestyle(self, linestyle):
+ if linestyle in LS: self.view.linestyle=linestyle
+ def setpointstyle(self, pointstyle):
+ if pointstyle in PS: self.view.pointstyle=pointstyle
+ def type(self): return Type(self)
+ def setname(self, n):
+ v=self.view
+ v.name=self.showname(n, v.shown, v.width, v.pointstyle, v.linestyle,
+ v.color)
+ def setshown(self, s): self.view.shown=s
+
+#####
+# Classe Property
+#####
+
+class Property(PropObj):
+ """ Classe da cui deriva ogni elemento Property
+
+ genealogia:
+ Property <- PropObj <- KigDOP <- object
+ """
+ def __init__(self, type, parent, shown, name, internal,
+ width, pointstyle, linestyle, color):
+ PropObj.__init__(self, True, type, (parent,), shown, name, internal,
+ width, pointstyle, linestyle, color)
+# print shown
+
+#####
+# Classe Object
+#####
+
+class Object(PropObj):
+ """ Classe da cui deriva ogni elemento Oggetto
+
+ genealogia:
+ Object <- PropObj <- KigDOP <- object
+ """
+
+ def __init__(self, type, objvec, shown, name, internal,
+ width, pointstyle, linestyle, color):
+ PropObj.__init__(self, False, type, objvec, shown, name, internal,
+ width, pointstyle, linestyle, color)
+
+#####
+# Data
+#####
+
+data=(\
+("Int", "int", "val"),
+("Double", "double", "val"),
+("String", "string", "convstr(val)"),
+)
+
+def convstr(s):
+ for o, n in DICT:
+ s=s.replace(o, n)
+ return s
+
+def databuild(nomeclasse, nomekig, v="val"):
+ """Create string with a Data class definition."""
+ return """class %s(Data):
+
+ def __init__(self, val):
+ Data.__init__(self, "%s", %s)
+""" % (nomeclasse, nomekig, v)
+
+for d in data:
+ p1, p2, p3 = d
+ exec databuild(p1, p2, p3)
+
+#####
+# Objects
+#####
+"""Da aggiungere:
+("ConvexHall", "ConvexHall", "polygon,", "(polygon,),"),
+("EllipseByFocusFocusPoint", "EllipseBFFP", "p1, p2, p3,", "(p1, p2, p3,),"),
+("HyperbolaByFocusFocusPoint", "HyperbolaBFFP", "p1, p2, p3,", "(p1, p2, p3,),"),
+(ConicsBy5Points", "ConicB5P", "p1, p2, p3, p4, p5,", "(p1, p2, p3, p4, p5),"),
+("ParabolaBy3Points", "ParabolaBTP", "p1, p2, p3,", "(p1, p2, p3,),"),
+("CocCurve", "CocCurve", "line, point,", "(line, point,),"),
+"""
+objects=(\
+###### Points class
+("Point", "FixedPoint", "x, y,", "(kig_double(x), kig_double(y)),"),
+("ConstrainedPoint", "ConstrainedPoint",
+ "t, curve,", "(kig_double(t), curve),"),
+("RelativePoint", "RelativePoint",
+ "x, y, p,", "(kig_double(x), kig_double(y), p),"),
+###### segments, rays, lines
+("Line", "LineAB", "p1, p2,", "(p1, p2),"),
+("Segment", "SegmentAB", "p1, p2,", "(p1, p2),"),
+("Ray", "RayAB", "p1, p2,", "(p1, p2),"),
+("Orthogonal", "LinePerpend", "line, point,", "(line, point,),"),
+("Parallel", "LineParallel", "line, point,", "(line, point,),"),
+###### Circles, arcs, ...
+("Circle", "CircleBCP", "center, point,", "(center, point,),"),
+("CircleByCenterRadius", "CircleBPR", "center, radius,", "(center, radius,),"),
+("CircleBy3Points", "CircleBTP", "p1, p2, p3,", "(p1, p2, p3,),"),
+("ArcBy3Points", "ArcBTP", "p1, p2, p3,", "(p1, p2, p3,),"),
+("ArcByCenterPointAngle", "ArcBCPA",
+ "center, point, angle,", "(center, point, angle),"),
+###### Conics...
+("ParabolaByDirectrixFocus", "ParabolaBDP", "line, point,", "(line, point,),"),
+("VerticalCubic", "VerticalCubicB4P", "p1, p2, p3, p4,", "(p1, p2, p3, p4),"),
+("ConicArc", "ConicArcBTPC", "p1, p2, p3, center,", "(p1, p2, p3, center),"),
+#####
+# intersections. The only standard object is the intersection
+# of two lines, which always gives one single point
+#####
+("LineLineIntersection", "LineLineIntersection", "l1, l2,", "(l1, l2),"),
+#####
+# Classe CircleCircleIntersection e ConicLineIntersection
+# l'intero "which" puo' assumere i valori 1 o -1 per indicare quale
+# delle due intersezioni si desidera ottenere
+# si potrebbe mettere un controllo...
+#####
+("CircleCircleIntersection", "CircleCircleIntersection",
+ "c1, c2, witch,", "(c1, c2, Int(witch),),"),
+("ConicLineIntersection", "ConicLineIntersection",
+ "conic, line, witch,", "(conic, line, Int(witch),),"),
+###### Classe Triangle
+("Triangle", "TriangleB3P", "p1, p2, p3,", "(p1, p2, p3),"),
+###### Classe Polygon (the only argument is a points vect)
+("Polygon", "PolygonBNP", "pvec,", "pvec,"),
+###### Classe PolygonBCV
+# Poligono regolare dati il centro e un vertice; il terzo argomento
+# e' un intero contenente il numero di lati
+("PolygonBCV", "PoligonBCV",
+ "center, vertex, n,", "(center, vertex, Int(n)),"),
+##### Classe PolygonVertex (poligono, intero >= 0)
+("PolygonVertex", "PolygonVertex",
+ "polygon, i,", "(polygon, Int(i)),"),
+##### Classe PolygonSide (poligono, intero >= 0)
+("PolygonSide", "PolygonSide",
+ "polygon, i,", "(polygon, Int(i)),"),
+###### vector, angle,...
+("Vector", "Vector", "p1, p2,", "(p1, p2),"),
+("Angle", "Angle", "p1, v, p2,", "(p1, v, p2),"),
+###### Transformations
+("Translate", "Translation", "obj, vector,", "(obj, vector),"),
+("CentralSymmetry", "PointReflection", "obj, center,", "(obj, center),"),
+("AxialSymmetry", "LineReflection", "obj, center,", "(obj, center),"),
+("Rotate", "Rotation",
+ "obj, center, angle,", "(obj, center, angle),"),
+("Scale", "ScalingOverCenter",
+ "obj, center, segment,", "(obj, center, segment),"),
+("Scale2", "ScalingOverCenter2",
+ "obj, center, s1, s2,", "(obj, center, s1, s2),"),
+("InvertPoint", "InvertPoint",
+ "point, circle,", "(point, circle),"),
+("CircularInversion", "CircularInversion",
+ "objecttoinvert, circle,", "(objecttoinvert, circle),"),
+("InvertLine", "InvertLine",
+ "line, circle,", "(line, circle),"),
+("InvertCircle", "InvertCircle",
+ "circletoinvert, circle,", "(circletoinvert, circle),"),
+("InvertArc", "InvertArc",
+ "arctoinvert, circle,", "(arctoinvert, circle),"),
+("InvertSegment", "InvertSegment",
+ "segment, circle,", "(segment, circle),"),
+###### Text, Label, ...
+("Text", "Label",
+ "point, string, boxed=0,",
+ "(Int(boxed), kig_point(point), kig_string(string)),"),
+("Label", "Label",
+ "obj, displ, string, boxed=0,",
+ "(Int(boxed),kig_relpoint(obj, displ),kig_string(string)),"),
+("VarText", "Label",
+ "point, string, vars, boxed=0,",
+ "(Int(boxed), kig_point(point), \
+ kig_string(string))+tuple(vars),"),
+("VarLabel", "Label",
+ "obj, displ, string, vars, boxed=0,",
+ "(Int(boxed), kig_relpoint(obj, displ), \
+ kig_string(string))+tuple(vars),"),
+###### Python scripting... we need some work here...
+("PythonScript", "PythonExecuteType",
+ "script, argvec,",
+ '(Object("PythonCompileType", (kig_string(script),), shown,\
+ name, internal, width, pointstyle, linestyle,\
+ color),)+tuple(argvec),'),
+)
+
+def objectbuild(nameclass, namekig, params, objparams):
+ """Create string with a Object class definition."""
+ return """class %s(Object):
+
+ def __init__(self, %s shown=None, name=None, internal=None,
+ width=None, pointstyle=None, linestyle=None, color=None):
+ Object.__init__(self, "%s", %s shown, name, internal,
+ width, pointstyle, linestyle, color)
+""" % (nameclass, params, namekig, objparams)
+
+for o in objects:
+ p1, p2, p3, p4 = o
+ exec objectbuild(p1, p2, p3, p4)
+
+#####
+# Propertys
+#####
+
+property=(\
+("Type", "base-object-type", "o,", "o,"),
+("Coordinate", "coordinate", "point,", "point,"),
+("XCoord", "coordinate-x", "point,", "point,"),
+("YCoord", "coordinate-y", "point,", "point,"),
+("MidPoints", "mid-point", "a, b,", "Segment(a, b, internal=True),"),
+("MidPoint", "mid-point", "segment,", "segment,"),
+("EndPointA", "end-point-A", "segment,", "segment,"),
+("EndPointB", "end-point-B", "segment,", "segment,"),
+("Length", "length", "segment,", "segment,"),
+("Equation", "equation", "segment,", "segment,"),
+("Slope", "slope", "segment,", "segment,"),
+("NumOfSides", "polygon-number-of-sides", "poly,", "poly,"),
+("Perimeter", "polygon-perimeter", "poly,", "poly,"),
+("Surface", "polygon-surface", "poly,", "poly,"),
+("CenterOfMass", "polygon-center-of-mass", "poly,", "poly,"),
+("WindingNumber", "polygon-winding-number", "poly,", "poly,"),
+("Radius", "radius", "circle,", "circle,"),
+("Center", "center", "circle,", "circle,"),
+("Bisector", "angle-bisector", "angle,", "angle,"),
+("Support", "support", "object,", "object,"),
+)
+
+def propertybuild(nameclass, namekig, params, objparams):
+ """Create string with a Property class definition."""
+ return """class %s(Property):
+
+ def __init__(self, %s shown=None, name=None, internal=False,
+ width=None, pointstyle=None, linestyle=None, color=None):
+ Property.__init__(self, "%s", %s shown, name, internal,
+ width, pointstyle, linestyle, color)
+""" % (nameclass, params, namekig, objparams)
+
+for p in property:
+ p1, p2, p3, p4 = p
+ exec propertybuild(p1, p2, p3, p4)
+
+#####
+# Start of properties definitions as Object's metod
+#####
+# da sistemare!
+points =(Point, ConstrainedPoint, RelativePoint, PolygonVertex)
+lines=(Segment, Ray, Vector, InvertLine)
+segments=(Segment, Vector, PolygonSide, InvertSegment)
+circles =(Circle, CircleBy3Points, CircularInversion, ArcBy3Points,
+ ArcByCenterPointAngle, InvertCircle)
+polygons=(Polygon, PolygonBCV, Triangle)
+angles =(Angle,)
+supp = circles+lines
+
+methods=(\
+("coordinate", "coordinate", points),
+("coordinate-x", "xcoord", points),
+("coordinate-y", "ycoord", points),
+("mid-point", "midpoint", segments),
+("end-point-A", "endpointA", segments),
+("end-point-B", "endpointB", segments),
+("length", "length", segments),
+("equation", "equation", lines),
+("slope", "slope", lines),
+("polygon-number-of-sides", "numofsides", polygons),
+("polygon-perimeter", "perimeter", polygons),
+("polygon-surface", "surface", polygons),
+("polygon-center-of-mass", "centerofmass", polygons),
+("polygon-winding-number", "windingnumber", polygons),
+("center", "center", polygons),
+("center", "center", circles),
+("angle-bisector", "bisector", angles),
+("support", "support", supp),
+)
+
+def methodsbuild(namekig):
+ """Create string with a method class definition."""
+ return """def method(self,shown=None, name=None, internal=False,
+ width=None, pointstyle=None, linestyle=None, color=None):
+ return Property("%s", self, shown, name, internal,
+ width, pointstyle, linestyle, color)
+""" % (namekig, )
+
+for p in methods:
+ p1, p2, cl = p
+ exec methodsbuild(p1)
+ for c in cl:
+ setattr(c, p2, method)
+
+#####
+# Usage
+#####
+
+def usage(codexit):
+ print >> sys.stderr, """
+usage: pykig.py [options...] file ...
+
+Options:
+ -h, --help Show this text.
+ -o <kig_file>
+ --output <kig_file> output <kig_file> no call Kig
+ -v, --version output version
+ -n, --nokig no call Kig
+
+examples:
+ $ pykig.py my_file.kpy
+ $ pykig.py -o output_file.kig my_file.kpy
+ $ ...
+"""
+ sys.exit(codexit)
+
+#####
+# Main body
+#####
+
+import sys, traceback, os
+#from math import * # for user's programs
+import math # for user's programs
+import getopt
+import atexit
+
+def prog():
+ try:
+ _opts, _args = getopt.getopt(sys.argv[1:], "hvno:",\
+ ["help", "version", "nokig", "output="])
+ except getopt.GetoptError:
+ print "GetoptError"
+ usage(2)
+ _callKig=True
+ _of=False
+ for _opt, _arg in _opts:
+ if _opt in ("-h", "--help"):
+ usage(0)
+ if _opt in ("-v", "--version"):
+ print "version:", version
+ sys.exit(0)
+ if _opt in ("-n", "--nokig"):
+ _callKig=False
+ elif _opt in ("-o", "--output"):
+ _outfilename=_arg
+ _of=True
+ _callKig=False # se c'è il file di output, non viene chiamato Kig
+ if len(_args)==0:
+ _infilename=raw_input("Nome del file di input: ")
+ if not _infilename:
+ print "No Input filename"
+ usage(2)
+ elif len(_args)==1:
+ _infilename=_args[0]
+ else:
+ print "No infilename"
+ usage(2)
+ try:
+ _infile = open(_infilename, 'r')
+ except:
+ print >> sys.stderr, _infilename, 'unreadable'
+ sys.exit(2)
+ if _of:
+ if _outfilename=="-":
+ _n, _e = os.path.splitext(_infilename)
+ _outfilename=_n+'.kig'
+ else:
+ _outfilename="/tmp/pykig" + str(os.getpid()) + ".kig"
+ global kigdocument
+ kigdocument=KigDocument(_outfilename, _callKig, _of)
+ kd=kigdocument
+ try:
+ execfile(_infilename, globals())
+ except:
+ print >> sys.stderr, 'syntax error in', _infilename
+ _info = sys.exc_info() # vorrei stampare il traceback...
+ traceback.print_exc()
+ sys.exit(3)
+ kigdocument.close()
+
+ if _infile != sys.stdin:
+ _infile.close()
+
+def lib():
+ _outfilename="/tmp/pykig" + str(os.getpid()) + ".kig"
+ global kigdocument
+ kigdocument=KigDocument(_outfilename)
+ kd=kigdocument
+ atexit.register(kigdocument.close)
+
+if __name__ == "__main__":
+ prog()
+else:
+ lib()
diff --git a/kig/scripting/Makefile.am b/kig/scripting/Makefile.am
new file mode 100644
index 00000000..c007a612
--- /dev/null
+++ b/kig/scripting/Makefile.am
@@ -0,0 +1,22 @@
+INCLUDES=$(all_includes) $(BOOST_PYTHON_INCLUDES)
+KDE_CXXFLAGS=$(USE_EXCEPTIONS)
+noinst_LTLIBRARIES=libscripting.la
+noinst_HEADERS = \
+ python_type.h \
+ python_scripter.h \
+ script-common.h \
+ script_mode.h \
+ newscriptwizard.h
+libscripting_la_SOURCES = \
+ python_type.cc \
+ python_scripter.cc \
+ script-common.cc \
+ script_mode.cc \
+ newscriptwizardbase.ui \
+ newscriptwizard.cc
+libscripting_la_LIBADD = $(BOOST_PYTHON_LIBS) $(PYTHON_LIBS) -lkatepartinterfaces
+libscripting_la_LDFLAGS = $(all_libraries) $(PYTHON_LDFLAGS)
+METASOURCES=AUTO
+
+xml_DATA = python-kig.xml
+xmldir = $(kde_datadir)/katepart/syntax
diff --git a/kig/scripting/newscriptwizard.cc b/kig/scripting/newscriptwizard.cc
new file mode 100644
index 00000000..165f8e98
--- /dev/null
+++ b/kig/scripting/newscriptwizard.cc
@@ -0,0 +1,234 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "newscriptwizard.h"
+#include "newscriptwizard.moc"
+
+#include "script_mode.h"
+
+#include <qlabel.h>
+#include <qlayout.h>
+
+//#include <kactionclasses.h>
+//#include <kactioncollection.h>
+// make it still work on old kde 3.1...
+#include <kaction.h>
+//
+#include <kapplication.h>
+#include <kglobalsettings.h>
+#include <kpopupmenu.h>
+#include <ktextedit.h>
+#include <ktexteditor/clipboardinterface.h>
+#include <ktexteditor/dynwordwrapinterface.h>
+#include <ktexteditor/editinterface.h>
+#include <ktexteditor/editorchooser.h>
+#include <ktexteditor/popupmenuinterface.h>
+#include <ktexteditor/undointerface.h>
+#include <ktexteditor/view.h>
+
+#include <assert.h>
+
+NewScriptWizard::~NewScriptWizard()
+{
+ if ( !document )
+ {
+ delete textedit;
+ }
+ else
+ {
+ //restoring the state of the dynamic word wrap
+ dynamic_cast<KTextEditor::DynWordWrapInterface*>( editor )->setDynWordWrap( prevDynWordWrap );
+ delete editor->document();
+ }
+}
+
+NewScriptWizard::NewScriptWizard( QWidget* parent, ScriptModeBase* mode )
+ : NewScriptWizardBase( parent, "New Script Wizard" ),
+ mmode( mode )
+{
+ document = KTextEditor::EditorChooser::createDocument( 0, "KTextEditor::Document" );
+// document = 0;
+
+ gridLayout->expand( 2, 1 );
+
+ if ( !document )
+ {
+ // there is no KDE textditor component installed, so we'll use a
+ // simplier KTextEdit
+ textedit = new KTextEdit( mpcode, "textedit" );
+ textedit->setFont( KGlobalSettings::fixedFont() );
+ gridLayout->addWidget( textedit, 1, 0 );
+ }
+ else
+ {
+ // creating the 'view', hat is what the user see and interact with
+ editor = document->createView( mpcode, "editor" );
+ gridLayout->addWidget( editor, 1, 0 );
+
+ // casting to the interfaces we'll use often
+ hli = dynamic_cast<KTextEditor::HighlightingInterface*>( document );
+
+ // displaying the left border with line numbers
+ KToggleAction *a = dynamic_cast<KToggleAction*>( editor->actionCollection()->action("view_line_numbers") );
+ a->activate();
+
+ // saving the state of dynamic word wrap and disabling it
+ prevDynWordWrap = dynamic_cast<KTextEditor::DynWordWrapInterface*>( editor )->dynWordWrap();
+ dynamic_cast<KTextEditor::DynWordWrapInterface*>( editor )->setDynWordWrap( false );
+
+ // saving the "no highlight" id
+ noHlStyle = hli->hlMode();
+
+ // creating the popup menu
+ KPopupMenu* pm = new KPopupMenu( editor );
+ // creating the actions for the code editor...
+ KActionCollection* ac = new KActionCollection( editor );
+ KAction* undoAction = KStdAction::undo( this, SLOT( slotUndo() ), ac );
+ KAction* redoAction = KStdAction::redo( this, SLOT( slotRedo() ), ac );
+ KAction* cutAction = KStdAction::cut( this, SLOT( slotCut() ), ac );
+ KAction* copyAction = KStdAction::copy( this, SLOT( slotCopy() ), ac );
+ KAction* pasteAction = KStdAction::paste( this, SLOT( slotPaste() ), ac );
+ // ... and plugging them into the popup menu (to build it, of course :) )
+ undoAction->plug( pm );
+ redoAction->plug( pm );
+ pm->insertSeparator();
+ cutAction->plug( pm );
+ copyAction->plug( pm );
+ pasteAction->plug( pm );
+
+ // finally, we install the popup menu
+ dynamic_cast<KTextEditor::PopupMenuInterface*>( editor )->installPopup( pm );
+ }
+
+ connect( this, SIGNAL( helpClicked() ), this, SLOT( slotHelpClicked() ) );
+}
+
+void NewScriptWizard::back()
+{
+ if ( currentPage() == mpcode )
+ {
+ // currentPage() is not yet updated, so we're now entering the
+ // args page..
+ mmode->argsPageEntered();
+ }
+ else assert( false );
+ NewScriptWizardBase::back();
+}
+
+void NewScriptWizard::next()
+{
+ if ( currentPage() == mpargs )
+ mmode->codePageEntered();
+ else assert( false );
+ if ( !document )
+ {
+ textedit->setFocus();
+ }
+ else
+ {
+ editor->setFocus();
+ }
+ NewScriptWizardBase::next();
+}
+
+void NewScriptWizard::reject()
+{
+ if ( mmode->queryCancel() )
+ NewScriptWizardBase::reject();
+}
+
+void NewScriptWizard::accept()
+{
+ if ( mmode->queryFinish() )
+ NewScriptWizardBase::accept();
+}
+
+void NewScriptWizard::slotHelpClicked()
+{
+ kapp->invokeHelp( QString::fromLatin1( "scripting" ),
+ QString::fromLatin1( "kig" ) );
+}
+
+void NewScriptWizard::setText( const QString& text )
+{
+ if ( !document )
+ {
+ textedit->setText( text );
+ }
+ else
+ {
+ dynamic_cast<KTextEditor::EditInterface*>( document )->setText( text );
+ }
+}
+
+QString NewScriptWizard::text()
+{
+ if ( !document )
+ {
+ return textedit->text();
+ }
+ else
+ {
+ return dynamic_cast<KTextEditor::EditInterface*>( document )->text();
+ }
+}
+
+void NewScriptWizard::setType( ScriptType::Type type )
+{
+ labelFillCode->setText( ScriptType::fillCodeStatement( type ) );
+
+ if ( !!document )
+ {
+ if ( type != ScriptType::Unknown )
+ {
+ for ( uint i = 0; i < hli->hlModeCount(); ++i )
+ {
+ if ( hli->hlModeName( i ) == ScriptType::highlightStyle( type ) )
+ {
+ // we found our highlight style, setting it
+ hli->setHlMode( i );
+ return;
+ }
+ }
+ }
+ else
+ {
+ hli->setHlMode( noHlStyle );
+ }
+ }
+}
+
+void NewScriptWizard::slotUndo()
+{
+ dynamic_cast<KTextEditor::UndoInterface*>( document )->undo();
+}
+
+void NewScriptWizard::slotRedo() {
+ dynamic_cast<KTextEditor::UndoInterface*>( document )->redo();
+}
+
+void NewScriptWizard::slotCut() {
+ dynamic_cast<KTextEditor::ClipboardInterface*>( editor )->cut();
+}
+
+void NewScriptWizard::slotCopy() {
+ dynamic_cast<KTextEditor::ClipboardInterface*>( editor )->copy();
+}
+
+void NewScriptWizard::slotPaste() {
+ dynamic_cast<KTextEditor::ClipboardInterface*>( editor )->paste();
+}
diff --git a/kig/scripting/newscriptwizard.h b/kig/scripting/newscriptwizard.h
new file mode 100644
index 00000000..67b51d94
--- /dev/null
+++ b/kig/scripting/newscriptwizard.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_SCRIPTING_NEWSCRIPTWIZARD_H
+#define KIG_SCRIPTING_NEWSCRIPTWIZARD_H
+
+#include "newscriptwizardbase.h"
+
+#include "script-common.h"
+
+#include <ktextedit.h>
+#include <ktexteditor/document.h>
+#include <ktexteditor/highlightinginterface.h>
+#include <ktexteditor/view.h>
+
+#include <algorithm>
+
+class ScriptModeBase;
+
+class NewScriptWizard
+ : public NewScriptWizardBase
+{
+ Q_OBJECT
+ ScriptModeBase* mmode;
+public:
+ NewScriptWizard( QWidget* parent, ScriptModeBase* mode );
+ ~NewScriptWizard();
+
+ void back();
+ void next();
+ void reject();
+
+ void setText( const QString& text );
+ QString text();
+
+ void setType( ScriptType::Type type );
+
+public slots:
+ void slotHelpClicked();
+ void accept();
+
+ void slotUndo();
+ void slotRedo();
+ void slotCut();
+ void slotCopy();
+ void slotPaste();
+
+protected:
+ KTextEdit* textedit;
+ KTextEditor::Document* document;
+ KTextEditor::HighlightingInterface* hli;
+ KTextEditor::View* editor;
+
+ uint noHlStyle;
+ bool prevDynWordWrap;
+};
+
+#endif
diff --git a/kig/scripting/newscriptwizardbase.ui b/kig/scripting/newscriptwizardbase.ui
new file mode 100644
index 00000000..30117961
--- /dev/null
+++ b/kig/scripting/newscriptwizardbase.ui
@@ -0,0 +1,81 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>NewScriptWizardBase</class>
+<widget class="QWizard">
+ <property name="name">
+ <cstring>NewScriptWizardBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>610</width>
+ <height>360</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>New Script</string>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>mpargs</cstring>
+ </property>
+ <attribute name="title">
+ <string>Select Arguments</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Select the argument objects ( if any )
+in the Kig window and press "Next".</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>mpcode</cstring>
+ </property>
+ <attribute name="title">
+ <string>Enter Code</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>gridLayout</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>labelFillCode</cstring>
+ </property>
+ <property name="text">
+ <string>Now fill in the code:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>ktextedit.h</includehint>
+</includehints>
+</UI>
diff --git a/kig/scripting/python-kig.xml b/kig/scripting/python-kig.xml
new file mode 100644
index 00000000..930d5f8f
--- /dev/null
+++ b/kig/scripting/python-kig.xml
@@ -0,0 +1,289 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE language>
+<!-- Python syntax highlightning v0.9 by Per Wigren -->
+<!-- Python syntax highlightning v1.2.x for Kig by Pino Toscano -->
+<language name="Python-Kig" version="1.2.1" kateversion="2.1" section="Scripts" extensions="*.py;*.pyw" mimetype="application/x-python;text/x-python" casesensitive="1">
+ <highlighting>
+ <list name="prep">
+ <item> import </item>
+ <item> from </item>
+ <item> as </item>
+ </list>
+
+ <list name="statements">
+ <item> and </item>
+ <item> assert </item>
+ <item> break </item>
+ <item> class </item>
+ <item> continue </item>
+ <item> def </item>
+ <item> del </item>
+ <item> elif </item>
+ <item> else </item>
+ <item> except </item>
+ <item> exec </item>
+ <item> finally </item>
+ <item> for </item>
+ <item> global </item>
+ <item> if </item>
+ <item> in </item>
+ <item> is </item>
+ <item> lambda </item>
+ <item> not </item>
+ <item> or </item>
+ <item> pass </item>
+ <item> print </item>
+ <item> raise </item>
+ <item> return </item>
+ <item> try </item>
+ <item> while </item>
+ <item> yield </item>
+ </list>
+
+ <list name="builtinfuncs">
+ <item> abs </item>
+ <item> apply </item>
+ <item> buffer </item>
+ <item> callable </item>
+ <item> chr </item>
+ <item> cmp </item>
+ <item> coerce </item>
+ <item> compile </item>
+ <item> complex </item>
+ <item> copyright </item>
+ <item> credits </item>
+ <item> delattr </item>
+ <item> dir </item>
+ <item> divmod </item>
+ <item> eval </item>
+ <item> execfile </item>
+ <item> exit </item>
+ <item> filter </item>
+ <item> float </item>
+ <item> getattr </item>
+ <item> globals </item>
+ <item> hasattr </item>
+ <item> hash </item>
+ <item> hex </item>
+ <item> id </item>
+ <item> input </item>
+ <item> int </item>
+ <item> intern </item>
+ <item> isinstance </item>
+ <item> issubclass </item>
+ <item> iter </item>
+ <item> len </item>
+ <item> license </item>
+ <item> list </item>
+ <item> locals </item>
+ <item> long </item>
+ <item> map </item>
+ <item> max </item>
+ <item> min </item>
+ <item> oct </item>
+ <item> open </item>
+ <item> ord </item>
+ <item> pow </item>
+ <item> quit </item>
+ <item> range </item>
+ <item> raw_input </item>
+ <item> reduce </item>
+ <item> reload </item>
+ <item> repr </item>
+ <item> round </item>
+ <item> setattr </item>
+ <item> slice </item>
+ <item> str </item>
+ <item> tuple </item>
+ <item> type </item>
+ <item> unichr </item>
+ <item> unicode </item>
+ <item> vars </item>
+ <item> xrange </item>
+ <item> zip </item>
+ <!-- BEGIN: math module functions -->
+ <item> acos </item>
+ <item> asin </item>
+ <item> atan </item>
+ <item> atan2 </item>
+ <item> ceil </item>
+ <item> cos </item>
+ <item> cosh </item>
+ <item> degrees </item>
+ <item> exp </item>
+ <item> fabs </item>
+ <item> floor </item>
+ <item> fmod </item>
+ <item> frexp </item>
+ <item> hypot </item>
+ <item> ldexp </item>
+ <item> log </item>
+ <item> log10 </item>
+ <item> modf </item>
+ <item> radians </item>
+ <item> sin </item>
+ <item> sinh </item>
+ <item> sqrt </item>
+ <item> tan </item>
+ <item> tanh </item>
+ <!-- END: math module functions -->
+ </list>
+
+ <list name="specialvars">
+ <item> None </item>
+ <item> self </item>
+ </list>
+
+ <list name="kigobjects">
+ <item> AbstractLine </item>
+ <item> Angle </item>
+ <item> Arc </item>
+ <item> BogusObject </item>
+ <item> CartesianConic </item>
+ <item> Circle </item>
+ <item> Conic </item>
+ <item> ConicCartesianData </item>
+ <item> ConicPolarData </item>
+ <item> Coordinate </item>
+ <item> Cubic </item>
+ <item> CubicCartesianData </item>
+ <item> Curve </item>
+ <item> DoubleObject </item>
+ <item> IntObject </item>
+ <item> InvalidObject </item>
+ <item> Line </item>
+ <item> LineData </item>
+ <item> Object </item>
+ <item> ObjectType </item>
+ <item> Point </item>
+ <item> PolarConic </item>
+ <item> Ray </item>
+ <item> Segment </item>
+ <item> StringObject </item>
+ <item> TestResultObject </item>
+ <item> Transformation </item>
+ <item> Vector </item>
+ </list>
+
+ <list name="mathconsts">
+ <item> e </item>
+ <item> pi </item>
+ </list>
+
+ <contexts>
+ <context name="Normal" attribute="Normal Text" lineEndContext="#stay">
+ <keyword attribute="Preprocessor" String="prep" context="#stay"/>
+ <keyword attribute="Keyword" String="statements" context="#stay"/>
+ <keyword attribute="Builtin Function" String="builtinfuncs" context="#stay"/>
+ <keyword attribute="Special Variable" String="specialvars" context="#stay"/>
+ <keyword attribute="Kig Object" String="kigobjects" context="#stay" />
+ <keyword attribute="Math Constants" String="mathconsts" context="#stay" />
+ <RegExpr attribute="Normal" String="[a-zA-Z_][a-zA-Z_0-9]+" context="#stay"/>
+
+ <RegExpr attribute="Complex" String=" ((([0-9]*\.[0-9]+|[0-9]+\.)|([0-9]+|([0-9]*\.[0-9]+|[0-9]+\.))[eE](\+|-)?[0-9]+)|[0-9]+)[jJ]" context="#stay"/>
+ <RegExpr attribute="Float" String="([0-9]+\.[0-9]*|\.[0-9]+)([eE][0-9]+)?" context="#stay"/>
+ <RegExpr attribute="Int" String="([1-9][0-9]*([eE][0-9]+)?|0)" context="#stay"/>
+ <RegExpr attribute="Long" String="[1-9][0-9]*([eE][0-9.]+)?[Ll]" context="#stay"/>
+ <RegExpr attribute="Hex" String="0[Xx][0-9a-fA-F]+" context="#stay"/>
+ <RegExpr attribute="Octal" String="0[1-9][0-9]*" context="#stay"/>
+
+ <RegExpr attribute="Raw String" String="[rR]'" context="Raw A-string"/>
+ <RegExpr attribute="Raw String" String="[rR]&quot;" context="Raw Q-string"/>
+
+ <RegExpr attribute="Comment" String="#.*$" context="#stay"/>
+ <RegExpr attribute="Comment" String="^\s*'''" context="Tripple A-comment"/>
+ <RegExpr attribute="Comment" String="^\s*&quot;&quot;&quot;" context="Tripple Q-comment"/>
+
+ <StringDetect attribute="String" String="'''" context="Tripple A-string"/>
+ <StringDetect attribute="String" String="&quot;&quot;&quot;" context="Tripple Q-string"/>
+ <DetectChar attribute="String" char="'" context="Single A-string"/>
+ <DetectChar attribute="String" char="&quot;" context="Single Q-string"/>
+
+ <RegExpr attribute="Operator" String="[+*/\(\)%\|\[\]\{\}:=;\!&lt;&gt;!^&amp;~-]" context="#stay"/>
+
+ </context>
+
+ <context name="Tripple A-comment" attribute="Comment" lineEndContext="#stay">
+ <HlCChar attribute="Comment" context="#stay"/>
+ <RegExpr attribute="Comment" String="'''" context="#pop"/>
+ </context>
+
+ <context name="Tripple Q-comment" attribute="Comment" lineEndContext="#stay">
+ <HlCChar attribute="Comment" context="#stay"/>
+ <RegExpr attribute="Comment" String="&quot;&quot;&quot;" context="#pop"/>
+ </context>
+
+ <context name="Tripple A-string" attribute="String" lineEndContext="#stay">
+ <HlCChar attribute="String" context="#stay"/>
+ <RegExpr attribute="Operator" String="%[a-zA-Z]" context="#stay"/>
+ <RegExpr attribute="String" String="'''" context="#pop"/>
+ </context>
+
+ <context name="Tripple Q-string" attribute="String" lineEndContext="#stay">
+ <HlCStringChar attribute="String" context="#stay"/>
+ <RegExpr attribute="Operator" String="%[a-zA-Z]" context="#stay"/>
+ <RegExpr attribute="String" String="&quot;&quot;&quot;" context="#pop"/>
+ </context>
+
+ <context name="Single A-comment" attribute="Comment" lineEndContext="#stay">
+ <HlCStringChar attribute="Comment" context="#stay"/>
+ <DetectChar attribute="Comment" char="'" context="#pop"/>
+ </context>
+
+ <context name="Single Q-comment" attribute="Comment" lineEndContext="#stay">
+ <HlCStringChar attribute="Comment" context="#stay"/>
+ <DetectChar attribute="Comment" char="&quot;" context="#pop"/>
+ </context>
+
+ <context name="Single A-string" attribute="String" lineEndContext="#stay">
+ <HlCStringChar attribute="String" context="#stay"/>
+ <RegExpr attribute="Operator" String="%[a-zA-Z]" context="#stay"/>
+ <DetectChar attribute="String" char="'" context="#pop"/>
+ </context>
+
+ <context name="Single Q-string" attribute="String" lineEndContext="#stay">
+ <HlCStringChar attribute="String" context="#stay"/>
+ <RegExpr attribute="Operator" String="%[a-zA-Z]" context="#stay"/>
+ <DetectChar attribute="String" char="&quot;" context="#pop"/>
+ </context>
+
+ <context name="Raw A-string" attribute="Raw String" lineEndContext="#stay">
+ <HlCStringChar attribute="Raw String" context="#stay"/>
+ <DetectChar attribute="Raw String" char="'" context="#pop"/>
+ </context>
+
+ <context name="Raw Q-string" attribute="Raw String" lineEndContext="#stay">
+ <HlCStringChar attribute="Raw String" context="#stay"/>
+ <DetectChar attribute="Raw String" char="&quot;" context="#pop"/>
+ </context>
+
+
+ </contexts>
+ <itemDatas>
+ <itemData name="Normal Text" defStyleNum="dsNormal"/>
+ <itemData name="Operator" defStyleNum="dsChar"/>
+ <itemData name="Keyword" defStyleNum="dsKeyword"/>
+ <itemData name="Builtin Function" defStyleNum="dsDataType"/>
+ <itemData name="Kig Object" defStyleNum="dsKeyword" color="#000080" selColor="#ffffff" bold="0" italic="0"/>
+ <itemData name="Math Constants" defStyleNum="dsKeyword" color="#008000" selColor="#00FF00" bold="0" italic="0"/>
+ <itemData name="Special Variable" defStyleNum="dsOthers"/>
+ <itemData name="Preprocessor" defStyleNum="dsChar"/>
+ <itemData name="Long" defStyleNum="dsOthers"/>
+ <itemData name="Float" defStyleNum="dsFloat"/>
+ <itemData name="Int" defStyleNum="dsDecVal"/>
+ <itemData name="Hex" defStyleNum="dsOthers"/>
+ <itemData name="Octal" defStyleNum="dsOthers"/>
+ <itemData name="Complex" defStyleNum="dsOthers"/>
+ <itemData name="Comment" defStyleNum="dsComment"/>
+ <itemData name="String" defStyleNum="dsString"/>
+ <itemData name="Raw String" defStyleNum="dsString"/>
+ </itemDatas>
+ </highlighting>
+ <general>
+<!-- <folding indentationsensitive="1" /> -->
+ <comments>
+ <comment name="singleLine" start="#" />
+ </comments>
+ <keywords casesensitive="1" />
+ </general>
+</language>
diff --git a/kig/scripting/python-scripting-api-dox-mainpage.dox b/kig/scripting/python-scripting-api-dox-mainpage.dox
new file mode 100644
index 00000000..9bf6bbcb
--- /dev/null
+++ b/kig/scripting/python-scripting-api-dox-mainpage.dox
@@ -0,0 +1,26 @@
+/** \mainpage Kig Python Scripting API Documentation
+ * \section Introduction
+ * This is the documentation of the Kig Python Scripting API. It is
+ * intended as a reference for people using the Kig Python Scripting
+ * System. The Documentation is generated from the C++ sources for
+ * the classes, and unfortunately, this means that the documentation
+ * uses a C++ syntax. However, if you ignore this fact, and simply
+ * look at the API as a set of classes with member and static
+ * functions, then you should be fine.
+ *
+ * \section The API
+ * This API is mostly meant to be used from user-defined calc()
+ * functions. In these functions, it is necessary to
+ * \li access the information of the argument \ref ObjectImp's
+ * \li construct and return a new ObjectImp
+ *
+ * Both uses require the ObjectImp API to be exported to Python, and
+ * this is the major part of this API. Some more classes are also
+ * exported, but mostly because they are used from one of the
+ * ObjectImp's APIs.
+ *
+ * \section Links
+ *
+ * Next suggested reading is the
+ * \ref ObjectImp "documentation of the ObjectImp class".
+ */
diff --git a/kig/scripting/python_scripter.cc b/kig/scripting/python_scripter.cc
new file mode 100644
index 00000000..7e833d5c
--- /dev/null
+++ b/kig/scripting/python_scripter.cc
@@ -0,0 +1,578 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "python_scripter.h"
+
+#include <iostream>
+#include <string>
+#include <Python.h>
+#include <boost/python.hpp>
+#include <boost/mpl/bool.hpp>
+
+#include "../misc/common.h"
+#include "../misc/coordinate.h"
+#include "../misc/cubic-common.h"
+#include "../misc/kigtransform.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/common.h"
+#include "../objects/circle_imp.h"
+#include "../objects/cubic_imp.h"
+#include "../objects/line_imp.h"
+#include "../objects/other_imp.h"
+#include "../objects/point_imp.h"
+
+using namespace boost::python;
+
+BOOST_PYTHON_MODULE_INIT( kig )
+{
+ class_<Coordinate>( "Coordinate" )
+ .def( init<double, double>() )
+ .def( init<const Coordinate&>() )
+ .def( "invalidCoord", &Coordinate::invalidCoord )
+ .staticmethod( "invalidCoord" )
+ .def( "valid", &Coordinate::valid )
+ .def( "distance", &Coordinate::distance )
+ .def( "length", &Coordinate::length )
+ .def( "squareLength", &Coordinate::squareLength )
+ .def( "orthogonal", &Coordinate::orthogonal )
+ .def( "round", &Coordinate::round )
+ .def( "normalize", &Coordinate::normalize )
+ .def( -self )
+// .def( self = self )
+ .def( self += self )
+ .def( self -= self )
+ .def( self *= other<double>() )
+ .def( self *= other<int>() )
+ .def( self /= other<double>() )
+ .def( self / other<double>() )
+ .def( self + self )
+ .def( self - self )
+ .def( self * other<double>() )
+ .def( other<double>() * self )
+ .def( self * self )
+ .def_readwrite( "x", &Coordinate::x )
+ .def_readwrite( "y", &Coordinate::y )
+ ;
+
+ class_<LineData>( "LineData" )
+ .def( init<Coordinate, Coordinate>() )
+ .def( "dir", &LineData::dir )
+ .def( "length", &LineData::length )
+ .def( "isParallelTo", &LineData::isParallelTo )
+ .def_readwrite( "a", &LineData::a )
+ .def_readwrite( "b", &LineData::b )
+ ;
+
+ // we need this cause Transformation::apply is overloaded and
+ // otherwise using Transformation::apply would be ambiguous..
+ const Coordinate (Transformation::*transformapplyfunc)( const Coordinate& ) const = &Transformation::apply;
+ class_<Transformation>( "Transformation", no_init )
+ .def( "apply", transformapplyfunc )
+ .def( "isHomothetic", &Transformation::isHomothetic )
+ .def( "inverse", &Transformation::inverse )
+ .def( "identity", &Transformation::identity )
+ .def( "translation", &Transformation::translation )
+ .def( "rotation", &Transformation::rotation )
+ .def( "pointReflection", &Transformation::pointReflection )
+ .def( "lineReflection", &Transformation::lineReflection )
+ .def( "castShadow", &Transformation::castShadow )
+ .def( "projectiveRotation", &Transformation::projectiveRotation )
+ .def( "scalingOverPoint", &Transformation::scalingOverPoint )
+ .def( "scalingOverLine", &Transformation::scalingOverLine )
+ .def( self * self )
+ .def( self == self )
+ .staticmethod( "identity" )
+ .staticmethod( "translation" )
+ .staticmethod( "rotation" )
+ .staticmethod( "pointReflection" )
+ .staticmethod( "lineReflection" )
+ .staticmethod( "castShadow" )
+ .staticmethod( "projectiveRotation" )
+ .staticmethod( "scalingOverPoint" )
+ .staticmethod( "scalingOverLine" )
+ ;
+
+ class_<ObjectImpType, boost::noncopyable>( "ObjectType", no_init )
+ .def( "fromInternalName", &ObjectImpType::typeFromInternalName,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "fromInternalName" )
+ .def( "inherits", &ObjectImpType::inherits )
+ .def( "internalName", &ObjectImpType::internalName )
+ .def( "translatedName", &ObjectImpType::translatedName )
+ .def( "selectStatement", &ObjectImpType::selectStatement )
+ .def( "removeAStatement", &ObjectImpType::removeAStatement )
+ .def( "addAStatement", &ObjectImpType::addAStatement )
+ .def( "moveAStatement", &ObjectImpType::moveAStatement )
+ .def( "attachToThisStatement", &ObjectImpType::attachToThisStatement )
+ ;
+
+ class_<ObjectImp, boost::noncopyable>( "Object", no_init )
+ .def( "stype", &ObjectImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( "inherits", &ObjectImp::inherits )
+ .def( "transform", &ObjectImp::transform,
+ return_value_policy<manage_new_object>() )
+ .def( "valid", &ObjectImp::valid )
+ .def( "copy", &ObjectImp::copy,
+ return_value_policy<manage_new_object>() )
+ .def( "equals", &ObjectImp::equals )
+ ;
+
+ class_<CurveImp, bases<ObjectImp>, boost::noncopyable>( "Curve", no_init )
+ .def( "stype", &CurveImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+// .def( "getParam", &CurveImp::getParam )
+// .def( "getPoint", &CurveImp::getPoint );
+ ;
+ class_<PointImp, bases<ObjectImp> >( "Point", init<Coordinate>() )
+ .def( "stype", &PointImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( "coordinate", &PointImp::coordinate,
+ return_internal_reference<1>() )
+ .def( "setCoordinate", &PointImp::setCoordinate )
+ ;
+
+ class_<AbstractLineImp, bases<CurveImp>, boost::noncopyable >( "AbstractLine", no_init )
+ .def( "stype", &AbstractLineImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( "slope", &AbstractLineImp::slope )
+ .def( "equationString", &AbstractLineImp::equationString )
+ .def( "data", &AbstractLineImp::data )
+ ;
+
+ class_<SegmentImp, bases<AbstractLineImp> >( "Segment", init<Coordinate, Coordinate>() )
+ .def( "stype", &SegmentImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( init<LineData>() )
+ .def( "length", &SegmentImp::length )
+ ;
+
+ class_<RayImp, bases<AbstractLineImp> >( "Ray", init<Coordinate, Coordinate>() )
+ .def( "stype", &RayImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( init<LineData>() )
+ ;
+
+ class_<LineImp, bases<AbstractLineImp> >( "Line", init<Coordinate, Coordinate>() )
+ .def( "stype", &LineImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( init<LineData>() )
+ ;
+
+ class_<ConicCartesianData>( "ConicCartesianData", init<double,double,double,double,double,double>() )
+ .def( init<ConicPolarData>() )
+ .def( "invalidData", &ConicCartesianData::invalidData )
+ .staticmethod( "invalidData" )
+ .def( "valid", &ConicCartesianData::valid )
+// .def( init<double[6]>() )
+// .def_readwrite( "coeffs", &ConicCartesianData::coeffs )
+ ;
+
+ class_<ConicPolarData>( "ConicPolarData", init<Coordinate, double, double, double>() )
+ .def( init<ConicCartesianData>() )
+ .def_readwrite( "focus1", &ConicPolarData::focus1 )
+ .def_readwrite( "pdimen", &ConicPolarData::pdimen )
+ .def_readwrite( "ecostheta0", &ConicPolarData::ecostheta0 )
+ .def_readwrite( "esintheta0", &ConicPolarData::esintheta0 )
+ ;
+
+ class_<ConicImp, bases<CurveImp>, boost::noncopyable >( "Conic", no_init )
+ .def( "stype", &ConicImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( "conicType", &ConicImp::conicType )
+// .def( "conicTypeString", &ConicImp::conicTypeString )
+// .def( "cartesianEquationString", &ConicImp::cartesianEquationString )
+// .def( "polarEquationString", &ConicImp::polarEquationString )
+ .def( "cartesianData", &ConicImp::cartesianData )
+ .def( "polarData", &ConicImp::polarData )
+ .def( "focus1", &ConicImp::focus1 )
+ .def( "focus2", &ConicImp::focus2 )
+ ;
+
+ class_<ConicImpCart, bases<ConicImp> >( "CartesianConic", init<ConicCartesianData>() )
+ ;
+ class_<ConicImpPolar, bases<ConicImp> >( "PolarConic", init<ConicPolarData>() )
+ ;
+
+ class_<CircleImp, bases<ConicImp> >( "Circle", init<Coordinate, double>() )
+ .def( "stype", &CircleImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( "center", &CircleImp::center )
+ .def( "radius", &CircleImp::radius )
+ .def( "squareRadius", &CircleImp::squareRadius )
+ .def( "surface", &CircleImp::surface )
+ .def( "circumference", &CircleImp::circumference )
+ ;
+
+ class_<VectorImp, bases<CurveImp> >( "Vector", init<Coordinate, Coordinate>() )
+ .def( "stype", &VectorImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( "length", &VectorImp::length )
+ .def( "dir", &VectorImp::dir )
+ .def( "data", &VectorImp::data )
+ ;
+
+ class_<AngleImp, bases<ObjectImp> >( "Angle", init<Coordinate, double, double>() )
+ .def( "stype", &AngleImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( "size", &AngleImp::size )
+ .def( "point", &AngleImp::point )
+ .def( "startAngle", &AngleImp::startAngle )
+ .def( "angle", &AngleImp::angle )
+ ;
+
+ class_<ArcImp, bases<ObjectImp> >( "Arc", init<Coordinate, double, double, double>() )
+ .def( "stype", &ArcImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( "startAngle", &ArcImp::startAngle )
+ .def( "angle", &ArcImp::angle )
+ .def( "radius", &ArcImp::radius )
+ .def( "center", &ArcImp::center )
+ .def( "firstEndPoint", &ArcImp::firstEndPoint )
+ .def( "secondEndPoint", &ArcImp::secondEndPoint )
+ .def( "sectorSurface", &ArcImp::sectorSurface )
+ ;
+
+ class_<BogusImp, bases<ObjectImp>, boost::noncopyable >( "BogusObject", no_init )
+ .def( "stype", &BogusImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ ;
+
+ class_<InvalidImp, bases<BogusImp> >( "InvalidObject", init<>() )
+ .def( "stype", &InvalidImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ ;
+
+ class_<DoubleImp, bases<BogusImp> >( "DoubleObject", init<double>() )
+ .def( "stype", &DoubleImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( "data", &DoubleImp::data )
+ .def( "setData", &DoubleImp::setData )
+ ;
+
+ class_<IntImp, bases<BogusImp> >( "IntObject", init<int>() )
+ .def( "stype", &IntImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( "data", &IntImp::data )
+ .def( "setData", &IntImp::setData )
+ ;
+
+ class_<StringImp, bases<BogusImp> >( "StringObject", no_init )
+ .def( "stype", &StringImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+// .def( "data", &StringImp::data )
+// .def( "setData", &StringImp::setData )
+ ;
+
+ class_<TestResultImp, bases<BogusImp> >( "TestResultObject", no_init )
+ .def( "stype", &TestResultImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+// .def( "data", &TestResultImp::data )
+ ;
+
+// class_<TextImp, bases<ObjectImp> >( "Text", init<string, Coordinate, bool>() )
+// .def( "stype", &TextImp::stype,
+// return_value_policy<reference_existing_object>() )
+// .staticmethod( "stype" )
+// .def( "text", &TextImp::text )
+// .def( "coordinate", &TextImp::coordinate )
+// .def( "hasFrame", &TextImp::hasFrame )
+// ;
+
+ class_<CubicCartesianData>( "CubicCartesianData", init<double,double,double,double,double,double,double,double,double,double>() )
+ .def( "invalidData", &CubicCartesianData::invalidData )
+ .staticmethod( "invalidData" )
+ .def( "valid", &CubicCartesianData::valid )
+// .def( init<double[10]>() )
+// .def_readwrite( "coeffs", &CubicCartesianData::coeffs )
+ ;
+
+ class_<CubicImp, bases<CurveImp> >( "Cubic", init<CubicCartesianData>() )
+ .def( "stype", &CubicImp::stype,
+ return_value_policy<reference_existing_object>() )
+ .staticmethod( "stype" )
+ .def( "data", &CubicImp::data )
+ ;
+
+}
+
+PythonScripter* PythonScripter::instance()
+{
+ static PythonScripter t;
+ return &t;
+}
+
+class PythonScripter::Private
+{
+public:
+ dict mainnamespace;
+};
+
+// allocates a new string using new [], and copies contents into it..
+static char* newstring( const char* contents )
+{
+ char* ret = new char[strlen( contents ) + 1];
+ strcpy( ret, contents );
+ return ret;
+}
+
+PythonScripter::PythonScripter()
+{
+ d = new Private;
+
+ // tell the python interpreter about our API..
+
+ // the newstring stuff is to prevent warnings about conversion from
+ // const char* to char*..
+ char* s = newstring( "kig" );
+ PyImport_AppendInittab( s, initkig );
+ // we can't delete this yet, since python keeps a pointer to it..
+ // This means we have a small but harmless memory leak here, but it
+ // doesn't hurt at all, since it could only be freed at the end of
+ // the program, at which time it is freed by the system anyway if we
+ // don't do it..
+ //delete [] s;
+
+ Py_Initialize();
+
+ s = newstring( "import math; from math import *;" );
+ PyRun_SimpleString( s );
+ delete [] s;
+ s = newstring( "import kig; from kig import *;" );
+ PyRun_SimpleString( s );
+ delete [] s;
+ s = newstring( "import traceback;" );
+ PyRun_SimpleString( s );
+ delete [] s;
+
+ // find the main namespace..
+
+ s = newstring( "__main__" );
+ handle<> main_module( borrowed( PyImport_AddModule( s ) ) );
+ delete [] s;
+
+ handle<> mnh(borrowed( PyModule_GetDict(main_module.get()) ));
+ d->mainnamespace = extract<dict>( mnh.get() );
+}
+
+PythonScripter::~PythonScripter()
+{
+ PyErr_Clear();
+ Py_Finalize();
+ delete d;
+}
+
+class CompiledPythonScript::Private
+{
+public:
+ int ref;
+ object calcfunc;
+ // TODO
+// object movefunc;
+};
+
+ObjectImp* CompiledPythonScript::calc( const Args& args, const KigDocument& )
+{
+ return PythonScripter::instance()->calc( *this, args );
+}
+
+CompiledPythonScript::~CompiledPythonScript()
+{
+ --d->ref;
+ if ( d->ref == 0 )
+ delete d;
+}
+
+CompiledPythonScript::CompiledPythonScript( Private* ind )
+ : d( ind )
+{
+ ++d->ref;
+}
+
+CompiledPythonScript PythonScripter::compile( const char* code )
+{
+ clearErrors();
+ dict retdict;
+ bool error = false;
+ try
+ {
+ (void) PyRun_String( const_cast<char*>( code ), Py_file_input,
+ d->mainnamespace.ptr(), retdict.ptr() );
+ }
+ catch( ... )
+ {
+ error = true;
+ };
+ error |= static_cast<bool>( PyErr_Occurred() );
+ if ( error )
+ {
+ saveErrors();
+ retdict.clear();
+ }
+
+ // debugging stuff, removed.
+// std::string dictstring = extract<std::string>( str( retdict ) );
+
+ CompiledPythonScript::Private* ret = new CompiledPythonScript::Private;
+ ret->ref = 0;
+ ret->calcfunc = retdict.get( "calc" );
+ return CompiledPythonScript( ret );
+}
+
+CompiledPythonScript::CompiledPythonScript( const CompiledPythonScript& s )
+ : d( s.d )
+{
+ ++d->ref;
+}
+
+std::string PythonScripter::lastErrorExceptionType() const
+{
+ return lastexceptiontype;
+}
+
+std::string PythonScripter::lastErrorExceptionValue() const
+{
+ return lastexceptionvalue;
+}
+
+std::string PythonScripter::lastErrorExceptionTraceback() const
+{
+ return lastexceptiontraceback;
+}
+
+ObjectImp* PythonScripter::calc( CompiledPythonScript& script, const Args& args )
+{
+ clearErrors();
+ object calcfunc = script.d->calcfunc;
+ try
+ {
+ std::vector<object> objectvect;
+ objectvect.reserve( args.size() );
+
+ for ( int i = 0; i < (int) args.size(); ++i )
+ {
+ object o( boost::ref( *args[i] ) );
+ objectvect.push_back( o );
+ }
+
+ handle<> argstuph( PyTuple_New( args.size() ) );
+ for ( int i = 0; i < (int) objectvect.size(); ++i )
+ {
+ PyTuple_SetItem( argstuph.get(), i, (objectvect.begin() +i)->ptr() );
+ };
+ tuple argstup( argstuph );
+
+ handle<> reth( PyEval_CallObject( calcfunc.ptr(), argstup.ptr() ) );
+// object resulto = calcfunc( argstup );
+// handle<> reth( PyEval_CallObject( calcfunc.ptr(), args ) );
+ object resulto( reth );
+
+ extract<ObjectImp&> result( resulto );
+ if( ! result.check() ) return new InvalidImp;
+ else
+ {
+ ObjectImp& ret = result();
+ return ret.copy();
+ };
+ }
+ catch( ... )
+ {
+ saveErrors();
+
+ return new InvalidImp;
+ };
+}
+
+void PythonScripter::saveErrors()
+{
+ erroroccurred = true;
+ PyObject* poexctype;
+ PyObject* poexcvalue;
+ PyObject* poexctraceback;
+ PyErr_Fetch( &poexctype, &poexcvalue, &poexctraceback );
+ handle<> exctypeh( poexctype );
+ handle<> excvalueh( poexcvalue );
+
+ object exctype( exctypeh );
+ object excvalue( excvalueh );
+ object exctraceback;
+ if ( poexctraceback )
+ {
+ handle<> exctracebackh( poexctraceback );
+ exctraceback = object( exctracebackh );
+ }
+
+ lastexceptiontype = extract<std::string>( str( exctype ) )();
+ lastexceptionvalue = extract<std::string>( str( excvalue ) )();
+
+ object printexcfunc = d->mainnamespace[ "traceback" ].attr( "format_exception" );
+
+ list tracebacklist = extract<list>( printexcfunc( exctype, excvalue, exctraceback ) )();
+ str tracebackstr( "" );
+ while ( true )
+ {
+ try {
+ str s = extract<str>( tracebacklist.pop() );
+ tracebackstr += s;
+ }
+ catch( ... )
+ {
+ break;
+ }
+ }
+
+ lastexceptiontraceback = extract<std::string>( tracebackstr )();
+ PyErr_Clear();
+}
+
+void PythonScripter::clearErrors()
+{
+ PyErr_Clear();
+ lastexceptiontype.clear();
+ lastexceptionvalue.clear();
+ lastexceptiontraceback.clear();
+ erroroccurred = false;
+}
+
+bool CompiledPythonScript::valid()
+{
+ return !!d->calcfunc;
+}
+
+bool PythonScripter::errorOccurred() const
+{
+ return erroroccurred;
+}
+
diff --git a/kig/scripting/python_scripter.h b/kig/scripting/python_scripter.h
new file mode 100644
index 00000000..464b5d3e
--- /dev/null
+++ b/kig/scripting/python_scripter.h
@@ -0,0 +1,69 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_SCRIPTING_PYTHON_SCRIPTER_H
+#define KIG_SCRIPTING_PYTHON_SCRIPTER_H
+
+#include "../objects/common.h"
+
+#include <string>
+
+class KigDocument;
+class ObjectImp;
+
+class CompiledPythonScript
+{
+ friend class PythonScripter;
+ class Private;
+ Private* const d;
+ CompiledPythonScript( Private* );
+public:
+ CompiledPythonScript( const CompiledPythonScript& s );
+ ~CompiledPythonScript();
+ ObjectImp* calc( const Args& a, const KigDocument& doc );
+
+ bool valid();
+};
+
+class PythonScripter
+{
+ friend class CompiledPythonScript;
+ class Private;
+ Private* d;
+ PythonScripter();
+ ~PythonScripter();
+
+ void clearErrors();
+ void saveErrors();
+
+ bool erroroccurred;
+ std::string lastexceptiontype;
+ std::string lastexceptionvalue;
+ std::string lastexceptiontraceback;
+public:
+ static PythonScripter* instance();
+
+ bool errorOccurred() const;
+ std::string lastErrorExceptionType() const;
+ std::string lastErrorExceptionValue() const;
+ std::string lastErrorExceptionTraceback() const;
+
+ CompiledPythonScript compile( const char* code );
+ ObjectImp* calc( CompiledPythonScript& script, const Args& args );
+};
+
+#endif
diff --git a/kig/scripting/python_type.cc b/kig/scripting/python_type.cc
new file mode 100644
index 00000000..0180e828
--- /dev/null
+++ b/kig/scripting/python_type.cc
@@ -0,0 +1,195 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "python_type.h"
+
+#include "python_scripter.h"
+
+#include "../objects/object_imp.h"
+#include "../objects/bogus_imp.h"
+
+class PythonCompiledScriptImp
+ : public BogusImp
+{
+ mutable CompiledPythonScript mscript;
+public:
+ typedef BogusImp Parent;
+ static const ObjectImpType* stype();
+ const ObjectImpType* type() const;
+
+ PythonCompiledScriptImp( const CompiledPythonScript& s );
+
+ void visit( ObjectImpVisitor* vtor ) const;
+ ObjectImp* copy() const;
+ bool equals( const ObjectImp& rhs ) const;
+
+ bool isCache() const;
+
+ CompiledPythonScript& data() const { return mscript; };
+};
+
+PythonCompiledScriptImp::PythonCompiledScriptImp( const CompiledPythonScript& s )
+ : BogusImp(), mscript( s )
+{
+
+}
+
+const ObjectImpType* PythonCompiledScriptImp::stype()
+{
+ static const ObjectImpType t( BogusImp::stype(), "python-compiled-script-imp",
+ 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+ return &t;
+}
+
+const ObjectImpType* PythonCompiledScriptImp::type() const
+{
+ return PythonCompiledScriptImp::stype();
+}
+
+void PythonCompiledScriptImp::visit( ObjectImpVisitor* ) const
+{
+ // TODO ?
+}
+
+ObjectImp* PythonCompiledScriptImp::copy() const
+{
+ return new PythonCompiledScriptImp( mscript );
+}
+
+bool PythonCompiledScriptImp::equals( const ObjectImp& ) const
+{
+ // problem ?
+ return true;
+}
+
+bool PythonCompiledScriptImp::isCache() const
+{
+ return true;
+}
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PythonCompileType )
+
+PythonCompileType::PythonCompileType()
+ : ObjectType( "PythonCompileType" )
+{
+}
+
+PythonCompileType::~PythonCompileType()
+{
+}
+
+const PythonCompileType* PythonCompileType::instance()
+{
+ static const PythonCompileType t;
+ return &t;
+}
+
+const ObjectImpType* PythonCompileType::impRequirement( const ObjectImp*, const Args& ) const
+{
+ return StringImp::stype();
+}
+
+const ObjectImpType* PythonCompileType::resultId() const
+{
+ return PythonCompiledScriptImp::stype();
+}
+
+ObjectImp* PythonCompileType::calc( const Args& parents, const KigDocument& ) const
+{
+ assert( parents.size() == 1 );
+ if ( !parents[0]->inherits( StringImp::stype() ) ) return new InvalidImp;
+
+ const StringImp* si = static_cast<const StringImp*>( parents[0] );
+ QString s = si->data();
+
+ CompiledPythonScript cs = PythonScripter::instance()->compile( s.latin1() );
+
+ if ( cs.valid() )
+ return new PythonCompiledScriptImp( cs );
+ else
+ return new InvalidImp();
+}
+
+KIG_INSTANTIATE_OBJECT_TYPE_INSTANCE( PythonExecuteType )
+
+PythonExecuteType::PythonExecuteType()
+ : ObjectType( "PythonExecuteType" )
+{
+}
+
+PythonExecuteType::~PythonExecuteType()
+{
+}
+
+const PythonExecuteType* PythonExecuteType::instance()
+{
+ static const PythonExecuteType t;
+ return &t;
+}
+
+ObjectImp* PythonExecuteType::calc( const Args& parents, const KigDocument& d ) const
+{
+ assert( parents.size() >= 1 );
+ if( !parents[0]->inherits( PythonCompiledScriptImp::stype() ) ) return new InvalidImp;
+
+ CompiledPythonScript& script = static_cast<const PythonCompiledScriptImp*>( parents[0] )->data();
+
+ Args args( parents.begin() + 1, parents.end() );
+ return script.calc( args, d );
+}
+
+const ObjectImpType* PythonExecuteType::impRequirement( const ObjectImp* o, const Args& parents ) const
+{
+ if ( o == parents[0] ) return PythonCompiledScriptImp::stype();
+ else return ObjectImp::stype();
+}
+
+const ObjectImpType* PythonExecuteType::resultId() const
+{
+ return ObjectImp::stype();
+}
+
+std::vector<ObjectCalcer*> PythonCompileType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ return args;
+}
+
+Args PythonCompileType::sortArgs( const Args& args ) const
+{
+ return args;
+}
+
+std::vector<ObjectCalcer*> PythonExecuteType::sortArgs( const std::vector<ObjectCalcer*>& args ) const
+{
+ return args;
+}
+
+Args PythonExecuteType::sortArgs( const Args& args ) const
+{
+ return args;
+}
+
+bool PythonCompileType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
+{
+ return false;
+}
+
+bool PythonExecuteType::isDefinedOnOrThrough( const ObjectImp*, const Args& ) const
+{
+ return false;
+}
+
diff --git a/kig/scripting/python_type.h b/kig/scripting/python_type.h
new file mode 100644
index 00000000..1e76b0b8
--- /dev/null
+++ b/kig/scripting/python_type.h
@@ -0,0 +1,63 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_SCRIPTING_PYTHON_TYPE_H
+#define KIG_SCRIPTING_PYTHON_TYPE_H
+
+#include "../objects/object_type.h"
+
+class PythonCompileType
+ : public ObjectType
+{
+ PythonCompileType();
+ ~PythonCompileType();
+public:
+ static const PythonCompileType* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& d ) const;
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ const ObjectImpType* resultId() const;
+
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const;
+ Args sortArgs( const Args& args ) const;
+};
+
+class PythonExecuteType
+ : public ObjectType
+{
+ PythonExecuteType();
+ ~PythonExecuteType();
+public:
+ static const PythonExecuteType* instance();
+
+ ObjectImp* calc( const Args& parents, const KigDocument& d ) const;
+
+ const ObjectImpType* impRequirement( const ObjectImp* o, const Args& parents ) const;
+ bool isDefinedOnOrThrough( const ObjectImp* o, const Args& parents ) const;
+ const ObjectImpType* resultId() const;
+
+ std::vector<ObjectCalcer*> sortArgs( const std::vector<ObjectCalcer*>& args ) const;
+ Args sortArgs( const Args& args ) const;
+
+// virtual QStringList specialActions() const;
+// virtual void executeAction( int i, RealObject* o, KigDocument& d, KigWidget& w,
+// NormalMode& m ) const;
+};
+
+#endif
diff --git a/kig/scripting/script-common.cc b/kig/scripting/script-common.cc
new file mode 100644
index 00000000..4bd2cbd8
--- /dev/null
+++ b/kig/scripting/script-common.cc
@@ -0,0 +1,95 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "script-common.h"
+
+#include <qstring.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+struct script_prop
+{
+ const char* fillCodeStatement;
+ const char* icon;
+ const char* highlightStyle;
+};
+
+static const script_prop scripts_properties[] =
+{
+ { I18N_NOOP( "Now fill in the code:" ), "shellscript", "" },
+ { I18N_NOOP( "Now fill in the Python code:" ), "source_py", "Python-Kig" }
+};
+
+QString ScriptType::fillCodeStatement( ScriptType::Type type )
+{
+ return i18n( scripts_properties[type].fillCodeStatement );
+}
+
+QString ScriptType::templateCode( ScriptType::Type type, std::list<ObjectHolder*> args )
+{
+ if ( type == Python )
+ {
+ QString tempcode = QString::fromLatin1( "def calc( " );
+ bool firstarg = true;
+ QString temparg = i18n( "Note to translators: this should be a default "
+ "name for an argument in a Python function. The "
+ "default is \"arg%1\" which would become arg1, "
+ "arg2, etc. Give something which seems "
+ "appropriate for your language.", "arg%1" );
+
+ uint id = 1;
+ for ( std::list<ObjectHolder*>::const_iterator i = args.begin(); i != args.end(); ++i )
+ {
+ if ( !firstarg ) tempcode += ", ";
+ else firstarg = false;
+ QString n = ( *i )->name();
+ tempcode += n.isEmpty() ? temparg.arg( id ) : n;
+ id++;
+ };
+ tempcode +=
+ " ):\n"
+ "\t# Calculate whatever you want to show here, and return it.\n"
+ "\t# For example, to implement a mid point, you would put\n"
+ "\t# this code here:\n"
+ "\t#\treturn Point( ( arg1.coordinate() + arg2.coordinate() ) / 2 )\n"
+ "\t# Please refer to the manual for more information.\n"
+ "\n";
+ return tempcode;
+ }
+
+ kdDebug() << "No such script type: " << type << endl;
+ return "";
+}
+
+const char* ScriptType::icon( ScriptType::Type type )
+{
+ return scripts_properties[type].icon;
+}
+
+QString ScriptType::highlightStyle( ScriptType::Type type )
+{
+ return QString( scripts_properties[type].highlightStyle );
+}
+
+ScriptType::Type ScriptType::intToType( int type )
+{
+ if ( type == 1 )
+ return Python;
+
+ return Unknown;
+}
diff --git a/kig/scripting/script-common.h b/kig/scripting/script-common.h
new file mode 100644
index 00000000..1c384453
--- /dev/null
+++ b/kig/scripting/script-common.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2004 Pino Toscano <toscano.pino@tiscali.it>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_SCRIPTING_SCRIPT_COMMON_H
+#define KIG_SCRIPTING_SCRIPT_COMMON_H
+
+#include <algorithm>
+#include <list>
+
+#include "../objects/object_holder.h"
+
+class QString;
+
+class ScriptType
+{
+public:
+ /**
+ * This enum represents all the script language types actually in
+ * Kig. The first type ( Unknown ) can be used if we don't want
+ * particular tunings for a script language.
+ */
+ enum Type { Unknown = 0, Python = 1 };
+ /**
+ * Returns an i18n'ed statement like 'Now fill in the code:' with
+ * the name of the script language.
+ */
+ static QString fillCodeStatement( ScriptType::Type type );
+ /**
+ * Returns a template code for a script language.
+ */
+ static QString templateCode( ScriptType::Type type, std::list<ObjectHolder*> args );
+ /**
+ * Returns the icon's name for a script language.
+ */
+ static const char* icon( ScriptType::Type type );
+ /**
+ * Returns the Kate highlight stytle name for a script language.
+ */
+ static QString highlightStyle( ScriptType::Type type );
+ /**
+ * Converts an int to a ScriptType::Type. Useful when reading script
+ * types from files.
+ */
+ static ScriptType::Type intToType( int type );
+};
+
+#endif
diff --git a/kig/scripting/script_mode.cc b/kig/scripting/script_mode.cc
new file mode 100644
index 00000000..000b99f8
--- /dev/null
+++ b/kig/scripting/script_mode.cc
@@ -0,0 +1,362 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#include "script_mode.h"
+
+#include "newscriptwizard.h"
+#include "python_type.h"
+#include "python_scripter.h"
+
+#include "../kig/kig_commands.h"
+#include "../kig/kig_part.h"
+#include "../kig/kig_view.h"
+#include "../misc/calcpaths.h"
+#include "../misc/kigpainter.h"
+#include "../modes/dragrectmode.h"
+#include "../objects/bogus_imp.h"
+#include "../objects/object_imp.h"
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+
+#include <kcursor.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+
+void ScriptModeBase::dragRect( const QPoint& p, KigWidget& w )
+{
+ if ( mwawd != SelectingArgs ) return;
+
+ DragRectMode dm( p, mdoc, w );
+ mdoc.runMode( &dm );
+ std::vector<ObjectHolder*> ret = dm.ret();
+
+ KigPainter pter( w.screenInfo(), &w.stillPix, mdoc.document() );
+ if ( dm.needClear() )
+ {
+ std::vector<ObjectHolder*> tmp( margs.begin(), margs.begin() );
+ pter.drawObjects( tmp, false );
+ margs.clear();
+ }
+
+ std::copy( ret.begin(), ret.end(), std::inserter( margs, margs.begin() ) );
+ pter.drawObjects( ret, true );
+
+ w.updateCurPix( pter.overlay() );
+ w.updateWidget();
+}
+
+void ScriptModeBase::leftClickedObject( ObjectHolder* o, const QPoint&,
+ KigWidget& w, bool )
+{
+ std::list<ObjectHolder*>::iterator dup_o;
+
+ if ( mwawd != SelectingArgs ) return;
+
+ KigPainter pter( w.screenInfo(), &w.stillPix, mdoc.document() );
+
+ if ( (dup_o = std::find( margs.begin(), margs.end(), o )) != margs.end() )
+ {
+ margs.erase( dup_o );
+ pter.drawObject( o, false );
+ }
+ else
+ {
+ margs.push_back( o );
+ pter.drawObject( o, true );
+ };
+ w.updateCurPix( pter.overlay() );
+ w.updateWidget();
+}
+
+void ScriptModeBase::mouseMoved( const std::vector<ObjectHolder*>& os,
+ const QPoint& pt, KigWidget& w, bool )
+{
+ if ( mwawd != SelectingArgs ) return;
+
+ w.updateCurPix();
+ if ( os.empty() )
+ {
+ w.setCursor( KCursor::arrowCursor() );
+ mdoc.emitStatusBarText( 0 );
+ w.updateWidget();
+ }
+ else
+ {
+ // the cursor is over an object, show object type next to cursor
+ // and set statusbar text
+
+ w.setCursor( KCursor::handCursor() );
+ QString selectstat = os.front()->selectStatement();
+
+ // statusbar text
+ mdoc.emitStatusBarText( selectstat );
+ KigPainter p( w.screenInfo(), &w.curPix, mdoc.document() );
+
+ // set the text next to the arrow cursor
+ QPoint point = pt;
+ point.setX(point.x()+15);
+
+ p.drawTextStd( point, selectstat );
+ w.updateWidget( p.overlay() );
+ }
+}
+
+ScriptModeBase::ScriptModeBase( KigPart& doc )
+ : BaseMode( doc ), mwizard( 0 ), mpart( doc ),
+ mwawd( SelectingArgs )
+{
+ mwizard = new NewScriptWizard( doc.widget(), this );
+
+ doc.redrawScreen();
+}
+
+ScriptModeBase::~ScriptModeBase()
+{
+}
+
+void ScriptModeBase::killMode()
+{
+ mdoc.doneMode( this );
+}
+
+bool ScriptCreationMode::queryCancel()
+{
+ killMode();
+ return true;
+}
+
+void ScriptModeBase::argsPageEntered()
+{
+ mwawd = SelectingArgs;
+ mdoc.redrawScreen();
+}
+
+void ScriptModeBase::enableActions()
+{
+ KigMode::enableActions();
+ // we don't enable any actions..
+}
+
+void ScriptModeBase::codePageEntered()
+{
+ if ( mwizard->text().isEmpty() )
+ {
+ // insert template code..
+ QString tempcode = ScriptType::templateCode( mtype, margs );
+ mwizard->setText( tempcode );
+ };
+ mwizard->setFinishEnabled( mwizard->mpcode, true );
+ mwawd = EnteringCode;
+ mdoc.redrawScreen();
+}
+
+void ScriptModeBase::redrawScreen( KigWidget* w )
+{
+ std::vector<ObjectHolder*> sel;
+ if ( mwawd == SelectingArgs )
+ sel = std::vector<ObjectHolder*>( margs.begin(), margs.end() );
+ w->redrawScreen( sel );
+ w->updateScrollBars();
+}
+
+bool ScriptCreationMode::queryFinish()
+{
+ std::vector<ObjectCalcer*> args;
+
+ QString script = mwizard->text();
+ args.push_back( new ObjectConstCalcer( new StringImp( script ) ) );
+
+ ObjectTypeCalcer* compiledscript =
+ new ObjectTypeCalcer( PythonCompileType::instance(), args );
+ compiledscript->calc( mdoc.document() );
+
+ args.clear();
+ args.push_back( compiledscript );
+ for ( std::list<ObjectHolder*>::iterator i = margs.begin();
+ i != margs.end(); ++i )
+ args.push_back( ( *i )->calcer() );
+
+ ObjectTypeCalcer::shared_ptr reto =
+ new ObjectTypeCalcer( PythonExecuteType::instance(), args );
+ reto->calc( mdoc.document() );
+
+ if ( reto->imp()->inherits( InvalidImp::stype() ) )
+ {
+ PythonScripter* inst = PythonScripter::instance();
+ QCString errtrace = inst->lastErrorExceptionTraceback().c_str();
+ if ( inst->errorOccurred() )
+ {
+ KMessageBox::detailedSorry(
+ mwizard, i18n( "The Python interpreter caught an error during the execution of your "
+ "script. Please fix the script and click the Finish button again." ),
+ i18n( "The Python Interpreter generated the following error output:\n%1").arg( errtrace ) );
+ }
+ else
+ {
+ KMessageBox::sorry(
+ mwizard, i18n( "There seems to be an error in your script. The Python interpreter "
+ "reported no errors, but the script does not generate "
+ "a valid object. Please fix the script, and click the Finish button "
+ "again." ) );
+ }
+ return false;
+ }
+ else
+ {
+ mdoc.addObject( new ObjectHolder( reto.get() ) );
+ killMode();
+ return true;
+ }
+}
+
+void ScriptModeBase::midClicked( const QPoint&, KigWidget& )
+{
+}
+
+void ScriptModeBase::rightClicked( const std::vector<ObjectHolder*>&,
+ const QPoint&, KigWidget& )
+{
+}
+
+void ScriptModeBase::setScriptType( ScriptType::Type type )
+{
+ mtype = type;
+ mwizard->setType( mtype );
+ if ( mtype != ScriptType::Unknown )
+ {
+ KIconLoader* il = mpart.instance()->iconLoader();
+ mwizard->setIcon( il->loadIcon( ScriptType::icon( mtype ), KIcon::Small ) );
+ }
+}
+
+void ScriptModeBase::addArgs( const std::vector<ObjectHolder*>& obj, KigWidget& w )
+{
+ KigPainter pter( w.screenInfo(), &w.stillPix, mdoc.document() );
+
+ std::copy( obj.begin(), obj.end(), std::inserter( margs, margs.begin() ) );
+ pter.drawObjects( obj, true );
+
+ w.updateCurPix( pter.overlay() );
+ w.updateWidget();
+}
+
+void ScriptModeBase::goToCodePage()
+{
+ mwizard->next();
+}
+
+ScriptCreationMode::ScriptCreationMode( KigPart& doc )
+ : ScriptModeBase( doc )
+{
+ mwizard->show();
+}
+
+ScriptCreationMode::~ScriptCreationMode()
+{
+}
+
+ScriptEditMode::ScriptEditMode( ObjectTypeCalcer* exec_calc, KigPart& doc )
+ : ScriptModeBase( doc ), mexecuted( exec_calc )
+{
+ mwawd = EnteringCode;
+
+ mexecargs = mexecuted->parents();
+ assert( mexecargs.size() >= 1 );
+
+ mcompiledargs = mexecargs[0]->parents();
+ assert( mcompiledargs.size() == 1 );
+
+ const ObjectImp* imp = static_cast<ObjectConstCalcer*>( mcompiledargs[0] )->imp();
+ assert( dynamic_cast<const StringImp*>( imp ) );
+ // save the original script text, in case the user modifies the text
+ // in the editor and aborts the editing
+ morigscript = static_cast<const StringImp*>( imp )->data();
+
+ mwizard->setCaption( i18n( "'Edit' is a verb", "Edit Script" ) );
+ mwizard->setText( morigscript );
+ mwizard->show();
+ mwizard->next();
+ mwizard->backButton()->setEnabled( false );
+ mwizard->finishButton()->setEnabled( true );
+}
+
+ScriptEditMode::~ScriptEditMode()
+{
+}
+
+bool ScriptEditMode::queryFinish()
+{
+ MonitorDataObjects mon( mcompiledargs );
+
+ static_cast<ObjectConstCalcer*>( mcompiledargs[0] )->switchImp( new StringImp( mwizard->text() ) );
+ mexecargs[0]->calc( mpart.document() );
+
+ mexecuted->calc( mpart.document() );
+
+ mpart.redrawScreen();
+
+ KigCommand* comm = new KigCommand( mpart, i18n( "Edit Python Script" ) );
+ mon.finish( comm );
+
+ if ( mexecuted->imp()->inherits( InvalidImp::stype() ) )
+ {
+ PythonScripter* inst = PythonScripter::instance();
+ QCString errtrace = inst->lastErrorExceptionTraceback().c_str();
+ if ( inst->errorOccurred() )
+ {
+ KMessageBox::detailedSorry(
+ mpart.widget(), i18n( "The Python interpreter caught an error during the execution of your "
+ "script. Please fix the script." ),
+ i18n( "The Python Interpreter generated the following error output:\n%1").arg( errtrace ) );
+ }
+ else
+ {
+ KMessageBox::sorry(
+ mpart.widget(), i18n( "There seems to be an error in your script. The Python interpreter "
+ "reported no errors, but the script does not generate "
+ "a valid object. Please fix the script." ) );
+ }
+ delete comm;
+ return false;
+ }
+
+ mpart.history()->addCommand( comm );
+ mpart.setModified( true );
+
+ killMode();
+ return true;
+}
+
+bool ScriptEditMode::queryCancel()
+{
+ // reverting the original script text
+ static_cast<ObjectConstCalcer*>( mcompiledargs[0] )->switchImp( new StringImp( morigscript ) );
+ mexecargs[0]->calc( mpart.document() );
+
+ mexecuted->calc( mpart.document() );
+ // paranoic check
+ assert( !mexecuted->imp()->inherits( InvalidImp::stype() ) );
+
+ mpart.redrawScreen();
+
+ // no need to further checks here, as the original script text is ok
+
+ killMode();
+ return true;
+}
+
diff --git a/kig/scripting/script_mode.h b/kig/scripting/script_mode.h
new file mode 100644
index 00000000..4cbfd737
--- /dev/null
+++ b/kig/scripting/script_mode.h
@@ -0,0 +1,119 @@
+// Copyright (C) 2003 Dominique Devriese <devriese@kde.org>
+
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+
+// This program 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+
+#ifndef KIG_SCRIPTING_SCRIPT_MODE_H
+#define KIG_SCRIPTING_SCRIPT_MODE_H
+
+#include "script-common.h"
+
+#include "../modes/base_mode.h"
+
+#include <list>
+
+class NewScriptWizard;
+
+/**
+ * Base mode to interact with a script.
+ */
+class ScriptModeBase
+ : public BaseMode
+{
+protected:
+ ScriptModeBase( KigPart& doc );
+
+// mp: argument list is implemented as a std::list instead of std::set
+// because otherwise the user loses the correct argument ordering (in
+// case of more than one argument
+ std::list<ObjectHolder*> margs;
+ NewScriptWizard* mwizard;
+
+ KigPart& mpart;
+
+ enum WAWD { SelectingArgs, EnteringCode };
+ WAWD mwawd;
+
+private:
+ ScriptType::Type mtype;
+
+public:
+ virtual ~ScriptModeBase();
+
+ void dragRect( const QPoint& p, KigWidget& w );
+// void dragObject( const Objects& os, const QPoint& pointClickedOn, KigWidget& w, bool ctrlOrShiftDown );
+ void leftClickedObject( ObjectHolder* o, const QPoint& p,
+ KigWidget& w, bool actrlOrShiftDown );
+ void mouseMoved( const std::vector<ObjectHolder*>& os, const QPoint& p,
+ KigWidget& w, bool shiftpressed );
+ void midClicked( const QPoint&, KigWidget& );
+ void rightClicked( const std::vector<ObjectHolder*>&, const QPoint&, KigWidget& );
+
+ void argsPageEntered();
+ void codePageEntered();
+
+ virtual bool queryFinish() = 0;
+ virtual bool queryCancel() = 0;
+
+ void redrawScreen( KigWidget* w );
+
+ void killMode();
+
+ void enableActions();
+
+ void setScriptType( ScriptType::Type type );
+
+ void addArgs( const std::vector<ObjectHolder*>& obj, KigWidget& w );
+
+ void goToCodePage();
+
+};
+
+/**
+ * Script mode to create a script.
+ */
+class ScriptCreationMode
+ : public ScriptModeBase
+{
+public:
+ ScriptCreationMode( KigPart& doc );
+ virtual ~ScriptCreationMode();
+
+ virtual bool queryFinish();
+ virtual bool queryCancel();
+};
+
+/**
+ * Script mode to edit an already-built script.
+ */
+class ScriptEditMode
+ : public ScriptModeBase
+{
+private:
+ ObjectTypeCalcer* mexecuted;
+ std::vector<ObjectCalcer*> mexecargs;
+ std::vector<ObjectCalcer*> mcompiledargs;
+
+ QString morigscript;
+
+public:
+ ScriptEditMode( ObjectTypeCalcer* exec_calc, KigPart& doc );
+ virtual ~ScriptEditMode();
+
+ virtual bool queryFinish();
+ virtual bool queryCancel();
+};
+
+#endif